mercurial/lock.py
author Gregory Szorc <gregory.szorc@gmail.com>
Tue, 20 Feb 2018 18:55:58 -0800
branchstable
changeset 36755 ff4bc0ab6740
parent 35209 9153871d50e0
child 35897 4b1c04082cdc
permissions -rw-r--r--
wireproto: check permissions when executing "batch" command (BC) (SEC) For as long as the "batch" command has existed (introduced by bd88561afb4b and first released as part of Mercurial 1.9), that command (like most wire commands introduced after 2008) lacked an entry in the hgweb permissions table. And since we don't verify permissions if an entry is missing from the permissions table, this meant that executing a command via "batch" would bypass all permissions checks. The security implications are significant: a Mercurial HTTP server would allow writes via "batch" wire protocol commands as long as the HTTP request were processed by Mercurial and the process running the Mercurial HTTP server had write access to the repository. The Mercurial defaults of servers being read-only and the various web.* config options to define access control were bypassed. In addition, "batch" could be used to exfiltrate data from servers that were configured to not allow read access. Both forms of permissions bypass could be mitigated to some extent by using HTTP authentication. This would prevent HTTP requests from hitting Mercurial's server logic. However, any authenticated request would still be able to bypass permissions checks via "batch" commands. The easiest exploit was to send "pushkey" commands via "batch" and modify the state of bookmarks, phases, and obsolescence markers. However, I suspect a well-crafted HTTP request could trick the server into running the "unbundle" wire protocol command, effectively performing a full `hg push` to create new changesets on the remote. This commit plugs this gaping security hole by having the "batch" command perform permissions checking on each sub-command that is being batched. We do this by threading a permissions checking callable all the way to the protocol handler. The threading is a bit hacky from a code perspective. But it preserves API compatibility, which is the proper thing to do on the stable branch. One of the subtle things we do is assume that a command with an undefined permission is a "push" command. This is the safest thing to do from a security perspective: we don't want to take chances that a command could perform a write even though the server is configured to not allow writes. As the test changes demonstrate, it is no longer possible to bypass permissions via the "batch" wire protocol command. .. bc:: The "batch" wire protocol command now enforces permissions of each invoked sub-command. Wire protocol commands must define their operation type or the "batch" command will assume they can write data and will prevent their execution on HTTP servers unless the HTTP request method is POST, the server is configured to allow pushes, and the (possibly authenticated) HTTP user is authorized to perform a push.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
9309
cfdcb7a465af localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents: 8312
diff changeset
     1
# lock.py - simple advisory locking scheme for mercurial
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
     2
#
2859
345bac2bc4ec update copyrights.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2579
diff changeset
     3
# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
     4
#
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 8113
diff changeset
     5
# This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 9858
diff changeset
     6
# GNU General Public License version 2 or any later version.
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
     7
25956
8cd30e9277ae lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     8
from __future__ import absolute_import
8cd30e9277ae lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     9
26473
5f94e64f182c lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents: 26387
diff changeset
    10
import contextlib
25956
8cd30e9277ae lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    11
import errno
30921
1f151a33af8e lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents: 30920
diff changeset
    12
import os
25956
8cd30e9277ae lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    13
import socket
8cd30e9277ae lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    14
import time
8113
87a1605979e4 add a deprecation warning for gc based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 8108
diff changeset
    15
import warnings
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    16
35208
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    17
from .i18n import _
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    18
25956
8cd30e9277ae lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    19
from . import (
31375
d57aa655ce97 lock: encode result of gethostname into a bytestring
Augie Fackler <augie@google.com>
parents: 31354
diff changeset
    20
    encoding,
25956
8cd30e9277ae lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    21
    error,
30921
1f151a33af8e lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents: 30920
diff changeset
    22
    pycompat,
25956
8cd30e9277ae lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    23
    util,
8cd30e9277ae lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    24
)
8cd30e9277ae lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    25
30920
dc9f086c7691 lock: move lock._host calculation to a function
Jun Wu <quark@fb.com>
parents: 28959
diff changeset
    26
