diff options
author | skip.montanaro <skip.montanaro@gmail.com> | 2010-11-06 21:25:25 +0000 |
---|---|---|
committer | skip.montanaro <skip.montanaro@gmail.com> | 2010-11-06 21:25:25 +0000 |
commit | 2065cfa86adab2e0458607391d6ec44a75d42f93 (patch) | |
tree | 414c583b6a2a1ba2a1726d547086c0b602db9067 | |
parent | c5019dd6073623582465ec6c10f8118f07b306aa (diff) | |
download | lockfile-2065cfa86adab2e0458607391d6ec44a75d42f93.tar.gz |
add symlinklockfile module
-rw-r--r-- | lockfile/symlinklockfile.py | 66 | ||||
-rw-r--r-- | test/test_lockfile.py | 8 |
2 files changed, 73 insertions, 1 deletions
diff --git a/lockfile/symlinklockfile.py b/lockfile/symlinklockfile.py new file mode 100644 index 0000000..0447e22 --- /dev/null +++ b/lockfile/symlinklockfile.py @@ -0,0 +1,66 @@ +from __future__ import absolute_import + +import time +import os + +from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout, + AlreadyLocked) + +class SymlinkLockFile(LockBase): + """Lock access to a file using symlink(2).""" + + def __init__(self, path, threaded=True): + # super(SymlinkLockFile).__init(...) + LockBase.__init__(self, path, threaded) + # split it back! + self.unique_name = os.path.split(self.unique_name)[1] + + def acquire(self, timeout=None): + # Hopefully unnecessary for symlink. + #try: + # open(self.unique_name, "wb").close() + #except IOError: + # raise LockFailed("failed to create %s" % self.unique_name) + + end_time = time.time() + if timeout is not None and timeout > 0: + end_time += timeout + + while True: + # Try and create a hard link to it. + try: + os.symlink(self.unique_name, self.lock_file) + except OSError: + # Link creation failed. Maybe we've double-locked? + if self.i_am_locking(): + # Linked to out unique name. Proceed. + return + else: + # Otherwise the lock creation failed. + if timeout is not None and time.time() > end_time: + if timeout > 0: + raise LockTimeout + else: + raise AlreadyLocked + time.sleep(timeout/10 if timeout is not None else 0.1) + else: + # Link creation succeeded. We're good to go. + return + + def release(self): + if not self.is_locked(): + raise NotLocked + elif not self.i_am_locking(): + raise NotMyLock + os.unlink(self.lock_file) + + def is_locked(self): + return os.path.islink(self.lock_file) + + def i_am_locking(self): + return os.path.islink(self.lock_file) and \ + os.readlink(self.lock_file) == self.unique_name + + def break_lock(self): + if os.path.islink(self.lock_file): # exists && link + os.unlink(self.lock_file) diff --git a/test/test_lockfile.py b/test/test_lockfile.py index 3b70cdd..e1f4f72 100644 --- a/test/test_lockfile.py +++ b/test/test_lockfile.py @@ -1,12 +1,18 @@ import sys -import lockfile.linklockfile, lockfile.mkdirlockfile, lockfile.pidlockfile +import lockfile.linklockfile +import lockfile.mkdirlockfile +import lockfile.pidlockfile +import lockfile.symlinklockfile from compliancetest import ComplianceTest class TestLinkLockFile(ComplianceTest): class_to_test = lockfile.linklockfile.LinkLockFile +class TestSymlinkLockFile(ComplianceTest): + class_to_test = lockfile.symlinklockfile.SymlinkLockFile + class TestMkdirLockFile(ComplianceTest): class_to_test = lockfile.mkdirlockfile.MkdirLockFile |