[PATCH 1 of 3 STABLE?] localrepo: invalidate all file caches at acquisition of wlock (issue4378)

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Fri Nov 13 18:46:23 UTC 2015


# HG changeset patch
# User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
# Date 1447437921 -32400
#      Sat Nov 14 03:05:21 2015 +0900
# Branch stable
# Node ID 98381200f4c2516f7d04a550881ae92371f890f9
# Parent  8a256cee72c890c761918ec1d244b286694ac51b
localrepo: invalidate all file caches at acquisition of wlock (issue4378)

'repo.commit()' acquires "wlock" at the beginning of itself, and it is
enough to isolate parallel "hg commit"-like commands in many cases,
but sometimes not. For example:

    1. "hg commit" process P1 acquires wlock at the beginning of
       'repo.commit()'

    2. "hg commit" process P2 accesses 'repo.changelog' for some
       preparation, and this causes caching it

       recent "hg commit" implementation causes indirect access to
       changelog via 'repo.branchheads()'

    3. P2 waits for wlock at the beginning of 'repo.commit()'

    4. P1 creates new revision R1 as new parent of dirstate, and adds
       it to '.hg/store/00changelog.i'

    5. P1 releases wlock

    6. P2 acquires wlock

    7. P2 tries to get parents of dirstate

    8. cached 'repo.changelog' causes 'null' parent, because it
       doesn't contain R1 newly created above

    9. P2 creates new revision R2 as root (= orphan) revision

"dirstate parents" isn't target of store lock, but it is sensitive to
changes on '.hg/store/00changelog.i'.

The root cause of this issue is that properties cached before
acquisition of wlock are used, even if they are already changed on the
filesystem at acquisition of wlock.

To avoid such situation, this patch invalidates all file caches at
acquisition of wlock: 'invalidateall()' implies both 'invalidate()'
and 'invalidatedirstate()'.

'invalidate()' itself does not discard cached object, but force each
properties to check timestamp and so on (= lstat(2)) at next
access. It should be cheaper enough than processing inside wlock
scope.

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1327,7 +1327,7 @@ class localrepository(object):
             self._filecache['dirstate'].refresh()
 
         l = self._lock(self.vfs, "wlock", wait, unlock,
-                       self.invalidatedirstate, _('working directory of %s') %
+                       self.invalidateall, _('working directory of %s') %
                        self.origroot,
                        inheritchecker=self._wlockchecktransaction,
                        parentenvvar='HG_WLOCK_LOCKER')


More information about the Mercurial-devel mailing list