[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