def _getlockprefix():
dc9f086c7691 lock: move lock._host calculation to a function
Jun Wu <quark@fb.com>
parents: 28959
diff changeset
    27
    """Return a string which is used to differentiate pid namespaces
dc9f086c7691 lock: move lock._host calculation to a function
Jun Wu <quark@fb.com>
parents: 28959
diff changeset
    28
dc9f086c7691 lock: move lock._host calculation to a function
Jun Wu <quark@fb.com>
parents: 28959
diff changeset
    29
    It's useful to detect "dead" processes and remove stale locks with
30921
1f151a33af8e lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents: 30920
diff changeset
    30
    confidence. Typically it's just hostname. On modern linux, we include an
1f151a33af8e lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents: 30920
diff changeset
    31
    extra Linux-specific pid namespace identifier.
30920
dc9f086c7691 lock: move lock._host calculation to a function
Jun Wu <quark@fb.com>
parents: 28959
diff changeset
    32
    """
31378
2e48c776a874 lock: do not encode result of gethostname on Python 2
Yuya Nishihara <yuya@tcha.org>
parents: 31375
diff changeset
    33
    result = socket.gethostname()
2e48c776a874 lock: do not encode result of gethostname on Python 2
Yuya Nishihara <yuya@tcha.org>
parents: 31375
diff changeset
    34
    if pycompat.ispy3:
2e48c776a874 lock: do not encode result of gethostname on Python 2
Yuya Nishihara <yuya@tcha.org>
parents: 31375
diff changeset
    35
        result = result.encode(pycompat.sysstr(encoding.encoding), 'replace')
30921
1f151a33af8e lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents: 30920
diff changeset
    36
    if pycompat.sysplatform.startswith('linux'):
1f151a33af8e lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents: 30920
diff changeset
    37
        try:
1f151a33af8e lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents: 30920
diff changeset
    38
            result += '/%x' % os.stat('/proc/self/ns/pid').st_ino
1f151a33af8e lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents: 30920
diff changeset
    39
        except OSError as ex:
1f151a33af8e lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents: 30920
diff changeset
    40
            if ex.errno not in (errno.ENOENT, errno.EACCES, errno.ENOTDIR):
1f151a33af8e lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents: 30920
diff changeset
    41
                raise
1f151a33af8e lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents: 30920
diff changeset
    42
    return result
30920
dc9f086c7691 lock: move lock._host calculation to a function
Jun Wu <quark@fb.com>
parents: 28959
diff changeset
    43
35209
9153871d50e0 lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents: 35208
diff changeset
    44
def trylock(ui, vfs, lockname, timeout, warntimeout, *args, **kwargs):
35208
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    45
    """return an acquired lock or raise an a LockHeld exception
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    46
35209
9153871d50e0 lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents: 35208
diff changeset
    47
    This function is responsible to issue warnings and or debug messages about
9153871d50e0 lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents: 35208
diff changeset
    48
    the held lock while trying to acquires it."""
35208
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    49
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    50
    def printwarning(printer, locker):
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    51
        """issue the usual "waiting on lock" message through any channel"""
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    52
        # show more details for new-style locks
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    53
        if ':' in locker:
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    54
            host, pid = locker.split(":", 1)
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    55
            msg = _("waiting for lock on %s held by process %r "
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    56
                    "on host %r\n") % (l.desc, pid, host)
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    57
        else:
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    58
            msg = _("waiting for lock on %s held by %r\n") % (l.desc, locker)
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    59
        printer(msg)
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    60
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    61
    l = lock(vfs, lockname, 0, *args, dolock=False, **kwargs)
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    62
35209
9153871d50e0 lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents: 35208
diff changeset
    63
    debugidx = 0 if (warntimeout and timeout) else -1
35208
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    64
    warningidx = 0
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    65
    if not timeout:
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    66
        warningidx = -1
35209
9153871d50e0 lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents: 35208
diff changeset
    67
    elif warntimeout:
9153871d50e0 lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents: 35208
diff changeset
    68
        warningidx = warntimeout
35208
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    69
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    70
    delay = 0
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    71
    while True:
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    72
        try:
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    73
            l._trylock()
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    74
            break
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    75
        except error.LockHeld as inst:
35209
9153871d50e0 lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents: 35208
diff changeset
    76
            if delay == debugidx:
9153871d50e0 lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents: 35208
diff changeset
    77
                printwarning(ui.debug, inst.locker)
