##// END OF EJS Templates
Backed out changeset: e1dde7363601
Backed out changeset: e1dde7363601

File last commit:

r10263:25e57239 stable
r11310:ac873ecf default
Show More
lock.py
137 lines | 4.2 KiB | text/x-python | PythonLexer
Greg Ward
localrepo: document the locking scheme a little better...
r9309 # lock.py - simple advisory locking scheme for mercurial
mpm@selenic.com
Simply repository locking...
r161 #
Vadim Gelfer
update copyrights.
r2859 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
mpm@selenic.com
Simply repository locking...
r161 #
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
mpm@selenic.com
Simply repository locking...
r161
Simon Heimberg
separate import lines from mercurial and general python modules
r8312 import util, error
import errno, os, socket, time
Ronny Pfannschmidt
add a deprecation warning for gc based lock releasing
r8113 import warnings
mpm@selenic.com
Simply repository locking...
r161
Eric Hopper
Convert all classes to new-style classes by deriving them from object.
r1559 class lock(object):
Greg Ward
localrepo: document the locking scheme a little better...
r9309 '''An advisory lock held by one process to control access to a set
of files. Non-cooperating processes or incorrectly written scripts
can ignore Mercurial's locking scheme and stomp all over the
repository, so don't do that.
Typically used via localrepository.lock() to lock the repository
store (.hg/store/) or localrepository.wlock() to lock everything
else under .hg/.'''
Vadim Gelfer
change lock format to let us detect and break stale locks....
r1877 # lock is symlink on platforms that support it, file on others.
# symlink is used because create of directory entry and contents
# are atomic even over nfs.
# old-style lock: symlink to pid
# new-style lock: symlink to hostname:pid
Bryan O'Sullivan
lock.py: cache hostname, but not pid, in case we fork
r4947 _host = None
Vadim Gelfer
fix backtrace printed when cannot get lock....
r2016 def __init__(self, file, timeout=-1, releasefn=None, desc=None):
mpm@selenic.com
Simply repository locking...
r161 self.f = file
self.held = 0
Benoit Boissinot
add a timeout when a lock is held (default 1024 sec)...
r1787 self.timeout = timeout
Benoit Boissinot
add a releasefn keyword to lock.lock...
r1530 self.releasefn = releasefn
Vadim Gelfer
fix backtrace printed when cannot get lock....
r2016 self.desc = desc
mpm@selenic.com
Simply repository locking...
r161 self.lock()
def __del__(self):
Ronny Pfannschmidt
made repo locks recursive and deprecate refcounting based lock releasing...
r8108 if self.held:
Ronny Pfannschmidt
add a deprecation warning for gc based lock releasing
r8113 warnings.warn("use lock.release instead of del lock",
category=DeprecationWarning,
stacklevel=2)
Ronny Pfannschmidt
made repo locks recursive and deprecate refcounting based lock releasing...
r8108 # ensure the lock will be removed
# even if recursive locking did occur
self.held = 1
mpm@selenic.com
Simply repository locking...
r161 self.release()
def lock(self):
Benoit Boissinot
add a timeout when a lock is held (default 1024 sec)...
r1787 timeout = self.timeout
mpm@selenic.com
Simply repository locking...
r161 while 1:
try:
self.trylock()
return 1
Matt Mackall
error: move lock errors...
r7640 except error.LockHeld, inst:
Benoit Boissinot
add a timeout when a lock is held (default 1024 sec)...
r1787 if timeout != 0:
mpm@selenic.com
Simply repository locking...
r161 time.sleep(1)
Benoit Boissinot
add a timeout when a lock is held (default 1024 sec)...
r1787 if timeout > 0:
timeout -= 1
mpm@selenic.com
Simply repository locking...
r161 continue
Matt Mackall
error: move lock errors...
r7640 raise error.LockHeld(errno.ETIMEDOUT, inst.filename, self.desc,
inst.locker)
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Simply repository locking...
r161 def trylock(self):
Ronny Pfannschmidt
made repo locks recursive and deprecate refcounting based lock releasing...
r8108 if self.held:
self.held += 1
return
Bryan O'Sullivan
lock.py: cache hostname, but not pid, in case we fork
r4947 if lock._host is None:
lock._host = socket.gethostname()
Thomas Arendsen Hein
Use format string for lockname again (was changed by 3e25a6eb5c9a)
r4959 lockname = '%s:%s' % (lock._host, os.getpid())
Vadim Gelfer
change lock format to let us detect and break stale locks....
r1877 while not self.held:
try:
Bryan O'Sullivan
lock.py: cache hostname, but not pid, in case we fork
r4947 util.makelock(lockname, self.f)
Vadim Gelfer
change lock format to let us detect and break stale locks....
r1877 self.held = 1
except (OSError, IOError), why:
if why.errno == errno.EEXIST:
locker = self.testlock()
Thomas Arendsen Hein
Don't step into an endless loop when lock file is empty.
r3686 if locker is not None:
Matt Mackall
error: move lock errors...
r7640 raise error.LockHeld(errno.EAGAIN, self.f, self.desc,
locker)
Vadim Gelfer
change lock format to let us detect and break stale locks....
r1877 else:
Matt Mackall
error: move lock errors...
r7640 raise error.LockUnavailable(why.errno, why.strerror,
why.filename, self.desc)
Vadim Gelfer
change lock format to let us detect and break stale locks....
r1877
def testlock(self):
Thomas Arendsen Hein
Don't step into an endless loop when lock file is empty.
r3686 """return id of locker if lock is valid, else None.
If old-style lock, we cannot tell what machine locker is on.
with new-style lock, if locker is on this machine, we can
see if locker is alive. If locker is on this machine but
not alive, we can safely break lock.
The lock file is only deleted when None is returned.
"""
Vadim Gelfer
change lock format to let us detect and break stale locks....
r1877 locker = util.readlock(self.f)
Benoit Boissinot
use __contains__, index or split instead of str.find...
r2579 try:
host, pid = locker.split(":", 1)
except ValueError:
Vadim Gelfer
change lock format to let us detect and break stale locks....
r1877 return locker
Bryan O'Sullivan
lock.py: cache hostname, but not pid, in case we fork
r4947 if host != lock._host:
Vadim Gelfer
change lock format to let us detect and break stale locks....
r1877 return locker
mpm@selenic.com
Simply repository locking...
r161 try:
Benoit Boissinot
use __contains__, index or split instead of str.find...
r2579 pid = int(pid)
Benoit Boissinot
lock: catch specific exceptions
r9685 except ValueError:
Vadim Gelfer
change lock format to let us detect and break stale locks....
r1877 return locker
if util.testpid(pid):
return locker
# if locker dead, break lock. must do this with another lock
# held, or can race and break valid lock.
try:
Benoit Boissinot
lock: the correct way to do a trylock() is to use a timeout of 0
r9858 l = lock(self.f + '.break', timeout=0)
Vadim Gelfer
change lock format to let us detect and break stale locks....
r1877 os.unlink(self.f)
l.release()
Matt Mackall
error: move lock errors...
r7640 except error.LockError:
Vadim Gelfer
change lock format to let us detect and break stale locks....
r1877 return locker
mpm@selenic.com
Simply repository locking...
r161
def release(self):
Ronny Pfannschmidt
made repo locks recursive and deprecate refcounting based lock releasing...
r8108 if self.held > 1:
self.held -= 1
Benoit Boissinot
lock: use '==' instead of 'is' for integer equality ('is' may not work)
r9680 elif self.held == 1:
mpm@selenic.com
Simply repository locking...
r161 self.held = 0
Benoit Boissinot
add a releasefn keyword to lock.lock...
r1530 if self.releasefn:
self.releasefn()
mpm@selenic.com
Fix troubles with clone and exception handling...
r503 try:
os.unlink(self.f)
Benoit Boissinot
lock: catch specific exceptions
r9685 except OSError:
pass
mpm@selenic.com
Simply repository locking...
r161
Ronny Pfannschmidt
made repo locks recursive and deprecate refcounting based lock releasing...
r8108 def release(*locks):
for lock in locks:
if lock is not None:
lock.release()