~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: John Arbash Meinel
  • Date: 2008-10-30 00:55:00 UTC
  • mto: (3815.2.5 prepare-1.9)
  • mto: This revision was merged to the branch mainline in revision 3811.
  • Revision ID: john@arbash-meinel.com-20081030005500-r5cej1cxflqhs3io
Switch so that we are using a simple timestamp as the first action.

Show diffs side-by-side

added added

removed removed

Lines of Context:
278
278
            revision_ids = set(repository.get_ancestry(target,
279
279
                                                       topo_sorted=False))
280
280
            self.revision_ids = revision_ids.difference(self.base_ancestry)
 
281
        self.revision_keys = set([(revid,) for revid in self.revision_ids])
281
282
 
282
283
    def do_write(self):
283
284
        """Write all data to the bundle"""
284
 
        self.bundle.begin()
285
 
        self.write_info()
286
 
        self.write_files()
287
 
        self.write_revisions()
288
 
        self.bundle.end()
 
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()
289
294
        return self.revision_ids
290
295
 
291
296
    def write_info(self):
296
301
        self.bundle.add_info_record(serializer=serializer_format,
297
302
                                    supports_rich_root=supports_rich_root)
298
303
 
299
 
    def iter_file_revisions(self):
300
 
        """Iterate through all relevant revisions of all files.
301
 
 
302
 
        This is the correct implementation, but is not compatible with bzr.dev,
303
 
        because certain old revisions were not converted correctly, and have
304
 
        the wrong "revision" marker in inventories.
305
 
        """
306
 
        transaction = self.repository.get_transaction()
307
 
        altered = self.repository.fileids_altered_by_revision_ids(
308
 
            self.revision_ids)
309
 
        for file_id, file_revision_ids in altered.iteritems():
310
 
            vf = self.repository.weave_store.get_weave(file_id, transaction)
311
 
            yield vf, file_id, file_revision_ids
312
 
 
313
 
    def iter_file_revisions_aggressive(self):
314
 
        """Iterate through all relevant revisions of all files.
315
 
 
316
 
        This uses the standard iter_file_revisions to determine what revisions
317
 
        are referred to by inventories, but then uses the versionedfile to
318
 
        determine what the build-dependencies of each required revision.
319
 
 
320
 
        All build dependencies which are not ancestors of the base revision
321
 
        are emitted.
322
 
        """
323
 
        for vf, file_id, file_revision_ids in self.iter_file_revisions():
324
 
            new_revision_ids = set()
325
 
            pending = list(file_revision_ids)
326
 
            while len(pending) > 0:
327
 
                revision_id = pending.pop()
328
 
                if revision_id in new_revision_ids:
329
 
                    continue
330
 
                if revision_id in self.base_ancestry:
331
 
                    continue
332
 
                new_revision_ids.add(revision_id)
333
 
                pending.extend(vf.get_parent_map([revision_id])[revision_id])
334
 
            yield vf, file_id, new_revision_ids
335
 
 
336
304
    def write_files(self):
337
305
        """Write bundle records for all revisions of all files"""
338
 
        for vf, file_id, revision_ids in self.iter_file_revisions():
339
 
            self.add_mp_records('file', file_id, vf, revision_ids)
 
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)
340
313
 
341
314
    def write_revisions(self):
342
315
        """Write bundle records for all revisions and signatures"""
343
 
        inv_vf = self.repository.get_inventory_weave()
344
 
        revision_order = list(multiparent.topo_iter(inv_vf, self.revision_ids))
 
316
        inv_vf = self.repository.inventories
 
317
        revision_order = [key[-1] for key in multiparent.topo_iter_keys(inv_vf,
 
318
            self.revision_keys)]
345
319
        if self.target is not None and self.target in self.revision_ids:
346
320
            revision_order.remove(self.target)
347
321
            revision_order.append(self.target)
348
 
        self.add_mp_records('inventory', None, inv_vf, revision_order)
 
322
        self._add_mp_records_keys('inventory', inv_vf, [(revid,) for revid in revision_order])
349
323
        parent_map = self.repository.get_parent_map(revision_order)
350
324
        for revision_id in revision_order:
351
325
            parents = parent_map.get(revision_id, None)
374
348
                base = parents[0]
375
349
        return base, target
376
350
 
377
 
    def add_mp_records(self, repo_kind, file_id, vf, revision_ids):
 
351
    def _add_mp_records_keys(self, repo_kind, vf, keys):
378
352
        """Add multi-parent diff records to a bundle"""
379
 
        revision_ids = list(multiparent.topo_iter(vf, revision_ids))
380
 
        mpdiffs = vf.make_mpdiffs(revision_ids)
381
 
        sha1s = vf.get_sha1s(revision_ids)
382
 
        parent_map = vf.get_parent_map(revision_ids)
383
 
        for mpdiff, revision_id, sha1, in zip(mpdiffs, revision_ids, sha1s):
