[Pkg-bazaar-commits] ./bzr/unstable r615: Major rework of locking code:
Martin Pool
mbp at sourcefrog.net
Fri Apr 10 08:20:24 UTC 2009
------------------------------------------------------------
revno: 615
committer: Martin Pool <mbp at sourcefrog.net>
timestamp: Wed 2005-06-01 16:09:59 +1000
message:
Major rework of locking code:
- New ReadLock and WriteLock objects, with unlock methods, and that
give a warning if they leak without being unlocked
- The lock file is opened readonly for read locks, which should avoid
problems when the user only has read permission for a branch.
- Selective definitions of locking code is perhaps simpler now
modified:
bzrlib/branch.py
bzrlib/lock.py
-------------- next part --------------
=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py 2005-06-01 04:09:38 +0000
+++ b/bzrlib/branch.py 2005-06-01 06:09:59 +0000
@@ -128,6 +128,7 @@
base = None
_lock_mode = None
_lock_count = None
+ _lock = None
def __init__(self, base, init=False, find_root=True):
"""Create new branch object at a particular location.
@@ -157,7 +158,6 @@
['use "bzr init" to initialize a new working tree',
'current bzr can only operate from top-of-tree'])
self._check_format()
- self._lockfile = self.controlfile('branch-lock', 'wb')
self.text_store = ImmutableStore(self.controlfilename('text-store'))
self.revision_store = ImmutableStore(self.controlfilename('revision-store'))
@@ -172,10 +172,10 @@
def __del__(self):
- if self._lock_mode:
+ if self._lock_mode or self._lock:
from warnings import warn
warn("branch %r was not explicitly unlocked" % self)
- self.unlock()
+ self._lock.unlock()
@@ -187,9 +187,9 @@
self._lock_mode)
self._lock_count += 1
else:
- from bzrlib.lock import lock, LOCK_EX
+ from bzrlib.lock import WriteLock
- lock(self._lockfile, LOCK_EX)
+ self._lock = WriteLock(self.controlfilename('branch-lock'))
self._lock_mode = 'w'
self._lock_count = 1
@@ -201,9 +201,9 @@
"invalid lock mode %r" % self._lock_mode
self._lock_count += 1
else:
- from bzrlib.lock import lock, LOCK_SH
+ from bzrlib.lock import ReadLock
- lock(self._lockfile, LOCK_SH)
+ self._lock = ReadLock(self.controlfilename('branch-lock'))
self._lock_mode = 'r'
self._lock_count = 1
@@ -217,9 +217,8 @@
if self._lock_count > 1:
self._lock_count -= 1
else:
- assert self._lock_count == 1
- from bzrlib.lock import unlock
- unlock(self._lockfile)
+ self._lock.unlock()
+ self._lock = None
self._lock_mode = self._lock_count = None
=== modified file 'bzrlib/lock.py'
--- a/bzrlib/lock.py 2005-06-01 04:09:38 +0000
+++ b/bzrlib/lock.py 2005-06-01 06:09:59 +0000
@@ -28,73 +28,147 @@
Eventually we may need to use some kind of lock representation that
will work on a dumb filesystem without actual locking primitives.
+
+This defines two classes: ReadLock and WriteLock, which can be
+implemented in different ways on different platforms. Both have an
+unlock() method.
"""
import sys, os
-import bzrlib
from trace import mutter, note, warning
from errors import LockError
+class _base_Lock(object):
+ def _open(self, filename, filemode):
+ self.f = open(filename, filemode)
+ return self.f
+
+
+ def __del__(self):
+ if self.f:
+ from warnings import warn
+ warn("lock on %r not released" % self.f)
+ self.unlock()
+
+ def unlock(self):
+ raise NotImplementedError()
+
+
+
+
+
+
+############################################################
+# msvcrt locks
+
+
try:
import fcntl
- LOCK_SH = fcntl.LOCK_SH
- LOCK_EX = fcntl.LOCK_EX
- LOCK_NB = fcntl.LOCK_NB
- def lock(f, flags):
- try:
- fcntl.flock(f, flags)
- except Exception, e:
- raise LockError(e)
-
- def unlock(f):
- try:
- fcntl.flock(f, fcntl.LOCK_UN)
- except Exception, e:
- raise LockError(e)
+
+ class _fcntl_FileLock(_base_Lock):
+ f = None
+
+ def unlock(self):
+ fcntl.flock(self.f, fcntl.LOCK_UN)
+ self.f.close()
+ del self.f
+
+
+ class _fcntl_WriteLock(_fcntl_FileLock):
+ def __init__(self, filename):
+ try:
+ fcntl.flock(self._open(filename, 'wb'), fcntl.LOCK_EX)
+ except Exception, e:
+ raise LockError(e)
+
+
+ class _fcntl_ReadLock(_fcntl_FileLock):
+ def __init__(self, filename):
+ try:
+ fcntl.flock(self._open(filename, 'rb'), fcntl.LOCK_SH)
+ except Exception, e:
+ raise LockError(e)
+
+ WriteLock = _fcntl_WriteLock
+ ReadLock = _fcntl_ReadLock
except ImportError:
try:
import win32con, win32file, pywintypes
- LOCK_SH = 0 # the default
- LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
- LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
-
- def lock(f, flags):
- try:
- if type(f) == file:
- hfile = win32file._get_osfhandle(f.fileno())
- else:
- hfile = win32file._get_osfhandle(f)
- overlapped = pywintypes.OVERLAPPED()
- win32file.LockFileEx(hfile, flags, 0, 0x7fff0000, overlapped)
- except Exception, e:
- raise LockError(e)
-
- def unlock(f):
- try:
- if type(f) == file:
- hfile = win32file._get_osfhandle(f.fileno())
- else:
- hfile = win32file._get_osfhandle(f)
- overlapped = pywintypes.OVERLAPPED()
- win32file.UnlockFileEx(hfile, 0, 0x7fff0000, overlapped)
- except Exception, e:
- raise LockError(e)
+
+
+ #LOCK_SH = 0 # the default
+ #LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
+ #LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
+
+ class _w32c_FileLock(_base_Lock):
+ def _lock(self, filename, openmode, lockmode):
+ try:
+ self._open(filename, openmode)
+ self.hfile = win32file._get_osfhandle(self.f.fileno())
+ overlapped = pywintypes.OVERLAPPED()
+ win32file.LockFileEx(self.hfile, lockmode, 0, 0x7fff0000, overlapped)
+ except Exception, e:
+ raise LockError(e)
+
+ def unlock(self):
+ try:
+ overlapped = pywintypes.OVERLAPPED()
+ win32file.UnlockFileEx(self.hfile, 0, 0x7fff0000, overlapped)
+ self.f.close()
+ self.f = None
+ except Exception, e:
+ raise LockError(e)
+
+
+
+ class _w32c_ReadLock(_w32c_FileLock):
+ def __init__(self, filename):
+ _w32c_FileLock._lock(self, filename, 'rb', 0)
+
+ class _w32c_WriteLock(_w32c_FileLock):
+ def __init__(self, filename):
+ _w32c_FileLock._lock(self, filename, 'wb',
+ win32con.LOCKFILE_EXCLUSIVE_LOCK)
+
+
+
+ WriteLock = _w32c_WriteLock
+ ReadLock = _w32c_ReadLock
+
except ImportError:
try:
import msvcrt
+
+
# Unfortunately, msvcrt.locking() doesn't distinguish between
# read locks and write locks. Also, the way the combinations
# work to get non-blocking is not the same, so we
# have to write extra special functions here.
- LOCK_SH = 1
- LOCK_EX = 2
- LOCK_NB = 4
-
- def lock(f, flags):
+
+ class _msvc_FileLock(_base_Lock):
+ LOCK_SH = 1
+ LOCK_EX = 2
+ LOCK_NB = 4
+ def unlock(self):
+ _msvc_unlock(self.f)
+
+
+ class _msvc_ReadLock(_msvc_FileLock):
+ def __init__(self, filename):
+ _msvc_lock(self._open(filename, 'rb'), self.LOCK_SH)
+
+
+ class _msvc_WriteLock(_msvc_FileLock):
+ def __init__(self, filename):
+ _msvc_lock(self._open(filename, 'wb'), self.LOCK_EX)
+
+
+
+ def _msvc_lock(f, flags):
try:
# Unfortunately, msvcrt.LK_RLCK is equivalent to msvcrt.LK_LOCK
# according to the comments, LK_RLCK is open the lock for writing.
@@ -110,14 +184,14 @@
fn = f
fpos = os.lseek(fn, 0,0)
os.lseek(fn, 0,0)
-
- if flags & LOCK_SH:
- if flags & LOCK_NB:
+
+ if flags & self.LOCK_SH:
+ if flags & self.LOCK_NB:
lock_mode = msvcrt.LK_NBLCK
else:
lock_mode = msvcrt.LK_LOCK
- elif flags & LOCK_EX:
- if flags & LOCK_NB:
+ elif flags & self.LOCK_EX:
+ if flags & self.LOCK_NB:
lock_mode = msvcrt.LK_NBRLCK
else:
lock_mode = msvcrt.LK_RLCK
@@ -130,7 +204,7 @@
except Exception, e:
raise LockError(e)
- def unlock(f):
+ def _msvc_unlock(f):
try:
if type(f) == file:
fpos = f.tell()
@@ -147,14 +221,18 @@
os.lseek(fn, fpos, 0)
except Exception, e:
raise LockError(e)
+
+
+
+ WriteLock = _msvc_WriteLock
+ ReadLock = _msvc_ReadLock
except ImportError:
- from warnings import Warning
-
- warning("please write a locking method for platform %r" % sys.platform)
-
- # Creating no-op lock/unlock for now
- def lock(f, flags):
- pass
- def unlock(f):
- pass
+ raise NotImplementedError("please write a locking method "
+ "for platform %r" % sys.platform)
+
+
+
+
+
+
More information about the Pkg-bazaar-commits
mailing list