[Checkins] SVN: relstorage/trunk/ Merged changes from the 1.1 branch.

Shane Hathaway shane at hathawaymix.org
Sat May 10 02:43:24 EDT 2008


Log message for revision 86608:
  Merged changes from the 1.1 branch.
  
  This is my first try at merging in Subversion.  Is it really this hard?
  This is how I did it:
  
    svn merge -r 85842:86602 ../branches/1.1 .
  
  Figuring out those revision numbers was complicated.
  
  With Mercurial this would have been a breeze:
  
    hg pull ../branches/1.1
  
  That command would simply do the right thing.  Isn't there an equivalent
  for Subversion?  Hmph.
  
  

Changed:
  U   relstorage/trunk/CHANGELOG.txt
  U   relstorage/trunk/notes/migrate-1.0.1.txt
  U   relstorage/trunk/relstorage/adapters/mysql.py
  U   relstorage/trunk/relstorage/adapters/postgresql.py

-=-
Modified: relstorage/trunk/CHANGELOG.txt
===================================================================
--- relstorage/trunk/CHANGELOG.txt	2008-05-10 06:34:34 UTC (rev 86607)
+++ relstorage/trunk/CHANGELOG.txt	2008-05-10 06:43:24 UTC (rev 86608)
@@ -1,4 +1,13 @@
 
+RelStorage 1.1b2
+
+- Made the MySQL locks database-specific rather than server-wide.  This is
+  important for multi-database configurations.
+
+- In the PostgreSQL adapter, made the pack lock fall back to table locking
+  rather than advisory locks for PostgreSQL 8.1.
+
+
 RelStorage 1.1b1
 
 - Fixed the use of setup.py without setuptools.  Thanks to Chris Withers.

Modified: relstorage/trunk/notes/migrate-1.0.1.txt
===================================================================
--- relstorage/trunk/notes/migrate-1.0.1.txt	2008-05-10 06:34:34 UTC (rev 86607)
+++ relstorage/trunk/notes/migrate-1.0.1.txt	2008-05-10 06:43:24 UTC (rev 86608)
@@ -5,8 +5,6 @@
 
     CREATE INDEX object_state_prev_tid ON object_state (prev_tid);
 
-    DROP TABLE pack_lock;
-
     DROP INDEX pack_object_keep_zoid;
     CREATE INDEX pack_object_keep_false ON pack_object (zoid)
         WHERE keep = false;
@@ -17,7 +15,7 @@
 
     CREATE INDEX current_object_tid ON current_object (tid);
 
-    ALTER TABLE object_ref PRIMARY KEY (tid, zoid, to_zoid);
+    ALTER TABLE object_ref ADD PRIMARY KEY (tid, zoid, to_zoid);
     DROP INDEX object_ref_from;
     DROP INDEX object_ref_tid;
     DROP INDEX object_ref_to;
@@ -32,6 +30,17 @@
         tid         BIGINT NOT NULL PRIMARY KEY
     );
 
+Users of PostgreSQL 8.2 and above should also drop the pack_lock table since
+it has been replaced with an advisory lock:
+
+    DROP TABLE pack_lock;
+
+Users of PostgreSQL 8.1 and below still need the pack_lock table.  If you
+have deleted it, please create it again with the following statement:
+
+    CREATE TABLE pack_lock ();
+
+
 MySQL:
 
     CREATE INDEX object_state_prev_tid ON object_state (prev_tid);
@@ -55,6 +64,7 @@
         tid         BIGINT NOT NULL PRIMARY KEY
     ) ENGINE = MyISAM;
 
+
 Oracle:
 
     CREATE INDEX object_state_prev_tid ON object_state (prev_tid);

Modified: relstorage/trunk/relstorage/adapters/mysql.py
===================================================================
--- relstorage/trunk/relstorage/adapters/mysql.py	2008-05-10 06:34:34 UTC (rev 86607)
+++ relstorage/trunk/relstorage/adapters/mysql.py	2008-05-10 06:43:24 UTC (rev 86608)
@@ -411,12 +411,7 @@
 
     def start_commit(self, cursor):
         """Prepare to commit."""
-        # Hold commit_lock to prevent concurrent commits.
-        cursor.execute("SELECT GET_LOCK('relstorage.commit', %s)",
-            (commit_lock_timeout,))
-        locked = cursor.fetchone()[0]
-        if not locked:
-            raise StorageError("Unable to acquire commit lock")
+        self._hold_commit_lock(cursor)
 
     def get_tid_and_time(self, cursor):
         """Returns the most recent tid and the current database time.
@@ -519,12 +514,12 @@
     def commit_phase2(self, cursor, txn):
         """Final transaction commit."""
         cursor.connection.commit()
-        cursor.execute("SELECT RELEASE_LOCK('relstorage.commit')")
+        self._release_commit_lock(cursor)
 
     def abort(self, cursor, txn=None):
         """Abort the commit.  If txn is not None, phase 1 is also aborted."""
         cursor.connection.rollback()
-        cursor.execute("SELECT RELEASE_LOCK('relstorage.commit')")
+        self._release_commit_lock(cursor)
 
     def new_oid(self, cursor):
         """Return a new, unused OID."""
@@ -543,7 +538,7 @@
 
         Raise an exception if packing or undo is already in progress.
         """
