[CalendarServer-changes] [4849] CalendarServer/trunk/twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Thu Dec 10 09:28:32 PST 2009


Revision: 4849
          http://trac.macosforge.org/projects/calendarserver/changeset/4849
Author:   cdaboo at apple.com
Date:     2009-12-10 09:28:29 -0800 (Thu, 10 Dec 2009)
Log Message:
-----------
Make sure db upgrades are done with an exclusive transaction.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/index.py
    CalendarServer/trunk/twistedcaldav/sql.py

Modified: CalendarServer/trunk/twistedcaldav/index.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/index.py	2009-12-09 23:37:16 UTC (rev 4848)
+++ CalendarServer/trunk/twistedcaldav/index.py	2009-12-10 17:28:29 UTC (rev 4849)
@@ -460,34 +460,27 @@
                 """
             )
 
-    def _db_upgrade(self, old_version):
+    def _db_can_upgrade(self, old_version):
         """
-        Upgrade the database tables.
+        Can we do an in-place upgrade
         """
         
-        schemaChanged = False
+        # Previous versions can be upgraded as per _db_upgrade_data_tables
+        return True
 
+    def _db_upgrade_data_tables(self, q, old_version):
+        """
+        Upgrade the data from an older version of the DB.
+        """
+
         # When going to version 8 all we need to do is add an index
         if old_version < "8":
-            self._db_connection = sqlite.connect(self.dbpath, isolation_level=None)
-            q = self._db_connection.cursor()
             q.execute("create index STARTENDFLOAT on TIMESPAN (START, END, FLOAT)")
-            schemaChanged = True
 
-        # When going to version 7 all we need to do is add a column to the time-range
+        # When going to version 7,8 all we need to do is add a column to the resource and timespan
         if old_version < "7":
-            self._db_connection = sqlite.connect(self.dbpath, isolation_level=None)
-            q = self._db_connection.cursor()
             q.execute("alter table RESOURCE add column ORGANIZER text default '?'")
             q.execute("alter table TIMESPAN add column FBTYPE text(1) default '?'")
-            schemaChanged = True
-            
-        if schemaChanged:
-            self._db_upgrade_schema(q)
-            self._db_close()
-            return self._db()
-        else:
-            return super(AbstractCalendarIndex, self)._db_upgrade(old_version)
 
     def notExpandedBeyond(self, minDate):
         """

Modified: CalendarServer/trunk/twistedcaldav/sql.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/sql.py	2009-12-09 23:37:16 UTC (rev 4848)
+++ CalendarServer/trunk/twistedcaldav/sql.py	2009-12-10 17:28:29 UTC (rev 4849)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -99,24 +99,9 @@
                 # Create CALDAV table if needed
 
                 if self._test_schema_table(q):
-                    q.execute(
-                        """
-                        select VALUE from CALDAV
-                         where KEY = 'SCHEMA_VERSION'
-                        """)
-                    version = q.fetchone()
+                    
+                    version, dbtype = self._get_schema_version(q)
 
-                    if version is not None: version = version[0]
-
-                    q.execute(
-                        """
-                        select VALUE from CALDAV
-                         where KEY = 'TYPE'
-                        """)
-                    dbtype = q.fetchone()
-
-                    if dbtype is not None: dbtype = dbtype[0]
-
                     if (version != self._db_version()) or (dbtype != self._db_type()):
 
                         # Clean-up first
@@ -125,13 +110,6 @@
                         self._db_connection.close()
                         del(self._db_connection)
 
-                        if version != self._db_version():
-                            log.err("Database %s has different schema (v.%s vs. v.%s)"
-                                    % (db_filename, version, self._db_version()))
-                            
-                            # Upgrade the DB
-                            return self._db_upgrade(version)
-
                         if dbtype != self._db_type():
                             log.err("Database %s has different type (%s vs. %s)"
                                     % (db_filename, dbtype, self._db_type()))
@@ -140,6 +118,13 @@
                             os.remove(db_filename)
                             return self._db()
 
+                        if version != self._db_version():
+                            log.err("Database %s has different schema (v.%s vs. v.%s)"
+                                    % (db_filename, version, self._db_version()))
+                            
+                            # Upgrade the DB
+                            return self._db_upgrade(version)
+
                 else:
                     self._db_init(db_filename, q)
 
@@ -155,6 +140,27 @@
         """)
         return q.fetchone()
 
+    def _get_schema_version(self, q):
+        q.execute(
+            """
+            select VALUE from CALDAV
+             where KEY = 'SCHEMA_VERSION'
+            """)
+        version = q.fetchone()
+
+        if version is not None: version = version[0]
+
+        q.execute(
+            """
+            select VALUE from CALDAV
+             where KEY = 'TYPE'
+            """)
+        dbtype = q.fetchone()
+
+        if dbtype is not None: dbtype = dbtype[0]
+
+        return version, dbtype
+
     def _db_init(self, db_filename, q):
         """
         Initialise the underlying database tables.
@@ -228,24 +234,38 @@
         if do_commit:
             self._db_commit()
 
+    def _db_can_upgrade(self, old_version):
+        
+        return self.persistent
+
     def _db_upgrade(self, old_version):
         """
         Upgrade the database tables.
         """
         
-        if self.persistent:
+        if self._db_can_upgrade(old_version):
             self._db_connection = sqlite.connect(self.dbpath, isolation_level=None)
             q = self._db_connection.cursor()
-            self._db_upgrade_data_tables(q, old_version)
-            self._db_upgrade_schema(q)
+            q.execute("begin exclusive transaction")
+
+            # We re-check whether the schema version again AFTER we've got an exclusive
+            # lock as some other server process may have snuck in and already upgraded it
+            # before we got the lock, or whilst we were waiting for it.
+            version, _ignore_dbtype = self._get_schema_version(q)
+
+            if version != self._db_version():
+                self._db_upgrade_data_tables(q, old_version)
+                self._db_upgrade_schema(q)
+
+            q.execute("commit")
             self._db_close()
-            return self._db()
         else:
             # Non-persistent DB's by default can be removed and re-created. However, for simple
             # DB upgrades they SHOULD override this method and handle those for better performance.
             os.remove(self.dbpath)
-            return self._db()
-    
+
+        return self._db()
+
     def _db_upgrade_data_tables(self, q, old_version):
         """
         Upgrade the data from an older version of the DB.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20091210/fffb13af/attachment.html>


More information about the calendarserver-changes mailing list