Package ganeti :: Package utils :: Module filelock
[hide private]
[frames] | no frames]

Source Code for Module ganeti.utils.filelock

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2006, 2007, 2010, 2011 Google Inc. 
  5  # All rights reserved. 
  6  # 
  7  # Redistribution and use in source and binary forms, with or without 
  8  # modification, are permitted provided that the following conditions are 
  9  # met: 
 10  # 
 11  # 1. Redistributions of source code must retain the above copyright notice, 
 12  # this list of conditions and the following disclaimer. 
 13  # 
 14  # 2. Redistributions in binary form must reproduce the above copyright 
 15  # notice, this list of conditions and the following disclaimer in the 
 16  # documentation and/or other materials provided with the distribution. 
 17  # 
 18  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
 19  # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
 20  # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 21  # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
 22  # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 23  # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 24  # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 25  # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 26  # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 27  # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 28  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 29   
 30  """Utility functions for file-based locks. 
 31   
 32  """ 
 33   
 34  import fcntl 
 35  import errno 
 36  import os 
 37  import logging 
 38   
 39  from ganeti import errors 
 40  from ganeti.utils import retry 
41 42 43 -def LockFile(fd):
44 """Locks a file using POSIX locks. 45 46 @type fd: int 47 @param fd: the file descriptor we need to lock 48 49 """ 50 try: 51 fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) 52 except IOError, err: 53 if err.errno == errno.EAGAIN: 54 raise errors.LockError("File already locked") 55 raise
56
57 58 -class FileLock(object):
59 """Utility class for file locks. 60 61 """
62 - def __init__(self, fd, filename):
63 """Constructor for FileLock. 64 65 @type fd: file 66 @param fd: File object 67 @type filename: str 68 @param filename: Path of the file opened at I{fd} 69 70 """ 71 self.fd = fd 72 self.filename = filename
73 74 @classmethod
75 - def Open(cls, filename):
76 """Creates and opens a file to be used as a file-based lock. 77 78 @type filename: string 79 @param filename: path to the file to be locked 80 81 """ 82 # Using "os.open" is necessary to allow both opening existing file 83 # read/write and creating if not existing. Vanilla "open" will truncate an 84 # existing file -or- allow creating if not existing. 85 return cls(os.fdopen(os.open(filename, os.O_RDWR | os.O_CREAT, 0664), "w+"), 86 filename)
87
88 - def __del__(self):
89 self.Close()
90
91 - def Close(self):
92 """Close the file and release the lock. 93 94 """ 95 if hasattr(self, "fd") and self.fd: 96 self.fd.close() 97 self.fd = None
98
99 - def _flock(self, flag, blocking, timeout, errmsg):
100 """Wrapper for fcntl.flock. 101 102 @type flag: int 103 @param flag: operation flag 104 @type blocking: bool 105 @param blocking: whether the operation should be done in blocking mode. 106 @type timeout: None or float 107 @param timeout: for how long the operation should be retried (implies 108 non-blocking mode). 109 @type errmsg: string 110 @param errmsg: error message in case operation fails. 111 112 """ 113 assert self.fd, "Lock was closed" 114 assert timeout is None or timeout >= 0, \ 115 "If specified, timeout must be positive" 116 assert not (flag & fcntl.LOCK_NB), "LOCK_NB must not be set" 117 118 # When a timeout is used, LOCK_NB must always be set 119 if not (timeout is None and blocking): 120 flag |= fcntl.LOCK_NB 121 122 if timeout is None: 123 self._Lock(self.fd, flag, timeout) 124 else: 125 try: 126 retry.Retry(self._Lock, (0.1, 1.2, 1.0), timeout, 127 args=(self.fd, flag, timeout)) 128 except retry.RetryTimeout: 129 raise errors.LockError(errmsg)
130 131 @staticmethod
132 - def _Lock(fd, flag, timeout):
133 try: 134 fcntl.flock(fd, flag) 135 except IOError, err: 136 if timeout is not None and err.errno == errno.EAGAIN: 137 raise retry.RetryAgain() 138 139 logging.exception("fcntl.flock failed") 140 raise
141
142 - def Exclusive(self, blocking=False, timeout=None):
143 """Locks the file in exclusive mode. 144 145 @type blocking: boolean 146 @param blocking: whether to block and wait until we 147 can lock the file or return immediately 148 @type timeout: int or None 149 @param timeout: if not None, the duration to wait for the lock 150 (in blocking mode) 151 152 """ 153 self._flock(fcntl.LOCK_EX, blocking, timeout, 154 "Failed to lock %s in exclusive mode" % self.filename)
155
156 - def Shared(self, blocking=False, timeout=None):
157 """Locks the file in shared mode. 158 159 @type blocking: boolean 160 @param blocking: whether to block and wait until we 161 can lock the file or return immediately 162 @type timeout: int or None 163 @param timeout: if not None, the duration to wait for the lock 164 (in blocking mode) 165 166 """ 167 self._flock(fcntl.LOCK_SH, blocking, timeout, 168 "Failed to lock %s in shared mode" % self.filename)
169
170 - def Unlock(self, blocking=True, timeout=None):
171 """Unlocks the file. 172 173 According to C{flock(2)}, unlocking can also be a nonblocking 174 operation:: 175 176 To make a non-blocking request, include LOCK_NB with any of the above 177 operations. 178 179 @type blocking: boolean 180 @param blocking: whether to block and wait until we 181 can lock the file or return immediately 182 @type timeout: int or None 183 @param timeout: if not None, the duration to wait for the lock 184 (in blocking mode) 185 186 """ 187 self._flock(fcntl.LOCK_UN, blocking, timeout, 188 "Failed to unlock %s" % self.filename)
189