# HG changeset patch # User Boris Feld # Date 1470672882 -7200 # Node ID 0720e6265c8ad1dded51af78244bee96db3d3f5f # Parent 9bb4decd43b0c9fd0e1902ccaae550126fe415ce reposvfs: add a ward to check if locks are properly taken we wrap 'repo.svfs.audit' to check for the store lock when accessing file in '.hg/store' for writing. This caught a couple of instance where the transaction was released after the lock, we should probably have a dedicated checker for that case. diff -r 9bb4decd43b0 -r 0720e6265c8a mercurial/localrepo.py --- a/mercurial/localrepo.py Tue Jul 11 12:38:17 2017 +0200 +++ b/mercurial/localrepo.py Mon Aug 08 18:14:42 2016 +0200 @@ -423,6 +423,12 @@ self.svfs = self.store.vfs self.sjoin = self.store.join self.vfs.createmode = self.store.createmode + if (self.ui.configbool('devel', 'all-warnings') or + self.ui.configbool('devel', 'check-locks')): + if util.safehasattr(self.svfs, 'vfs'): # this is filtervfs + self.svfs.vfs.audit = self._getsvfsward(self.svfs.vfs.audit) + else: # standard vfs + self.svfs.audit = self._getsvfsward(self.svfs.audit) self._applyopenerreqs() if create: self._writerequirements() @@ -496,6 +502,25 @@ return ret return checkvfs + def _getsvfsward(self, origfunc): + """build a ward for self.svfs""" + rref = weakref.ref(self) + def checksvfs(path, mode=None): + ret = origfunc(path, mode=mode) + repo = rref() + if repo is None or not util.safehasattr(repo, '_lockref'): + return + if mode in (None, 'r', 'rb'): + return + if path.startswith(repo.sharedpath): + # truncate name relative to the repository (.hg) + path = path[len(repo.sharedpath) + 1:] + if repo._currentlock(repo._lockref) is None: + repo.ui.develwarn('write with no lock: "%s"' % path, + stacklevel=3) + return ret + return checksvfs + def close(self): self._writecaches() diff -r 9bb4decd43b0 -r 0720e6265c8a tests/test-devel-warnings.t --- a/tests/test-devel-warnings.t Tue Jul 11 12:38:17 2017 +0200 +++ b/tests/test-devel-warnings.t Mon Aug 08 18:14:42 2016 +0200 @@ -49,6 +49,11 @@ > with repo.vfs(b'branch', 'a'): > pass > + > @command(b'no-lock-write', [], '') + > def nolockwrite(ui, repo): + > with repo.svfs(b'fncache', 'a'): + > pass + > > @command(b'stripintr', [], '') > def stripintr(ui, repo): > lo = repo.lock() @@ -114,6 +119,9 @@ $ hg no-wlock-write devel-warn: write with no wlock: "branch" at: $TESTTMP/buggylocking.py:* (nowlockwrite) (glob) + $ hg no-lock-write + devel-warn: write with no lock: "fncache" at: $TESTTMP/buggylocking.py:* (nolockwrite) (glob) + Stripping from a transaction $ echo a > a