You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

84 lines
3.0 KiB

4 years ago
  1. from __future__ import absolute_import, division
  2. import time
  3. import os
  4. import sys
  5. import errno
  6. from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout,
  7. AlreadyLocked)
  8. class MkdirLockFile(LockBase):
  9. """Lock file by creating a directory."""
  10. def __init__(self, path, threaded=True, timeout=None):
  11. """
  12. >>> lock = MkdirLockFile('somefile')
  13. >>> lock = MkdirLockFile('somefile', threaded=False)
  14. """
  15. LockBase.__init__(self, path, threaded, timeout)
  16. # Lock file itself is a directory. Place the unique file name into
  17. # it.
  18. self.unique_name = os.path.join(self.lock_file,
  19. "%s.%s%s" % (self.hostname,
  20. self.tname,
  21. self.pid))
  22. def acquire(self, timeout=None):
  23. timeout = timeout if timeout is not None else self.timeout
  24. end_time = time.time()
  25. if timeout is not None and timeout > 0:
  26. end_time += timeout
  27. if timeout is None:
  28. wait = 0.1
  29. else:
  30. wait = max(0, timeout / 10)
  31. while True:
  32. try:
  33. os.mkdir(self.lock_file)
  34. except OSError:
  35. err = sys.exc_info()[1]
  36. if err.errno == errno.EEXIST:
  37. # Already locked.
  38. if os.path.exists(self.unique_name):
  39. # Already locked by me.
  40. return
  41. if timeout is not None and time.time() > end_time:
  42. if timeout > 0:
  43. raise LockTimeout("Timeout waiting to acquire"
  44. " lock for %s" %
  45. self.path)
  46. else:
  47. # Someone else has the lock.
  48. raise AlreadyLocked("%s is already locked" %
  49. self.path)
  50. time.sleep(wait)
  51. else:
  52. # Couldn't create the lock for some other reason
  53. raise LockFailed("failed to create %s" % self.lock_file)
  54. else:
  55. open(self.unique_name, "wb").close()
  56. return
  57. def release(self):
  58. if not self.is_locked():
  59. raise NotLocked("%s is not locked" % self.path)
  60. elif not os.path.exists(self.unique_name):
  61. raise NotMyLock("%s is locked, but not by me" % self.path)
  62. os.unlink(self.unique_name)
  63. os.rmdir(self.lock_file)
  64. def is_locked(self):
  65. return os.path.exists(self.lock_file)
  66. def i_am_locking(self):
  67. return (self.is_locked() and
  68. os.path.exists(self.unique_name))
  69. def break_lock(self):
  70. if os.path.exists(self.lock_file):
  71. for name in os.listdir(self.lock_file):
  72. os.unlink(os.path.join(self.lock_file, name))
  73. os.rmdir(self.lock_file)