Rev 4636: Merge more-auto-resolvable-conflicts into next in file:///home/vila/src/bzr/experimental/conflict-manager/

Vincent Ladeuil v.ladeuil+lp at free.fr
Fri Nov 12 09:35:50 GMT 2010


At file:///home/vila/src/bzr/experimental/conflict-manager/

------------------------------------------------------------
revno: 4636 [merge]
revision-id: v.ladeuil+lp at free.fr-20101112093550-09e5gwbm849t13hr
parent: v.ladeuil+lp at free.fr-20101112093421-cvi642pphr4ghuep
parent: v.ladeuil+lp at free.fr-20101112093550-lu7eyt0kg4ztdyf7
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: next
timestamp: Fri 2010-11-12 10:35:50 +0100
message:
  Merge more-auto-resolvable-conflicts into next
modified:
  bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
  bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
  bzrlib/tests/blackbox/test_branch.py test_branch.py-20060524161337-noms9gmcwqqrfi8y-1
  bzrlib/tests/per_branch/test_tags.py test_tags.py-20070212110545-w2s799hm2jlbsmg5-1
  doc/en/release-notes/bzr-2.3.txt NEWS-20050323055033-4e00b5db738777ff
-------------- next part --------------
=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2010-10-12 09:46:37 +0000
+++ b/bzrlib/branch.py	2010-11-11 03:53:12 +0000
@@ -92,6 +92,7 @@
         self._revision_id_to_revno_cache = None
         self._partial_revision_id_to_revno_cache = {}
         self._partial_revision_history_cache = []
+        self._tags_bytes = None
         self._last_revision_info_cache = None
         self._merge_sorted_revisions_cache = None
         self._open_hook()
@@ -227,6 +228,7 @@
             possible_transports=[self.bzrdir.root_transport])
         return a_branch.repository
 
+    @needs_read_lock
     def _get_tags_bytes(self):
         """Get the bytes of a serialised tags dict.
 
@@ -239,7 +241,9 @@
         :return: The bytes of the tags file.
         :seealso: Branch._set_tags_bytes.
         """
-        return self._transport.get_bytes('tags')
+        if self._tags_bytes is None:
+            self._tags_bytes = self._transport.get_bytes('tags')
+        return self._tags_bytes
 
     def _get_nick(self, local=False, possible_transports=None):
         config = self.get_config()
@@ -876,8 +880,12 @@
 
         :seealso: Branch._get_tags_bytes.
         """
-        return _run_with_write_locked_target(self, self._transport.put_bytes,
-            'tags', bytes)
+        return _run_with_write_locked_target(self, self._set_tags_bytes_locked,
+                bytes)
+
+    def _set_tags_bytes_locked(self, bytes):
+        self._tags_bytes = bytes
+        return self._transport.put_bytes('tags', bytes)
 
     def _cache_revision_history(self, rev_history):
         """Set the cached revision history to rev_history.
@@ -913,6 +921,7 @@
         self._merge_sorted_revisions_cache = None
         self._partial_revision_history_cache = []
         self._partial_revision_id_to_revno_cache = {}
