mercurial/lock.py
author Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
Wed, 22 Apr 2009 02:01:22 +0200
changeset 8108 a26d33749bd8
parent 7640 7197812e8d44
child 8113 87a1605979e4
permissions -rw-r--r--
made repo locks recursive and deprecate refcounting based lock releasing all locks should use the explicit lock.release mercurial.lock.lock.__del__ handles unwrapping recursive locks localrepo.lock/wlock are still using weakref in order to keep backward compatibiltiy to releasing locks via garbage collection by ensuring the release on __del__
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
     1
# lock.py - simple locking scheme for mercurial
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
#
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
     5
# This software may be used and distributed according to the terms
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
     6
# of the GNU General Public License, incorporated herein by reference.
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
     7
7640
7197812e8d44 error: move lock errors
Matt Mackall <mpm@selenic.com>
parents: 4959
diff changeset
     8
import errno, os, socket, time, util, error
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
     9
1559
59b3639df0a9 Convert all classes to new-style classes by deriving them from object.
Eric Hopper <hopper@omnifarious.org>
parents: 1530
diff changeset
    10
class lock(object):
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
    11
    # 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
    12
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
    13
    # 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
    14
    # 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
    15
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
    16
    # 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
    17
    # 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
    18
4947
3e25a6eb5c9a lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents: 3877
diff changeset
    19
    _host = None
3e25a6eb5c9a lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents: 3877
diff changeset
    20
2016
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
    21
    def __init__(self, file, timeout=-1, releasefn=None, desc=None):
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    22
        self.f = file
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    23
        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
    24
        self.timeout = timeout
1530
abfab59fce79 add a releasefn keyword to lock.lock
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 1062
diff changeset
    25
        self.releasefn = releasefn
2016
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
    26
        self.desc = desc
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    27
        self.lock()
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    28
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    29
    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
    30
        if self.held:
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
    31
            # 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
    32
            # 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
    33
            self.held = 1
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
    34
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    35
        self.release()
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    36
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    37
    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
    38
        timeout = self.timeout
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    39
        while 1:
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    40
            try:
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    41
                self.trylock()
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    42
                return 1
7640
7197812e8d44 error: move lock errors
Matt Mackall <mpm@selenic.com>
parents: 4959
diff changeset
    43
            except error.LockHeld, 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
    44
                if timeout != 0:
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    45
                    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
    46
                    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
    47
                        timeout -= 1
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    48
                    continue
7640
7197812e8d44 error: move lock errors
Matt Mackall <mpm@selenic.com>
parents: 4959
diff changeset
    49
                raise error.LockHeld(errno.ETIMEDOUT, inst.filename, self.desc,
7197812e8d44 error: move lock errors
Matt Mackall <mpm@selenic.com>
parents: 4959
diff changeset
    50
                                     inst.locker)
515
03f27b1381f9 Whitespace cleanups
mpm@selenic.com
parents: 503
diff changeset
    51
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    52
    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
    53
        if self.held:
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
    54
            self.held += 1
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
    55
            return
4947
3e25a6eb5c9a lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents: 3877
diff changeset
    56
        if lock._host is None:
3e25a6eb5c9a lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents: 3877
diff changeset
    57
            lock._host = socket.gethostname()
4959
8933b8ea871a Use format string for lockname again (was changed by 3e25a6eb5c9a)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4947
diff changeset
    58
        lockname = '%s:%s' % (lock._host, os.getpid())
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
    59
        while not self.held:
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
    60
            try:
4947
3e25a6eb5c9a lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents: 3877
diff changeset
    61
                util.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
    62
                self.held = 1
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
    63
            except (OSError, IOError), why:
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
    64
                if why.errno == errno.EEXIST:
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
    65
                    locker = self.testlock()
3686
4308f4cdc07b Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 2859
diff changeset
    66
                    if locker is not None:
7640
7197812e8d44 error: move lock errors
Matt Mackall <mpm@selenic.com>
parents: 4959
diff changeset
    67
                        raise error.LockHeld(errno.EAGAIN, self.f, self.desc,
7197812e8d44 error: move lock errors
Matt Mackall <mpm@selenic.com>
parents: 4959
diff changeset
    68
                                             locker)
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
    69
                else:
7640
7197812e8d44 error: move lock errors
Matt Mackall <mpm@selenic.com>
parents: 4959
diff changeset
    70
                    raise error.LockUnavailable(why.errno, why.strerror,
7197812e8d44 error: move lock errors
Matt Mackall <mpm@selenic.com>
parents: 4959
diff changeset
    71
                                                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
    72
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
    73
    def testlock(self):
3686
4308f4cdc07b Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 2859
diff changeset
    74
        """return id of locker if lock is valid, else None.
4308f4cdc07b Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 2859
diff changeset
    75
4308f4cdc07b Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 2859
diff changeset
    76
        If old-style lock, we cannot tell what machine locker is on.
4308f4cdc07b Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 2859
diff changeset
    77
        with new-style lock, if locker is on this machine, we can
4308f4cdc07b Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 2859
diff changeset
    78
        see if locker is alive.  If locker is on this machine but
4308f4cdc07b Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 2859
diff changeset
    79
        not alive, we can safely break lock.
4308f4cdc07b Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 2859
diff changeset
    80
4308f4cdc07b Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 2859
diff changeset
    81
        The lock file is only deleted when None is returned.
4308f4cdc07b Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 2859
diff changeset
    82
4308f4cdc07b Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 2859
diff changeset
    83
        """
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
    84
        locker = util.readlock(self.f)
2579
0875cda033fd use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2016
diff changeset
    85
        try:
0875cda033fd use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2016
diff changeset
    86
            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
    87
        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
    88
            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
    89
        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
    90
            return locker
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
    91
        try:
2579
0875cda033fd use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2016
diff changeset
    92
            pid = int(pid)
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
    93
        except:
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
    94
            return locker
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
    95
        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
    96
            return locker
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
    97
        # 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
    98
        # 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
    99
        try:
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   100
            l = lock(self.f + '.break')
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   101
            l.trylock()
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   102
            os.unlink(self.f)
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
   103
            l.release()
7640
7197812e8d44 error: move lock errors
Matt Mackall <mpm@selenic.com>
parents: 4959
diff changeset
   104
        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
   105
            return locker
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   106
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   107
    def release(self):
8108
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   108
        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
   109
            self.held -= 1
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   110
        elif self.held is 1:
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   111
            self.held = 0
1530
abfab59fce79 add a releasefn keyword to lock.lock
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 1062
diff changeset
   112
            if self.releasefn:
abfab59fce79 add a releasefn keyword to lock.lock
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 1062
diff changeset
   113
                self.releasefn()
503
c6a2e41c8c60 Fix troubles with clone and exception handling
mpm@selenic.com
parents: 429
diff changeset
   114
            try:
c6a2e41c8c60 Fix troubles with clone and exception handling
mpm@selenic.com
parents: 429
diff changeset
   115
                os.unlink(self.f)
c6a2e41c8c60 Fix troubles with clone and exception handling
mpm@selenic.com
parents: 429
diff changeset
   116
            except: pass
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
   117
8108
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   118
def release(*locks):
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   119
    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
   120
        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
   121
            lock.release()
a26d33749bd8 made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7640
diff changeset
   122