Rev 3378: Create a StackedKnitAccess object to permit combining access objects for knits. in http://people.ubuntu.com/~robertc/baz2.0/shallow-branch

Robert Collins robertc at robertcollins.net
Tue Jun 17 04:56:15 BST 2008


At http://people.ubuntu.com/~robertc/baz2.0/shallow-branch

------------------------------------------------------------
revno: 3378
revision-id: robertc at robertcollins.net-20080617035603-2s1yg68n3jrgglxp
parent: robertc at robertcollins.net-20080612032525-hp52uf3wa7546c4u
committer: Robert Collins <robertc at robertcollins.net>
branch nick: stacking-knits
timestamp: Tue 2008-06-17 13:56:03 +1000
message:
  Create a StackedKnitAccess object to permit combining access objects for knits.
modified:
  bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
  bzrlib/tests/test_knit.py      test_knit.py-20051212171302-95d4c00dd5f11f2b
=== modified file 'bzrlib/knit.py'
--- a/bzrlib/knit.py	2008-06-11 07:22:00 +0000
+++ b/bzrlib/knit.py	2008-06-17 03:56:03 +0000
@@ -2264,6 +2264,81 @@
         self._write_index = index
 
 
+class StackedAccess(object):
+    """Access to records in multiple access objects."""
+
+    def __init__(self, backends):
+        """Create a StackedAccess object.
+        
+        :param backends: A dict of backends to query. This is referenced as
+            self.backends after construction and may be updated as needed.
+            Each key in backends should be the Index object that generates 
+            access_memo's to read from, and the value should be the access
+            object to pass such queries too.
+        """
+        self.backends = backends
+        self.writer = None
+
+    def add_raw_records(self, key_sizes, raw_data):
+        """Add raw knit bytes to.
+
+        The data is sent to the current writer's add_raw_records method
+        verbatim.
+
+        The result's are adapted in the manner expected by get_raw_records so
+        that they can be immediately requested again if desired.
+
+        :param sizes: An iterable of tuples containing the key and size of each
+            raw data segment.
+        :param raw_data: A bytestring containing the data.
+        :return: A list of memos to retrieve the record later. Each memo is an
+            opaque index memo. For StackedAccess the memo is: 
+            ((backend, original_memo), pos, size).
+        """
+        if type(raw_data) != str:
+            raise AssertionError(
+                'data must be plain bytes was %s' % type(raw_data))
+        result = []
+        writer = self.writer
+        for memo in self.backends[writer].add_raw_records(key_sizes, raw_data):
+            result.append(((writer, memo), memo[1], memo[2]))
+        return result
+
+    def get_raw_records(self, memos_for_retrieval):
+        """Get the raw bytes for a records.
+
+        :param memos_for_retrieval: An iterable containing the access memos for
+            retrieving the bytes.
+        :return: An iterator over the bytes of the records.
+        """
+        # Group into same-backend requests (without losing order), and then
+        # dispatch:
+        request_lists = []
+        current_index = None
+        for (index, original_memo), _, _ in memos_for_retrieval:
+            if current_index == index:
+                current_list.append(original_memo)
+            else:
+                if current_index is not None:
+                    request_lists.append((current_index, current_list))
+                current_index = index
+                current_list = [original_memo]
+        # handle the last entry
+        if current_index is not None:
+            request_lists.append((current_index, current_list))
+        for index, memos in request_lists:
+            for result in self.backends[index].get_raw_records(memos):
+                yield result
+
+    def set_writer(self, index):
+        """Select which backend from self.backends to write new records to.
+        
+        :param index: An index listed in self.backends that new writes should
+            be directed to.
+        """
+        self.writer = index
+
+
 # Deprecated, use PatienceSequenceMatcher instead
 KnitSequenceMatcher = patiencediff.PatienceSequenceMatcher
 

=== modified file 'bzrlib/tests/test_knit.py'
--- a/bzrlib/tests/test_knit.py	2008-06-11 04:20:16 +0000
+++ b/bzrlib/tests/test_knit.py	2008-06-17 03:56:03 +0000
@@ -46,6 +46,7 @@
     _KnitGraphIndex,
     _KnitKeyAccess,
     make_file_factory,
+    StackedAccess,
     )
 from bzrlib.osutils import split_lines
 from bzrlib.symbol_versioning import one_four
@@ -359,6 +360,62 @@
         self.assertEqual(['1234567890'], list(access.get_raw_records(memos)))
 
 
+class TestStackedKnitAccess(TestCaseWithMemoryTransport):
+    """Tests for the stacking access logic."""
+
+    def get_access(self):
+        return self._get_access()[0]
+
+    def _get_access(self, packname='packfile', index='FOO'):
+        transport = self.get_transport()
+        def write_data(bytes):
+            transport.append_bytes(packname, bytes)
+        writer = pack.ContainerWriter(write_data)
+        writer.begin()
+        access = _DirectPackAccess({})
+        access.set_writer(writer, index, (transport, packname))
+        return access, writer
+
+    def get_backend(self, name):
+        """Get a .knit style access instance for use as a backend."""
+        mapper = ConstantMapper(name)
+        access = _KnitKeyAccess(self.get_transport(), mapper)
+        return access
+
+    def test_read_from_two_backends(self):
+        backend1 = self.get_backend('1')
+        memos1 = backend1.add_raw_records([(('key1',), 10)], '1234567890')
+        backend2 = self.get_backend('2')
+        memos2 = backend2.add_raw_records([(('key2',), 10)], '0987654321')
+        backends = {"1":backend1, "2":backend2}
+        access = StackedAccess(backends)
+        # StackedIndex will decorate access_memos with the index returning
+        # each memo:
+        memos = [(("1", memos1[0]), 0, 10),(("2", memos2[0]), 0, 10)]
+        self.assertEqual(['1234567890', '0987654321'],
+            list(access.get_raw_records(memos)))
+
+    def test_set_writer(self):
+        """The writer should be settable post construction."""
+        backend1 = self.get_backend('1')
+        backend2 = self.get_backend('2')
+        backends = {"1":backend1, "2":backend2}
+        access = StackedAccess(backends)
+        # We test by writing data, changing the writer, writing again,
+        # Then reading both.
+        access.set_writer("1")
+        memos1 = access.add_raw_records([(('key1',), 10)], '1234567890')
+        # the returned memo should be decorated with the writer index
+        # and preserve the position and size fields:
+        self.assertEqual([(("1", (('key1',), 0, 10)), 0, 10)], memos1)
+        access.set_writer("2")
+        memos2 = access.add_raw_records([(('key2',), 10)], '0987654321')
+        self.assertEqual([(("2", (('key2',), 0, 10)), 0, 10)], memos2)
+        memos = [memos1[0], memos2[0]]
+        self.assertEqual(['1234567890', '0987654321'],
+            list(access.get_raw_records(memos)))
+
+
 class LowLevelKnitDataTests(TestCase):
 
     def create_gz_content(self, text):




More information about the bazaar-commits mailing list