+        self._tags_bytes = None
 
     def _gen_revision_history(self):
         """Return sequence of revision hashes on to this branch.

=== modified file 'bzrlib/remote.py'
--- a/bzrlib/remote.py	2010-09-26 02:27:37 +0000
+++ b/bzrlib/remote.py	2010-11-11 03:53:12 +0000
@@ -2369,7 +2369,13 @@
         self._ensure_real()
         return self._real_branch._get_tags_bytes()
 
+    @needs_read_lock
     def _get_tags_bytes(self):
+        if self._tags_bytes is None:
+            self._tags_bytes = self._get_tags_bytes_via_hpss()
+        return self._tags_bytes
+
+    def _get_tags_bytes_via_hpss(self):
         medium = self._client._medium
         if medium._is_remote_before((1, 13)):
             return self._vfs_get_tags_bytes()
@@ -2385,6 +2391,8 @@
         return self._real_branch._set_tags_bytes(bytes)
 
     def _set_tags_bytes(self, bytes):
+        if self.is_locked():
+            self._tags_bytes = bytes
         medium = self._client._medium
         if medium._is_remote_before((1, 18)):
             self._vfs_set_tags_bytes(bytes)

=== modified file 'bzrlib/tests/blackbox/test_branch.py'
--- a/bzrlib/tests/blackbox/test_branch.py	2010-07-21 20:09:34 +0000
+++ b/bzrlib/tests/blackbox/test_branch.py	2010-11-10 05:43:15 +0000
@@ -414,7 +414,7 @@
         # being too low. If rpc_count increases, more network roundtrips have
         # become necessary for this use case. Please do not adjust this number
         # upwards without agreement from bzr's network support maintainers.
-        self.assertLength(38, self.hpss_calls)
+        self.assertLength(37, self.hpss_calls)
 
     def test_branch_from_trivial_branch_streaming_acceptance(self):
         self.setup_smart_server_with_call_log()
@@ -429,7 +429,7 @@
         # being too low. If rpc_count increases, more network roundtrips have
         # become necessary for this use case. Please do not adjust this number
         # upwards without agreement from bzr's network support maintainers.
-        self.assertLength(10, self.hpss_calls)
+        self.assertLength(9, self.hpss_calls)
 
     def test_branch_from_trivial_stacked_branch_streaming_acceptance(self):
         self.setup_smart_server_with_call_log()
@@ -449,7 +449,7 @@
         # being too low. If rpc_count increases, more network roundtrips have
         # become necessary for this use case. Please do not adjust this number
         # upwards without agreement from bzr's network support maintainers.
-        self.assertLength(15, self.hpss_calls)
+        self.assertLength(14, self.hpss_calls)
 
 
 class TestRemoteBranch(TestCaseWithSFTPServer):

=== modified file 'bzrlib/tests/per_branch/test_tags.py'
--- a/bzrlib/tests/per_branch/test_tags.py	2010-03-12 02:14:56 +0000
+++ b/bzrlib/tests/per_branch/test_tags.py	2010-11-11 03:53:12 +0000
@@ -108,7 +108,6 @@
         # and it keeps the same value
         self.assertEquals(b2.tags.lookup_tag('conflicts'), 'revid-2')
 
-
     def test_unicode_tag(self):
         b1 = self.make_branch('b')
         tag_name = u'\u3070'
@@ -143,6 +142,90 @@
         b2 = self.make_branch('b2')
         b1.tags.merge_to(b2.tags)
 
+    def test_read_lock_caches_tags(self):
+        """Tags are read from a branch only once during a read-lock."""
+        # Open the same branch twice.  Read-lock one, and then mutate the tags
+        # in the second.  The read-locked branch never re-reads the tags, so it
+        # never observes the changed/new tags.
+        b1 = self.make_branch('b')
+        b1.tags.set_tag('one', 'rev-1')
+        b2 = b1.bzrdir.open_branch()
+        b1.lock_read()
+        self.assertEqual({'one': 'rev-1'}, b1.tags.get_tag_dict())
+        # Add a tag and modify a tag in b2.  b1 is read-locked and has already
+        # read the tags, so it is unaffected.
+        b2.tags.set_tag('one', 'rev-1-changed')
+        b2.tags.set_tag('two', 'rev-2')
+        self.assertEqual({'one': 'rev-1'}, b1.tags.get_tag_dict())
+        b1.unlock()
+        # Once unlocked the cached value is forgotten, so now the latest tags
+        # will be retrieved.
+        self.assertEqual(
+            {'one': 'rev-1-changed', 'two': 'rev-2'}, b1.tags.get_tag_dict())
+
+    def test_unlocked_does_not_cache_tags(self):
+        """Unlocked branches do not cache tags."""
+        # Open the same branch twice.
+        b1 = self.make_branch('b')
+        b1.tags.set_tag('one', 'rev-1')
+        b2 = b1.bzrdir.open_branch()
+        self.assertEqual({'one': 'rev-1'}, b1.tags.get_tag_dict())
+        # Add a tag and modify a tag in b2.  b1 isn't locked, so it will
+        # immediately return the new tags too.
+        b2.tags.set_tag('one', 'rev-1-changed')
+        b2.tags.set_tag('two', 'rev-2')
+        self.assertEqual(
+            {'one': 'rev-1-changed', 'two': 'rev-2'}, b1.tags.get_tag_dict())
+
+    def test_cached_tag_dict_not_accidentally_mutable(self):
+        """When there's a cached version of the tags, b.tags.get_tag_dict
+        returns a copy of the cached data so that callers cannot accidentally
+        corrupt the cache.
+        """
+        b = self.make_branch('b')
+        b.tags.set_tag('one', 'rev-1')
+        self.addCleanup(b.lock_read().unlock)
+        # The first time the data returned will not be in the cache
+        tags_dict = b.tags.get_tag_dict()
+        tags_dict['two'] = 'rev-2'
+        # The second time the data comes from the cache
+        tags_dict = b.tags.get_tag_dict()
+        tags_dict['three'] = 'rev-3'
+        # The get_tag_dict() result should still be unchanged, even though we
+        # mutated its earlier return values.
+        self.assertEqual({'one': 'rev-1'}, b.tags.get_tag_dict())
+
+    def make_write_locked_branch_with_one_tag(self):
+        b = self.make_branch('b')
+        b.tags.set_tag('one', 'rev-1')
+        self.addCleanup(b.lock_write().unlock)
+        # Populate the cache
+        b.tags.get_tag_dict()
+        return b
+
+    def test_set_tag_invalides_cache(self):
+        b = self.make_write_locked_branch_with_one_tag()
+        b.tags.set_tag('one', 'rev-1-changed')
+        self.assertEqual({'one': 'rev-1-changed'}, b.tags.get_tag_dict())
+
+    def test_delete_tag_invalides_cache(self):
+        b = self.make_write_locked_branch_with_one_tag()
+        b.tags.delete_tag('one')
+        self.assertEqual({}, b.tags.get_tag_dict())
+
+    def test_merge_to_invalides_cache(self):
+        b1 = self.make_write_locked_branch_with_one_tag()
+        b2 = self.make_branch('b2')
+        b2.tags.set_tag('two', 'rev-2')
+        b2.tags.merge_to(b1.tags)
+        self.assertEqual(
+            {'one': 'rev-1', 'two': 'rev-2'}, b1.tags.get_tag_dict())
+
+    def test_rename_revisions_invalides_cache(self):
+        b = self.make_write_locked_branch_with_one_tag()
+        b.tags.rename_revisions({'rev-1': 'rev-1-changed'})
+        self.assertEqual({'one': 'rev-1-changed'}, b.tags.get_tag_dict())
+
 
 class TestUnsupportedTags(per_branch.TestCaseWithBranch):
     """Formats that don't support tags should give reasonable errors."""

=== modified file 'doc/en/release-notes/bzr-2.3.txt'
--- a/doc/en/release-notes/bzr-2.3.txt	2010-11-12 09:34:20 +0000
+++ b/doc/en/release-notes/bzr-2.3.txt	2010-11-12 09:35:50 +0000
@@ -26,6 +26,10 @@
 .. Improvements to existing commands, especially improved performance 
    or memory usage, or better results.
 
+* Bazaar now caches a branch's tags while that branch is read-locked.
+  This removes 1 network roundtrip from most interactions with a remote
+  branch.  (Andrew Bennetts)
+
 * ``bzr config <option>`` will now display only the value itself so scripts
   can use it to query the currently active configuration. Displaying several
   options matching a given regular expression is now controlled via the



More information about the bazaar-commits mailing list