Rev 4414: A new heads() method based on gdfo. in file:///home/vila/src/bzr/reviews/vila-better-heads/

Vincent Ladeuil v.ladeuil+lp at free.fr
Wed Jun 17 13:32:22 BST 2009


At file:///home/vila/src/bzr/reviews/vila-better-heads/

------------------------------------------------------------
revno: 4414
revision-id: v.ladeuil+lp at free.fr-20090617123221-ijscdmxhxds026c0
parent: v.ladeuil+lp at free.fr-20090616134841-mu1e58vknaend6dz
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: vila-better-heads
timestamp: Wed 2009-06-17 14:32:21 +0200
message:
  A new heads() method based on gdfo.
  
  * bzrlib/tests/test__known_graph.py:
  (TestKnownGraph.test_heads_with_ghost): Add tests to ensure ghosts
  are corectly handled.
  
  * bzrlib/_known_graph_py.py:
  (KnownGraph.heads): A new version taking avantage of gdfo to
  reduce the number of nodes processed. This implementation passes
  all the currenlty defined tests and then some. Using time_graph.py
  reports 0.220s instead of the previous 7.350s.
-------------- next part --------------
=== modified file 'bzrlib/_known_graph_py.py'
--- a/bzrlib/_known_graph_py.py	2009-06-16 13:48:41 +0000
+++ b/bzrlib/_known_graph_py.py	2009-06-17 12:32:21 +0000
@@ -245,6 +245,65 @@
         This is done by searching the ancestries of each key.  Any key that is
         reachable from another key is not returned; all the others are.
 
+        This operation scales with the relative depth between any two keys. It
+        uses gdfo to avoid walking all ancestry.
+
+        :param keys: An iterable of keys.
+        :return: A set of the heads. Note that as a set there is no ordering
+            information. Callers will need to filter their input to create
+            order if they need it.
+        """
+        candidate_nodes = dict((key, self._nodes[key]) for key in keys)
+        if revision.NULL_REVISION in candidate_nodes:
+            # NULL_REVISION is only a head if it is the only entry
+            candidate_nodes.pop(revision.NULL_REVISION)
+            if not candidate_nodes:
+                return frozenset([revision.NULL_REVISION])
+        if len(candidate_nodes) < 2:
+            # No or only one candidate
+            return frozenset(candidate_nodes)
+        heads_key = frozenset(candidate_nodes)
+        if heads_key != frozenset(keys):
+            # Mention duplicates
+            note('%s != %s', heads_key, frozenset(keys))
+        # Do we have a cached result ?
+        try:
+            heads = self._known_heads[heads_key]
+            return heads
+        except KeyError:
+            pass
+        # Let's compute the heads
+        seen = {}
+        pending = []
+        min_gdfo = None
+        for node in candidate_nodes.values():
+            if node.parent_keys: # protect against ghosts, jam, fixme ?
+                pending.extend(node.parent_keys)
+            if min_gdfo is None or node.gdfo < min_gdfo:
+                min_gdfo = node.gdfo
+        nodes = self._nodes
+        while pending:
+            node_key = pending.pop()
+            if node_key in seen:
+                # node already appears in some ancestry
+                continue
+            seen[node_key] = True
+            node = nodes[node_key]
+            if node.gdfo <= min_gdfo:
+                continue
+            if node.parent_keys: # protect against ghosts, jam, fixme ?
+                pending.extend(node.parent_keys)
+        heads = heads_key.difference(seen.keys())
+        if self.do_cache:
+            self._known_heads[heads_key] = heads
+        return heads
+
+    def xheads(self, keys):
+        """Return the heads from amongst keys.
+
+        This is done by searching the ancestries of each key.  Any key that is
+        reachable from another key is not returned; all the others are.
+
         This operation scales with the relative depth between any two keys. If
         any two keys are completely disconnected all ancestry of both sides
         will be retrieved.

=== modified file 'bzrlib/tests/test__known_graph.py'
--- a/bzrlib/tests/test__known_graph.py	2009-06-12 19:37:30 +0000
+++ b/bzrlib/tests/test__known_graph.py	2009-06-17 12:32:21 +0000
@@ -230,3 +230,14 @@
         self.assertEqual(set(['z']), graph.heads(['w', 's', 'z']))
         self.assertEqual(set(['w', 'q']), graph.heads(['w', 's', 'q']))
         self.assertEqual(set(['z']), graph.heads(['s', 'z']))
+
+    def test_heads_with_ghost(self):
+        graph = self.make_known_graph(test_graph.with_ghost)
+        self.assertEqual(set(['e', 'g']), graph.heads(['e', 'g']))
+        self.assertEqual(set(['a', 'c']), graph.heads(['a', 'c']))
+        self.assertEqual(set(['a', 'g']), graph.heads(['a', 'g']))
+        self.assertEqual(set(['f', 'g']), graph.heads(['f', 'g']))
+        self.assertEqual(set(['c']), graph.heads(['c', 'g']))
+        self.assertEqual(set(['c']), graph.heads(['c', 'b', 'd', 'g']))
+        self.assertEqual(set(['a', 'c']), graph.heads(['a', 'c', 'e', 'g']))
+        self.assertEqual(set(['a', 'c']), graph.heads(['a', 'c', 'f']))



More information about the bazaar-commits mailing list