Package instant :: Module locking
[hide private]
[frames] | no frames]

Source Code for Module instant.locking

  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: 
39 - def get_lock(cache_dir, module_name):
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
57 - def release_lock(lock):
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
64 - def release_all_locks():
65 pass
66 67 elif fcntl:
68 - def get_lock(cache_dir, module_name):
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
89 - def release_lock(lock):
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
108 - def release_all_locks():
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
117 - def get_lock(cache_dir, module_name):
118 return None
119
120 - def release_lock(lock):
121 pass
122
123 - def release_all_locks():
124 pass
125