symlinklockfile.py 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. from __future__ import absolute_import
  2. import os
  3. import time
  4. from . import (LockBase, NotLocked, NotMyLock, LockTimeout,
  5. AlreadyLocked)
  6. class SymlinkLockFile(LockBase):
  7. """Lock access to a file using symlink(2)."""
  8. def __init__(self, path, threaded=True, timeout=None):
  9. # super(SymlinkLockFile).__init(...)
  10. LockBase.__init__(self, path, threaded, timeout)
  11. # split it back!
  12. self.unique_name = os.path.split(self.unique_name)[1]
  13. def acquire(self, timeout=None):
  14. # Hopefully unnecessary for symlink.
  15. # try:
  16. # open(self.unique_name, "wb").close()
  17. # except IOError:
  18. # raise LockFailed("failed to create %s" % self.unique_name)
  19. timeout = timeout if timeout is not None else self.timeout
  20. end_time = time.time()
  21. if timeout is not None and timeout > 0:
  22. end_time += timeout
  23. while True:
  24. # Try and create a symbolic link to it.
  25. try:
  26. os.symlink(self.unique_name, self.lock_file)
  27. except OSError:
  28. # Link creation failed. Maybe we've double-locked?
  29. if self.i_am_locking():
  30. # Linked to out unique name. Proceed.
  31. return
  32. else:
  33. # Otherwise the lock creation failed.
  34. if timeout is not None and time.time() > end_time:
  35. if timeout > 0:
  36. raise LockTimeout("Timeout waiting to acquire"
  37. " lock for %s" %
  38. self.path)
  39. else:
  40. raise AlreadyLocked("%s is already locked" %
  41. self.path)
  42. time.sleep(timeout / 10 if timeout is not None else 0.1)
  43. else:
  44. # Link creation succeeded. We're good to go.
  45. return
  46. def release(self):
  47. if not self.is_locked():
  48. raise NotLocked("%s is not locked" % self.path)
  49. elif not self.i_am_locking():
  50. raise NotMyLock("%s is locked, but not by me" % self.path)
  51. os.unlink(self.lock_file)
  52. def is_locked(self):
  53. return os.path.islink(self.lock_file)
  54. def i_am_locking(self):
  55. return (os.path.islink(self.lock_file)
  56. and os.readlink(self.lock_file) == self.unique_name)
  57. def break_lock(self):
  58. if os.path.islink(self.lock_file): # exists && link
  59. os.unlink(self.lock_file)