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  # 
  6  # This program is free software; you can redistribute it and/or modify 
  7  # it under the terms of the GNU General Public License as published by 
  8  # the Free Software Foundation; either version 2 of the License, or 
  9  # (at your option) any later version. 
 10  # 
 11  # This program is distributed in the hope that it will be useful, but 
 12  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 14  # General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the Free Software 
 18  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
 19  # 02110-1301, USA. 
 20   
 21  """Utility functions for file-based locks. 
 22   
 23  """ 
 24   
 25  import fcntl 
 26  import errno 
 27  import os 
 28  import logging 
 29   
 30  from ganeti import errors 
 31  from ganeti.utils import retry 
32 33 34 -def LockFile(fd):
35 """Locks a file using POSIX locks. 36 37 @type fd: int 38 @param fd: the file descriptor we need to lock 39 40 """ 41 try: 42 fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) 43 except IOError, err: 44 if err.errno == errno.EAGAIN: 45 raise errors.LockError("File already locked") 46 raise
47
48 49 -class FileLock(object):
50 """Utility class for file locks. 51 52 """
53 - def __init__(self, fd, filename):
54 """Constructor for FileLock. 55 56 @type fd: file 57 @param fd: File object 58 @type filename: str 59 @param filename: Path of the file opened at I{fd} 60 61 """ 62 self.fd = fd 63 self.filename = filename
64 65 @classmethod
66 - def Open(cls, filename):
67 """Creates and opens a file to be used as a file-based lock. 68 69 @type filename: string 70 @param filename: path to the file to be locked 71 72 """ 73 # Using "os.open" is necessary to allow both opening existing file 74 # read/write and creating if not existing. Vanilla "open" will truncate an 75 # existing file -or- allow creating if not existing. 76 return cls(os.fdopen(os.open(filename, os.O_RDWR | os.O_CREAT, 0664), "w+"), 77 filename)
78
79 - def __del__(self):
80 self.Close()
81
82 - def Close(self):
83 """Close the file and release the lock. 84 85 """ 86 if hasattr(self, "fd") and self.fd: 87 self.fd.close() 88 self.fd = None
89
90 - def _flock(self, flag, blocking, timeout, errmsg):
91 """Wrapper for fcntl.flock. 92 93 @type flag: int 94 @param flag: operation flag 95 @type blocking: bool 96 @param blocking: whether the operation should be done in blocking mode. 97 @type timeout: None or float 98 @param timeout: for how long the operation should be retried (implies 99 non-blocking mode). 100 @type errmsg: string 101 @param errmsg: error message in case operation fails. 102 103 """ 104 assert self.fd, "Lock was closed" 105 assert timeout is None or timeout >= 0, \ 106 "If specified, timeout must be positive" 107 assert not (flag & fcntl.LOCK_NB), "LOCK_NB must not be set" 108 109 # When a timeout is used, LOCK_NB must always be set 110 if not (timeout is None and blocking): 111 flag |= fcntl.LOCK_NB 112 113 if timeout is None: 114 self._Lock(self.fd, flag, timeout) 115 else: 116 try: 117 retry.Retry(self._Lock, (0.1, 1.2, 1.0), timeout, 118 args=(self.fd, flag, timeout)) 119 except retry.RetryTimeout: 120 raise errors.LockError(errmsg)
121 122 @staticmethod
123 - def _Lock(fd, flag, timeout):
124 try: 125 fcntl.flock(fd, flag) 126 except IOError, err: 127 if timeout is not None and err.errno == errno.EAGAIN: 128 raise retry.RetryAgain() 129 130 logging.exception("fcntl.flock failed") 131 raise
132
133 - def Exclusive(self, blocking=False, timeout=None):
134 """Locks the file in exclusive mode. 135 136 @type blocking: boolean 137 @param blocking: whether to block and wait until we 138 can lock the file or return immediately 139 @type timeout: int or None 140 @param timeout: if not None, the duration to wait for the lock 141 (in blocking mode) 142 143 """ 144 self._flock(fcntl.LOCK_EX, blocking, timeout, 145 "Failed to lock %s in exclusive mode" % self.filename)
146
147 - def Shared(self, blocking=False, timeout=None):
148 """Locks the file in shared mode. 149 150 @type blocking: boolean 151 @param blocking: whether to block and wait until we 152 can lock the file or return immediately 153 @type timeout: int or None 154 @param timeout: if not None, the duration to wait for the lock 155 (in blocking mode) 156 157 """ 158 self._flock(fcntl.LOCK_SH, blocking, timeout, 159 "Failed to lock %s in shared mode" % self.filename)
160
161 - def Unlock(self, blocking=True, timeout=None):
162 """Unlocks the file. 163 164 According to C{flock(2)}, unlocking can also be a nonblocking 165 operation:: 166 167 To make a non-blocking request, include LOCK_NB with any of the above 168 operations. 169 170 @type blocking: boolean 171 @param blocking: whether to block and wait until we 172 can lock the file or return immediately 173 @type timeout: int or None 174 @param timeout: if not None, the duration to wait for the lock 175 (in blocking mode) 176 177 """ 178 self._flock(fcntl.LOCK_UN, blocking, timeout, 179 "Failed to unlock %s" % self.filename)
180