Undo commit 95680ed: "Switch to using a separate lockfile per target."

This was required for old versions of MacOS X, but the bug has now been
fixed, so let's de-clutter the .redo directory by reducing to a single
lock file instead of one per fid.

This reverts commit 08b05fd72f92fa0061b3d082b391151b43cd7497.
This commit is contained in:
Avery Pennarun 2018-11-23 19:35:42 -05:00
commit d664099c9d

View file

@ -35,9 +35,17 @@ def _connect(dbfile):
return _db return _db
# We need to keep a process-wide fd open for all access to the lock file.
# Because POSIX lock files are insane, if you close *one* fd pointing
# at a given inode, it will immediately release *all* locks on that inode from
# your pid, even if those locks are on a different fd. This is literally
# never what you want. To avoid the problem, always use just a single fd.
_lockfile = None
_db = None _db = None
def db(): def db():
global _db global _db, _lockfile
if _db: if _db:
return _db return _db
@ -51,6 +59,10 @@ def db():
else: else:
raise raise
_lockfile = os.open(os.path.join(vars.BASE, '.redo/locks'),
os.O_RDWR | os.O_CREAT, 0666)
close_on_exec(_lockfile, True)
must_create = not os.path.exists(dbfile) must_create = not os.path.exists(dbfile)
if not must_create: if not must_create:
_db = _connect(dbfile) _db = _connect(dbfile)
@ -399,10 +411,7 @@ class Lock:
def __init__(self, fid): def __init__(self, fid):
self.owned = False self.owned = False
self.fid = fid self.fid = fid
self.lockfile = None assert(_lockfile >= 0)
self.lockfile = os.open(os.path.join(vars.BASE, '.redo/lock.%d' % fid),
os.O_RDWR | os.O_CREAT, 0666)
close_on_exec(self.lockfile, True)
assert(_locks.get(fid,0) == 0) assert(_locks.get(fid,0) == 0)
_locks[fid] = 1 _locks[fid] = 1
@ -410,8 +419,6 @@ class Lock:
_locks[self.fid] = 0 _locks[self.fid] = 0
if self.owned: if self.owned:
self.unlock() self.unlock()
if self.lockfile is not None:
os.close(self.lockfile)
def check(self): def check(self):
assert(not self.owned) assert(not self.owned)
@ -421,8 +428,9 @@ class Lock:
def trylock(self): def trylock(self):
self.check() self.check()
assert not self.owned
try: try:
fcntl.lockf(self.lockfile, fcntl.LOCK_EX|fcntl.LOCK_NB, 0, 0) fcntl.lockf(_lockfile, fcntl.LOCK_EX|fcntl.LOCK_NB, 1, self.fid)
except IOError, e: except IOError, e:
if e.errno in (errno.EAGAIN, errno.EACCES): if e.errno in (errno.EAGAIN, errno.EACCES):
pass # someone else has it locked pass # someone else has it locked
@ -434,14 +442,15 @@ class Lock:
def waitlock(self, shared=False): def waitlock(self, shared=False):
self.check() self.check()
fcntl.lockf(self.lockfile, assert not self.owned
fcntl.lockf(_lockfile,
fcntl.LOCK_SH if shared else fcntl.LOCK_EX, fcntl.LOCK_SH if shared else fcntl.LOCK_EX,
0, 0) 1, self.fid)
self.owned = True self.owned = True
def unlock(self): def unlock(self):
if not self.owned: if not self.owned:
raise Exception("can't unlock %r - we don't own it" raise Exception("can't unlock %r - we don't own it"
% self.lockname) % self.lockname)
fcntl.lockf(self.lockfile, fcntl.LOCK_UN, 0, 0) fcntl.lockf(_lockfile, fcntl.LOCK_UN, 1, self.fid)
self.owned = False self.owned = False