Rev 4025: (robertc) Allow VersionedFiles to insert and hold record streams in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Fri Feb 20 08:24:53 GMT 2009


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 4025
revision-id: pqm at pqm.ubuntu.com-20090220082449-8wtrcem3dypgq53q
parent: pqm at pqm.ubuntu.com-20090220071304-mb95xwtanwl2bqa4
parent: robertc at robertcollins.net-20090220074552-q7gauu6msiusotyg
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Fri 2009-02-20 08:24:49 +0000
message:
  (robertc) Allow VersionedFiles to insert and hold record streams
  	which need missing compression parents. (Andrew Bennetts,
  	Robert Collins)
modified:
  bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
  bzrlib/repofmt/pack_repo.py    pack_repo.py-20070813041115-gjv5ma7ktfqwsjgn-1
  bzrlib/tests/test_versionedfile.py test_versionedfile.py-20060222045249-db45c9ed14a1c2e5
  bzrlib/versionedfile.py        versionedfile.py-20060222045106-5039c71ee3b65490
    ------------------------------------------------------------
    revno: 4009.3.13
    revision-id: robertc at robertcollins.net-20090220074552-q7gauu6msiusotyg
    parent: robertc at robertcollins.net-20090220023828-rcqd2pyw22zqjkwl
    committer: Robert Collins <robertc at robertcollins.net>
    branch nick: integration
    timestamp: Fri 2009-02-20 18:45:52 +1100
    message:
      Fix typo.
    modified:
      bzrlib/repofmt/pack_repo.py    pack_repo.py-20070813041115-gjv5ma7ktfqwsjgn-1
    ------------------------------------------------------------
    revno: 4009.3.12
    revision-id: robertc at robertcollins.net-20090220023828-rcqd2pyw22zqjkwl
    parent: robertc at robertcollins.net-20090220015545-qloec8tf9jnqi2d8
    committer: Robert Collins <robertc at robertcollins.net>
    branch nick: VersionedFiles.insert-record-stream.partial
    timestamp: Fri 2009-02-20 13:38:28 +1100
    message:
      Polish on inserting record streams with missing compression parents.
    modified:
      bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
      bzrlib/repofmt/pack_repo.py    pack_repo.py-20070813041115-gjv5ma7ktfqwsjgn-1
      bzrlib/tests/test_versionedfile.py test_versionedfile.py-20060222045249-db45c9ed14a1c2e5
      bzrlib/versionedfile.py        versionedfile.py-20060222045106-5039c71ee3b65490
    ------------------------------------------------------------
    revno: 4009.3.11
    revision-id: robertc at robertcollins.net-20090220015545-qloec8tf9jnqi2d8
    parent: andrew.bennetts at canonical.com-20090220012317-xyijy32wo1flhaxo
    parent: pqm at pqm.ubuntu.com-20090220012608-hh2rwz1cqd43mjrm
    committer: Robert Collins <robertc at robertcollins.net>
    branch nick: VersionedFiles.insert-record-stream.partial
    timestamp: Fri 2009-02-20 12:55:45 +1100
    message:
      Merge bzr.dev (resolve knit.py conflicts).
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
      bzrlib/index.py                index.py-20070712131115-lolkarso50vjr64s-1
      bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
      bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
      bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
      bzrlib/repofmt/pack_repo.py    pack_repo.py-20070813041115-gjv5ma7ktfqwsjgn-1
      bzrlib/shelf_ui.py             shelver.py-20081005210102-33worgzwrtdw0yrm-1
      bzrlib/smart/branch.py         branch.py-20061124031907-mzh3pla28r83r97f-1
      bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
      bzrlib/tests/blackbox/test_push.py test_push.py-20060329002750-929af230d5d22663
      bzrlib/tests/branch_implementations/test_branch.py testbranch.py-20050711070244-121d632bc37d7253
      bzrlib/tests/branch_implementations/test_hooks.py test_hooks.py-20070129154855-blhpwxmvjs07waei-1
      bzrlib/tests/branch_implementations/test_sprout.py test_sprout.py-20070521151739-b8t8p7axw1h966ws-1
      bzrlib/tests/bzrdir_implementations/test_bzrdir.py test_bzrdir.py-20060131065642-0ebeca5e30e30866
      bzrlib/tests/per_repository/test_add_fallback_repository.py test_add_fallback_re-20080215040003-8w9n4ck9uqdxj18m-1
      bzrlib/tests/per_repository/test_repository.py test_repository.py-20060131092128-ad07f494f5c9d26c
      bzrlib/tests/test_bzrdir.py    test_bzrdir.py-20060131065654-deba40eef51cf220
      bzrlib/tests/test_index.py     test_index.py-20070712131115-lolkarso50vjr64s-2
      bzrlib/tests/test_knit.py      test_knit.py-20051212171302-95d4c00dd5f11f2b
      bzrlib/tests/test_remote.py    test_remote.py-20060720103555-yeeg2x51vn0rbtdp-2
      bzrlib/tests/test_shelf_ui.py  test_shelf_ui.py-20081027155203-wtcuazg85wp9u4fv-1
      bzrlib/tests/test_transport.py testtransport.py-20050718175618-e5cdb99f4555ddce
      bzrlib/tests/test_ui.py        test_ui.py-20051130162854-458e667a7414af09
      bzrlib/trace.py                trace.py-20050309040759-c8ed824bdcd4748a
      bzrlib/transport/__init__.py   transport.py-20050711165921-4978aa7ce1285ad5
      bzrlib/transport/http/_urllib2_wrappers.py _urllib2_wrappers.py-20060913231729-ha9ugi48ktx481ao-1
      bzrlib/transport/remote.py     ssh.py-20060608202016-c25gvf1ob7ypbus6-1
      bzrlib/ui/text.py              text.py-20051130153916-2e438cffc8afc478
      bzrlib/win32utils.py           win32console.py-20051021033308-123c6c929d04973d
    ------------------------------------------------------------
    revno: 4009.3.10
    revision-id: andrew.bennetts at canonical.com-20090220012317-xyijy32wo1flhaxo
    parent: andrew.bennetts at canonical.com-20090220012200-cw346vv8xz4o18mr
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: missing-parents-integration
    timestamp: Fri 2009-02-20 12:23:17 +1100
    message:
      Remove more cruft.
    modified:
      bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
    ------------------------------------------------------------
    revno: 4009.3.9
    revision-id: andrew.bennetts at canonical.com-20090220012200-cw346vv8xz4o18mr
    parent: andrew.bennetts at canonical.com-20090220010452-eb19b0owqfmfuwcb
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: missing-parents-integration
    timestamp: Fri 2009-02-20 12:22:00 +1100
    message:
      Remove some XXXs.
    modified:
      bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
    ------------------------------------------------------------
    revno: 4009.3.8
    revision-id: andrew.bennetts at canonical.com-20090220010452-eb19b0owqfmfuwcb
    parent: andrew.bennetts at canonical.com-20090220005210-df3lbaxuyv754oju
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: missing-parents-integration
    timestamp: Fri 2009-02-20 12:04:52 +1100
    message:
      Fix test failure.
    modified:
      bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
    ------------------------------------------------------------
    revno: 4009.3.7
    revision-id: andrew.bennetts at canonical.com-20090220005210-df3lbaxuyv754oju
    parent: andrew.bennetts at canonical.com-20090219054246-c9vqv0u1ow1cs5ev
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: missing-parents-integration
    timestamp: Fri 2009-02-20 11:52:10 +1100
    message:
      Most tests passing.
    modified:
      bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
      bzrlib/tests/test_versionedfile.py test_versionedfile.py-20060222045249-db45c9ed14a1c2e5
    ------------------------------------------------------------
    revno: 4009.3.6
    revision-id: andrew.bennetts at canonical.com-20090219054246-c9vqv0u1ow1cs5ev
    parent: andrew.bennetts at canonical.com-20090218004640-31m284sljo9myc00
    parent: andrew.bennetts at canonical.com-20090219035237-o147dwr881zgd71d
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: missing-parents-integration
    timestamp: Thu 2009-02-19 16:42:46 +1100
    message:
      Merge missing-parents-in-pack-index.
    modified:
      bzrlib/btree_index.py          index.py-20080624222253-p0x5f92uyh5hw734-7
      bzrlib/index.py                index.py-20070712131115-lolkarso50vjr64s-1
      bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
      bzrlib/repofmt/pack_repo.py    pack_repo.py-20070813041115-gjv5ma7ktfqwsjgn-1
      bzrlib/tests/test_btree_index.py test_index.py-20080624222253-p0x5f92uyh5hw734-13
      bzrlib/tests/test_index.py     test_index.py-20070712131115-lolkarso50vjr64s-2
      bzrlib/tests/test_knit.py      test_knit.py-20051212171302-95d4c00dd5f11f2b
      bzrlib/tests/test_pack_repository.py test_pack_repository-20080801043947-eaw0e6h2gu75kwmy-1
    ------------------------------------------------------------
    revno: 4009.3.5
    revision-id: andrew.bennetts at canonical.com-20090218004640-31m284sljo9myc00
    parent: andrew.bennetts at canonical.com-20090218004328-0mws03fs0sfflpmn
    parent: andrew.bennetts at canonical.com-20090217054444-xhb5m6x05tjf5b26
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: missing-parents-integration
    timestamp: Wed 2009-02-18 11:46:40 +1100
    message:
      Merge missing-parents-in-pack-index work-in-progress.
    modified:
      bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
      bzrlib/tests/test_knit.py      test_knit.py-20051212171302-95d4c00dd5f11f2b
    ------------------------------------------------------------
    revno: 4009.3.4
    revision-id: andrew.bennetts at canonical.com-20090218004328-0mws03fs0sfflpmn
    parent: andrew.bennetts at canonical.com-20090217012534-k6574qvmaibkeehi
    parent: pqm at pqm.ubuntu.com-20090216172448-vj35mjoe463c3bk2
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: insert_record_stream-missing-parents
    timestamp: Wed 2009-02-18 11:43:28 +1100
    message:
      Merge bzr.dev.
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
      bzrlib/reconfigure.py          reconfigure.py-20070908040425-6ykgo7escxhyrg9p-1
      bzrlib/tests/blackbox/test_reconfigure.py test_reconfigure.py-20070908173426-khfo5fi2rgzgtwj3-1
      bzrlib/tests/test_reconfigure.py test_reconfigure.py-20070908040425-6ykgo7escxhyrg9p-2
      doc/developers/ppa.txt         ppa.txt-20080722055539-606u7t2z32t3ae4w-1
      tools/packaging/build-packages.sh buildpackages.sh-20080821102059-fzlodktas65qmo1k-1
      tools/packaging/update-changelogs.sh updatechangelogs.sh-20080821102059-fzlodktas65qmo1k-2
      tools/packaging/update-packaging-branches.sh updatepackagingbranc-20080825210254-6is8ciit1yzyd3a2-1
    ------------------------------------------------------------
    revno: 4009.3.3
    revision-id: andrew.bennetts at canonical.com-20090217012534-k6574qvmaibkeehi
    parent: andrew.bennetts at canonical.com-20090217005419-i9qdpanq2cwm3j59
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: insert_record_stream-missing-parents
    timestamp: Tue 2009-02-17 12:25:34 +1100
    message:
      Add docstrings.
    modified:
      bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
      bzrlib/tests/test_versionedfile.py test_versionedfile.py-20060222045249-db45c9ed14a1c2e5
      bzrlib/versionedfile.py        versionedfile.py-20060222045106-5039c71ee3b65490
    ------------------------------------------------------------
    revno: 4009.3.2
    revision-id: andrew.bennetts at canonical.com-20090217005419-i9qdpanq2cwm3j59
    parent: andrew.bennetts at canonical.com-20090216051228-bfsjg5hvvbtu7wg5
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: insert_record_stream-missing-parents
    timestamp: Tue 2009-02-17 11:54:19 +1100
    message:
      Add test_insert_record_stream_delta_missing_basis_can_be_added_later.
    modified:
      bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
      bzrlib/tests/test_versionedfile.py test_versionedfile.py-20060222045249-db45c9ed14a1c2e5
      bzrlib/versionedfile.py        versionedfile.py-20060222045106-5039c71ee3b65490
    ------------------------------------------------------------
    revno: 4009.3.1
    revision-id: andrew.bennetts at canonical.com-20090216051228-bfsjg5hvvbtu7wg5
    parent: pqm at pqm.ubuntu.com-20090215032052-9749wepsy6dgnq9l
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: insert_record_stream-missing-parents
    timestamp: Mon 2009-02-16 16:12:28 +1100
    message:
      Fix test_insert_record_stream_delta_missing_basis_no_corruption to test what it claims to, and fix KnitVersionedFiles.get_record_stream to match the expected exception.
    modified:
      bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
      bzrlib/tests/test_versionedfile.py test_versionedfile.py-20060222045249-db45c9ed14a1c2e5
