hgsql: move repo._afterlock callbacks execution after the sqllock release

Summary:
We are overriding the _afterlock to mind one more lock before executing
callbacks. We need that so our post commit hooks are executed out of the lock.

Test Plan: run tests

Reviewers: #sourcecontrol, ttung, durham

Reviewed By: durham

Differential Revision: https://phabricator.fb.com/D2809038

Signature: t1:2809038:1452124328:3b1d2da7711cdf1c97fe06d5dcf07be253582fcd
This commit is contained in:
Mateusz Kwapich 2016-01-06 16:37:46 -08:00
parent 45bc7261ee
commit bd3030045b
2 changed files with 25 additions and 4 deletions

View File

@ -35,7 +35,7 @@ UNIQUE KEY bookmarkindex (repo, namespace, name)
from mercurial.node import bin, hex, nullid, nullrev
from mercurial.i18n import _
from mercurial.extensions import wrapfunction, wrapcommand
from mercurial import error, cmdutil, revlog, localrepo
from mercurial import error, cmdutil, revlog
from mercurial import wireproto, bookmarks, repair, commands, hg, mdiff, phases
from mercurial import util, changegroup, exchange, bundle2, bundlerepo
from mercurial import demandimport
@ -366,7 +366,7 @@ def wraprepo(repo):
lockname = self._lockname(name)
# cast to int to prevent passing bad sql data
self.sqlcursor.execute("SELECT GET_LOCK('%s', %s)" %
self.sqlcursor.execute("SELECT GET_LOCK('%s', %s)" %
(lockname, self.locktimeout))
result = int(self.sqlcursor.fetchall()[0][0])
@ -375,10 +375,13 @@ def wraprepo(repo):
lockname)
self.heldlocks.add(name)
def hassqllock(self, name):
def hassqllock(self, name, checkserver=True):
if not name in self.heldlocks:
return False
if not checkserver:
return True
lockname = self._lockname(name)
self.sqlcursor.execute("SELECT IS_USED_LOCK('%s')" % (lockname,))
lockheldby = self.sqlcursor.fetchall()[0][0]
@ -398,6 +401,10 @@ def wraprepo(repo):
self.sqlcursor.fetchall()
self.heldlocks.discard(name)
for callback in self.sqlpostrelease:
callback()
self.sqlpostrelease = []
def transaction(self, *args, **kwargs):
tr = super(sqllocalrepo, self).transaction(*args, **kwargs)
if tr.count > 1:
@ -919,6 +926,12 @@ def wraprepo(repo):
raise CorruptionException(("unable to verify %d dependent " +
"revisions before adding a commit") % (len(missingrevs)))
def _afterlock(self, callback):
if self.hassqllock(writelock, checkserver=False):
self.sqlpostrelease.append(callback)
else:
return super(sqllocalrepo, self)._afterlock(callback)
ui = repo.ui
sqlargs = {}
@ -943,6 +956,7 @@ def wraprepo(repo):
repo.disablesync = False
repo.pendingrevs = []
repo.heldlocks = set()
repo.sqlpostrelease = []
repo.__class__ = sqllocalrepo

View File

@ -9,7 +9,7 @@
> bundle2lazylocking=True
> EOF
Test verify sql lock is not held during prelockrebase hook
Test verify sql lock is not held during prelockrebase and txnclose hooks
$ cat >> $TESTTMP/locktester.py <<EOF
> import os
@ -24,10 +24,17 @@ Test verify sql lock is not held during prelockrebase hook
$ cat >> master/.hg/hgrc <<EOF
> [hooks]
> prepushrebase=python:$TESTTMP/locktester.py:checklock
> txnclose=python:$TESTTMP/locktester.py:checklock
> EOF
$ cd master
$ touch a && hg ci -Aqm a
error: txnclose hook failed: lock was FREE
error: txnclose hook failed: lock was FREE
error: txnclose hook failed: lock was FREE
error: txnclose hook failed: lock was FREE
error: txnclose hook failed: lock was FREE
$ hg book master
error: txnclose hook failed: lock was FREE
$ cd ..
$ initclient client