Package pulp :: Package client :: Module lock
[hide private]
[frames] | no frames]

Source Code for Module pulp.client.lock

  1  # 
  2  # Copyright (c) 2010 Red Hat, Inc. 
  3  # 
  4  # This software is licensed to you under the GNU General Public License, 
  5  # version 2 (GPLv2). There is NO WARRANTY for this software, express or 
  6  # implied, including the implied warranties of MERCHANTABILITY or FITNESS 
  7  # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 
  8  # along with this software; if not, see 
  9  # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 
 10  # 
 11  # Red Hat trademarks are not licensed under GPLv2. No permission is 
 12  # granted to use or replicate Red Hat trademarks that are incorporated 
 13  # in this software or its documentation. 
 14  # 
 15   
 16  """ 
 17  Contains locking classes. 
 18  """ 
 19   
 20  import os 
 21  import re 
 22  import time 
 23  import fcntl 
 24  from threading import RLock as Mutex 
 25   
 26   
27 -class LockFailed(Exception):
28 pass
29 30
31 -class LockFile:
32 """ 33 File based locking. 34 @ivar path: The absolute path to the lock file. 35 @type path: str 36 @ivar pid: current process id. 37 @type pid: int 38 @ivar fp: The I{file pointer} to the lock file. 39 @ivar fp: I{file-like} pointer. 40 """ 41
42 - def __init__(self, path):
43 """ 44 @param path: The absolute path to the lock file. 45 @type path: str 46 """ 47 self.path = path 48 self.pid = None 49 self.fp = None
50
51 - def open(self):
52 """ 53 Open the lock file. 54 Created in not exists. Opened with file locking. 55 """ 56 if self.notcreated(): 57 self.fp = open(self.path, 'w') 58 self.setpid() 59 self.close() 60 self.fp = open(self.path, 'r+') 61 fd = self.fp.fileno() 62 fcntl.flock(fd, fcntl.LOCK_EX)
63
64 - def getpid(self):
65 """ 66 Get the process id. 67 @return: The pid in the lock file, else the current pid. 68 @rtype: int 69 """ 70 if self.pid is None: 71 content = self.fp.read().strip() 72 if content: 73 self.pid = int(content) 74 return self.pid
75
76 - def setpid(self, pid=os.getpid()):
77 """ 78 Write our procecss id and flush. 79 @param pid: The process ID. 80 @type pid: int 81 """ 82 self.fp.seek(0) 83 content = str(pid) 84 self.fp.write(content) 85 self.fp.flush()
86
87 - def mypid(self):
88 """ 89 Get the current process id. 90 @return: This process id. 91 @rtype: int 92 """ 93 return ( os.getpid() == self.getpid() )
94
95 - def valid(self):
96 """ 97 Get whether the pid in the file is valid. 98 @return: True if valid. 99 @rtype: bool 100 """ 101 status = False 102 try: 103 os.kill(self.getpid(), 0) 104 status = True 105 except Exception, e: 106 pass 107 return status
108
109 - def delete(self):
110 """ 111 Delete the lock file. 112 """ 113 if self.mypid() or not self.valid(): 114 self.close() 115 os.unlink(self.path)
116
117 - def close(self):
118 """ 119 Close the file and release the file lock. 120 Reset pid & fp to (None). 121 """ 122 try: 123 fd = self.fp.fileno() 124 fcntl.flock(fd, fcntl.LOCK_UN) 125 self.fp.close() 126 except: 127 pass 128 self.pid = None 129 self.fp = None
130
131 - def notcreated(self):
132 """ 133 Get if file not created. 134 @return: True if file not created. 135 @rtype: bool 136 """ 137 return ( not os.path.exists(self.path) )
138
139 - def __del__(self):
140 """ cleanup """ 141 self.close()
142 143
144 -class Lock:
145 """ 146 File backed Reentrant lock. 147 @cvar mutex: A thread mutex. 148 @type mutex: L{Mutex} 149 """ 150 151 mutex = Mutex() 152
153 - def __init__(self, path):
154 self.depth = 0 155 self.path = path 156 dir, fn = os.path.split(self.path) 157 if not os.path.exists(dir): 158 os.makedirs(dir)
159
160 - def acquire(self, wait=True):
161 """ 162 Acquire the lock. 163 @param wait: Indicates call will block and wait for the lock. 164 @type wait: boolean 165 """ 166 f = LockFile(self.path) 167 try: 168 while True: 169 f.open() 170 pid = f.getpid() 171 if f.mypid(): 172 self.P() 173 return 174 if f.valid(): 175 f.close() 176 if wait: 177 time.sleep(0.5) 178 else: 179 raise LockFailed() 180 else: 181 break 182 self.P() 183 f.setpid() 184 finally: 185 f.close()
186
187 - def update(self, pid):
188 """ 189 Update the process ID. 190 @param pid: The process ID. 191 @type pid: int 192 """ 193 if not self.acquired(): 194 raise Exception, 'not acquired' 195 f = LockFile(self.path) 196 try: 197 f.open() 198 f.setpid(pid) 199 finally: 200 f.close()
201
202 - def release(self):
203 """ 204 Release the lock. 205 """ 206 if not self.acquired(): 207 return 208 self.V() 209 if self.acquired(): 210 return 211 f = LockFile(self.path) 212 try: 213 f.open() 214 f.delete() 215 finally: 216 f.close()
217
218 - def acquired(self):
219 """ 220 Test to see if acquired. 221 @return: True if acquired. 222 @rtype: bool 223 """ 224 mutex = self.mutex 225 mutex.acquire() 226 try: 227 return ( self.depth > 0 ) 228 finally: 229 mutex.release()
230
231 - def P(self):
232 """ 233 Do semiphore (P) operation. 234 @return: self 235 @rtype: L{Lock} 236 """ 237 mutex = self.mutex 238 mutex.acquire() 239 try: 240 self.depth += 1 241 finally: 242 mutex.release() 243 return self
244
245 - def V(self):
246 """ 247 Do semiphore (V) operation. 248 @return: self 249 @rtype: L{Lock} 250 """ 251 mutex = self.mutex 252 mutex.acquire() 253 try: 254 if self.acquired(): 255 self.depth -= 1 256 finally: 257 mutex.release() 258 return self
259
260 - def __del__(self):
261 try: 262 self.release() 263 except: 264 pass
265