=== modified file 'bzrlib/knit.py'
--- a/bzrlib/knit.py	2009-02-20 00:43:38 +0000
+++ b/bzrlib/knit.py	2009-02-20 02:38:28 +0000
@@ -1475,12 +1475,26 @@
                     added_keys.extend(
                         [index_entry[0] for index_entry in index_entries])
                     del buffered_index_entries[key]
-        # If there were any deltas which had a missing basis parent, error.
         if buffered_index_entries:
-            from pprint import pformat
-            raise errors.BzrCheckError(
-                "record_stream refers to compression parents not in %r:\n%s"
-                % (self, pformat(sorted(buffered_index_entries.keys()))))
+            # There were index entries buffered at the end of the stream,
+            # So these need to be added (if the index supports holding such
+            # entries for later insertion)
+            for key in buffered_index_entries:
+                index_entries = buffered_index_entries[key]
+                self._index.add_records(index_entries,
+                    missing_compression_parents=True)
+
+    def get_missing_compression_parent_keys(self):
+        """Return an iterable of keys of missing compression parents.
+
+        Check this after calling insert_record_stream to find out if there are
+        any missing compression parents.  If there are, the records that
+        depend on them are not able to be inserted safely. For atomic
+        KnitVersionedFiles built on packs, the transaction should be aborted or
+        suspended - commit will fail at this point. Nonatomic knits will error
+        earlier because they have no staging area to put pending entries into.
+        """
+        return self._index.get_missing_compression_parents()
 
     def iter_lines_added_or_present_in_keys(self, keys, pb=None):
         """Iterate over the lines in the versioned files from keys.
@@ -1837,14 +1851,23 @@
         self._reset_cache()
         self.has_graph = True
 
-    def add_records(self, records, random_id=False):
+    def add_records(self, records, random_id=False, missing_compression_parents=False):
         """Add multiple records to the index.
         
         :param records: a list of tuples:
                          (key, options, access_memo, parents).
         :param random_id: If True the ids being added were randomly generated
             and no check for existence will be performed.
