[PATCH] localrepo: Add locking to _branchtags around _writebrancache

Joshua Redstone joshua.redstone at fb.com
Thu May 24 09:50:53 CDT 2012


# HG changeset patch
# User Joshua Redstone <joshua.redstone at fb.com>
# Date 1336812429 25200
# Node ID b3bb1d7360c481b847431fc0d264111b1d93f993
# Parent  2ac08d8b21aa7b6e0a062afed5a3f357ccef67f9
localrepo:  Add locking to _branchtags around _writebrancache

Read code paths such as via localrepo.branchmap() may end up calling
_writebranchcache without having acquire a repo lock, potentially leading to
races with other repo mutations.  This fix acquires the repo lock if not yet
held before calling _writebranchcache.

diff -r 2ac08d8b21aa -r b3bb1d7360c4 mercurial/localrepo.py
--- a/mercurial/localrepo.py	Tue May 22 14:37:20 2012 -0500
+++ b/mercurial/localrepo.py	Sat May 12 01:47:09 2012 -0700
@@ -481,8 +481,18 @@
         if lrev != tiprev:
             ctxgen = (self[r] for r in xrange(lrev + 1, tiprev + 1))
             self._updatebranchcache(partial, ctxgen)
-            self._writebranchcache(partial, self.changelog.tip(), tiprev)
-
+            # Read code paths (e.g., from branchmap()) do not have the lock
+            # yet.  Lock acquisition may fail if we do not have write-access
+            # to the directory.
+            try:
+                wlock = self.wlock(wait=False)
+                try:
+                    self._writebranchcache(partial, self.changelog.tip(),
+                                           tiprev)
+                finally:
+                    wlock.release()
+            except error.LockError:
+                pass
         return partial
 
     def updatebranchcache(self):
diff -r 2ac08d8b21aa -r b3bb1d7360c4 mercurial/statichttprepo.py
--- a/mercurial/statichttprepo.py	Tue May 22 14:37:20 2012 -0500
+++ b/mercurial/statichttprepo.py	Sat May 12 01:47:09 2012 -0700
@@ -133,6 +133,11 @@
     def lock(self, wait=True):
         raise util.Abort(_('cannot lock static-http repository'))
 
+    def wlock(self, wait=True):
+        raise error.LockError(0, "statichttprepository",
+                              "statichttprepository does not support locking",
+                              "statichttprepository")
+
 def instance(ui, path, create):
     if create:
         raise util.Abort(_('cannot create new static-http repository'))
diff -r 2ac08d8b21aa -r b3bb1d7360c4 tests/test-bheads.t
--- a/tests/test-bheads.t	Tue May 22 14:37:20 2012 -0500
+++ b/tests/test-bheads.t	Sat May 12 01:47:09 2012 -0700
@@ -31,6 +31,14 @@
 
 =======
 
+Not being able to update the branchheads cache should not make read ops fail
+  $ echo "junk" > $TESTTMP/a/.hg/cache/branchheads
+  $ chmod -R u-w $TESTTMP/a/.hg
+  $ heads
+  1: Adding a branch (a)
+  0: Adding root node ()
+  $ chmod -R u+w $TESTTMP/a/.hg
+
   $ hg update -C 0
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ echo 'b' >b


More information about the Mercurial-devel mailing list