sqlitelockfile.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. from __future__ import absolute_import, division
  2. import time
  3. import os
  4. try:
  5. unicode
  6. except NameError:
  7. unicode = str
  8. from . import LockBase, NotLocked, NotMyLock, LockTimeout, AlreadyLocked
  9. class SQLiteLockFile(LockBase):
  10. "Demonstrate SQL-based locking."
  11. testdb = None
  12. def __init__(self, path, threaded=True, timeout=None):
  13. """
  14. >>> lock = SQLiteLockFile('somefile')
  15. >>> lock = SQLiteLockFile('somefile', threaded=False)
  16. """
  17. LockBase.__init__(self, path, threaded, timeout)
  18. self.lock_file = unicode(self.lock_file)
  19. self.unique_name = unicode(self.unique_name)
  20. if SQLiteLockFile.testdb is None:
  21. import tempfile
  22. _fd, testdb = tempfile.mkstemp()
  23. os.close(_fd)
  24. os.unlink(testdb)
  25. del _fd, tempfile
  26. SQLiteLockFile.testdb = testdb
  27. import sqlite3
  28. self.connection = sqlite3.connect(SQLiteLockFile.testdb)
  29. c = self.connection.cursor()
  30. try:
  31. c.execute("create table locks"
  32. "("
  33. " lock_file varchar(32),"
  34. " unique_name varchar(32)"
  35. ")")
  36. except sqlite3.OperationalError:
  37. pass
  38. else:
  39. self.connection.commit()
  40. import atexit
  41. atexit.register(os.unlink, SQLiteLockFile.testdb)
  42. def acquire(self, timeout=None):
  43. timeout = timeout if timeout is not None else self.timeout
  44. end_time = time.time()
  45. if timeout is not None and timeout > 0:
  46. end_time += timeout
  47. if timeout is None:
  48. wait = 0.1
  49. elif timeout <= 0:
  50. wait = 0
  51. else:
  52. wait = timeout / 10
  53. cursor = self.connection.cursor()
  54. while True:
  55. if not self.is_locked():
  56. # Not locked. Try to lock it.
  57. cursor.execute("insert into locks"
  58. " (lock_file, unique_name)"
  59. " values"
  60. " (?, ?)",
  61. (self.lock_file, self.unique_name))
  62. self.connection.commit()
  63. # Check to see if we are the only lock holder.
  64. cursor.execute("select * from locks"
  65. " where unique_name = ?",
  66. (self.unique_name,))
  67. rows = cursor.fetchall()
  68. if len(rows) > 1:
  69. # Nope. Someone else got there. Remove our lock.
  70. cursor.execute("delete from locks"
  71. " where unique_name = ?",
  72. (self.unique_name,))
  73. self.connection.commit()
  74. else:
  75. # Yup. We're done, so go home.
  76. return
  77. else:
  78. # Check to see if we are the only lock holder.
  79. cursor.execute("select * from locks"
  80. " where unique_name = ?",
  81. (self.unique_name,))
  82. rows = cursor.fetchall()
  83. if len(rows) == 1:
  84. # We're the locker, so go home.
  85. return
  86. # Maybe we should wait a bit longer.
  87. if timeout is not None and time.time() > end_time:
  88. if timeout > 0:
  89. # No more waiting.
  90. raise LockTimeout("Timeout waiting to acquire"
  91. " lock for %s" %
  92. self.path)
  93. else:
  94. # Someone else has the lock and we are impatient..
  95. raise AlreadyLocked("%s is already locked" % self.path)
  96. # Well, okay. We'll give it a bit longer.
  97. time.sleep(wait)
  98. def release(self):
  99. if not self.is_locked():
  100. raise NotLocked("%s is not locked" % self.path)
  101. if not self.i_am_locking():
  102. raise NotMyLock("%s is locked, but not by me (by %s)" %
  103. (self.unique_name, self._who_is_locking()))
  104. cursor = self.connection.cursor()
  105. cursor.execute("delete from locks"
  106. " where unique_name = ?",
  107. (self.unique_name,))
  108. self.connection.commit()
  109. def _who_is_locking(self):
  110. cursor = self.connection.cursor()
  111. cursor.execute("select unique_name from locks"
  112. " where lock_file = ?",
  113. (self.lock_file,))
  114. return cursor.fetchone()[0]
  115. def is_locked(self):
  116. cursor = self.connection.cursor()
  117. cursor.execute("select * from locks"
  118. " where lock_file = ?",
  119. (self.lock_file,))
  120. rows = cursor.fetchall()
  121. return not not rows
  122. def i_am_locking(self):
  123. cursor = self.connection.cursor()
  124. cursor.execute("select * from locks"
  125. " where lock_file = ?"
  126. " and unique_name = ?",
  127. (self.lock_file, self.unique_name))
  128. return not not cursor.fetchall()
  129. def break_lock(self):
  130. cursor = self.connection.cursor()
  131. cursor.execute("delete from locks"
  132. " where lock_file = ?",
  133. (self.lock_file,))
  134. self.connection.commit()