+        :param missing_compression_parents: If True the records being added are
+            only compressed against texts already in the index (or inside
+            records). If False the records all refer to unavailable texts (or
+            texts inside records) as compression parents.
         """
+        if missing_compression_parents:
+            # It might be nice to get the edge of the records. But keys isn't
+            # _wrong_.
+            keys = sorted(record[0] for record in records)
+            raise errors.RevisionNotPresent(keys, self)
         paths = {}
         for record in records:
             key = record[0]
@@ -2213,7 +2236,8 @@
     def __repr__(self):
         return "%s(%r)" % (self.__class__.__name__, self._graph_index)
 
-    def add_records(self, records, random_id=False):
+    def add_records(self, records, random_id=False,
+        missing_compression_parents=False):
         """Add multiple records to the index.
         
         This function does not insert data into the Immutable GraphIndex
@@ -2225,6 +2249,10 @@
                          (key, options, access_memo, parents).
         :param random_id: If True the ids being added were randomly generated
             and no check for existence will be performed.
+        :param missing_compression_parents: If True the records being added are
+            only compressed against texts already in the index (or inside
+            records). If False the records all refer to unavailable texts (or
+            texts inside records) as compression parents.
         """
         if not self._add_callback:
             raise errors.ReadOnlyError(self)
@@ -2232,6 +2260,7 @@
         # anymore.
 
         keys = {}
+        compression_parents = set()
         for (key, options, access_memo, parents) in records:
             if self._parents:
                 parents = tuple(parents)
@@ -2248,6 +2277,8 @@
                 if self._deltas:
                     if 'line-delta' in options:
                         node_refs = (parents, (parents[0],))
+                        if missing_compression_parents:
+                            compression_parents.add(parents[0])
                     else:
                         node_refs = (parents, ())
                 else:
@@ -2275,6 +2306,17 @@
             for key, (value, node_refs) in keys.iteritems():
                 result.append((key, value))
         self._add_callback(result)
+        if missing_compression_parents:
+            # This may appear to be incorrect (it does not check for
+            # compression parents that are in the existing graph index),
+            # but such records won't have been buffered, so this is
+            # actually correct: every entry when
+            # missing_compression_parents==True either has a missing parent, or
+            # a parent that is one of the keys in records.
+            compression_parents.difference_update(keys)
+            self._missing_compression_parents.update(compression_parents)
+        # Adding records may have satisfied missing compression parents.
+        self._missing_compression_parents.difference_update(keys)
         
     def scan_unvalidated_index(self, graph_index):
         """Inform this _KnitGraphIndex that there is an unvalidated index.
