pretxnchangegroup hook fails because it can't acquire lock

Simon King simon at simonking.org.uk
Tue Nov 5 05:41:08 CST 2013


On Tue, Nov 5, 2013 at 9:06 AM, Pierre-Yves David
<pierre-yves.david at ens-lyon.org> wrote:
>
> On 5 nov. 2013, at 03:16, Mick Jordan wrote:
>
>> I have a pretxnchangegroup hook on a repo 'x' that runs a python script that, essentially, calls "hg push x-2', where other tests runs to determine whether the changegroup should be accepted. The repo is on a server that is receiving the push via http, using Apache 2.2 and hgweb. All the repo files are group apache and the owner of the files is trusted in the apache user .hgrc file. The system is essentially a Red Hat Linux 6.
>>
>> Mercurial is 2.2.2 and running under Python 2.6.6, which is the default installed Python. The hook script is running under python2.7.5, as it needs features from that version.
>>
>> First, 'hg outgoing http://x' works fine, so the basic permissions are correct (it too a while to get that far).
>>
>> However, the 'hg push http://x'  does not. The "hg push x-2" in the hook hangs waiting for the lock on 'x' and eventually times out. I can see the lock file in 'x/.hg/store' which is a symbolic link to the python process running hgweb.cgi (and hence the hook). Now, almost exactly the same configuration exists on another machine, running slightly different versions of Apache, hg, Linux and python and works flawlessly. So what is the problem on my machine? Does 'push' really need the lock? Is it yet another weird permissions problem?
>>
>> I can verify in another shell that I can clone 'x' to, say, 'y', but if I also explicitly attempt to then  'hg push 'y' ', I get the same 'waiting for lock message'.
>>
>> Someone who understand the Mercurial locking system please explain why this works on one machine but not another?
>
> from mercurial 2.1, hg push lock the repo (because push may change local phases). We made that optional (it push anyway if it fails to lock) in 2.6
>

(For reference, the BTS entry for this was
http://bz.selenic.com/show_bug.cgi?id=3684)

When the inability to lock the repository is caused by permission
problems, the fix in 2.6 is fine. However, in Mick's case, the problem
is that the repository is already locked by the parent push process.
The child push process tries to lock the repository and eventually
times out, and the parent push is rolled back.

Steps to reproduce:

#------------------------
hg init src
hg init dest1
hg init dest2

cat >dest1/.hg/hgrc <<EOF
[hooks]
pretxnchangegroup.push = hg push ../dest2
EOF

cat >hgrc <<EOF
[ui]
timeout=5
EOF

cd src/
touch a
hg ci -Am0

HGRCPATH=$PWD/../hgrc hg push ../dest1/
#------------------------

Result:

waiting for lock on repository /tmp/simonk/hgtest/dest1 held by 'srv:4187'
abort: repository /tmp/simonk/hgtest/dest1: timed out waiting for lock
held by srv:4187
transaction abort!
rollback completed
abort: pretxnchangegroup.push hook exited with status 255


I worked around this with an in-process hook to perform the push.
Because it's in-process, it inherits the parent lock so doesn't have
this problem:

#------------------------
import mercurial.commands

# It is no longer possible to run "hg push" in a pretxnchangegroup
# hook, because pushing requires locking the repository. This is an
# in-python version of the hook that works around the problem.
def pushwhilelocked(ui, repo, **kwargs):
    destnames = ['ontxnchangegroup', 'default-push', 'default']
    for dest in destnames:
        path = ui.config('paths', dest, None)
        if path is not None:
            break
    else:
        raise mercurial.util.Abort('no path to push to')

    return mercurial.commands.push(ui, repo, dest)
#------------------------

Enable it in the repository with something like:

[hooks]
pretxnchangegroup.push = python:/path/to/hook/script.py:pushwhilelocked


Hope that helps,

Simon


More information about the Mercurial mailing list