~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

  • Committer: Andrew Bennetts
  • Date: 2009-08-25 01:25:57 UTC
  • mfrom: (4642 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4657.
  • Revision ID: andrew.bennetts@canonical.com-20090825012557-1ku5o09nv3ra9n12
Merge from bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
3732
3732
            return False
3733
3733
        return True
3734
3734
 
3735
 
    def _get_delta_for_revision(self, tree, parent_ids, basis_id, cache):
 
3735
    def _get_trees(self, revision_ids, cache):
 
3736
        possible_trees = []
 
3737
        for rev_id in revision_ids:
 
3738
            if rev_id in cache:
 
3739
                possible_trees.append((rev_id, cache[rev_id]))
 
3740
            else:
 
3741
                # Not cached, but inventory might be present anyway.
 
3742
                try:
 
3743
                    tree = self.source.revision_tree(rev_id)
 
3744
                except errors.NoSuchRevision:
 
3745
                    # Nope, parent is ghost.
 
3746
                    pass
 
3747
                else:
 
3748
                    cache[rev_id] = tree
 
3749
                    possible_trees.append((rev_id, tree))
 
3750
        return possible_trees
 
3751
 
 
3752
    def _get_delta_for_revision(self, tree, parent_ids, possible_trees):
3736
3753
        """Get the best delta and base for this revision.
3737
3754
 
3738
3755
        :return: (basis_id, delta)
3739
3756
        """
3740
 
        possible_trees = [(parent_id, cache[parent_id])
3741
 
                          for parent_id in parent_ids
3742
 
                           if parent_id in cache]
3743
 
        if len(possible_trees) == 0:
3744
 
            # There either aren't any parents, or the parents aren't in the
3745
 
            # cache, so just use the last converted tree
3746
 
            possible_trees.append((basis_id, cache[basis_id]))
3747
3757
        deltas = []
 
3758
        # Generate deltas against each tree, to find the shortest.
 
3759
        texts_possibly_new_in_tree = set()
3748
3760
        for basis_id, basis_tree in possible_trees:
3749
3761
            delta = tree.inventory._make_delta(basis_tree.inventory)
 
3762
            for old_path, new_path, file_id, new_entry in delta:
 
3763
                if new_path is None:
 
3764
                    # This file_id isn't present in the new rev, so we don't
 
3765
                    # care about it.
 
3766
                    continue
 
3767
                if not new_path:
 
3768
                    # Rich roots are handled elsewhere...
 
3769
                    continue
 
3770
                kind = new_entry.kind
 
3771
                if kind != 'directory' and kind != 'file':
 
3772
                    # No text record associated with this inventory entry.
 
3773
                    continue
 
3774
                # This is a directory or file that has changed somehow.
 
3775
                texts_possibly_new_in_tree.add((file_id, new_entry.revision))
3750
3776
            deltas.append((len(delta), basis_id, delta))
3751
3777
        deltas.sort()
3752
3778
        return deltas[0][1:]
3753
3779
 
 
3780
    def _fetch_parent_invs_for_stacking(self, parent_map, cache):
 
3781
        """Find all parent revisions that are absent, but for which the
 
3782
        inventory is present, and copy those inventories.
 
3783
 
 
3784
        This is necessary to preserve correctness when the source is stacked
 
3785
        without fallbacks configured.  (Note that in cases like upgrade the
 
3786
        source may be not have _fallback_repositories even though it is
 
3787
        stacked.)
 
3788
        """
 
3789
        parent_revs = set()
 
3790
        for parents in parent_map.values():
 
3791
            parent_revs.update(parents)
 
3792
        present_parents = self.source.get_parent_map(parent_revs)
 
3793
        absent_parents = set(parent_revs).difference(present_parents)
 
3794
        parent_invs_keys_for_stacking = self.source.inventories.get_parent_map(
 
3795
            (rev_id,) for rev_id in absent_parents)
 
3796
        parent_inv_ids = [key[-1] for key in parent_invs_keys_for_stacking]
 
3797
        for parent_tree in self.source.revision_trees(parent_inv_ids):
 
3798
            current_revision_id = parent_tree.get_revision_id()
 
3799
            parents_parents_keys = parent_invs_keys_for_stacking[
 
3800
                (current_revision_id,)]
 
3801
            parents_parents = [key[-1] for key in parents_parents_keys]
 
3802
            basis_id = _mod_revision.NULL_REVISION
 
3803
            basis_tree = self.source.revision_tree(basis_id)
 
3804
            delta = parent_tree.inventory._make_delta(basis_tree.inventory)
 
3805
            self.target.add_inventory_by_delta(
 
3806
                basis_id, delta, current_revision_id, parents_parents)
 
3807
            cache[current_revision_id] = parent_tree
 
3808
 
3754
3809
    def _fetch_batch(self, revision_ids, basis_id, cache):
3755
3810
        """Fetch across a few revisions.
3756
3811
 
3769
3824
        pending_deltas = []
3770
3825
        pending_revisions = []
3771
3826
        parent_map = self.source.get_parent_map(revision_ids)
 
3827
        self._fetch_parent_invs_for_stacking(parent_map, cache)
3772
3828
        for tree in self.source.revision_trees(revision_ids):
 
3829
            # Find a inventory delta for this revision.
 
3830
            # Find text entries that need to be copied, too.
3773
3831
            current_revision_id = tree.get_revision_id()
3774
3832
            parent_ids = parent_map.get(current_revision_id, ())
 
3833
            parent_trees = self._get_trees(parent_ids, cache)
 
3834
            possible_trees = list(parent_trees)
 
3835
            if len(possible_trees) == 0:
 
3836
                # There either aren't any parents, or the parents are ghosts,
 
3837
                # so just use the last converted tree.
 
3838
                possible_trees.append((basis_id, cache[basis_id]))
3775
3839
            basis_id, delta = self._get_delta_for_revision(tree, parent_ids,
3776
 
                                                           basis_id, cache)
 
3840
                                                           possible_trees)
3777
3841
            if self._converting_to_rich_root:
3778
3842
                self._revision_id_to_root_id[current_revision_id] = \
3779
3843
                    tree.get_root_id()
3780
 
            # Find text entries that need to be copied
 
3844
            # Determine which texts are in present in this revision but not in
 
3845
            # any of the available parents.
 
3846
            texts_possibly_new_in_tree = set()
3781
3847
            for old_path, new_path, file_id, entry in delta:
3782
 
                if new_path is not None:
3783
 
                    if not new_path:
3784
 
                        # This is the root
3785
 
                        if not self.target.supports_rich_root():
3786
 
                            # The target doesn't support rich root, so we don't
3787
 
                            # copy
3788
 
                            continue
3789
 
                        if self._converting_to_rich_root:
3790
 
                            # This can't be copied normally, we have to insert
3791
 
                            # it specially
3792
 
                            root_keys_to_create.add((file_id, entry.revision))
3793
 
                            continue
3794
 
                    text_keys.add((file_id, entry.revision))
 
3848
                if new_path is None:
 
3849
                    # This file_id isn't present in the new rev
 
3850
                    continue
 
3851
                if not new_path:
 
3852
                    # This is the root
 
3853
                    if not self.target.supports_rich_root():
 
3854
                        # The target doesn't support rich root, so we don't
 
3855
                        # copy
 
3856
                        continue
 
3857
                    if self._converting_to_rich_root:
 
3858
                        # This can't be copied normally, we have to insert
 
3859
                        # it specially
 
3860
                        root_keys_to_create.add((file_id, entry.revision))
 
3861
                        continue
 
3862
                kind = entry.kind
 
3863
                texts_possibly_new_in_tree.add((file_id, entry.revision))
 
3864
            for basis_id, basis_tree in possible_trees:
 
3865
                basis_inv = basis_tree.inventory
 
3866
                for file_key in list(texts_possibly_new_in_tree):
 
3867
                    file_id, file_revision = file_key
 
3868
                    try:
 
3869
                        entry = basis_inv[file_id]
 
3870
                    except errors.NoSuchId:
 
3871
                        continue
 
3872
                    if entry.revision == file_revision:
 
3873
                        texts_possibly_new_in_tree.remove(file_key)
 
3874
            text_keys.update(texts_possibly_new_in_tree)
3795
3875
            revision = self.source.get_revision(current_revision_id)
3796
3876
            pending_deltas.append((basis_id, delta,
3797
3877
                current_revision_id, revision.parent_ids))
3833
3913
            for parent_tree in self.source.revision_trees(parent_map):
3834
3914
                current_revision_id = parent_tree.get_revision_id()
3835
3915
                parents_parents = parent_map[current_revision_id]
 
3916
                possible_trees = self._get_trees(parents_parents, cache)
 
3917
                if len(possible_trees) == 0:
 
3918
                    # There either aren't any parents, or the parents are
 
3919
                    # ghosts, so just use the last converted tree.
 
3920
                    possible_trees.append((basis_id, cache[basis_id]))
3836
3921
                basis_id, delta = self._get_delta_for_revision(parent_tree,
3837
 
                    parents_parents, basis_id, cache)
 
3922
                    parents_parents, possible_trees)
3838
3923
                self.target.add_inventory_by_delta(
3839
3924
                    basis_id, delta, current_revision_id, parents_parents)
3840
3925
        # insert signatures and revisions