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