1501
1497
'containing %d revisions. Packing %d files into %d affecting %d'
1502
1498
' revisions', self, total_packs, total_revisions, num_old_packs,
1503
1499
num_new_packs, num_revs_affected)
1504
self._execute_pack_operations(pack_operations,
1500
result = self._execute_pack_operations(pack_operations,
1505
1501
reload_func=self._restart_autopack)
1506
1502
mutter('Auto-packing repository %s completed', self)
1509
1505
def _execute_pack_operations(self, pack_operations, _packer_class=Packer,
1510
1506
reload_func=None):
1554
1551
def _already_packed(self):
1555
1552
"""Is the collection already packed?"""
1556
return len(self._names) < 2
1553
return not (self.repo._format.pack_compresses or (len(self._names) > 1))
1555
def pack(self, hint=None):
1559
1556
"""Pack the pack collection totally."""
1560
1557
self.ensure_loaded()
1561
1558
total_packs = len(self._names)
1562
1559
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
1561
total_revisions = self.revision_index.combined_index.key_count()
1568
1562
# XXX: the following may want to be a class, to pack with a given
1570
1564
mutter('Packing repository %s, which has %d pack files, '
1571
'containing %d revisions into 1 packs.', self, total_packs,
1565
'containing %d revisions with hint %r.', self, total_packs,
1566
total_revisions, hint)
1573
1567
# determine which packs need changing
1574
pack_distribution = [1]
1575
1568
pack_operations = [[0, []]]
1576
1569
for pack in self.all_packs():
1577
pack_operations[-1][0] += pack.get_revision_count()
1578
pack_operations[-1][1].append(pack)
1570
if not hint or pack.name in hint:
1571
pack_operations[-1][0] += pack.get_revision_count()
1572
pack_operations[-1][1].append(pack)
1579
1573
self._execute_pack_operations(pack_operations, OptimisingPacker)
1581
1575
def plan_autopack_combinations(self, existing_packs, pack_distribution):
2388
class KnitPackStreamSource(StreamSource):
2389
"""A StreamSource used to transfer data between same-format KnitPack repos.
2391
This source assumes:
2392
1) Same serialization format for all objects
2393
2) Same root information
2394
3) XML format inventories
2395
4) Atomic inserts (so we can stream inventory texts before text
2400
def __init__(self, from_repository, to_format):
2401
super(KnitPackStreamSource, self).__init__(from_repository, to_format)
2402
self._text_keys = None
2403
self._text_fetch_order = 'unordered'
2405
def _get_filtered_inv_stream(self, revision_ids):
2406
from_repo = self.from_repository
2407
parent_ids = from_repo._find_parent_ids_of_revisions(revision_ids)
2408
parent_keys = [(p,) for p in parent_ids]
2409
find_text_keys = from_repo._find_text_key_references_from_xml_inventory_lines
2410
parent_text_keys = set(find_text_keys(
2411
from_repo._inventory_xml_lines_for_keys(parent_keys)))
2412
content_text_keys = set()
2413
knit = KnitVersionedFiles(None, None)
2414
factory = KnitPlainFactory()
2415
def find_text_keys_from_content(record):
2416
if record.storage_kind not in ('knit-delta-gz', 'knit-ft-gz'):
2417
raise ValueError("Unknown content storage kind for"
2418
" inventory text: %s" % (record.storage_kind,))
2419
# It's a knit record, it has a _raw_record field (even if it was
2420
# reconstituted from a network stream).
2421
raw_data = record._raw_record
2422
# read the entire thing
2423
revision_id = record.key[-1]
2424
content, _ = knit._parse_record(revision_id, raw_data)
2425
if record.storage_kind == 'knit-delta-gz':
2426
line_iterator = factory.get_linedelta_content(content)
2427
elif record.storage_kind == 'knit-ft-gz':
2428
line_iterator = factory.get_fulltext_content(content)
2429
content_text_keys.update(find_text_keys(
2430
[(line, revision_id) for line in line_iterator]))
2431
revision_keys = [(r,) for r in revision_ids]
2432
def _filtered_inv_stream():
2433
source_vf = from_repo.inventories
2434
stream = source_vf.get_record_stream(revision_keys,
2436
for record in stream:
2437
if record.storage_kind == 'absent':
2438
raise errors.NoSuchRevision(from_repo, record.key)
2439
find_text_keys_from_content(record)
2441
self._text_keys = content_text_keys - parent_text_keys
2442
return ('inventories', _filtered_inv_stream())
2444
def _get_text_stream(self):
2445
# Note: We know we don't have to handle adding root keys, because both
2446
# the source and target are the identical network name.
2447
text_stream = self.from_repository.texts.get_record_stream(
2448
self._text_keys, self._text_fetch_order, False)
2449
return ('texts', text_stream)
2451
def get_stream(self, search):
2452
revision_ids = search.get_keys()
2453
for stream_info in self._fetch_revision_texts(revision_ids):
2455
self._revision_keys = [(rev_id,) for rev_id in revision_ids]
2456
yield self._get_filtered_inv_stream(revision_ids)
2457
yield self._get_text_stream()
2387
2461
class RepositoryFormatPack(MetaDirRepositoryFormat):
2388
2462
"""Format logic for pack structured repositories.