~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

(jam) Tweak the delta base selection for InterDifferingSerializer
        conversions.

Show diffs side-by-side

added added

removed removed

Lines of Context:
3232
3232
            return False
3233
3233
        return True
3234
3234
 
3235
 
    def _fetch_batch(self, revision_ids, basis_id, basis_tree):
 
3235
    def _get_delta_for_revision(self, tree, parent_ids, basis_id, cache):
 
3236
        """Get the best delta and base for this revision.
 
3237
 
 
3238
        :return: (basis_id, delta)
 
3239
        """
 
3240
        possible_trees = [(parent_id, cache[parent_id])
 
3241
                          for parent_id in parent_ids
 
3242
                           if parent_id in cache]
 
3243
        if len(possible_trees) == 0:
 
3244
            # There either aren't any parents, or the parents aren't in the
 
3245
            # cache, so just use the last converted tree
 
3246
            possible_trees.append((basis_id, cache[basis_id]))
 
3247
        deltas = []
 
3248
        for basis_id, basis_tree in possible_trees:
 
3249
            delta = tree.inventory._make_delta(basis_tree.inventory)
 
3250
            deltas.append((len(delta), basis_id, delta))
 
3251
        deltas.sort()
 
3252
        return deltas[0][1:]
 
3253
 
 
3254
    def _fetch_batch(self, revision_ids, basis_id, cache):
3236
3255
        """Fetch across a few revisions.
3237
3256
 
3238
3257
        :param revision_ids: The revisions to copy
3239
 
        :param basis_id: The revision_id of basis_tree
3240
 
        :param basis_tree: A tree that is not in revision_ids which should
3241
 
            already exist in the target.
3242
 
        :return: (basis_id, basis_tree) A new basis to use now that these trees
3243
 
            have been copied.
 
3258
        :param basis_id: The revision_id of a tree that must be in cache, used
 
3259
            as a basis for delta when no other base is available
 
3260
        :param cache: A cache of RevisionTrees that we can use.
 
3261
        :return: The revision_id of the last converted tree. The RevisionTree
 
3262
            for it will be in cache
3244
3263
        """
3245
3264
        # Walk though all revisions; get inventory deltas, copy referenced
3246
3265
        # texts that delta references, insert the delta, revision and
3248
3267
        text_keys = set()
3249
3268
        pending_deltas = []
3250
3269
        pending_revisions = []
 
3270
        parent_map = self.source.get_parent_map(revision_ids)
3251
3271
        for tree in self.source.revision_trees(revision_ids):
3252
3272
            current_revision_id = tree.get_revision_id()
3253
 
            delta = tree.inventory._make_delta(basis_tree.inventory)
 
3273
            parent_ids = parent_map.get(current_revision_id, ())
 
3274
            basis_id, delta = self._get_delta_for_revision(tree, parent_ids,
 
3275
                                                           basis_id, cache)
 
3276
            # Find text entries that need to be copied
3254
3277
            for old_path, new_path, file_id, entry in delta:
3255
3278
                if new_path is not None:
3256
3279
                    if not (new_path or self.target.supports_rich_root()):
3257
 
                        # We leave the inventory delta in, because that
3258
 
                        # will have the deserialised inventory root
3259
 
                        # pointer.
 
3280
                        # We don't copy the text for the root node unless the
 
3281
                        # target supports_rich_root.
3260
3282
                        continue
3261
3283
                    # TODO: Do we need:
3262
3284
                    #       "if entry.revision == current_revision_id" ?
3266
3288
            pending_deltas.append((basis_id, delta,
3267
3289
                current_revision_id, revision.parent_ids))
3268
3290
            pending_revisions.append(revision)
 
3291
            cache[current_revision_id] = tree
3269
3292
            basis_id = current_revision_id
3270
 
            basis_tree = tree
3271
3293
        # Copy file texts
3272
3294
        from_texts = self.source.texts
3273
3295
        to_texts = self.target.texts
3287
3309
            except errors.NoSuchRevision:
3288
3310
                pass
3289
3311
            self.target.add_revision(revision.revision_id, revision)
3290
 
        return basis_id, basis_tree
 
3312
        return basis_id
3291
3313
 
3292
3314
    def _fetch_all_revisions(self, revision_ids, pb):
3293
3315
        """Fetch everything for the list of revisions.
3299
3321
        """
3300
3322
        basis_id, basis_tree = self._get_basis(revision_ids[0])
3301
3323
        batch_size = 100
 
3324
        cache = lru_cache.LRUCache(100)
 
3325
        cache[basis_id] = basis_tree
 
3326
        del basis_tree # We don't want to hang on to it here
3302
3327
        for offset in range(0, len(revision_ids), batch_size):
3303
3328
            self.target.start_write_group()
3304
3329
            try:
3305
3330
                pb.update('Transferring revisions', offset,
3306
3331
                          len(revision_ids))
3307
3332
                batch = revision_ids[offset:offset+batch_size]
3308
 
                basis_id, basis_tree = self._fetch_batch(batch,
3309
 
                    basis_id, basis_tree)
 
3333
                basis_id = self._fetch_batch(batch, basis_id, cache)
3310
3334
            except:
3311
3335
                self.target.abort_write_group()
3312
3336
                raise