~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bundle/serializer/v4.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-12-20 16:16:34 UTC
  • mfrom: (3123.5.18 hardlinks)
  • Revision ID: pqm@pqm.ubuntu.com-20071220161634-2kcjb650o21ydko4
Accelerate build_tree using similar workingtrees (abentley)

Show diffs side-by-side

added added

removed removed

Lines of Context:
107
107
    @staticmethod
108
108
    def encode_name(content_kind, revision_id, file_id=None):
109
109
        """Encode semantic ids as a container name"""
110
 
        if content_kind not in ('revision', 'file', 'inventory', 'signature',
111
 
                'info'):
112
 
            raise ValueError(content_kind)
 
110
        assert content_kind in ('revision', 'file', 'inventory', 'signature',
 
111
                                'info')
 
112
 
113
113
        if content_kind == 'file':
114
 
            if file_id is None:
115
 
                raise AssertionError()
 
114
            assert file_id is not None
116
115
        else:
117
 
            if file_id is not None:
118
 
                raise AssertionError()
 
116
            assert file_id is None
119
117
        if content_kind == 'info':
120
 
            if revision_id is not None:
121
 
                raise AssertionError()
122
 
        elif revision_id is None:
123
 
            raise AssertionError()
 
118
            assert revision_id is None
 
119
        else:
 
120
            assert revision_id is not None
124
121
        names = [n.replace('/', '//') for n in
125
122
                 (content_kind, revision_id, file_id) if n is not None]
126
123
        return '/'.join(names)
278
275
            revision_ids = set(repository.get_ancestry(target,
279
276
                                                       topo_sorted=False))
280
277
            self.revision_ids = revision_ids.difference(self.base_ancestry)
281
 
        self.revision_keys = set([(revid,) for revid in self.revision_ids])
282
278
 
283
279
    def do_write(self):
284
280
        """Write all data to the bundle"""
285
 
        self.repository.lock_read()
286
 
        try:
287
 
            self.bundle.begin()
288
 
            self.write_info()
289
 
            self.write_files()
290
 
            self.write_revisions()
291
 
            self.bundle.end()
292
 
        finally:
293
 
            self.repository.unlock()
 
281
        self.bundle.begin()
 
282
        self.write_info()
 
283
        self.write_files()
 
284
        self.write_revisions()
 
285
        self.bundle.end()
294
286
        return self.revision_ids
295
287
 
296
288
    def write_info(self):
301
293
        self.bundle.add_info_record(serializer=serializer_format,
302
294
                                    supports_rich_root=supports_rich_root)
303
295
 
 
296
    def iter_file_revisions(self):
 
297
        """Iterate through all relevant revisions of all files.
 
298
 
 
299
        This is the correct implementation, but is not compatible with bzr.dev,
 
300
        because certain old revisions were not converted correctly, and have
 
301
        the wrong "revision" marker in inventories.
 
302
        """
 
303
        transaction = self.repository.get_transaction()
 
304
        altered = self.repository.fileids_altered_by_revision_ids(
 
305
            self.revision_ids)
 
306
        for file_id, file_revision_ids in altered.iteritems():
 
307
            vf = self.repository.weave_store.get_weave(file_id, transaction)
 
308
            yield vf, file_id, file_revision_ids
 
309
 
 
310
    def iter_file_revisions_aggressive(self):
 
311
        """Iterate through all relevant revisions of all files.
 
312
 
 
313
        This uses the standard iter_file_revisions to determine what revisions
 
314
        are referred to by inventories, but then uses the versionedfile to
 
315
        determine what the build-dependencies of each required revision.
 
316
 
 
317
        All build dependencies which are not ancestors of the base revision
 
318
        are emitted.
 
319
        """
 
320
        for vf, file_id, file_revision_ids in self.iter_file_revisions():
 
321
            new_revision_ids = set()
 
322
            pending = list(file_revision_ids)
 
323
            while len(pending) > 0:
 
324
                revision_id = pending.pop()
 
325
                if revision_id in new_revision_ids:
 
326
                    continue
 
327
                if revision_id in self.base_ancestry:
 
328
                    continue
 
329
                new_revision_ids.add(revision_id)
 
330
                pending.extend(vf.get_parents(revision_id))
 
331
            yield vf, file_id, new_revision_ids
 
332
 
304
333
    def write_files(self):
305
334
        """Write bundle records for all revisions of all files"""
306
 
        text_keys = []
307
 
        altered_fileids = self.repository.fileids_altered_by_revision_ids(
308
 
                self.revision_ids)