35208
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    78
            if delay == warningidx:
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    79
                printwarning(ui.warn, inst.locker)
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    80
            if timeout <= delay:
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    81
                raise error.LockHeld(errno.ETIMEDOUT, inst.filename,
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    82
                                     l.desc, inst.locker)
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    83
            time.sleep(1)
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    84
            delay += 1
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    85
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    86
    l.delay = delay
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    87
    if l.delay:
35209
9153871d50e0 lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents: 35208
diff changeset
    88
        if 0 <= warningidx <= l.delay:
9153871d50e0 lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents: 35208
diff changeset
    89
            ui.warn(_("got lock after %s seconds\n") % l.delay)
9153871d50e0 lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents: 35208
diff changeset
    90
        else:
9153871d50e0 lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents: 35208
diff changeset
    91
            ui.debug("got lock after %s seconds\n" % l.delay)
35208
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    92
    if l.acquirefn:
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    93
        l.acquirefn()
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    94
    return l
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
    95
1559
59b3639df0a9 Convert all classes to new-style classes by deriving them from object.
Eric Hopper <hopper@omnifarious.org>
parents: 1530
diff changeset
    96
class lock(object):
9309
cfdcb7a465af localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents: 8312
diff changeset
    97
    '''An advisory lock held by one process to control access to a set
cfdcb7a465af localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents: 8312
diff changeset
    98
    of files.  Non-cooperating processes or incorrectly written scripts
cfdcb7a465af localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents: 8312
diff changeset
    99
    can ignore Mercurial's locking scheme and stomp all over the
cfdcb7a465af localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents: 8312
diff changeset
   100
    repository, so don't do that.
cfdcb7a465af localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents: 8312
diff changeset
   101
cfdcb7a465af localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents: 8312
diff changeset
   102
    Typically used via localrepository.lock() to lock the repository
cfdcb7a465af localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents: 8312
diff changeset
   103
    store (.hg/store/) or localrepository.wlock() to lock everything
cfdcb7a465af localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents: 8312
diff changeset
   104
    else under .hg/.'''
cfdcb7a465af localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents: 8312
diff changeset
   105
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   106
    # lock is symlink on platforms that support it, file on others.
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   107
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   108
    # symlink is used because create of directory entry and contents
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   109
    # are atomic even over nfs.
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   110
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   111
    # old-style lock: symlink to pid
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   112
    # new-style lock: symlink to hostname:pid
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   113
4947
3e25a6eb5c9a lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents: 3877
diff changeset
   114
    _host = None
3e25a6eb5c9a lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents: 3877
diff changeset
   115
26321
db4c192cb9b3 lock: move acquirefn call to inside the lock
Siddharth Agarwal <sid0@fb.com>
parents: 26291
diff changeset
   116
    def __init__(self, vfs, file, timeout=-1, releasefn=None, acquirefn=None,
35208
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
   117
                 desc=None, inheritchecker=None, parentlock=None,
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
   118
                 dolock=True):
20091
abfe6a8e619b lock: take both vfs and lock file path relative to vfs to access via vfs
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 19927
diff changeset
   119
        self.vfs = vfs
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   120
        self.f = file
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   121
        self.held = 0
1787
e431344e604c add a timeout when a lock is held (default 1024 sec)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 1753
diff changeset
   122
        self.timeout = timeout
1530
abfab59fce79 add a releasefn keyword to lock.lock
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 1062
diff changeset
   123
        self.releasefn = releasefn
26321
db4c192cb9b3 lock: move acquirefn call to inside the lock
Siddharth Agarwal <sid0@fb.com>
parents: 26291
diff changeset
   124
        self.acquirefn = acquirefn
2016
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
   125
        self.desc = desc
26498
e8564e04382d lock: add a way to prevent locks from being inherited
Siddharth Agarwal <sid0@fb.com>
parents: 26474
diff changeset
   126
        self._inheritchecker = inheritchecker
26356
927fa07a2ba4 lock: introduce state to keep track of inheritance
Siddharth Agarwal <sid0@fb.com>
parents: 26321
diff changeset
   127
        self.parentlock = parentlock
927fa07a2ba4 lock: introduce state to keep track of inheritance
Siddharth Agarwal <sid0@fb.com>
parents: 26321
diff changeset
   128
        self._parentheld = False