-        stmt = "SELECT GET_LOCK('relstorage.pack', 0)"
+        stmt = "SELECT GET_LOCK(CONCAT(DATABASE(), '.pack'), 0)"
         cursor.execute(stmt)
         res = cursor.fetchone()[0]
         if not res:
@@ -552,7 +547,7 @@
 
     def release_pack_lock(self, cursor):
         """Release the pack lock."""
-        stmt = "SELECT RELEASE_LOCK('relstorage.pack')"
+        stmt = "SELECT RELEASE_LOCK(CONCAT(DATABASE(), '.pack'))"
         cursor.execute(stmt)
 
 
@@ -574,11 +569,11 @@
 
 
     def _hold_commit_lock(self, cursor):
-        """Hold the commit lock for packing.
+        """Hold the commit lock.
 
         This overrides the method by the same name in common.Adapter.
         """
-        cursor.execute("SELECT GET_LOCK('relstorage.commit', %s)",
+        cursor.execute("SELECT GET_LOCK(CONCAT(DATABASE(), '.commit'), %s)",
             (commit_lock_timeout,))
         locked = cursor.fetchone()[0]
         if not locked:
@@ -586,12 +581,11 @@
 
 
     def _release_commit_lock(self, cursor):
-        """Release the commit lock.  This is used during packing.
+        """Release the commit lock.
 
         This overrides the method by the same name in common.Adapter.
         """
-        stmt = "SELECT RELEASE_LOCK('relstorage.commit')"
-        cursor.execute(stmt)
+        cursor.execute("SELECT RELEASE_LOCK(CONCAT(DATABASE(), '.commit'))")
 
 
     _poll_query = "SELECT tid FROM transaction ORDER BY tid DESC LIMIT 1"

Modified: relstorage/trunk/relstorage/adapters/postgresql.py
===================================================================
--- relstorage/trunk/relstorage/adapters/postgresql.py	2008-05-10 06:34:34 UTC (rev 86607)
+++ relstorage/trunk/relstorage/adapters/postgresql.py	2008-05-10 06:43:24 UTC (rev 86608)
@@ -16,6 +16,7 @@
 from base64 import decodestring, encodestring
 import logging
 import psycopg2, psycopg2.extensions
+import re
 from ZODB.POSException import StorageError
 
 from common import Adapter
@@ -135,7 +136,10 @@
         """
         cursor.execute(stmt)
 
+        if not self._pg_has_advisory_locks(cursor):
+            cursor.execute("CREATE TABLE pack_lock ()")
 
+
     def prepare_schema(self):
         """Create the database schema if it does not already exist."""
         conn, cursor = self.open()
@@ -207,6 +211,20 @@
                         psycopg2.OperationalError):
                     pass
 
+    def _pg_version(self, cursor):
+        """Return the (major, minor) version of PostgreSQL"""
+        cursor.execute("SELECT version()")
+        v = cursor.fetchone()[0]
+        m = re.search(r"([0-9]+)[.]([0-9]+)", v)
+        if m is None:
+            raise AssertionError("Unable to detect PostgreSQL version: " + v)
+        else:
+            return int(m.group(1)), int(m.group(2))
+
+    def _pg_has_advisory_locks(self, cursor):
+        """Return true if this version of PostgreSQL supports advisory locks"""
+        return self._pg_version(cursor) >= (8, 2)
+
     def open_for_load(self):
         """Open and initialize a connection for loading objects.
 
@@ -570,21 +588,27 @@
         cursor.execute(stmt)
         return cursor.fetchone()[0]
 
-
     def hold_pack_lock(self, cursor):
         """Try to acquire the pack lock.
 
         Raise an exception if packing or undo is already in progress.
         """
-        stmt = "SELECT pg_try_advisory_lock(1)"
-        cursor.execute(stmt)
-        locked = cursor.fetchone()[0]
-        if not locked:
-            raise StorageError('A pack or undo operation is in progress')
+        if self._pg_has_advisory_locks(cursor):
+            cursor.execute("SELECT pg_try_advisory_lock(1)")
+            locked = cursor.fetchone()[0]
+            if not locked:
+                raise StorageError('A pack or undo operation is in progress')
+        else:
+            # b/w compat
+            try:
+                cursor.execute("LOCK pack_lock IN EXCLUSIVE MODE NOWAIT")
+            except psycopg2.DatabaseError:
+                raise StorageError('A pack or undo operation is in progress')
 
     def release_pack_lock(self, cursor):
         """Release the pack lock."""
-        stmt = "SELECT pg_advisory_unlock(1)"
-        cursor.execute(stmt)
+        if self._pg_has_advisory_locks(cursor):
+            cursor.execute("SELECT pg_advisory_unlock(1)")
+        # else no action needed since the lock will be released at txn commit
 
     _poll_query = "EXECUTE get_latest_tid"



More information about the Checkins mailing list