157
def __init__(self, filename):
157
def __init__(self, filename, _ignore_write_lock=False):
158
158
super(_fcntl_ReadLock, self).__init__()
159
159
self.filename = osutils.realpath(filename)
160
if self.filename in _fcntl_WriteLock._open_locks:
160
if not _ignore_write_lock and self.filename in _fcntl_WriteLock._open_locks:
161
161
raise errors.LockContention(self.filename)
162
162
_fcntl_ReadLock._open_locks.setdefault(self.filename, 0)
163
163
_fcntl_ReadLock._open_locks[self.filename] += 1
179
179
_fcntl_ReadLock._open_locks[self.filename] = count - 1
182
def temporary_write_lock(self):
183
"""Try to grab a write lock on the file.
185
On platforms that support it, this will upgrade to a write lock
186
without unlocking the file.
187
Otherwise, this will release the read lock, and try to acquire a
190
:return: A token which can be used to switch back to a read lock.
192
assert self.filename not in _fcntl_WriteLock._open_locks
193
return _fcntl_TemporaryWriteLock(self)
196
class _fcntl_TemporaryWriteLock(_base_Lock):
197
"""A token used when grabbing a temporary_write_lock.
199
Call restore_read_lock() when you are done with the write lock.
202
def __init__(self, read_lock):
203
super(_fcntl_TemporaryWriteLock, self).__init__()
204
self._read_lock = read_lock
205
self.filename = read_lock.filename
207
count = _fcntl_ReadLock._open_locks[self.filename]
209
# Something else also has a read-lock, so we cannot grab a
211
raise errors.LockContention(self.filename)
213
assert self.filename not in _fcntl_WriteLock._open_locks
215
# See if we can open the file for writing. Another process might
216
# have a read lock. We don't use self._open() because we don't want
217
# to create the file if it exists. That would have already been
218
# done by _fcntl_ReadLock
220
new_f = open(self.filename, 'rb+')
222
if e.errno in (errno.EACCES, errno.EPERM):
223
raise errors.ReadOnlyLockError(self.filename, str(e))
226
# LOCK_NB will cause IOError to be raised if we can't grab a
228
fcntl.lockf(new_f, fcntl.LOCK_SH | fcntl.LOCK_NB)
230
# TODO: Raise a more specific error based on the type of error
231
raise errors.LockError(e)
232
_fcntl_WriteLock._open_locks.add(self.filename)
236
def restore_read_lock(self):
237
"""Restore the original ReadLock.
239
For fcntl, since we never released the read lock, just release the
240
write lock, and return the original lock.
242
fcntl.lockf(self.f, fcntl.LOCK_UN)
244
_fcntl_WriteLock._open_locks.remove(self.filename)
245
# Avoid reference cycles
246
read_lock = self._read_lock
247
self._read_lock = None
183
251
_lock_classes.append(('fcntl', _fcntl_WriteLock, _fcntl_ReadLock))