927fa07a2ba4 lock: introduce state to keep track of inheritance
Siddharth Agarwal <sid0@fb.com>
parents: 26321
diff changeset
   129
        self._inherited = False
15589
cc24e4ed3e0c lock: change name of release chain
Matt Mackall <mpm@selenic.com>
parents: 15583
diff changeset
   130
        self.postrelease  = []
26383
0fceb34806e1 lock: add a wrapper to os.getpid() to make testing easier
Siddharth Agarwal <sid0@fb.com>
parents: 26359
diff changeset
   131
        self.pid = self._getpid()
35208
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
   132
        if dolock:
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
   133
            self.delay = self.lock()
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
   134
            if self.acquirefn:
1b758105b5c7 lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents: 32088
diff changeset
   135
                self.acquirefn()
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   136
27797
054abf2377e8 lock: turn a lock into a Python context manager
Bryan O'Sullivan <bryano@fb.com>
parents: 26498
diff changeset
   137
    def __enter__(self):
054abf2377e8 lock: turn a lock into a Python context manager
Bryan O'Sullivan <bryano@fb.com>
parents: 26498
diff changeset
   138
        return self
054abf2377e8 lock: turn a lock into a Python context manager
Bryan O'Sullivan <bryano@fb.com>
parents: 26498
diff changeset
   139
054abf2377e8 lock: turn a lock into a Python context manager
Bryan O'Sullivan <bryano@fb.com>
parents: 26498
diff changeset
   140
    def __exit__(self, exc_type, exc_value, exc_tb):
054abf2377e8 lock: turn a lock into a Python context manager
Bryan O'Sullivan <bryano@fb.com>
parents: 26498
diff changeset
   141
        self.release()
054abf2377e8 lock: turn a lock into a Python context manager
Bryan O'Sullivan <bryano@fb.com>
parents: 26498
diff changeset
   142
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   143
    def __del__(self):
8108
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   144
        if self.held:
8113
87a1605979e4 add a deprecation warning for gc based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 8108
diff changeset
   145
            warnings.warn("use lock.release instead of del lock",
87a1605979e4 add a deprecation warning for gc based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 8108
diff changeset
   146
                    category=DeprecationWarning,
87a1605979e4 add a deprecation warning for gc based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 8108
diff changeset
   147
                    stacklevel=2)
87a1605979e4 add a deprecation warning for gc based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 8108
diff changeset
   148
8108
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   149
            # ensure the lock will be removed
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   150
            # even if recursive locking did occur
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   151
            self.held = 1
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   152
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   153
        self.release()
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   154
26383
0fceb34806e1 lock: add a wrapper to os.getpid() to make testing easier
Siddharth Agarwal <sid0@fb.com>
parents: 26359
diff changeset
   155
    def _getpid(self):
28027
14033c5dd261 util: enable getpid to be replaced
timeless <timeless@mozdev.org>
parents: 27797
diff changeset
   156
        # wrapper around util.getpid() to make testing easier
14033c5dd261 util: enable getpid to be replaced
timeless <timeless@mozdev.org>
parents: 27797
diff changeset
   157
        return util.getpid()
26383
0fceb34806e1 lock: add a wrapper to os.getpid() to make testing easier
Siddharth Agarwal <sid0@fb.com>
parents: 26359
diff changeset
   158
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   159
    def lock(self):
1787
e431344e604c add a timeout when a lock is held (default 1024 sec)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 1753
diff changeset
   160
        timeout = self.timeout
14494
1ffeeb91c55d check-code: flag 0/1 used as constant Boolean expression
Martin Geisler <mg@lazybytes.net>
parents: 13281
diff changeset
   161
        while True:
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   162
            try:
26082
b188f60bd955 lock: make trylock private
Matt Mackall <mpm@selenic.com>
parents: 26081
diff changeset
   163
                self._trylock()
20380
c697b70f295f localrepo: give a sigh of relief when getting lock after waiting for it
Mads Kiilerich <madski@unity3d.com>
parents: 20091
diff changeset
   164
                return self.timeout - timeout
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23032
diff changeset
   165
            except error.LockHeld as inst:
1787
e431344e604c add a timeout when a lock is held (default 1024 sec)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 1753
diff changeset
   166
                if timeout != 0:
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   167
                    time.sleep(1)