309
 
        for file_id, revision_ids in altered_fileids.iteritems():
310
 
            for revision_id in revision_ids:
311
 
                text_keys.append((file_id, revision_id))
312
 
        self._add_mp_records_keys('file', self.repository.texts, text_keys)
 
335
        for vf, file_id, revision_ids in self.iter_file_revisions():
 
336
            self.add_mp_records('file', file_id, vf, revision_ids)
313
337
 
314
338
    def write_revisions(self):
315
339
        """Write bundle records for all revisions and signatures"""
316
 
        inv_vf = self.repository.inventories
317
 
        revision_order = [key[-1] for key in multiparent.topo_iter_keys(inv_vf,
318
 
            self.revision_keys)]
 
340
        inv_vf = self.repository.get_inventory_weave()
 
341
        revision_order = list(multiparent.topo_iter(inv_vf, self.revision_ids))
319
342
        if self.target is not None and self.target in self.revision_ids:
320
343
            revision_order.remove(self.target)
321
344
            revision_order.append(self.target)
322
 
        self._add_mp_records_keys('inventory', inv_vf, [(revid,) for revid in revision_order])
 
345
        self.add_mp_records('inventory', None, inv_vf, revision_order)
323
346
        parent_map = self.repository.get_parent_map(revision_order)
324
347
        for revision_id in revision_order:
325
348
            parents = parent_map.get(revision_id, None)
348
371
                base = parents[0]
349
372
        return base, target
350
373
 
351
 
    def _add_mp_records_keys(self, repo_kind, vf, keys):
 
374
    def add_mp_records(self, repo_kind, file_id, vf, revision_ids):
352
375
        """Add multi-parent diff records to a bundle"""
353
 
        ordered_keys = list(multiparent.topo_iter_keys(vf, keys))
354
 
        mpdiffs = vf.make_mpdiffs(ordered_keys)
355
 
        sha1s = vf.get_sha1s(ordered_keys)
356
 
        parent_map = vf.get_parent_map(ordered_keys)
357
 
        for mpdiff, item_key, in zip(mpdiffs, ordered_keys):
358
 
            sha1 = sha1s[item_key]
359
 
            parents = [key[-1] for key in parent_map[item_key]]
 
376
        revision_ids = list(multiparent.topo_iter(vf, revision_ids))
 
377
        mpdiffs = vf.make_mpdiffs(revision_ids)
 
378
        sha1s = vf.get_sha1s(revision_ids)
 
379
        for mpdiff, revision_id, sha1, in zip(mpdiffs, revision_ids, sha1s):
 
380
            parents = vf.get_parents(revision_id)
360
381
            text = ''.join(mpdiff.to_patch())
361
 
            # Infer file id records as appropriate.
362
 
            if len(item_key) == 2:
363
 
                file_id = item_key[0]
364
 
            else:
365
 
                file_id = None
366
382
            self.bundle.add_multiparent_record(text, sha1, parents, repo_kind,
367
 
                                               item_key[-1], file_id)
 
383
                                               revision_id, file_id)
368
384
 
369
385
 
370
386
class BundleInfoV4(object):
477
493
        for bytes, metadata, repo_kind, revision_id, file_id in\
478
494
            self._container.iter_records():
479
495
            if repo_kind == 'info':
480
 
                if self._info is not None:
481
 
                    raise AssertionError()
 
496
                assert self._info is None
482
497
                self._handle_info(metadata)
483
 
            if (pending_file_records and
484
 
                (repo_kind, file_id) != ('file', current_file)):
485
 
                # Flush the data for a single file - prevents memory
486
 
                # spiking due to buffering all files in memory.
487
 
                self._install_mp_records_keys(self._repository.texts,
488
 
                    pending_file_records)
 
498
            if (repo_kind, file_id) != ('file', current_file):
 
499
                if len(pending_file_records) > 0:
 
500
                    self._install_mp_records(current_versionedfile,
 
501
                                             pending_file_records)
489
502
                current_file = None
490
 
                del pending_file_records[:]
 
503
                current_versionedfile = None
 
504
                pending_file_records = []
491
505
            if len(pending_inventory_records) > 0 and repo_kind != 'inventory':
492
 
                self._install_inventory_records(pending_inventory_records)
 
506
                self._install_inventory_records(inventory_vf,
 
507
                                                pending_inventory_records)
493
508
                pending_inventory_records = []
494
509
            if repo_kind == 'inventory':
495
 
                pending_inventory_records.append(((revision_id,), metadata, bytes))
 
510
                if inventory_vf is None:
 
511
                    inventory_vf = self._repository.get_inventory_weave()
 
