137
137
self._pack_transport = pack_transport
138
138
self._suffix_offsets = {'.rix':0, '.iix':1, '.tix':2, '.six':3}
141
143
def add_pack_to_memory(self, pack):
142
144
"""Make a Pack object available to the repository to satisfy queries.
144
146
:param pack: A Pack object.
146
148
self.packs.append(pack)
149
assert pack.name not in self._packs
150
self._packs[pack.name] = pack
147
151
if self.repo._revision_all_indices is None:
148
152
# to make this function more useful, perhaps we should make an
149
153
# all_indices object in future?
189
193
for name in self.names():
190
result.append(Pack(self._pack_transport, name, None, None, None))
194
result.append(self.get_pack_by_name(name))
193
197
def all_pack_details(self):
252
256
# one revision for each to the total revision count, to get
253
257
# a matching distribution.
255
existing_packs.append((revision_count, transport_and_name))
259
existing_packs.append((revision_count, transport_and_name,
260
self.get_pack_by_name(transport_and_name[1])))
256
261
pack_operations = self.plan_autopack_combinations(
257
262
existing_packs, pack_distribution)
258
263
self._execute_pack_operations(pack_operations)
481
486
:param pack_operations: A list of [revision_count, packs_to_combine].
484
for revision_count, pack_details in pack_operations:
489
for revision_count, pack_list in pack_operations:
485
490
# we may have no-ops from the setup logic
486
if len(pack_details) == 0:
491
if len(pack_list) == 0:
488
493
# have a progress bar?
489
self._combine_packs(pack_details)
494
pack_details = [details for details,_ in pack_list]
495
packs = [pack for _, pack in pack_list]
496
assert pack_details[0].__class__ == tuple
497
self._combine_packs(pack_details, packs)
490
498
for pack_detail in pack_details:
491
499
self._remove_pack_by_name(pack_detail[1])
492
500
# record the newly available packs and stop advertising the old
494
502
self._save_pack_names()
495
503
# move the old packs out of the way
496
for revision_count, pack_details in pack_operations:
504
for revision_count, pack_list in pack_operations:
505
pack_details = [details for details,_ in pack_list]
497
506
self._obsolete_packs(pack_details)
521
530
revision_count = index.key_count()
522
531
pack_operations[-1][0] += revision_count
523
pack_operations[-1][1].append(transport_and_name)
532
pack_operations[-1][1].append((transport_and_name,
533
self.get_pack_by_name(transport_and_name[1])))
524
534
self._execute_pack_operations(pack_operations)
526
536
if not self.repo.is_in_write_group():
529
539
def plan_autopack_combinations(self, existing_packs, pack_distribution):
540
"""Plan a pack operation.
542
:param existing_packs: The packs to pack.
543
:parma pack_distribution: A list with the number of revisions desired
530
546
if len(existing_packs) <= len(pack_distribution):
532
548
existing_packs.sort(reverse=True)
537
553
# distribution chart we will include its contents in the new pack for
538
554
# that position. If its larger, we remove its size from the
539
555
# distribution chart
540
next_pack_rev_count, next_pack_details = existing_packs.pop(0)
556
next_pack_rev_count, next_pack_details, next_pack = existing_packs.pop(0)
541
557
if next_pack_rev_count >= pack_distribution[0]:
542
558
# this is already packed 'better' than this, so we can
543
559
# not waste time packing it.
553
569
# add the revisions we're going to add to the next output pack
554
570
pack_operations[-1][0] += next_pack_rev_count
555
571
# allocate this pack to the next pack sub operation
556
pack_operations[-1][1].append(next_pack_details)
572
pack_operations[-1][1].append((next_pack_details, next_pack))
557
573
if pack_operations[-1][0] >= pack_distribution[0]:
558
574
# this pack is used up, shift left.
559
575
del pack_distribution[0]
562
578
return pack_operations
564
def _combine_packs(self, pack_details):
580
def _combine_packs(self, pack_details, packs):
565
581
"""Combine the data from the packs listed in pack_details.
567
583
This does little more than a bulk copy of data. One key difference
683
699
sizes = [int(digits) for digits in value.split(' ')]
684
700
self._names[name] = sizes
702
def get_pack_by_name(self, name):
703
"""Get a Pack object by name.
705
:param name: The name of the pack - e.g. '123456'
706
:return: A Pack object.
709
return self._packs[name]
711
rev_index = self._make_index(name, '.rix')
712
inv_index = self._make_index(name, '.iix')
713
txt_index = self._make_index(name, '.tix')
714
sig_index = self._make_index(name, '.six')
715
result = Pack(self._pack_transport, name, rev_index, inv_index,
716
txt_index, sig_index)
717
self._packs[name] = result
686
720
def allocate(self, name, revision_index_length, inventory_index_length,
687
721
text_index_length, signature_index_length):
688
722
"""Allocate name in the list of packs.
711
745
objects, and pack_map is a mapping from those objects to the
712
746
pack tuple they describe.
714
size_offset = self._suffix_offsets[suffix]
717
748
self.ensure_loaded()
718
750
for name in self.names():
719
751
# TODO: maybe this should expose size to us to allow
720
752
# sorting of the indices for better performance ?
721
index_name = name + suffix
722
index_size = self._names[name][size_offset]
723
new_index = GraphIndex(
724
self._index_transport, index_name, index_size)
725
indices.append(new_index)
726
pack_map[new_index] = self._pack_tuple(name)
727
return pack_map, indices
753
details.append(self._pack_tuple(name))
754
return self._make_index_to_pack_map(details, suffix)
756
def _make_index(self, name, suffix):
757
size_offset = self._suffix_offsets[suffix]
758
index_name = name + suffix
759
index_size = self._names[name][size_offset]
761
self._index_transport, index_name, index_size)
729
763
def _max_pack_count(self, total_revisions):
730
764
"""Return the maximum number of packs to use for total revisions.
802
837
# this should really reuse the existing index objects for these
803
838
# packs - this means making the way they are managed in the repo be
805
size_offset = self._suffix_offsets[index_suffix]
807
843
for transport, name in pack_details:
808
844
index_name = name[:-5] + index_suffix
809
index_size = self._names[index_name][index_size]
810
indices[GraphIndex(self._index_transport, index_name, index_size)] = \
845
new_index = self._make_index(index_name, index_suffix)
846
indices.append(new_index)
847
pack_map[new_index] = (transport, name)
848
return pack_map, indices
814
850
def _inv_index_map(self, pack_details):
815
851
"""Get a map of inv index -> packs for pack_details."""
816
return self._make_index_to_pack_map(pack_details, '.iix')
852
return self._make_index_to_pack_map(pack_details, '.iix')[0]
818
def _revision_index_map(self, pack_details):
854
def _revision_index_map(self, pack_details, packs):
819
855
"""Get a map of revision index -> packs for pack_details."""
820
return self._make_index_to_pack_map(pack_details, '.rix')
856
return self._make_index_to_pack_map(pack_details, '.rix')[0]
822
858
def _signature_index_map(self, pack_details):
823
859
"""Get a map of signature index -> packs for pack_details."""
824
return self._make_index_to_pack_map(pack_details, '.six')
860
return self._make_index_to_pack_map(pack_details, '.six')[0]
826
862
def _text_index_map(self, pack_details):
827
863
"""Get a map of text index -> packs for pack_details."""
828
return self._make_index_to_pack_map(pack_details, '.tix')
864
return self._make_index_to_pack_map(pack_details, '.tix')[0]
830
866
def _index_contents(self, pack_map, key_filter=None):
831
867
"""Get an iterable of the index contents from a pack_map.