1787
e431344e604c add a timeout when a lock is held (default 1024 sec)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 1753
diff changeset
   168
                    if timeout > 0:
e431344e604c add a timeout when a lock is held (default 1024 sec)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 1753
diff changeset
   169
                        timeout -= 1
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   170
                    continue
7640
7197812e8d44 error: move lock errors
Matt Mackall <mpm@selenic.com>
parents: 4959
diff changeset
   171
                raise error.LockHeld(errno.ETIMEDOUT, inst.filename, self.desc,
7197812e8d44 error: move lock errors
Matt Mackall <mpm@selenic.com>
parents: 4959
diff changeset
   172
                                     inst.locker)
515
03f27b1381f9 Whitespace cleanups
mpm@selenic.com
parents: 503
diff changeset
   173
26082
b188f60bd955 lock: make trylock private
Matt Mackall <mpm@selenic.com>
parents: 26081
diff changeset
   174
    def _trylock(self):
8108
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   175
        if self.held:
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   176
            self.held += 1
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   177
            return
4947
3e25a6eb5c9a lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents: 3877
diff changeset
   178
        if lock._host is None:
30920
dc9f086c7691 lock: move lock._host calculation to a function
Jun Wu <quark@fb.com>
parents: 28959
diff changeset
   179
            lock._host = _getlockprefix()
31354
e6a2b625e0d9 lock: use %d to format integer into a bytestring
Augie Fackler <augie@google.com>
parents: 30921
diff changeset
   180
        lockname = '%s:%d' % (lock._host, self.pid)
26081
3b6e5914edd8 lock: loop a finite number of times in trylock (issue4787)
Matt Mackall <mpm@selenic.com>
parents: 25956
diff changeset
   181
        retry = 5
3b6e5914edd8 lock: loop a finite number of times in trylock (issue4787)
Matt Mackall <mpm@selenic.com>
parents: 25956
diff changeset
   182
        while not self.held and retry:
3b6e5914edd8 lock: loop a finite number of times in trylock (issue4787)
Matt Mackall <mpm@selenic.com>
parents: 25956
diff changeset
   183
            retry -= 1
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   184
            try:
20091
abfe6a8e619b lock: take both vfs and lock file path relative to vfs to access via vfs
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 19927
diff changeset
   185
                self.vfs.makelock(lockname, self.f)
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   186
                self.held = 1
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23032
diff changeset
   187
            except (OSError, IOError) as why:
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   188
                if why.errno == errno.EEXIST:
26387
e16f80f89a29 lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents: 26383
diff changeset
   189
                    locker = self._readlock()
32087
e1938d6051da lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 31378
diff changeset
   190
                    if locker is None:
e1938d6051da lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 31378
diff changeset
   191
                        continue
e1938d6051da lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 31378
diff changeset
   192
26387
e16f80f89a29 lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents: 26383
diff changeset
   193
                    # special case where a parent process holds the lock -- this
e16f80f89a29 lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents: 26383
diff changeset
   194
                    # is different from the pid being different because we do
e16f80f89a29 lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents: 26383
diff changeset
   195
                    # want the unlock and postrelease functions to be called,
e16f80f89a29 lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents: 26383
diff changeset
   196
                    # but the lockfile to not be removed.
e16f80f89a29 lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents: 26383
diff changeset
   197
                    if locker == self.parentlock:
e16f80f89a29 lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents: 26383
diff changeset
   198
                        self._parentheld = True
e16f80f89a29 lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents: 26383
diff changeset
   199
                        self.held = 1
e16f80f89a29 lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents: 26383
diff changeset
   200
                        return
e16f80f89a29 lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents: 26383
diff changeset
   201
                    locker = self._testlock(locker)
3686
4308f4cdc07b Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 2859
diff changeset
   202
                    if locker is not None:
20091
abfe6a8e619b lock: take both vfs and lock file path relative to vfs to access via vfs
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 19927
diff changeset
   203
                        raise error.LockHeld(errno.EAGAIN,
abfe6a8e619b lock: take both vfs and lock file path relative to vfs to access via vfs
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 19927
diff changeset
   204
                                             self.vfs.join(self.f), self.desc,
7640
7197812e8d44 error: move lock errors
Matt Mackall <mpm@selenic.com>
parents: 4959
diff changeset
   205
                                             locker)
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   206
                else:
