| from __future__ import absolute_import |
| |
| import os |
| import time |
| |
| from . import (LockBase, NotLocked, NotMyLock, LockTimeout, |
| AlreadyLocked) |
| |
| |
| class SymlinkLockFile(LockBase): |
| """Lock access to a file using symlink(2).""" |
| |
| def __init__(self, path, threaded=True, timeout=None): |
| # super(SymlinkLockFile).__init(...) |
| LockBase.__init__(self, path, threaded, timeout) |
| # 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) |
| 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 |
| |
| while True: |
| # Try and create a symbolic 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("Timeout waiting to acquire" |
| " lock for %s" % |
| self.path) |
| else: |
| raise AlreadyLocked("%s is already locked" % |
| self.path) |
| 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("%s is not locked" % self.path) |
| elif not self.i_am_locking(): |
| raise NotMyLock("%s is locked, but not by me" % self.path) |
| 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) |