@@ -2291,8 +2333,10 @@
             self._missing_compression_parents.update(new_missing)
 
     def get_missing_compression_parents(self):
-        """Return the keys of compression parents missing from unvalidated
-        indices.
+        """Return the keys of missing compression parents.
+
+        Missing compression parents occur when a record stream was missing
+        basis texts, or a index was scanned that had missing basis texts.
         """
         return frozenset(self._missing_compression_parents)
 

=== modified file 'bzrlib/repofmt/pack_repo.py'
--- a/bzrlib/repofmt/pack_repo.py	2009-02-20 00:43:38 +0000
+++ b/bzrlib/repofmt/pack_repo.py	2009-02-20 07:45:52 +0000
@@ -1812,8 +1812,7 @@
                 ('texts', self.repo.texts),
                 ('signatures', self.repo.signatures),
                 ):
-            # We use KnitVersionedFiles exclusively so can rely on _index.
-            missing = versioned_file._index.get_missing_compression_parents()
+            missing = versioned_file.get_missing_compression_parent_keys()
             all_missing.update([(prefix,) + key for key in missing])
         if all_missing:
             raise errors.BzrCheckError(

=== modified file 'bzrlib/tests/test_versionedfile.py'
--- a/bzrlib/tests/test_versionedfile.py	2009-01-22 01:03:44 +0000
+++ b/bzrlib/tests/test_versionedfile.py	2009-02-20 02:38:28 +0000
@@ -47,6 +47,7 @@
 from bzrlib.tests import (
     TestCase,
     TestCaseWithMemoryTransport,
+    TestNotApplicable,
     TestScenarioApplier,
     TestSkipped,
     condition_isinstance,
@@ -94,30 +95,35 @@
                 ConstantMapper('inventory')),
             'graph':True,
             'key_length':1,
+            'support_partial_insertion': False,
             }),
         ('named-knit', {
             'cleanup':None,
             'factory':make_file_factory(False, ConstantMapper('revisions')),
             'graph':True,
             'key_length':1,
+            'support_partial_insertion': False,
             }),
-        ('named-nograph-knit-pack', {
+        ('named-nograph-nodelta-knit-pack', {
             'cleanup':cleanup_pack_knit,
             'factory':make_pack_factory(False, False, 1),
             'graph':False,
             'key_length':1,
+            'support_partial_insertion': False,
             }),
         ('named-graph-knit-pack', {
             'cleanup':cleanup_pack_knit,
             'factory':make_pack_factory(True, True, 1),
             'graph':True,
             'key_length':1,
+            'support_partial_insertion': True,
             }),
         ('named-graph-nodelta-knit-pack', {
             'cleanup':cleanup_pack_knit,
             'factory':make_pack_factory(True, False, 1),
             'graph':True,
             'key_length':1,
+            'support_partial_insertion': False,
             }),
         ]
     len_two_adapter.scenarios = [
@@ -127,18 +133,21 @@
                 PrefixMapper()),
             'graph':True,
             'key_length':2,
+            'support_partial_insertion': False,
             }),
         ('annotated-knit-escape', {
             'cleanup':None,
             'factory':make_file_factory(True, HashEscapedPrefixMapper()),
             'graph':True,
             'key_length':2,
+            'support_partial_insertion': False,
             }),
         ('plain-knit-pack', {
             'cleanup':cleanup_pack_knit,
             'factory':make_pack_factory(True, True, 2),
             'graph':True,
             'key_length':2,
+            'support_partial_insertion': True,
             }),
         ]
     for test in iter_suite_tests(to_adapt):
@@ -1969,20 +1978,72 @@
         else:
             self.assertIdenticalVersionedFile(source, files)
 
+    def get_knit_delta_source(self):
+        """Get a source that can produce a stream with knit delta records,
+        regardless of this test's scenario.
+        """
+        mapper = self.get_mapper()
+        source_transport = self.get_transport('source')
+        source_transport.mkdir('.')
+        source = make_file_factory(False, mapper)(source_transport)
+        get_diamond_files(source, self.key_length, trailing_eol=True,
+            nograph=False, left_only=False)
+        return source
+
     def test_insert_record_stream_delta_missing_basis_no_corruption(self):
-        """Insertion where a needed basis is not included aborts safely."""
-        # We use a knit always here to be sure we are getting a binary delta.
-        mapper = self.get_mapper()
-        source_transport = self.get_transport('source')
-        source_transport.mkdir('.')
-        source = make_file_factory(False, mapper)(source_transport)
-        self.get_diamond_files(source)
-        entries = source.get_record_stream(['origin', 'merged'], 'unordered', False)
-        files = self.get_versionedfiles()
-        self.assertRaises(RevisionNotPresent, files.insert_record_stream,
-            entries)
+        """Insertion where a needed basis is not included notifies the caller
+        of the missing basis.  In the meantime a record missing its basis is
+        not added.
+        """
+        source = self.get_knit_delta_source()
+        keys = [self.get_simple_key('origin'), self.get_simple_key('merged')]
+        entries = source.get_record_stream(keys, 'unordered', False)
+        files = self.get_versionedfiles()
+        if self.support_partial_insertion:
+            self.assertEqual([],
+                list(files.get_missing_compression_parent_keys()))
+            files.insert_record_stream(entries)
+            missing_bases = files.get_missing_compression_parent_keys()
+            self.assertEqual(set([self.get_simple_key('left')]),
+                set(missing_bases))
+            self.assertEqual(set(keys), set(files.get_parent_map(keys)))
+        else:
+            self.assertRaises(
+                errors.RevisionNotPresent, files.insert_record_stream, entries)
+            files.check()
+
+    def test_insert_record_stream_delta_missing_basis_can_be_added_later(self):
+        """Insertion where a needed basis is not included notifies the caller
+        of the missing basis.  That basis can be added in a second
+        insert_record_stream call that does not need to repeat records present
+        in the previous stream.  The record(s) that required that basis are
+        fully inserted once their basis is no longer missing.
+        """
+        if not self.support_partial_insertion:
+            raise TestNotApplicable(
+                'versioned file scenario does not support partial insertion')
+        source = self.get_knit_delta_source()
+        entries = source.get_record_stream([self.get_simple_key('origin'),
+            self.get_simple_key('merged')], 'unordered', False)
+        files = self.get_versionedfiles()
+        files.insert_record_stream(entries)
+        missing_bases = files.get_missing_compression_parent_keys()
+        self.assertEqual(set([self.get_simple_key('left')]),
+            set(missing_bases))
+        # 'merged' is inserted (although a commit of a write group involving
+        # this versionedfiles would fail).
+        merged_key = self.get_simple_key('merged')
+        self.assertEqual(
+            [merged_key], files.get_parent_map([merged_key]).keys())
+        # Add the full delta closure of the missing records
+        missing_entries = source.get_record_stream(
+            missing_bases, 'unordered', True)
+        files.insert_record_stream(missing_entries)
+        # Now 'merged' is fully inserted (and a commit would succeed).
+        self.assertEqual([], list(files.get_missing_compression_parent_keys()))
+        self.assertEqual(
+            [merged_key], files.get_parent_map([merged_key]).keys())
         files.check()
-        self.assertEqual({}, files.get_parent_map([]))
 
     def test_iter_lines_added_or_present_in_keys(self):
         # test that we get at least an equalset of the lines added by

=== modified file 'bzrlib/versionedfile.py'
--- a/bzrlib/versionedfile.py	2009-02-03 01:38:45 +0000
+++ b/bzrlib/versionedfile.py	2009-02-20 02:38:28 +0000
@@ -925,6 +925,18 @@
 
     has_key = index._has_key_from_parent_map
 
+    def get_missing_compression_parent_keys(self):
+        """Return an iterable of keys of missing compression parents.
+
+        Check this after calling insert_record_stream to find out if there are
+        any missing compression parents.  If there are, the records that
+        depend on them are not able to be inserted safely. The precise
+        behaviour depends on the concrete VersionedFiles class in use.
+
+        Classes that do not support this will raise NotImplementedError.
+        """
+        raise NotImplementedError(self.get_missing_compression_parent_keys)
+
     def insert_record_stream(self, stream):
         """Insert a record stream into this container.
 




More information about the bazaar-commits mailing list