1501
1504
'containing %d revisions. Packing %d files into %d affecting %d'
1502
1505
' revisions', self, total_packs, total_revisions, num_old_packs,
1503
1506
num_new_packs, num_revs_affected)
1504
self._execute_pack_operations(pack_operations,
1507
result = self._execute_pack_operations(pack_operations,
1505
1508
reload_func=self._restart_autopack)
1506
1509
mutter('Auto-packing repository %s completed', self)
1509
1512
def _execute_pack_operations(self, pack_operations, _packer_class=Packer,
1510
1513
reload_func=None):
1554
1558
def _already_packed(self):
1555
1559
"""Is the collection already packed?"""
1556
return len(self._names) < 2
1560
return not (self.repo._format.pack_compresses or (len(self._names) > 1))
1562
def pack(self, hint=None):
1559
1563
"""Pack the pack collection totally."""
1560
1564
self.ensure_loaded()
1561
1565
total_packs = len(self._names)
1562
1566
if self._already_packed():
1563
# This is arguably wrong because we might not be optimal, but for
1564
# now lets leave it in. (e.g. reconcile -> one pack. But not
1567
1568
total_revisions = self.revision_index.combined_index.key_count()
1568
1569
# XXX: the following may want to be a class, to pack with a given
1570
1571
mutter('Packing repository %s, which has %d pack files, '
1571
'containing %d revisions into 1 packs.', self, total_packs,
1572
'containing %d revisions with hint %r.', self, total_packs,
1573
total_revisions, hint)
1573
1574
# determine which packs need changing
1574
pack_distribution = [1]
1575
1575
pack_operations = [[0, []]]
1576
1576
for pack in self.all_packs():
1577
pack_operations[-1][0] += pack.get_revision_count()
1578
pack_operations[-1][1].append(pack)
1577
if hint is None or pack.name in hint:
1578
# Either no hint was provided (so we are packing everything),
1579
# or this pack was included in the hint.
1580
pack_operations[-1][0] += pack.get_revision_count()
1581
pack_operations[-1][1].append(pack)
1579
1582
self._execute_pack_operations(pack_operations, OptimisingPacker)
1581
1584
def plan_autopack_combinations(self, existing_packs, pack_distribution):
2219
2225
self.revisions._index._key_dependencies.refs.clear()
2220
2226
self._pack_collection._abort_write_group()
2222
def _find_inconsistent_revision_parents(self):
2223
"""Find revisions with incorrectly cached parents.
2225
:returns: an iterator yielding tuples of (revison-id, parents-in-index,
2226
parents-in-revision).
2228
if not self.is_locked():
2229
raise errors.ObjectNotLocked(self)
2230
pb = ui.ui_factory.nested_progress_bar()
2233
revision_nodes = self._pack_collection.revision_index \
2234
.combined_index.iter_all_entries()
2235
index_positions = []
2236
# Get the cached index values for all revisions, and also the
2237
# location in each index of the revision text so we can perform
2239
for index, key, value, refs in revision_nodes:
2240
node = (index, key, value, refs)
2241
index_memo = self.revisions._index._node_to_position(node)
2242
if index_memo[0] != index:
2243
raise AssertionError('%r != %r' % (index_memo[0], index))
2244
index_positions.append((index_memo, key[0],
2245
tuple(parent[0] for parent in refs[0])))
2246
pb.update("Reading revision index", 0, 0)
2247
index_positions.sort()
2249
pb.update("Checking cached revision graph", 0,
2250
len(index_positions))
2251
for offset in xrange(0, len(index_positions), 1000):
2252
pb.update("Checking cached revision graph", offset)
2253
to_query = index_positions[offset:offset + batch_size]
2256
rev_ids = [item[1] for item in to_query]
2257
revs = self.get_revisions(rev_ids)
2258
for revision, item in zip(revs, to_query):
2259
index_parents = item[2]
2260
rev_parents = tuple(revision.parent_ids)
2261
if index_parents != rev_parents:
2262
result.append((revision.revision_id, index_parents,
2228
def _get_source(self, to_format):
2229
if to_format.network_name() == self._format.network_name():
2230
return KnitPackStreamSource(self, to_format)
2231
return super(KnitPackRepository, self)._get_source(to_format)
2268
2233
def _make_parents_provider(self):
2269
2234
return graph.CachingParentsProvider(self)
2352
class KnitPackStreamSource(StreamSource):
2353
"""A StreamSource used to transfer data between same-format KnitPack repos.
2355
This source assumes:
2356
1) Same serialization format for all objects
2357
2) Same root information
2358
3) XML format inventories
2359
4) Atomic inserts (so we can stream inventory texts before text
2364
def __init__(self, from_repository, to_format):
2365
super(KnitPackStreamSource, self).__init__(from_repository, to_format)
2366
self._text_keys = None
2367
self._text_fetch_order = 'unordered'
2369
def _get_filtered_inv_stream(self, revision_ids):
2370
from_repo = self.from_repository
2371
parent_ids = from_repo._find_parent_ids_of_revisions(revision_ids)
2372
parent_keys = [(p,) for p in parent_ids]
2373
find_text_keys = from_repo._find_text_key_references_from_xml_inventory_lines
2374
parent_text_keys = set(find_text_keys(
2375
from_repo._inventory_xml_lines_for_keys(parent_keys)))
2376
content_text_keys = set()
2377
knit = KnitVersionedFiles(None, None)
2378
factory = KnitPlainFactory()
2379
def find_text_keys_from_content(record):
2380
if record.storage_kind not in ('knit-delta-gz', 'knit-ft-gz'):
2381
raise ValueError("Unknown content storage kind for"
2382
" inventory text: %s" % (record.storage_kind,))
2383
# It's a knit record, it has a _raw_record field (even if it was
2384
# reconstituted from a network stream).
2385
raw_data = record._raw_record
2386
# read the entire thing
2387
revision_id = record.key[-1]
2388
content, _ = knit._parse_record(revision_id, raw_data)
2389
if record.storage_kind == 'knit-delta-gz':
2390
line_iterator = factory.get_linedelta_content(content)
2391
elif record.storage_kind == 'knit-ft-gz':
2392
line_iterator = factory.get_fulltext_content(content)
2393
content_text_keys.update(find_text_keys(
2394
[(line, revision_id) for line in line_iterator]))
2395
revision_keys = [(r,) for r in revision_ids]
2396
def _filtered_inv_stream():
2397
source_vf = from_repo.inventories
2398
stream = source_vf.get_record_stream(revision_keys,
2400
for record in stream:
2401
if record.storage_kind == 'absent':
2402
raise errors.NoSuchRevision(from_repo, record.key)
2403
find_text_keys_from_content(record)
2405
self._text_keys = content_text_keys - parent_text_keys
2406
return ('inventories', _filtered_inv_stream())
2408
def _get_text_stream(self):
2409
# Note: We know we don't have to handle adding root keys, because both
2410
# the source and target are the identical network name.
2411
text_stream = self.from_repository.texts.get_record_stream(
2412
self._text_keys, self._text_fetch_order, False)
2413
return ('texts', text_stream)
2415
def get_stream(self, search):
2416
revision_ids = search.get_keys()
2417
for stream_info in self._fetch_revision_texts(revision_ids):
2419
self._revision_keys = [(rev_id,) for rev_id in revision_ids]
2420
yield self._get_filtered_inv_stream(revision_ids)
2421
yield self._get_text_stream()
2387
2425
class RepositoryFormatPack(MetaDirRepositoryFormat):
2388
2426
"""Format logic for pack structured repositories.
2526
2561
_matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
2528
def check_conversion_target(self, target_format):
2529
if not target_format.rich_root_data:
2530
raise errors.BadConversionTarget(
2531
'Does not support rich root data.', target_format)
2532
if not getattr(target_format, 'supports_tree_reference', False):
2533
raise errors.BadConversionTarget(
2534
'Does not support nested trees', target_format)
2536
2563
def get_format_string(self):
2537
2564
"""See RepositoryFormat.get_format_string()."""
2538
2565
return "Bazaar pack repository format 1 with subtree support (needs bzr 0.92)\n"
2835
2836
_matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
2837
def check_conversion_target(self, target_format):
2838
if not target_format.rich_root_data:
2839
raise errors.BadConversionTarget(
2840
'Does not support rich root data.', target_format)
2841
if not getattr(target_format, 'supports_tree_reference', False):
2842
raise errors.BadConversionTarget(
2843
'Does not support nested trees', target_format)
2845
2838
def get_format_string(self):
2846
2839
"""See RepositoryFormat.get_format_string()."""
2847
2840
return ("Bazaar development format 2 with subtree support "