85 lines
3.0 KiB
Python
85 lines
3.0 KiB
Python
from __future__ import absolute_import, division
|
|
|
|
import time
|
|
import os
|
|
import sys
|
|
import errno
|
|
|
|
from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout,
|
|
AlreadyLocked)
|
|
|
|
|
|
class MkdirLockFile(LockBase):
|
|
"""Lock file by creating a directory."""
|
|
def __init__(self, path, threaded=True, timeout=None):
|
|
"""
|
|
>>> lock = MkdirLockFile('somefile')
|
|
>>> lock = MkdirLockFile('somefile', threaded=False)
|
|
"""
|
|
LockBase.__init__(self, path, threaded, timeout)
|
|
# Lock file itself is a directory. Place the unique file name into
|
|
# it.
|
|
self.unique_name = os.path.join(self.lock_file,
|
|
"%s.%s%s" % (self.hostname,
|
|
self.tname,
|
|
self.pid))
|
|
|
|
def acquire(self, timeout=None):
|
|
timeout = timeout if timeout is not None else self.timeout
|
|
end_time = time.time()
|
|
if timeout is not None and timeout > 0:
|
|
end_time += timeout
|
|
|
|
if timeout is None:
|
|
wait = 0.1
|
|
else:
|
|
wait = max(0, timeout / 10)
|
|
|
|
while True:
|
|
try:
|
|
os.mkdir(self.lock_file)
|
|
except OSError:
|
|
err = sys.exc_info()[1]
|
|
if err.errno == errno.EEXIST:
|
|
# Already locked.
|
|
if os.path.exists(self.unique_name):
|
|
# Already locked by me.
|
|
return
|
|
if timeout is not None and time.time() > end_time:
|
|
if timeout > 0:
|
|
raise LockTimeout("Timeout waiting to acquire"
|
|
" lock for %s" %
|
|
self.path)
|
|
else:
|
|
# Someone else has the lock.
|
|
raise AlreadyLocked("%s is already locked" %
|
|
self.path)
|
|
time.sleep(wait)
|
|
else:
|
|
# Couldn't create the lock for some other reason
|
|
raise LockFailed("failed to create %s" % self.lock_file)
|
|
else:
|
|
open(self.unique_name, "wb").close()
|
|
return
|
|
|
|
def release(self):
|
|
if not self.is_locked():
|
|
raise NotLocked("%s is not locked" % self.path)
|
|
elif not os.path.exists(self.unique_name):
|
|
raise NotMyLock("%s is locked, but not by me" % self.path)
|
|
os.unlink(self.unique_name)
|
|
os.rmdir(self.lock_file)
|
|
|
|
def is_locked(self):
|
|
return os.path.exists(self.lock_file)
|
|
|
|
def i_am_locking(self):
|
|
return (self.is_locked() and
|
|
os.path.exists(self.unique_name))
|
|
|
|
def break_lock(self):
|
|
if os.path.exists(self.lock_file):
|
|
for name in os.listdir(self.lock_file):
|
|
os.unlink(os.path.join(self.lock_file, name))
|
|
os.rmdir(self.lock_file)
|