Rev 3478: (broken) start working on some ideas for generating dotted revnos without searching the whole graph. in http://bzr.arbash-meinel.com/branches/bzr/1.6-dev/lazy_revno

John Arbash Meinel john at arbash-meinel.com
Fri Jun 6 14:10:33 BST 2008


At http://bzr.arbash-meinel.com/branches/bzr/1.6-dev/lazy_revno

------------------------------------------------------------
revno: 3478
revision-id: john at arbash-meinel.com-20080606131011-xv0frx6tepflevrw
parent: pqm at pqm.ubuntu.com-20080605191237-2306x0goo9pfh9to
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: lazy_revno
timestamp: Fri 2008-06-06 08:10:11 -0500
message:
  (broken) start working on some ideas for generating dotted revnos without searching the whole graph.
-------------- next part --------------
=== modified file 'bzrlib/graph.py'
--- a/bzrlib/graph.py	2008-05-29 20:17:37 +0000
+++ b/bzrlib/graph.py	2008-06-06 13:10:11 +0000
@@ -1397,3 +1397,90 @@
         """
         return self._keys
 
+
+class LazyRevnoMapper(object):
+    """Compute dotted revnos without walking the whole graph.
+    
+    :ivar _parent_provider: An object that implements .get_parent_map()
+    :ivar _distance_to_null: Map revision_id => known distance to null (aka
+        revno if this is in the mainline.)
+        Currently not used, this could be useful as it would be preserved
+        different tip_revision_ids.
+    :ivar _revno: Map revision_id => known revno, mainline revisions will be
+        a simple integer, others will be a 3-integer tuple
+    :ivar _known_children: revision_id => children we have encountered
+    :ivar _tip_revision_id: Dotted revnos are calculated relative to this
+        revision_id.
+    :ivar _merged_into_at_least: Map revision_id => the first mainline revno we
+        know of that has this revision in its ancestry.
+    :ivar _cur_mainline_tip: (revno, revision_id) tuple which indicates how far
+        we have walked along the mailine.
+    """
+
+    def __init__(self, parent_provider, tip_revision_id, tip_revno):
+        assert isinstance(tip_revno, int)
+        self._parent_provider = parent_provider
+        self.get_parent_map = self._parent_provider.get_parent_map
+        self._tip_revision_id = tip_revision_id
+        # self._distance_to_null = {tip_revision_id:tip_revno}
+        self._revno = {tip_revision_id:tip_revno}
+        self._merged_into_at_least = {tip_revision_id:tip_revno}
+        self._known_children = {}
+
+        self._cur_mainline_revno = tip_revno
+        self._cur_mainline_tip = tip_revision_id
+
+    def get_dotted_revno(self, revision_id):
+        """Compute the dotted revno for revision_id
+
+        :param revision_id: The revision id we are curious about.
+        :return: The revno for the given revision. Either a simple integer, or
+            a 3-integer tuple.
+        """
+        if revision_id in self._revno:
+            return self._revno[revision_id]
+
+    def _update_known_children(self, parent_map):
+        for revision_id, parent_ids in parent_map.iteritems():
+            for p_id in parent_ids:
+                self._known_children.setdefault(p_id, set()).add(revision_id)
+
+    def _find_boundary_revisions(self, revision_id):
+        """Walk backwards until we find the mainline revision we descend from.
+
+        This walks the left-hand parent of both the mainline and the
+        revision_id until we find the point at which they converge, reach
+        NULL_REVISION, or a ghost.
+        """
+        next_parent_request = set()
+        # Have we finished walking the mainline?
+        if self._cur_mainline_tip is not None:
+            next_parent_request.add(self._cur_mainline_tip)
+        next_parent_request.add(revision_id)
+
+        cur_revision_ancestor_id = revision_id
+        while cur_revision_ancestor_id is not None and next_parent_request:
+            if cur_revision_ancestor_id in self._revno:
+                # We know the revno for this revision, is it on the mainline?
+                revno = self._revno[cur_revision_ancestor_id]
+                if isinstance(revno, int): # Mainline, we are done
+                    pass # XXX: ???
+            parent_map = self.get_parent_map(next_parent_request)
+            self._update_known_children(parent_map)
+
+            # Step the mainline searcher
+            if self._cur_mainline_tip is not None:
+                # TODO: handle ghosts here
+                next_mainline_parents = parent_map[self._cur_mainline_tip]
+                next_mainline_tip = next_mainline_parents[0]
+                revno = self._cur_mainline_revno - 1
+                self._cur_mainline_tip = next_mainline_tip
+                self._cur_mainline_revno = revno
+                self._merged_into_at_least[next_mainline_tip] = revno
+                self._revno[next_mainline_tip] = revno
+
+            # XXX: handle ghosts
+            cur_parent_ids = parent_map[cur_revision_ancestor_id]
+            for p_id in cur_parent_ids:
+                self._known_children.setdefault(p_id,
+                    set()).add(cur_revision_ancestor_id)

=== modified file 'bzrlib/tests/test_graph.py'
--- a/bzrlib/tests/test_graph.py	2008-05-29 20:17:37 +0000
+++ b/bzrlib/tests/test_graph.py	2008-06-06 13:10:11 +0000
@@ -1354,3 +1354,20 @@
         # Use sorted because we don't care about the order, just that each is
         # only present 1 time.
         self.assertEqual(['a', 'b'], sorted(self.inst_pp.calls))
+
+
+class TestLazyRevnoMapper(TestGraphBase):
+
+    def make_mapper(self, ancestors, tip):
+        graph = self.make_graph(ancestors)
+        tip_revno = graph.find_distance_to_null(tip, [])
+        return _mod_graph.LazyRevnoMapper(graph, tip, tip_revno)
+
+    def test_init(self):
+        mapper = self.make_mapper(ancestry_1, 'rev4')
+        self.assertEqual(4, mapper._distance_to_null['rev4'])
+        self.assertEqual(4, mapper._dotted_revno['rev4'])
+
+    def test_tip_revision(self):
+        mapper = self.make_mapper(ancestry_1, 'rev4')
+        self.assertEqual(4, mapper.get_dotted_revno('rev4'))



More information about the bazaar-commits mailing list