7640
7197812e8d44 error: move lock errors
Matt Mackall <mpm@selenic.com>
parents: 4959
diff changeset
   207
                    raise error.LockUnavailable(why.errno, why.strerror,
7197812e8d44 error: move lock errors
Matt Mackall <mpm@selenic.com>
parents: 4959
diff changeset
   208
                                                why.filename, self.desc)
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   209
32088
0d892d820a51 lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 32087
diff changeset
   210
        if not self.held:
0d892d820a51 lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 32087
diff changeset
   211
            # use empty locker to mean "busy for frequent lock/unlock
0d892d820a51 lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 32087
diff changeset
   212
            # by many processes"
0d892d820a51 lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 32087
diff changeset
   213
            raise error.LockHeld(errno.EAGAIN,
0d892d820a51 lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 32087
diff changeset
   214
                                 self.vfs.join(self.f), self.desc, "")
0d892d820a51 lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 32087
diff changeset
   215
26290
9664d32bd6cb lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26082
diff changeset
   216
    def _readlock(self):
9664d32bd6cb lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26082
diff changeset
   217
        """read lock and return its value
9664d32bd6cb lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26082
diff changeset
   218
9664d32bd6cb lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26082
diff changeset
   219
        Returns None if no lock exists, pid for old-style locks, and host:pid
9664d32bd6cb lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26082
diff changeset
   220
        for new-style locks.
9664d32bd6cb lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26082
diff changeset
   221
        """
9664d32bd6cb lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26082
diff changeset
   222
        try:
9664d32bd6cb lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26082
diff changeset
   223
            return self.vfs.readlock(self.f)
9664d32bd6cb lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26082
diff changeset
   224
        except (OSError, IOError) as why:
9664d32bd6cb lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26082
diff changeset
   225
            if why.errno == errno.ENOENT:
9664d32bd6cb lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26082
diff changeset
   226
                return None
9664d32bd6cb lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26082
diff changeset
   227
            raise
9664d32bd6cb lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26082
diff changeset
   228
26291
1d33842c5b3e lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26290
diff changeset
   229
    def _testlock(self, locker):
26290
9664d32bd6cb lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26082
diff changeset
   230
        if locker is None:
9664d32bd6cb lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26082
diff changeset
   231
            return None
2579
0875cda033fd use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2016
diff changeset
   232
        try:
0875cda033fd use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2016
diff changeset
   233
            host, pid = locker.split(":", 1)
0875cda033fd use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2016
diff changeset
   234
        except ValueError:
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   235
            return locker
4947
3e25a6eb5c9a lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents: 3877
diff changeset
   236
        if host != lock._host:
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   237
            return locker
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   238
        try:
2579
0875cda033fd use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2016
diff changeset
   239
            pid = int(pid)
9685
a820cd39d415 lock: catch specific exceptions
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9680
diff changeset
   240
        except ValueError:
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   241
            return locker
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   242
        if util.testpid(pid):
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   243
            return locker
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   244
        # if locker dead, break lock.  must do this with another lock
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   245
        # held, or can race and break valid lock.
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   246
        try:
20091
abfe6a8e619b lock: take both vfs and lock file path relative to vfs to access via vfs
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 19927
diff changeset
   247
            l = lock(self.vfs, self.f + '.break', timeout=0)
abfe6a8e619b lock: take both vfs and lock file path relative to vfs to access via vfs
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 19927
diff changeset
   248
            self.vfs.unlink(self.f)
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   249
            l.release()
7640
7197812e8d44 error: move lock errors
Matt Mackall <mpm@selenic.com>
parents: 4959
diff changeset
   250
        except error.LockError:
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   251
            return locker
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   252
26291
1d33842c5b3e lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26290
diff changeset
   253
    def testlock(self):
