# a helper class with mkdir based locking, inspired by the lockfile module (alpha at the time of writing) but simpler class AlreadyLocked(Exception): pass class LockTimeout(Exception): pass class LockFailed(Exception): pass class NotLocked(Exception): pass class NotMyLock(Exception): pass class MkdirLockFile: def __init__(self,path): self.path = path self.lock_file = os.path.abspath(path) + ".lock" self.hostname = socket.gethostname() self.pid = os.getpid() self.tname = "" dirname = os.path.dirname(self.lock_file) self.unique_name = os.path.join(dirname, "%s%s.%s" % (self.hostname, self.tname, self.pid)) def acquire(self, timeout=None): 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 else: # Someone else has the lock. raise AlreadyLocked 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 elif not os.path.exists(self.unique_name): raise NotMyLock 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)