Rev 5100: Create an update policy. These are called when changes occur. in http://bzr.arbash-meinel.com/branches/bzr/lp/2.2.0b2-contained-pack
John Arbash Meinel
john at arbash-meinel.com
Mon Mar 8 21:15:16 GMT 2010
At http://bzr.arbash-meinel.com/branches/bzr/lp/2.2.0b2-contained-pack
------------------------------------------------------------
revno: 5100
revision-id: john at arbash-meinel.com-20100308211511-jmk25089ymoiwcl8
parent: john at arbash-meinel.com-20100308200153-ob1otaacxdq09gzb
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 2.2.0b2-contained-pack
timestamp: Mon 2010-03-08 15:15:11 -0600
message:
Create an update policy. These are called when changes occur.
Note that this still sees 'modify' as an remove+add pair.
-------------- next part --------------
=== modified file 'bzrlib/pack_collection.py'
--- a/bzrlib/pack_collection.py 2010-03-08 20:01:53 +0000
+++ b/bzrlib/pack_collection.py 2010-03-08 21:15:11 +0000
@@ -192,49 +192,27 @@
raise NotImplementedError(self.write_index)
-class GraphIndexPolicy(IndexPolicy):
- """An IndexPolicy that uses a GraphIndex at a particular location."""
-
- def __init__(self, transport, filename, builder_class, index_class):
- self.transport = transport
- self.filename = filename
- self._index_builder_class = builder_class
- self._index_class = index_class
-
- def _do_handle_missing_file(self):
- """What should we do if the file is not present when we want to read?
-
- By default, we do nothing, but a child can chose to raise an exception
- (meaning the file must always exist.)
- """
-
- def _do_get_file_mode(self):
- """Figure out what file mode we should use.
-
- Default is to just use 'None' which uses OS defaults.
- """
- return None
-
- def read_index(self):
- """See MemoTrackerPolicy.read_index"""
- try:
- index = self._index_class(self.transport, self.filename, size=None)
- index.key_count() # Trigger reading the header
- except errors.NoSuchFile, e:
- self._do_handle_missing_file()
- # if _do_handle_missing_file doesn't raise, then we just return
- # nothing, since there is nothing on disk to iterate.
- return []
- return [(k[0], v) for _, k, v in index.iter_all_entries()]
-
- def write_index(self, memos):
- """See MemoTrackerPolicy.write_index"""
- builder = self._index_builder_class(reference_lists=0,
- key_elements=1)
- for name, value in memos:
- builder.add_node((name,), value)
- self.transport.put_file(self.filename, builder.finish(),
- mode=self._do_get_file_mode())
+class UpdatePolicy(object):
+ """What should we do when data is updated."""
+
+ def memo_removed(self, name, value):
+ """Called when one of the entries is removed.
+
+ :param name: The name of the memo that was removed
+ :param value: The value for this name
+ """
+ # TODO: Do we need to know if this is a disk change (from save/reload
+ # noticing an update) versus a memory change (from calling code
+ # updating the info?)
+ raise NotImplementedError(self.memo_removed)
+
+ def memo_added(self, name, value):
+ """Called when one of the entries is removed.
+
+ :param name: The name of the memo that was removed
+ :param value: The value for this name
+ """
+ raise NotImplementedError(self.memo_added)
class MemoTracker(object):
@@ -255,9 +233,10 @@
not yet written to disk.)
"""
- def __init__(self, locking_policy, index_policy):
+ def __init__(self, locking_policy, index_policy, update_policy):
self.locking_policy = locking_policy
self.index_policy = index_policy
+ self.update_policy = update_policy
self._memos = None
# The set of memos() that were on disk when we read it last
self._last_read_memos = None
@@ -333,6 +312,7 @@
self._ensure_loaded()
assert name not in self._memos
self._memos[name] = value
+ self.update_policy.memo_added(name, value)
def get_memo(self, name):
"""Get the section (index) memo for the given name."""
@@ -347,6 +327,7 @@
self._ensure_loaded()
old = self._memos.pop(name)
assert old == value
+ self.update_policy.memo_removed(name, value)
def save(self):
"""Save the current in-memory content to disk."""
@@ -372,6 +353,59 @@
self.locking_policy.unlock()
+class GraphIndexPolicy(IndexPolicy):
+ """An IndexPolicy that uses a GraphIndex at a particular location."""
+
+ def __init__(self, transport, filename, builder_class, index_class):
+ self.transport = transport
+ self.filename = filename
+ self._index_builder_class = builder_class
+ self._index_class = index_class
+
+ def _do_handle_missing_file(self):
+ """What should we do if the file is not present when we want to read?
+
+ By default, we do nothing, but a child can chose to raise an exception
+ (meaning the file must always exist.)
+ """
+
+ def _do_get_file_mode(self):
+ """Figure out what file mode we should use.
+
+ Default is to just use 'None' which uses OS defaults.
+ """
+ return None
+
+ def read_index(self):
+ """See MemoTrackerPolicy.read_index"""
+ try:
+ index = self._index_class(self.transport, self.filename, size=None)
+ index.key_count() # Trigger reading the header
+ except errors.NoSuchFile, e:
+ self._do_handle_missing_file()
+ # if _do_handle_missing_file doesn't raise, then we just return
+ # nothing, since there is nothing on disk to iterate.
+ return []
+ return [(k[0], v) for _, k, v in index.iter_all_entries()]
+
+ def write_index(self, memos):
+ """See MemoTrackerPolicy.write_index"""
+ builder = self._index_builder_class(reference_lists=0,
+ key_elements=1)
+ for name, value in memos:
+ builder.add_node((name,), value)
+ self.transport.put_file(self.filename, builder.finish(),
+ mode=self._do_get_file_mode())
+
+
+class NoopUpdatePolicy(UpdatePolicy):
+
+ def memo_removed(self, name, value):
+ pass
+
+ def memo_added(self, name, value):
+ pass
+
class PackCollection(object):
"""This manages a collection of pack files.
=== modified file 'bzrlib/tests/test_pack_collection.py'
--- a/bzrlib/tests/test_pack_collection.py 2010-03-08 20:01:53 +0000
+++ b/bzrlib/tests/test_pack_collection.py 2010-03-08 21:15:11 +0000
@@ -141,6 +141,18 @@
return # No lock checking
+class LoggingUpdatePolicy(pack_collection.UpdatePolicy):
+
+ def __init__(self):
+ self.log = []
+
+ def memo_removed(self, name, value):
+ self.log.append(('removed', name, value))
+
+ def memo_added(self, name, value):
+ self.log.append(('added', name, value))
+
+
class TestMemoTracker(tests.TestCaseWithMemoryTransport):
_m1 = ('name1', 'content1')
@@ -158,7 +170,8 @@
tracker = pack_collection.MemoTracker(
TrivialLockingPolicy(),
pack_collection.GraphIndexPolicy(self.transport, 'meta',
- btree_index.BTreeBuilder, btree_index.BTreeGraphIndex))
+ btree_index.BTreeBuilder, btree_index.BTreeGraphIndex),
+ pack_collection.NoopUpdatePolicy())
return tracker
def assertDiffFromDisk(self, on_disk, active, d_removed, d_added,
@@ -194,6 +207,12 @@
self.assertEqual([(('name1',), 'content1')],
sorted([(n[1], n[2]) for n in btree.iter_all_entries()]))
+ def test_add_memo_calls_memo_added(self):
+ policy = LoggingUpdatePolicy()
+ self.tracker.update_policy = policy
+ self.tracker.add_memo(*self._m1)
+ self.assertEqual([('added', 'name1', 'content1')], policy.log)
+
def test_get_missing_memo(self):
self.assertRaises(KeyError, self.tracker.get_memo, 'not-there')
@@ -218,6 +237,13 @@
btree = btree_index.BTreeGraphIndex(self.transport, 'meta', size=None)
self.assertEqual(1, btree.key_count())
+ def test_remove_memo_calls_memo_removed(self):
+ policy = LoggingUpdatePolicy()
+ self.tracker.add_memo(*self._m1)
+ self.tracker.update_policy = policy
+ self.tracker.remove_memo(*self._m1)
+ self.assertEqual([('removed', 'name1', 'content1')], policy.log)
+
def test_add_with_concurrent_add(self):
self.tracker.add_memo(*self._m1)
self.tracker.save()
@@ -252,6 +278,26 @@
btree = btree_index.BTreeGraphIndex(self.transport, 'meta', size=None)
self.assertEqual(1, btree.key_count())
+ def test_save_calls_memo_added_removed(self):
+ self.tracker.add_memo(*self._m1)
+ self.tracker.add_memo(*self._m2)
+ self.tracker.save()
+ tracker2 = self.make_tracker()
+ tracker2.remove_memo(*self._m1)
+ tracker2.add_memo(*self._m3)
+ tracker2.save()
+ policy = LoggingUpdatePolicy()
+ self.tracker.update_policy = policy
+ self.tracker.save()
+ # When we save, tracker should notice that m1 was removed, and remove
+ # it from the in-memory structure.
+ self.assertEqual({'name2': 'content2',
+ 'name3': 'content3',
+ }, self.tracker._memos)
+ self.assertEqual([('removed', 'name1', 'content1'),
+ ('added', 'name3', 'content3'),
+ ], policy.log)
+
def test__diff_from_disk_no_changes(self):
self.tracker.add_memo(*self._m1)
self.tracker.save()
More information about the bazaar-commits
mailing list