Rev 3792: CombinedGraphIndex can now reload when calling key_count(). in http://bzr.arbash-meinel.com/branches/bzr/1.9-dev/pack_retry_153786
John Arbash Meinel
john at arbash-meinel.com
Thu Oct 23 21:08:23 BST 2008
At http://bzr.arbash-meinel.com/branches/bzr/1.9-dev/pack_retry_153786
------------------------------------------------------------
revno: 3792
revision-id: john at arbash-meinel.com-20081023200801-72xbksw2uyj8cdmq
parent: john at arbash-meinel.com-20081023193959-xdytlck4ym0vr6lt
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: pack_retry_153786
timestamp: Thu 2008-10-23 15:08:01 -0500
message:
CombinedGraphIndex can now reload when calling key_count().
-------------- next part --------------
=== modified file 'bzrlib/index.py'
--- a/bzrlib/index.py 2008-09-21 14:48:37 +0000
+++ b/bzrlib/index.py 2008-10-23 20:08:01 +0000
@@ -27,6 +27,7 @@
from bisect import bisect_right
from cStringIO import StringIO
import re
+import sys
from bzrlib.lazy_import import lazy_import
lazy_import(globals(), """
@@ -1106,12 +1107,16 @@
in the index list.
"""
- def __init__(self, indices):
+ def __init__(self, indices, reload_func=None):
"""Create a CombinedGraphIndex backed by indices.
:param indices: An ordered list of indices to query for data.
+ :param reload_func: A function to call if we find we are missing an
+ index. Should have the form reload_func() => True/False to indicate
+ if reloading actually changed anything.
"""
self._indices = indices
+ self._reload_func = reload_func
def __repr__(self):
return "%s(%s)" % (
@@ -1227,13 +1232,22 @@
def key_count(self):
"""Return an estimate of the number of keys in this index.
-
+
For CombinedGraphIndex this is approximated by the sum of the keys of
the child indices. As child indices may have duplicate keys this can
have a maximum error of the number of child indices * largest number of
keys in any index.
"""
- return sum((index.key_count() for index in self._indices), 0)
+ do_retry = True
+ while do_retry:
+ try:
+ return sum((index.key_count() for index in self._indices), 0)
+ except errors.NoSuchFile:
+ if self._reload_func is None:
+ raise
+ exc_type, exc_value, exc_traceback = sys.exc_info()
+ if not self._reload_func():
+ raise exc_type, exc_value, exc_traceback
def validate(self):
"""Validate that everything in the index can be accessed."""
=== modified file 'bzrlib/repofmt/pack_repo.py'
--- a/bzrlib/repofmt/pack_repo.py 2008-10-23 19:39:59 +0000
+++ b/bzrlib/repofmt/pack_repo.py 2008-10-23 20:08:01 +0000
@@ -452,10 +452,16 @@
# XXX: Probably 'can be written to' could/should be separated from 'acts
# like a knit index' -- mbp 20071024
- def __init__(self):
- """Create an AggregateIndex."""
+ def __init__(self, reload_func=None):
+ """Create an AggregateIndex.
+
+ :param reload_func: A function to call if we find we are missing an
+ index. Should have the form reload_func() => True/False to indicate
+ if reloading actually changed anything.
+ """
+ self._reload_func = reload_func
self.index_to_pack = {}
- self.combined_index = CombinedGraphIndex([])
+ self.combined_index = CombinedGraphIndex([], reload_func=reload_func)
self.data_access = _DirectPackAccess(self.index_to_pack)
self.add_callback = None
=== modified file 'bzrlib/tests/test_index.py'
--- a/bzrlib/tests/test_index.py 2008-09-02 17:52:00 +0000
+++ b/bzrlib/tests/test_index.py 2008-10-23 20:08:01 +0000
@@ -927,6 +927,38 @@
size = trans.put_file(name, stream)
return GraphIndex(trans, name, size)
+ def make_index_with_missing_children(self):
+ """Create a CombinedGraphIndex which will have missing indexes.
+
+ This creates a CGI which thinks it has 2 indexes, however they have
+ been deleted. If CGI._reload_func() is called, then it will repopulate
+ with a new index.
+
+ :return: (CombinedGraphIndex, reload_counter)
+ """
+ index1 = self.make_index('1', nodes=[(('1',), '', ())])
+ index2 = self.make_index('2', nodes=[(('2',), '', ())])
+ index3 = self.make_index('3', nodes=[
+ (('1',), '', ()),
+ (('2',), '', ())])
+
+ # total_reloads, num_changed, num_unchanged
+ reload_counter = [0, 0, 0]
+ def reload():
+ reload_counter[0] += 1
+ new_indices = [index3]
+ if index._indices == new_indices:
+ reload_counter[2] += 1
+ return False
+ reload_counter[1] += 1
+ index._indices[:] = new_indices
+ return True
+ index = CombinedGraphIndex([index1, index2], reload_func=reload)
+ trans = self.get_transport()
+ trans.delete('1')
+ trans.delete('2')
+ return index, reload_counter
+
def test_open_missing_index_no_error(self):
trans = self.get_transport()
index1 = GraphIndex(trans, 'missing', 100)
@@ -1070,6 +1102,20 @@
index = CombinedGraphIndex([])
index.validate()
+ def test_key_count_reloads(self):
+ index, reload_counter = self.make_index_with_missing_children()
+ self.assertEqual(2, index.key_count())
+ self.assertEqual([1, 1, 0], reload_counter)
+
+ def test_key_count_reloads_and_fails(self):
+ index, reload_counter = self.make_index_with_missing_children()
+ # We have deleted the underlying index, so we will try to reload, but
+ # still fail. This is mostly to test we don't get stuck in an infinite
+ # loop trying to reload
+ self.get_transport().delete('3')
+ self.assertRaises(errors.NoSuchFile, index.key_count)
+ self.assertEqual([2, 1, 1], reload_counter)
+
class TestInMemoryGraphIndex(TestCaseWithMemoryTransport):
More information about the bazaar-commits
mailing list