564
564
# _copy_inventory_texts
565
565
self._text_filter = None
566
566
self._extra_init()
567
self._pack_ordering = None
569
568
def _extra_init(self):
570
569
"""A template hook to allow extending the constructor trivially."""
572
def _packs_list_to_pack_map_and_index_list(self, packs, index_attribute):
571
def _pack_map_and_index_list(self, index_attribute, include_pack_obj=False):
573
572
"""Convert a list of packs to an index pack map and index list.
575
:param packs: The packs list to process.
576
574
:param index_attribute: The attribute that the desired index is found
578
576
:return: A tuple (map, list) where map contains the dict from
579
index:pack_tuple, and lsit contains the indices in the same order
577
index:pack_tuple, and lsit contains the indices in the preferred
585
index = getattr(pack, index_attribute)
582
for pack_obj in self.packs:
583
index = getattr(pack_obj, index_attribute)
586
584
indices.append(index)
587
pack_map[index] = pack.access_tuple()
585
pack_map[index] = pack_obj
588
586
return pack_map, indices
590
def _index_contents(self, pack_map, key_filter=None):
588
def _index_contents(self, indices, key_filter=None):
591
589
"""Get an iterable of the index contents from a pack_map.
593
:param pack_map: A map from indices to pack details.
594
:param key_filter: An optional filter to limit the
591
:param indices: The list of indices to query
592
:param key_filter: An optional filter to limit the keys returned.
597
indices = [index for index in pack_map.iterkeys()]
598
594
all_index = CombinedGraphIndex(indices)
599
595
if key_filter is None:
600
596
return all_index.iter_all_entries()
649
645
index_builder_class=self._pack_collection._index_builder_class,
650
646
index_class=self._pack_collection._index_class)
648
def _update_pack_order(self, entries, index_to_pack_map):
649
"""Determine how we want our packs to be ordered.
651
This changes the sort order of self.packs, based on the order found in
652
'entries'. This is mostly used to move unused packs to the end of the
653
list, so that future requests can avoid probing them.
655
:param entries: A list of (index, ...) tuples
656
:param index_to_pack_map: A mapping from index objects to pack objects.
660
for entry in entries:
662
if index not in seen_indexes:
663
packs.append(index_to_pack_map[index])
664
seen_indexes.add(index)
665
if len(packs) == len(self.packs):
666
if 'pack' in debug.debug_flags:
667
mutter('Not changing pack list, all packs used.')
669
seen_packs = set(packs)
670
for pack in self.packs:
671
if pack not in seen_packs:
674
if 'pack' in debug.debug_flags:
675
old_names = [p.access_tuple()[1] for p in self.packs]
676
new_names = [p.access_tuple()[1] for p in packs]
677
mutter('Reordering packs\nfrom: %s\n to: %s',
678
old_names, new_names)
652
681
def _copy_revision_texts(self):
653
682
"""Copy revision data to the new pack."""
654
683
# select revisions
658
687
revision_keys = None
659
688
# select revision keys
660
revision_index_map = self._packs_list_to_pack_map_and_index_list(
661
self.packs, 'revision_index')[0]
662
revision_nodes = self._index_contents(revision_index_map, revision_keys)
689
revision_index_map, revision_indices = self._pack_map_and_index_list(
691
revision_nodes = self._index_contents(revision_indices, revision_keys)
692
revision_nodes = list(revision_nodes)
693
self._update_pack_order(revision_nodes, revision_index_map)
663
694
# copy revision keys and adjust values
664
695
self.pb.update("Copying revision texts", 1)
665
696
total_items, readv_group_iter = self._revision_node_readv(revision_nodes)
685
716
# querying for keys here could introduce a bug where an inventory item
686
717
# is missed, so do not change it to query separately without cross
687
718
# checking like the text key check below.
688
inventory_index_map = self._packs_list_to_pack_map_and_index_list(
689
self.packs, 'inventory_index')[0]
690
inv_nodes = self._index_contents(inventory_index_map, inv_keys)
719
inventory_index_map, inventory_indices = self._pack_map_and_index_list(
721
inv_nodes = self._index_contents(inventory_indices, inv_keys)
691
722
# copy inventory keys and adjust values
692
723
# XXX: Should be a helper function to allow different inv representation
773
804
self._copy_text_texts()
774
805
# select signature keys
775
806
signature_filter = self._revision_keys # same keyspace
776
signature_index_map = self._packs_list_to_pack_map_and_index_list(
777
self.packs, 'signature_index')[0]
778
signature_nodes = self._index_contents(signature_index_map,
807
signature_index_map, signature_indices = self._pack_map_and_index_list(
809
signature_nodes = self._index_contents(signature_indices,
779
810
signature_filter)
780
811
# copy signature keys and adjust values
781
812
self.pb.update("Copying signature texts", 4)
831
862
# linear scan up the pack
832
863
pack_readv_requests.sort()
834
transport, path = index_map[index]
865
pack_obj = index_map[index]
866
transport, path = pack_obj.access_tuple()
835
867
reader = pack.make_readv_reader(transport, path,
836
868
[offset[0:2] for offset in pack_readv_requests])
837
869
for (names, read_func), (_1, _2, (key, eol_flag)) in \
875
907
pb.update("Copied record", record_index, total_items)
876
908
for index, readv_vector, node_vector in readv_group_iter:
878
transport, path = index_map[index]
910
pack_obj = index_map[index]
911
transport, path = pack_obj.access_tuple()
879
912
reader = pack.make_readv_reader(transport, path, readv_vector)
880
913
for (names, read_func), (key, eol_flag, references) in \
881
914
izip(reader.iter_records(), node_vector):
899
932
record_index += 1
901
934
def _get_text_nodes(self):
902
text_index_map = self._packs_list_to_pack_map_and_index_list(
903
self.packs, 'text_index')[0]
904
return text_index_map, self._index_contents(text_index_map,
935
text_index_map, text_indices = self._pack_map_and_index_list(
937
return text_index_map, self._index_contents(text_indices,
905
938
self._text_filter)
907
940
def _least_readv_node_readv(self, nodes):
1253
1286
# XXX: the following may want to be a class, to pack with a given
1255
mutter('Auto-packing repository %s, which has %d pack files, '
1256
'containing %d revisions into %d packs.', self, total_packs,
1257
total_revisions, self._max_pack_count(total_revisions))
1258
1288
# determine which packs need changing
1259
1289
pack_distribution = self.pack_distribution(total_revisions)
1260
1290
existing_packs = []
1275
1305
existing_packs.append((revision_count, pack))
1276
1306
pack_operations = self.plan_autopack_combinations(
1277
1307
existing_packs, pack_distribution)
1308
num_new_packs = len(pack_operations)
1309
num_old_packs = sum([len(po[1]) for po in pack_operations])
1310
num_revs_effected = sum([po[0] for po in pack_operations])
1311
mutter('Auto-packing repository %s, which has %d pack files, '
1312
'containing %d revisions. Packing %d files into %d effecting %d'
1313
' revisions', self, total_packs, total_revisions, num_old_packs,
1314
num_new_packs, num_revs_effected)
1278
1315
self._execute_pack_operations(pack_operations)