Rev 4194: Cache ghosts when we can get them from a RemoteRepository in get_parent_map. in http://people.ubuntu.com/~robertc/baz2.0/pending/Remote.negative_parents_cache
Robert Collins
robertc at robertcollins.net
Tue Mar 24 07:09:18 GMT 2009
At http://people.ubuntu.com/~robertc/baz2.0/pending/Remote.negative_parents_cache
------------------------------------------------------------
revno: 4194
revision-id: robertc at robertcollins.net-20090324070911-w59etn9q3f9xj4fu
parent: robertc at robertcollins.net-20090324060735-nk6ti3wq06062lvz
committer: Robert Collins <robertc at robertcollins.net>
branch nick: Remote.negative_parents_cache
timestamp: Tue 2009-03-24 18:09:11 +1100
message:
Cache ghosts when we can get them from a RemoteRepository in get_parent_map.
=== modified file 'bzrlib/graph.py'
--- a/bzrlib/graph.py 2009-03-24 05:11:56 +0000
+++ b/bzrlib/graph.py 2009-03-24 07:09:11 +0000
@@ -133,13 +133,13 @@
raise AssertionError('Cache enabled when already enabled.')
self._cache = {}
self._cache_misses = cache_misses
- self._missing_keys = set()
+ self.missing_keys = set()
def disable_cache(self):
"""Disable and clear the cache."""
self._cache = None
self._cache_misses = None
- self._missing_keys = set()
+ self.missing_keys = set()
def get_cached_map(self):
"""Return any cached get_parent_map values."""
@@ -157,14 +157,14 @@
# better.
needed_revisions = set(key for key in keys if key not in cache)
# Do not ask for negatively cached keys
- needed_revisions.difference_update(self._missing_keys)
+ needed_revisions.difference_update(self.missing_keys)
if needed_revisions:
parent_map = self._get_parent_map(needed_revisions)
cache.update(parent_map)
if self._cache_misses:
for key in needed_revisions:
if key not in parent_map:
- self._missing_keys.add(key)
+ self.note_missing_key(key)
result = {}
for key in keys:
value = cache.get(key)
@@ -172,6 +172,11 @@
result[key] = value
return result
+ def note_missing_key(self, key):
+ """Note that key is a missing key."""
+ if self._cache_misses:
+ self.missing_keys.add(key)
+
class Graph(object):
"""Provide incremental access to revision graphs.
=== modified file 'bzrlib/memorytree.py'
--- a/bzrlib/memorytree.py 2009-01-17 01:30:58 +0000
+++ b/bzrlib/memorytree.py 2009-03-24 07:09:11 +0000
@@ -212,8 +212,7 @@
def _populate_from_branch(self):
"""Populate the in-tree state from the branch."""
- self._basis_tree = self.branch.repository.revision_tree(
- self._branch_revision_id)
+ self._set_basis()
if self._branch_revision_id == _mod_revision.NULL_REVISION:
self._parent_ids = []
else:
@@ -280,13 +279,23 @@
_mod_revision.check_not_reserved_id(revision_id)
if len(revision_ids) == 0:
self._parent_ids = []
- self._basis_tree = self.branch.repository.revision_tree(
- _mod_revision.NULL_REVISION)
+ self._branch_revision_id = _mod_revision.NULL_REVISION
else:
self._parent_ids = revision_ids
- self._basis_tree = self.branch.repository.revision_tree(
- revision_ids[0])
self._branch_revision_id = revision_ids[0]
+ self._allow_leftmost_as_ghost = allow_leftmost_as_ghost
+ self._set_basis()
+
+ def _set_basis(self):
+ try:
+ self._basis_tree = self.branch.repository.revision_tree(
+ self._branch_revision_id)
+ except errors.NoSuchRevision:
+ if self._allow_leftmost_as_ghost:
+ self._basis_tree = self.branch.repository.revision_tree(
+ _mod_revision.NULL_REVISION)
+ else:
+ raise
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
"""See MutableTree.set_parent_trees()."""
=== modified file 'bzrlib/remote.py'
--- a/bzrlib/remote.py 2009-03-24 06:07:35 +0000
+++ b/bzrlib/remote.py 2009-03-24 07:09:11 +0000
@@ -1247,6 +1247,9 @@
for parents in parents_map.itervalues():
result_parents.update(parents)
stop_keys = result_parents.difference(start_set)
+ # We don't need to send ghosts back to the server as a position to
+ # stop either.
+ stop_keys.difference_update(self._unstacked_provider.missing_keys)
included_keys = start_set.intersection(result_parents)
start_set.difference_update(included_keys)
recipe = ('manual', start_set, stop_keys, len(parents_map))
@@ -1257,7 +1260,7 @@
raise ValueError(
"key %r not a plain string" % (key,))
verb = 'Repository.get_parent_map'
- args = (path,) + tuple(keys)
+ args = (path, 'include-missing:') + tuple(keys)
try:
response = self._call_with_body_bytes_expecting_body(
verb, args, body)
@@ -1291,8 +1294,14 @@
if len(d) > 1:
revision_graph[d[0]] = d[1:]
else:
- # No parents - so give the Graph result (NULL_REVISION,).
- revision_graph[d[0]] = (NULL_REVISION,)
+ # No parents:
+ if d[0].startswith('missing:'):
+ revid = d[0][8:]
+ self._unstacked_provider.note_missing_key(revid)
+ else:
+ # no parents - so give the Graph result
+ # (NULL_REVISION,).
+ revision_graph[d[0]] = (NULL_REVISION,)
return revision_graph
@needs_read_lock
=== modified file 'bzrlib/tests/test_graph.py'
--- a/bzrlib/tests/test_graph.py 2009-03-24 05:11:56 +0000
+++ b/bzrlib/tests/test_graph.py 2009-03-24 07:09:11 +0000
@@ -1432,6 +1432,13 @@
# only present 1 time.
self.assertEqual(['a', 'b'], sorted(self.inst_pp.calls))
+ def test_note_missing_key(self):
+ """After noting that a key is missing it is cached."""
+ self.caching_pp.note_missing_key('b')
+ self.assertEqual({}, self.caching_pp.get_parent_map(['b']))
+ self.assertEqual([], self.inst_pp.calls)
+ self.assertEqual(set(['b']), self.caching_pp.missing_keys)
+
class TestCachingParentsProviderExtras(tests.TestCaseWithTransport):
"""Test the behaviour when parents are provided that were not requested."""
=== modified file 'bzrlib/tests/test_remote.py'
--- a/bzrlib/tests/test_remote.py 2009-03-24 05:11:56 +0000
+++ b/bzrlib/tests/test_remote.py 2009-03-24 07:09:11 +0000
@@ -36,6 +36,7 @@
repository,
smart,
tests,
+ treebuilder,
urlutils,
)
from bzrlib.branch import Branch
@@ -1648,6 +1649,32 @@
'more-missing']))
self.assertLength(1, self.hpss_calls)
+ def test_get_parent_map_gets_ghosts_from_result(self):
+ # asking for a revision should negatively cache close ghosts in its
+ # ancestry.
+ self.setup_smart_server_with_call_log()
+ tree = self.make_branch_and_memory_tree('foo')
+ tree.lock_write()
+ try:
+ builder = treebuilder.TreeBuilder()
+ builder.start_tree(tree)
+ builder.build([])
+ builder.finish_tree()
+ tree.set_parent_ids(['non-existant'], allow_leftmost_as_ghost=True)
+ rev_id = tree.commit('')
+ finally:
+ tree.unlock()
+ tree.lock_read()
+ self.addCleanup(tree.unlock)
+ repo = tree.branch.repository
+ self.assertIsInstance(repo, RemoteRepository)
+ # ask for rev_id
+ repo.get_parent_map([rev_id])
+ self.reset_smart_call_log()
+ # Now asking for rev_id's ghost parent should not make calls
+ self.assertEqual({}, repo.get_parent_map(['non-existant']))
+ self.assertLength(0, self.hpss_calls)
+
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
@@ -2368,7 +2395,7 @@
rev_ord, expected_revs = self.get_ordered_revs('knit', 'topological')
self.assertEqual(expected_revs, rev_ord)
# Getting topological sort requires VFS calls still
- self.assertLength(14, self.hpss_calls)
+ self.assertLength(13, self.hpss_calls)
def test_stacked_get_stream_groupcompress(self):
# Repository._get_source.get_stream() from a stacked repository with
More information about the bazaar-commits
mailing list