Mercurial > hg
view mercurial/lock.py @ 1981:736b6c96bbbc
make incoming work via ssh (issue139); move chunk code into separate module.
Incoming ssh needs to detect the end of the changegroup, otherwise it would
block trying to read from the ssh pipe. This is done by parsing the
changegroup chunks.
bundlerepo.getchunk() already is identical to
localrepo.addchangegroup.getchunk(), which is followed by getgroup which
looks much like what you can re-use in bundlerepository.__init__() and in
write_bundle(). bundlerevlog.__init__.genchunk() looks very similar, too,
as do some while loops in localrepo.py.
Applied patch from Benoit Boissinot to move duplicate/related code
to mercurial/changegroup.py and use this to fix incoming ssh.
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Tue, 21 Mar 2006 11:47:21 +0100 |
parents | d314a89fa4f1 |
children | ff5c9a92f556 |
line wrap: on
line source
# lock.py - simple locking scheme for mercurial # # Copyright 2005 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. from demandload import * demandload(globals(), 'errno os socket time util') class LockException(Exception): pass class LockHeld(LockException): pass class LockUnavailable(LockException): pass class lock(object): # 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 def __init__(self, file, timeout=-1, releasefn=None): self.f = file self.held = 0 self.timeout = timeout self.releasefn = releasefn self.id = None self.host = None self.pid = None self.lock() def __del__(self): self.release() def lock(self): timeout = self.timeout while 1: try: self.trylock() return 1 except LockHeld, inst: if timeout != 0: time.sleep(1) if timeout > 0: timeout -= 1 continue raise inst def trylock(self): if self.id is None: self.host = socket.gethostname() self.pid = os.getpid() self.id = '%s:%s' % (self.host, self.pid) while not self.held: try: util.makelock(self.id, self.f) self.held = 1 except (OSError, IOError), why: if why.errno == errno.EEXIST: locker = self.testlock() if locker: raise LockHeld(locker) else: raise LockUnavailable(why) def testlock(self): '''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. locker = util.readlock(self.f) c = locker.find(':') if c == -1: return locker host = locker[:c] if host != self.host: return locker try: pid = int(locker[c+1:]) except: 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: l = lock(self.f + '.break') l.trylock() os.unlink(self.f) l.release() except (LockHeld, LockUnavailable): return locker def release(self): if self.held: self.held = 0 if self.releasefn: self.releasefn() try: os.unlink(self.f) except: pass