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