[Zope-Checkins] CVS: ZODB3/ZODB - lock_file.py:1.8

Barry Warsaw barry@wooz.org
Fri, 28 Feb 2003 14:50:07 -0500


Update of /cvs-repository/ZODB3/ZODB
In directory cvs.zope.org:/tmp/cvs-serv6460

Modified Files:
	lock_file.py 
Log Message:
Backport lock file changes from ZODB4.  Specifically, implement an
unlock_file() call which awaits Tim's backport of
winlock.UnlockFile().  This is no-op on *nix.

Also, implement a better API for dealing with lock files.  Use the
LockFile class for clean acquisition and release of locks, and
unlinking of lock files.


=== ZODB3/ZODB/lock_file.py 1.7 => 1.8 ===
--- ZODB3/ZODB/lock_file.py:1.7	Tue Dec  3 13:49:33 2002
+++ ZODB3/ZODB/lock_file.py	Fri Feb 28 14:50:06 2003
@@ -12,47 +12,63 @@
 #
 ##############################################################################
 
-from ZODB.POSException import StorageSystemError
+import os
+import errno
 
-# Try to create a function that creates Unix file locks.
 try:
     import fcntl
+except ImportError:
+    try:
+        from winlock import LockFile as _LockFile
+        from winlock import UnlockFile as _UnlockFile
+    except ImportError:
+        import zLOG
+        def lock_file(file):
+            zLOG.LOG('ZODB', zLOG.INFO,
+                     'No file-locking support on this platform')
 
-    lock_file_FLAG = fcntl.LOCK_EX | fcntl.LOCK_NB
+    # Windows
+    def lock_file(file):
+        # Lock just the first byte
+        _LockFile(file.fileno(), 0, 0, 1, 0)
+
+    def unlock_file(file):
+        _UnlockFile(file.fileno(), 0, 0, 1, 0)
+else:
+    # Unix
+    _flags = fcntl.LOCK_EX | fcntl.LOCK_NB
 
     def lock_file(file):
-        try:
-            un = file.fileno()
-        except:
-            return # don't care if not a real file
+        fcntl.flock(file.fileno(), _flags)
 
+    def unlock_file(file):
+        # File is automatically unlocked on close
+        pass
+
+
+
+# This is a better interface to use than the lockfile.lock_file() interface.
+# Creating the instance acquires the lock.  The file remains open.  Calling
+# close both closes and unlocks the lock file.
+class LockFile:
+    def __init__(self, path):
+        self._path = path
         try:
-            fcntl.flock(un, lock_file_FLAG)
-        except:
-            raise StorageSystemError, (
-                "Could not lock the database file.  There must be\n"
-                "another process that has opened the file.\n"
-                "<p>")
+            self._fp = open(path, 'r+')
+        except IOError, e:
+            if e.errno <> errno.ENOENT: raise
+            self._fp = open(path, 'w+')
+        # Acquire the lock and piss on the hydrant
+        lock_file(self._fp)
+        print >> self._fp, os.getpid()
+        self._fp.flush()
+
+    def close(self):
+        if self._fp is not None:
+            unlock_file(self._fp)
+            self._fp.close()
+            os.unlink(self._path)
+            self._fp = None
 
-except:
-    # Try windows-specific code:
-    try:
-        from winlock import LockFile
-        def lock_file(file):
-            try:
-                un=file.fileno()
-            except:
-                return # don't care if not a real file
-
-            try:
-                LockFile(un, 0, 0, 1, 0) # just lock the first byte, who cares
-            except:
-                raise StorageSystemError, (
-                    "Could not lock the database file.  There must be\n"
-                    "another process that has opened the file.\n"
-                    "<p>")
-    except:
-        import zLOG
-        def lock_file(file):
-            zLOG.LOG("FS", zLOG.INFO,
-                     "No file-locking support on this platform")
+    def __del__(self):
+        self.close()