1d33842c5b3e lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26290
diff changeset
   254
        """return id of locker if lock is valid, else None.
1d33842c5b3e lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26290
diff changeset
   255
1d33842c5b3e lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26290
diff changeset
   256
        If old-style lock, we cannot tell what machine locker is on.
1d33842c5b3e lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26290
diff changeset
   257
        with new-style lock, if locker is on this machine, we can
1d33842c5b3e lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26290
diff changeset
   258
        see if locker is alive.  If locker is on this machine but
1d33842c5b3e lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26290
diff changeset
   259
        not alive, we can safely break lock.
1d33842c5b3e lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26290
diff changeset
   260
1d33842c5b3e lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26290
diff changeset
   261
        The lock file is only deleted when None is returned.
1d33842c5b3e lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26290
diff changeset
   262
1d33842c5b3e lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26290
diff changeset
   263
        """
1d33842c5b3e lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26290
diff changeset
   264
        locker = self._readlock()
1d33842c5b3e lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26290
diff changeset
   265
        return self._testlock(locker)
1d33842c5b3e lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents: 26290
diff changeset
   266
26473
5f94e64f182c lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents: 26387
diff changeset
   267
    @contextlib.contextmanager
5f94e64f182c lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents: 26387
diff changeset
   268
    def inherit(self):
5f94e64f182c lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents: 26387
diff changeset
   269
        """context for the lock to be inherited by a Mercurial subprocess.
26357
6979a1369185 lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents: 26356
diff changeset
   270
26473
5f94e64f182c lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents: 26387
diff changeset
   271
        Yields a string that will be recognized by the lock in the subprocess.
5f94e64f182c lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents: 26387
diff changeset
   272
        Communicating this string to the subprocess needs to be done separately
5f94e64f182c lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents: 26387
diff changeset
   273
        -- typically by an environment variable.
26357
6979a1369185 lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents: 26356
diff changeset
   274
        """
6979a1369185 lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents: 26356
diff changeset
   275
        if not self.held:
6979a1369185 lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents: 26356
diff changeset
   276
            raise error.LockInheritanceContractViolation(
26473
5f94e64f182c lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents: 26387
diff changeset
   277
                'inherit can only be called while lock is held')
26357
6979a1369185 lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents: 26356
diff changeset
   278
        if self._inherited:
6979a1369185 lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents: 26356
diff changeset
   279
            raise error.LockInheritanceContractViolation(
26473
5f94e64f182c lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents: 26387
diff changeset
   280
                'inherit cannot be called while lock is already inherited')
26498
e8564e04382d lock: add a way to prevent locks from being inherited
Siddharth Agarwal <sid0@fb.com>
parents: 26474
diff changeset
   281
        if self._inheritchecker is not None:
e8564e04382d lock: add a way to prevent locks from being inherited
Siddharth Agarwal <sid0@fb.com>
parents: 26474
diff changeset
   282
            self._inheritchecker()
26357
6979a1369185 lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents: 26356
diff changeset
   283
        if self.releasefn:
6979a1369185 lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents: 26356
diff changeset
   284
            self.releasefn()
6979a1369185 lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents: 26356
diff changeset
   285
        if self._parentheld:
6979a1369185 lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents: 26356
diff changeset
   286
            lockname = self.parentlock
6979a1369185 lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents: 26356
diff changeset
   287
        else:
6979a1369185 lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents: 26356
diff changeset
   288
            lockname = '%s:%s' % (lock._host, self.pid)
6979a1369185 lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents: 26356
diff changeset
   289
        self._inherited = True
26473
5f94e64f182c lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents: 26387
diff changeset
   290
        try:
5f94e64f182c lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents: 26387
diff changeset
   291
            yield lockname
5f94e64f182c lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents: 26387
diff changeset
   292
        finally:
5f94e64f182c lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents: 26387
diff changeset
   293
            if self.acquirefn:
5f94e64f182c lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents: 26387
diff changeset
   294
                self.acquirefn()
5f94e64f182c lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents: 26387
diff changeset
   295
            self._inherited = False
26358
de5a52e5eb9e lock: add a method to reacquire the lock after subprocesses exit
Siddharth Agarwal <sid0@fb.com>
parents: 26357
diff changeset
   296
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   297
    def release(self):
15583
926a06f7a353 lock: add mechanism to register post release callback
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 14494
diff changeset
   298
        """release the lock and execute callback function if any
926a06f7a353 lock: add mechanism to register post release callback
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 14494
diff changeset
   299
17537
31f32a96e1e3 Merge spelling fixes
Bryan O'Sullivan <bryano@fb.com>
parents: 17427 17510
diff changeset
   300
        If the lock has been acquired multiple times, the actual release is
17510
7c44b703657b spelling: release
timeless@mozdev.org
parents: 15589
diff changeset
   301
        delayed to the last release call."""
