| Home | Trees | Indices | Help |
|
|---|
|
|
1 """File locking for the cache system, to avoid problems
2 when multiple processes work with the same module.
3 Only works on UNIX systems.
4
5 Two python libraries can be used:
6
7 flufl.lock : A nfs safe which can be downloaded from:
8
9 https://launchpad.net/flufl.lock
10
11 fcntl : A builtin Python module which only works on posix machines
12 and it is does unfortunately not work on nfs
13
14 """
15
16 __all__ = ["get_lock", "release_lock", "release_all_lock"]
17
18 import os.path
19 from .output import instant_error, instant_assert, instant_debug
20 from .paths import validate_cache_dir
21
22 try:
23 import flufl.lock
24 fcntl = None
25 except:
26 flufl = None
27 try:
28 import fcntl
29 except:
30 fcntl = None
31
32 # Keeping an overview of locks currently held,
33 # to avoid deadlocks within a single process.
34 _lock_names = {} # lock.fileno() -> lockname
35 _lock_files = {} # lockname -> lock
36 _lock_count = {} # lockname -> number of times this lock has been aquired and not yet released
37
38 if flufl:
40 "Get a new file lock."
41
42 from flufl.lock import Lock
43 from datetime import timedelta
44
45 lockname = module_name + ".lock"
46 count = _lock_count.get(lockname, 0)
47
48 instant_debug("Acquiring lock %s, count is %d." % (lockname, count))
49
50 cache_dir = validate_cache_dir(cache_dir)
51 lockname = os.path.join(cache_dir, lockname)
52 lock = Lock(lockname)
53 lock.lock()
54
55 return lock
56
58 "Release a lock currently held by Instant."
59 if lock.is_locked:
60 hostname, pid, lockname = lock.details
61 instant_debug("Releasing lock %s." % (lockname))
62 lock.unlock()
63
66
67 elif fcntl:
69 "Get a new file lock."
70 global _lock_names, _lock_files, _lock_count
71
72 lockname = module_name + ".lock"
73 count = _lock_count.get(lockname, 0)
74
75 instant_debug("Acquiring lock %s, count is %d." % (lockname, count))
76
77 if count == 0:
78 cache_dir = validate_cache_dir(cache_dir)
79 lock = open(os.path.join(cache_dir, lockname), "w")
80 fcntl.flock(lock.fileno(), fcntl.LOCK_EX)
81 _lock_names[lock.fileno()] = lockname
82 _lock_files[lockname] = lock
83 else:
84 lock = _lock_files[lockname]
85
86 _lock_count[lockname] = count + 1
87 return lock
88
90 "Release a lock currently held by Instant."
91 global _lock_names, _lock_files, _lock_count
92
93 lockname = _lock_names[lock.fileno()]
94 count = _lock_count[lockname]
95
96 instant_debug("Releasing lock %s, count is %d." % (lockname, count))
97
98 instant_assert(count > 0, "Releasing lock that Instant is supposedly not holding.")
99 instant_assert(lock is _lock_files[lockname], "Lock mismatch, might be something wrong in locking logic.")
100
101 del _lock_files[lockname]
102 del _lock_names[lock.fileno()]
103 _lock_count[lockname] = count - 1
104
105 fcntl.flock(lock.fileno(), fcntl.LOCK_UN)
106 lock.close()
107
109 "Release all locks currently held by Instant."
110 locks = list(_lock_files.values())
111 for lock in locks:
112 release_lock(lock)
113 instant_assert(all(_lock_count[lockname] == 0 for lockname in _lock_count), "Lock counts not zero after releasing all locks.")
114
115 else:
116 # Windows systems have no fcntl, implement these otherwise if locking is needed on windows
119
122
125
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Wed Apr 10 07:12:38 2013 | http://epydoc.sourceforge.net |