Patchwork [2,of,4,V3] branchmap: acquires lock before writting the rev branch cache

login
register
mail settings
Submitter Pierre-Yves David
Date Aug. 7, 2016, 2:24 p.m.
Message ID <c8475c98f614e363cf63.1470579893@nodosa.octopoid.net>
Download mbox | patch
Permalink /patch/16176/
State Accepted
Headers show

Comments

Pierre-Yves David - Aug. 7, 2016, 2:24 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@ens-lyon.org>
# Date 1470401836 -7200
#      Fri Aug 05 14:57:16 2016 +0200
# Node ID c8475c98f614e363cf634ecb11b311d3b3fcb6ca
# Parent  66809c98397f5b1dd69a5c3f0c98e44f6594f78f
# EXP-Topic vfsward
branchmap: acquires lock before writting the rev branch cache

We now attempt to acquire a lock and write the branch cache within that lock.
This would prevent cache corruption when multiple processes try to write the cache
at the same time.
Yuya Nishihara - Aug. 8, 2016, 12:31 p.m.
On Sun, 07 Aug 2016 16:24:53 +0200, Pierre-Yves David wrote:
> # HG changeset patch
> # User Pierre-Yves David <pierre-yves.david@ens-lyon.org>
> # Date 1470401836 -7200
> #      Fri Aug 05 14:57:16 2016 +0200
> # Node ID c8475c98f614e363cf634ecb11b311d3b3fcb6ca
> # Parent  66809c98397f5b1dd69a5c3f0c98e44f6594f78f
> # EXP-Topic vfsward
> branchmap: acquires lock before writting the rev branch cache
> 
> We now attempt to acquire a lock and write the branch cache within that lock.
> This would prevent cache corruption when multiple processes try to write the cache
> at the same time.
> 
> diff -r 66809c98397f -r c8475c98f614 mercurial/branchmap.py
> --- a/mercurial/branchmap.py	Fri Aug 05 14:54:46 2016 +0200
> +++ b/mercurial/branchmap.py	Fri Aug 05 14:57:16 2016 +0200
> @@ -470,8 +470,10 @@ class revbranchcache(object):
>      def write(self, tr=None):
>          """Save branch cache if it is dirty."""
>          repo = self._repo
> -        if True:
> +        wlock = None
> +        try:
>              if self._rbcnamescount < len(self._names):
> +                wlock = repo.wlock(wait=False)
>                  try:
>                      if self._rbcnamescount != 0:
>                          f = repo.vfs.open(_rbcnames, 'ab')
> @@ -501,6 +503,8 @@ class revbranchcache(object):
>  
>              start = self._rbcrevslen * _rbcrecsize
>              if start != len(self._rbcrevs):
> +                if wlock is None:
> +                    wlock = repo.wlock(wait=False)
>                  revs = min(len(repo.changelog),
>                             len(self._rbcrevs) // _rbcrecsize)
>                  try:
> @@ -521,3 +525,8 @@ class revbranchcache(object):
>                                    inst)
>                      return
>                  self._rbcrevslen = revs
> +        except error.LockHeld as inst:
> +            repo.ui.debug("couldn't write revision branch cache: %s\n" % inst)

We have to catch error.LockUnavailable as well in order to suppress permission
error. I'll do s/LockHeld/LockError/ in flight.

Patch

diff -r 66809c98397f -r c8475c98f614 mercurial/branchmap.py
--- a/mercurial/branchmap.py	Fri Aug 05 14:54:46 2016 +0200
+++ b/mercurial/branchmap.py	Fri Aug 05 14:57:16 2016 +0200
@@ -470,8 +470,10 @@  class revbranchcache(object):
     def write(self, tr=None):
         """Save branch cache if it is dirty."""
         repo = self._repo
-        if True:
+        wlock = None
+        try:
             if self._rbcnamescount < len(self._names):
+                wlock = repo.wlock(wait=False)
                 try:
                     if self._rbcnamescount != 0:
                         f = repo.vfs.open(_rbcnames, 'ab')
@@ -501,6 +503,8 @@  class revbranchcache(object):
 
             start = self._rbcrevslen * _rbcrecsize
             if start != len(self._rbcrevs):
+                if wlock is None:
+                    wlock = repo.wlock(wait=False)
                 revs = min(len(repo.changelog),
                            len(self._rbcrevs) // _rbcrecsize)
                 try:
@@ -521,3 +525,8 @@  class revbranchcache(object):
                                   inst)
                     return
                 self._rbcrevslen = revs
+        except error.LockHeld as inst:
+            repo.ui.debug("couldn't write revision branch cache: %s\n" % inst)
+        finally:
+            if wlock is not None:
+                wlock.release()