512
                if revision_id not in inventory_vf:
 
513
                    pending_inventory_records.append((revision_id, metadata,
 
514
                                                      bytes))
496
515
            if repo_kind == 'revision':
497
516
                target_revision = revision_id
498
517
                self._install_revision(revision_id, metadata, bytes)
500
519
                self._install_signature(revision_id, metadata, bytes)
501
520
            if repo_kind == 'file':
502
521
                current_file = file_id
503
 
                pending_file_records.append(((file_id, revision_id), metadata, bytes))
504
 
        self._install_mp_records_keys(self._repository.texts, pending_file_records)
 
522
                if current_versionedfile is None:
 
523
                    current_versionedfile = \
 
524
                        self._repository.weave_store.get_weave_or_empty(
 
525
                        file_id, self._repository.get_transaction())
 
526
                    pending_file_records = []
 
527
                if revision_id in current_versionedfile:
 
528
                    continue
 
529
                pending_file_records.append((revision_id, metadata, bytes))
 
530
        self._install_mp_records(current_versionedfile, pending_file_records)
505
531
        return target_revision
506
532
 
507
533
    def _handle_info(self, info):
522
548
                      records if r not in versionedfile]
523
549
        versionedfile.add_mpdiffs(vf_records)
524
550
 
525
 
    def _install_mp_records_keys(self, versionedfile, records):
526
 
        d_func = multiparent.MultiParent.from_patch
527
 
        vf_records = []
528
 
        for key, meta, text in records:
529
 
            # Adapt to tuple interface: A length two key is a file_id,
530
 
            # revision_id pair, a length 1 key is a
531
 
            # revision/signature/inventory. We need to do this because
532
 
            # the metadata extraction from the bundle has not yet been updated
533
 
            # to use the consistent tuple interface itself.
534
 
            if len(key) == 2:
535
 
                prefix = key[:1]
536
 
            else:
537
 
                prefix = ()
538
 
            parents = [prefix + (parent,) for parent in meta['parents']]
539
 
            vf_records.append((key, parents, meta['sha1'], d_func(text)))
540
 
        versionedfile.add_mpdiffs(vf_records)
541
 
 
542
 
    def _install_inventory_records(self, records):
 
551
    def _install_inventory_records(self, vf, records):
543
552
        if self._info['serializer'] == self._repository._serializer.format_num:
544
 
            return self._install_mp_records_keys(self._repository.inventories,
545
 
                records)
546
 
        for key, metadata, bytes in records:
547
 
            revision_id = key[-1]
 
553
            return self._install_mp_records(vf, records)
 
554
        for revision_id, metadata, bytes in records:
548
555
            parent_ids = metadata['parents']
549
556
            parents = [self._repository.get_inventory(p)
550
557
                       for p in parent_ids]
567
574
    def _handle_root(self, target_inv, parent_ids):
568
575
        revision_id = target_inv.revision_id
569
576
        if self.update_root:
570
 
            text_key = (target_inv.root.file_id, revision_id)
571
 
            parent_keys = [(target_inv.root.file_id, parent) for
572
 
                parent in parent_ids]
573
 
            self._repository.texts.add_lines(text_key, parent_keys, [])
 
577
            target_inv.root.revision = revision_id
 
578
            store = self._repository.weave_store
 
579
            transaction = self._repository.get_transaction()
 
580
            vf = store.get_weave_or_empty(target_inv.root.file_id, transaction)
 
581
            vf.add_lines(revision_id, parent_ids, [])
574
582
        elif not self._repository.supports_rich_root():
575
583
            if target_inv.root.revision != revision_id:
576
584
                raise errors.IncompatibleRevision(repr(self._repository))
577
585
 
 
586
 
578
587
    def _install_revision(self, revision_id, metadata, text):
579
588
        if self._repository.has_revision(revision_id):
580
589
            return
581
 
        revision = self._source_serializer.read_revision_from_string(text)
582
 
        self._repository.add_revision(revision.revision_id, revision)
 
590
        self._repository._add_revision_text(revision_id, text)
583
591
 
584
592
    def _install_signature(self, revision_id, metadata, text):
585
593
        transaction = self._repository.get_transaction()
586
 
        if self._repository.has_signature_for_revision_id(revision_id):
 
594
        if self._repository._revision_store.has_signature(revision_id,
 
595
                                                          transaction):
587
596
            return
588
 
        self._repository.add_signature_text(revision_id, text)
 
597
        self._repository._revision_store.add_revision_signature_text(
 
598
            revision_id, text, transaction)