def __init__(self, filename): super(_fcntl_WriteLock, self).__init__() # Check we can grab a lock before we actually open the file. self.filename = osutils.realpath(filename) if self.filename in _fcntl_WriteLock._open_locks: self._clear_f() raise errors.LockContention(self.filename) if self.filename in _fcntl_ReadLock._open_locks: if 'strict_locks' in debug.debug_flags: self._clear_f() raise errors.LockContention(self.filename) else: trace.mutter( 'Write lock taken w/ an open read lock on: %s' % (self.filename, )) self._open(self.filename, 'rb+') # reserve a slot for this lock - even if the lockf call fails, # at this point unlock() will be called, because self.f is set. # TODO: make this fully threadsafe, if we decide we care. _fcntl_WriteLock._open_locks.add(self.filename) try: # LOCK_NB will cause IOError to be raised if we can't grab a # lock right away. fcntl.lockf(self.f, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError, e: if e.errno in (errno.EAGAIN, errno.EACCES): # We couldn't grab the lock self.unlock() # we should be more precise about whats a locking # error and whats a random-other error raise errors.LockContention(self.filename, e)
def __init__(self, read_lock): super(_fcntl_TemporaryWriteLock, self).__init__() self._read_lock = read_lock self.filename = read_lock.filename count = _fcntl_ReadLock._open_locks[self.filename] if count > 1: # Something else also has a read-lock, so we cannot grab a # write lock. raise errors.LockContention(self.filename) if self.filename in _fcntl_WriteLock._open_locks: raise AssertionError('file already locked: %r' % (self.filename, )) # See if we can open the file for writing. Another process might # have a read lock. We don't use self._open() because we don't want # to create the file if it exists. That would have already been # done by _fcntl_ReadLock try: new_f = open(self.filename, 'rb+') except IOError, e: if e.errno in (errno.EACCES, errno.EPERM): raise errors.LockFailed(self.filename, str(e)) raise
def unlock(self): overlapped = pywintypes.OVERLAPPED() try: win32file.UnlockFileEx(self.hfile, 0, 0x7fff0000, overlapped) self._clear_f() except Exception, e: raise errors.LockContention(e)
def _lock(self, filename, openmode, lockmode): self._open(filename, openmode) self.hfile = msvcrt.get_osfhandle(self.f.fileno()) overlapped = OVERLAPPED() result = _LockFileEx( self.hfile, # HANDLE hFile lockmode, # DWORD dwFlags 0, # DWORD dwReserved 0x7fffffff, # DWORD nNumberOfBytesToLockLow 0x00000000, # DWORD nNumberOfBytesToLockHigh ctypes.byref(overlapped), # lpOverlapped ) if result == 0: self._clear_f() last_err = _GetLastError() if last_err in (ERROR_LOCK_VIOLATION, ): raise errors.LockContention(filename) raise errors.LockContention('Unknown locking error: %s' % (last_err, ))
def _open(self, filename, access, share, cflags, pymode): self.filename = osutils.realpath(filename) try: self._handle = win32file_CreateFile( filename, access, share, None, win32file.OPEN_ALWAYS, win32file.FILE_ATTRIBUTE_NORMAL, None) except pywintypes.error, e: if e.args[0] == winerror.ERROR_ACCESS_DENIED: raise errors.LockFailed(filename, e) if e.args[0] == winerror.ERROR_SHARING_VIOLATION: raise errors.LockContention(filename, e) raise
def _open(self, filename, access, share, cflags, pymode): self.filename = osutils.realpath(filename) handle = _CreateFile(filename, access, share, None, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0) if handle in (INVALID_HANDLE_VALUE, 0): e = ctypes.WinError() if e.args[0] == ERROR_ACCESS_DENIED: raise errors.LockFailed(filename, e) if e.args[0] == ERROR_SHARING_VIOLATION: raise errors.LockContention(filename, e) raise e fd = msvcrt.open_osfhandle(handle, cflags) self.f = os.fdopen(fd, pymode) return self.f
def __init__(self, filename): super(_fcntl_ReadLock, self).__init__() self.filename = osutils.realpath(filename) if self.filename in _fcntl_WriteLock._open_locks: if 'strict_locks' in debug.debug_flags: # We raise before calling _open so we don't need to # _clear_f raise errors.LockContention(self.filename) else: trace.mutter( 'Read lock taken w/ an open write lock on: %s' % (self.filename, )) _fcntl_ReadLock._open_locks.setdefault(self.filename, 0) _fcntl_ReadLock._open_locks[self.filename] += 1 self._open(filename, 'rb') try: # LOCK_NB will cause IOError to be raised if we can't grab a # lock right away. fcntl.lockf(self.f, fcntl.LOCK_SH | fcntl.LOCK_NB) except IOError, e: # we should be more precise about whats a locking # error and whats a random-other error raise errors.LockContention(self.filename, e)
def _translate_error(error_tuple): # Many exceptions need some state from the requestor to be properly # translated (e.g. they need a branch object). So this only translates a # few errors, and the rest are turned into a generic ErrorFromSmartServer. error_name = error_tuple[0] error_args = error_tuple[1:] if error_name == 'UnknownMethod': raise errors.UnknownSmartMethod(error_args[0]) if error_name == 'LockContention': raise errors.LockContention('(remote lock)') elif error_name == 'LockFailed': raise errors.LockFailed(*error_args[:2]) else: raise errors.ErrorFromSmartServer(error_tuple)
def _lock(self, filename, openmode, lockmode): self._open(filename, openmode) self.hfile = msvcrt.get_osfhandle(self.f.fileno()) overlapped = pywintypes.OVERLAPPED() try: win32file.LockFileEx(self.hfile, lockmode, 0, 0x7fff0000, overlapped) except pywintypes.error, e: self._clear_f() if e.args[0] in (winerror.ERROR_LOCK_VIOLATION, ): raise errors.LockContention(filename) ## import pdb; pdb.set_trace() raise
def __init__(self, filename): super(_fcntl_ReadLock, self).__init__() self.filename = osutils.realpath(filename) _fcntl_ReadLock._open_locks.setdefault(self.filename, 0) _fcntl_ReadLock._open_locks[self.filename] += 1 self._open(filename, 'rb') try: # LOCK_NB will cause IOError to be raised if we can't grab a # lock right away. fcntl.lockf(self.f, fcntl.LOCK_SH | fcntl.LOCK_NB) except IOError, e: # we should be more precise about whats a locking # error and whats a random-other error raise errors.LockContention(e)
def unlock(self): overlapped = OVERLAPPED() result = _UnlockFileEx( self.hfile, # HANDLE hFile 0, # DWORD dwReserved 0x7fffffff, # DWORD nNumberOfBytesToLockLow 0x00000000, # DWORD nNumberOfBytesToLockHigh ctypes.byref(overlapped), # lpOverlapped ) self._clear_f() if result == 0: self._clear_f() last_err = _GetLastError() raise errors.LockContention('Unknown unlocking error: %s' % (last_err, ))
class _fcntl_TemporaryWriteLock(_OSLock): """A token used when grabbing a temporary_write_lock. Call restore_read_lock() when you are done with the write lock. """ def __init__(self, read_lock): super(_fcntl_TemporaryWriteLock, self).__init__() self._read_lock = read_lock self.filename = read_lock.filename count = _fcntl_ReadLock._open_locks[self.filename] if count > 1: # Something else also has a read-lock, so we cannot grab a # write lock. raise errors.LockContention(self.filename) if self.filename in _fcntl_WriteLock._open_locks: raise AssertionError('file already locked: %r' % (self.filename, )) # See if we can open the file for writing. Another process might # have a read lock. We don't use self._open() because we don't want # to create the file if it exists. That would have already been # done by _fcntl_ReadLock try: new_f = open(self.filename, 'rb+') except IOError, e: if e.errno in (errno.EACCES, errno.EPERM): raise errors.LockFailed(self.filename, str(e)) raise try: # LOCK_NB will cause IOError to be raised if we can't grab a # lock right away. fcntl.lockf(new_f, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError, e: # TODO: Raise a more specific error based on the type of error raise errors.LockContention(self.filename, e)
def test_LockContention(self): # For now, LockContentions are always transmitted with no details. # Eventually they should include a relpath or url or something else to # identify which lock is busy. self.assertTranslationEqual(('LockContention', ), errors.LockContention('lock', 'msg'))