8108
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   302
        if self.held > 1:
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   303
            self.held -= 1
9680
8cea86d73887 lock: use '==' instead of 'is' for integer equality ('is' may not work)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9309
diff changeset
   304
        elif self.held == 1:
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   305
            self.held = 0
26383
0fceb34806e1 lock: add a wrapper to os.getpid() to make testing easier
Siddharth Agarwal <sid0@fb.com>
parents: 26359
diff changeset
   306
            if self._getpid() != self.pid:
18907
af9fa8d4c939 lock: if we fork, ensure that only the parent releases
Bryan O'Sullivan <bryano@fb.com>
parents: 17683
diff changeset
   307
                # we forked, and are not the parent
af9fa8d4c939 lock: if we fork, ensure that only the parent releases
Bryan O'Sullivan <bryano@fb.com>
parents: 17683
diff changeset
   308
                return
503
c6a2e41c8c60 Fix troubles with clone and exception handling
mpm@selenic.com
parents: 429
diff changeset
   309
            try:
23032
f484be02bd35 lock: while releasing, unlink lockfile even if the release function throws
Siddharth Agarwal <sid0@fb.com>
parents: 20380
diff changeset
   310
                if self.releasefn:
f484be02bd35 lock: while releasing, unlink lockfile even if the release function throws
Siddharth Agarwal <sid0@fb.com>
parents: 20380
diff changeset
   311
                    self.releasefn()
f484be02bd35 lock: while releasing, unlink lockfile even if the release function throws
Siddharth Agarwal <sid0@fb.com>
parents: 20380
diff changeset
   312
            finally:
26359
c545d51c901e lock.release: do not unlink inherited locks
Siddharth Agarwal <sid0@fb.com>
parents: 26358
diff changeset
   313
                if not self._parentheld:
c545d51c901e lock.release: do not unlink inherited locks
Siddharth Agarwal <sid0@fb.com>
parents: 26358
diff changeset
   314
                    try:
c545d51c901e lock.release: do not unlink inherited locks
Siddharth Agarwal <sid0@fb.com>
parents: 26358
diff changeset
   315
                        self.vfs.unlink(self.f)
c545d51c901e lock.release: do not unlink inherited locks
Siddharth Agarwal <sid0@fb.com>
parents: 26358
diff changeset
   316
                    except OSError:
c545d51c901e lock.release: do not unlink inherited locks
Siddharth Agarwal <sid0@fb.com>
parents: 26358
diff changeset
   317
                        pass
26474
431094a3b21f lock.release: don't call postrelease functions for inherited locks
Siddharth Agarwal <sid0@fb.com>
parents: 26473
diff changeset
   318
            # The postrelease functions typically assume the lock is not held
431094a3b21f lock.release: don't call postrelease functions for inherited locks
Siddharth Agarwal <sid0@fb.com>
parents: 26473
diff changeset
   319
            # at all.
431094a3b21f lock.release: don't call postrelease functions for inherited locks
Siddharth Agarwal <sid0@fb.com>
parents: 26473
diff changeset
   320
            if not self._parentheld:
431094a3b21f lock.release: don't call postrelease functions for inherited locks
Siddharth Agarwal <sid0@fb.com>
parents: 26473
diff changeset
   321
                for callback in self.postrelease:
431094a3b21f lock.release: don't call postrelease functions for inherited locks
Siddharth Agarwal <sid0@fb.com>
parents: 26473
diff changeset
   322
                    callback()
28959
518c3e392f75 lock: clear postrelease hooks list after usage
Gregory Szorc <gregory.szorc@gmail.com>
parents: 28027
diff changeset
   323
                # Prevent double usage and help clear cycles.
518c3e392f75 lock: clear postrelease hooks list after usage
Gregory Szorc <gregory.szorc@gmail.com>
parents: 28027
diff changeset
   324
                self.postrelease = None
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   325
8108
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   326
def release(*locks):
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   327
    for lock in locks:
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   328
        if lock is not None:
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   329
            lock.release()