~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repofmt/pack_repo.py

  • Committer: Robert Collins
  • Date: 2007-10-10 05:48:02 UTC
  • mto: This revision was merged to the branch mainline in revision 2933.
  • Revision ID: robertc@robertcollins.net-20071010054802-raogpryl9kq6t7ea
Various pack refactorings.

Show diffs side-by-side

added added

removed removed

Lines of Context:
137
137
        self._pack_transport = pack_transport
138
138
        self._suffix_offsets = {'.rix':0, '.iix':1, '.tix':2, '.six':3}
139
139
        self.packs = []
 
140
        # name:Pack mapping
 
141
        self._packs = {}
140
142
 
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.
145
147
        """
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?
187
191
        """
188
192
        result = []
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))
191
195
        return result
192
196
 
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.
254
258
                continue
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].
482
487
        :return: None.
483
488
        """
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:
487
492
                continue
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
493
501
        # packs
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)
498
507
 
499
508
    def pack(self):
520
529
                    continue
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)
525
535
        finally:
526
536
            if not self.repo.is_in_write_group():
527
537
                self.reset()
528
538
 
529
539
    def plan_autopack_combinations(self, existing_packs, pack_distribution):
 
540
        """Plan a pack operation.
 
541
 
 
542
        :param existing_packs: The packs to pack.
 
543
        :parma pack_distribution: A list with the number of revisions desired
 
544
            in each pack.
 
545
        """
530
546
        if len(existing_packs) <= len(pack_distribution):
531
547
            return []
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]
561
577
        
562
578
        return pack_operations
563
579
 
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.
566
582
 
567
583
        This does little more than a bulk copy of data. One key difference
575
591
        :return: None
576
592
        """
577
593
        # select revision keys
578
 
        revision_index_map = self._revision_index_map(pack_details)
 
594
        revision_index_map = self._revision_index_map(pack_details, packs)
579
595
        # select inventory keys
580
596
        inv_index_map = self._inv_index_map(pack_details)
581
597
        # select text keys
683
699
                sizes = [int(digits) for digits in value.split(' ')]
684
700
                self._names[name] = sizes
685
701
 
 
702
    def get_pack_by_name(self, name):
 
703
        """Get a Pack object by name.
 
704
 
 
705
        :param name: The name of the pack - e.g. '123456'
 
706
        :return: A Pack object.
 
707
        """
 
708
        try:
 
709
            return self._packs[name]
 
710
        except KeyError:
 
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
 
718
            return result
 
719
 
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.
713
747
        """
714
 
        size_offset = self._suffix_offsets[suffix]
715
 
        indices = []
716
 
        pack_map = {}
717
748
        self.ensure_loaded()
 
749
        details = []
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)
 
755
 
 
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]
 
760
        return GraphIndex(
 
761
            self._index_transport, index_name, index_size)
728
762
 
729
763
    def _max_pack_count(self, total_revisions):
730
764
        """Return the maximum number of packs to use for total revisions.
795
829
    def reset(self):
796
830
        self._names = None
797
831
        self.packs = []
 
832
        self._packs = {}
798
833
 
799
834
    def _make_index_to_pack_map(self, pack_details, index_suffix):
800
835
        """Given a list (transport,name), return a map of (index)->(transport, name)."""
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 
804
839
        # more sane.
805
 
        size_offset = self._suffix_offsets[index_suffix]
806
 
        indices = {}
 
840
        indices = []
 
841
        pack_map = {}
 
842
        self.ensure_loaded()
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)] = \
811
 
                (transport, name)
812
 
        return indices
 
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
813
849
 
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]
817
853
 
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]
821
857
 
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]
825
861
 
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]
829
865
 
830
866
    def _index_contents(self, pack_map, key_filter=None):
831
867
        """Get an iterable of the index contents from a pack_map.