384
 
            parents = parent_map[revision_id]
 
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]]
385
360
            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
386
366
            self.bundle.add_multiparent_record(text, sha1, parents, repo_kind,
387
 
                                               revision_id, file_id)
 
367
                                               item_key[-1], file_id)
388
368
 
389
369
 
390
370
class BundleInfoV4(object):
500
480
                if self._info is not None:
501
481
                    raise AssertionError()
502
482
                self._handle_info(metadata)
503
 
            if (repo_kind, file_id) != ('file', current_file):
504
 
                if len(pending_file_records) > 0:
505
 
                    self._install_mp_records(current_versionedfile,
506
 
                                             pending_file_records)
 
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)
507
489
                current_file = None
508
 
                current_versionedfile = None
509
 
                pending_file_records = []
 
490
                del pending_file_records[:]
510
491
            if len(pending_inventory_records) > 0 and repo_kind != 'inventory':
511
 
                self._install_inventory_records(inventory_vf,
512
 
                                                pending_inventory_records)
 
492
                self._install_inventory_records(pending_inventory_records)
513
493
                pending_inventory_records = []
514
494
            if repo_kind == 'inventory':
515
 
                if inventory_vf is None:
516
 
                    inventory_vf = self._repository.get_inventory_weave()
517
 
                if revision_id not in inventory_vf:
518
 
                    pending_inventory_records.append((revision_id, metadata,
519
 
                                                      bytes))
 
495
                pending_inventory_records.append(((revision_id,), metadata, bytes))
520
496
            if repo_kind == 'revision':
521
497
                target_revision = revision_id
522
498
                self._install_revision(revision_id, metadata, bytes)
524
500
                self._install_signature(revision_id, metadata, bytes)
525
501
            if repo_kind == 'file':
526
502
                current_file = file_id
527
 
                if current_versionedfile is None:
528
 
                    current_versionedfile = \
529
 
                        self._repository.weave_store.get_weave_or_empty(
530
 
                        file_id, self._repository.get_transaction())
531
 
                    pending_file_records = []
532
 
                if revision_id in current_versionedfile:
533
 
                    continue
534
 
                pending_file_records.append((revision_id, metadata, bytes))
535
 
        self._install_mp_records(current_versionedfile, pending_file_records)
 
503
                pending_file_records.append(((file_id, revision_id), metadata, bytes))
 
504
        self._install_mp_records_keys(self._repository.texts, pending_file_records)
536
505
        return target_revision
537
506
 
538
507
    def _handle_info(self, info):
553
522
                      records if r not in versionedfile]
554
523
        versionedfile.add_mpdiffs(vf_records)
555
524
 
556
 
    def _install_inventory_records(self, vf, records):
 
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):
557
543
        if self._info['serializer'] == self._repository._serializer.format_num:
558
 
            return self._install_mp_records(vf, records)
559
 
        for revision_id, metadata, bytes in records:
 
544
            return self._install_mp_records_keys(self._repository.inventories,
 
545
                records)
 
546
        for key, metadata, bytes in records:
 
547
            revision_id = key[-1]
560
548
            parent_ids = metadata['parents']
561
549
            parents = [self._repository.get_inventory(p)
562
550
                       for p in parent_ids]
579
567
    def _handle_root(self, target_inv, parent_ids):
580
568
        revision_id = target_inv.revision_id
581
569
        if self.update_root:
582
 
            target_inv.root.revision = revision_id
583
 
            store = self._repository.weave_store
584
 
            transaction = self._repository.get_transaction()
585
 
            vf = store.get_weave_or_empty(target_inv.root.file_id, transaction)
586
 
            vf.add_lines(revision_id, parent_ids, [])
 
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, [])
587
574
        elif not self._repository.supports_rich_root():
588
575
            if target_inv.root.revision != revision_id:
589
576
                raise errors.IncompatibleRevision(repr(self._repository))
590
577
 
591
 
 
592
578
    def _install_revision(self, revision_id, metadata, text):
593
579
        if self._repository.has_revision(revision_id):
594
580
            return
595
 
        if self._info['serializer'] == self._repository._serializer.format_num:
596
 
            self._repository._add_revision_text(revision_id, text)
597
 
        else:
598
 
            revision = self._source_serializer.read_revision_from_string(text)
599
 
            self._repository.add_revision(revision.revision_id, revision)
 
581
        revision = self._source_serializer.read_revision_from_string(text)
 
582
        self._repository.add_revision(revision.revision_id, revision)
600
583
 
601
584
    def _install_signature(self, revision_id, metadata, text):
602
585
        transaction = self._repository.get_transaction()
603
 
        if self._repository._revision_store.has_signature(revision_id,
604
 
                                                          transaction):
 
586
        if self._repository.has_signature_for_revision_id(revision_id):
605
587
            return
606
 
        self._repository._revision_store.add_revision_signature_text(
607
 
            revision_id, text, transaction)
 
588
        self._repository.add_signature_text(revision_id, text)