[CalendarServer-changes] [2007] CalendarServer/trunk/twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Wed Nov 14 12:57:26 PST 2007
Revision: 2007
http://trac.macosforge.org/projects/calendarserver/changeset/2007
Author: cdaboo at apple.com
Date: 2007-11-14 12:57:25 -0800 (Wed, 14 Nov 2007)
Log Message:
-----------
Prevent a race condition whereby multiple processes can attempt to create a database table more than once,
resulting in exceptions for all but the first process to do so.
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/sql.py
CalendarServer/trunk/twistedcaldav/test/test_sql.py
Modified: CalendarServer/trunk/twistedcaldav/sql.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/sql.py 2007-11-12 20:24:19 UTC (rev 2006)
+++ CalendarServer/trunk/twistedcaldav/sql.py 2007-11-14 20:57:25 UTC (rev 2007)
@@ -81,14 +81,8 @@
q = self._db_connection.cursor()
try:
# Create CALDAV table if needed
- q.execute(
- """
- select (1) from SQLITE_MASTER
- where TYPE = 'table' and NAME = 'CALDAV'
- """)
- caldav = q.fetchone()
- if caldav:
+ if self._test_schema_table(q):
q.execute(
"""
select VALUE from CALDAV
@@ -131,6 +125,13 @@
if q is not None: q.close()
return self._db_connection
+ def _test_schema_table(self, q):
+ q.execute("""
+ select (1) from SQLITE_MASTER
+ where TYPE = 'table' and NAME = 'CALDAV'
+ """)
+ return q.fetchone()
+
def _db_init(self, db_filename, q):
"""
Initialise the underlying database tables.
@@ -139,10 +140,23 @@
"""
log.msg("Initializing database %s" % (db_filename,))
- self._db_init_schema_table(q)
- self._db_init_data_tables(q)
- self._db_recreate()
+ # We need an exclusive lock here as we are making a big change to the database and we don't
+ # want other processes to get stomped on or stomp on us.
+ old_isolation = self._db_connection.isolation_level
+ self._db_connection.isolation_level = None
+ q.execute("begin exclusive transaction")
+
+ # We re-check whether the schema table is present again AFTER we've got an exclusive
+ # lock as some other server process may have snuck in and already created it
+ # before we got the lock, or whilst we were waiting for it.
+ if not self._test_schema_table(q):
+ self._db_init_schema_table(q)
+ self._db_init_data_tables(q)
+ self._db_recreate()
+ q.execute("commit")
+ self._db_connection.isolation_level = old_isolation
+
def _db_init_schema_table(self, q):
"""
Initialise the underlying database tables.
Modified: CalendarServer/trunk/twistedcaldav/test/test_sql.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_sql.py 2007-11-12 20:24:19 UTC (rev 2006)
+++ CalendarServer/trunk/twistedcaldav/test/test_sql.py 2007-11-14 20:57:25 UTC (rev 2007)
@@ -20,6 +20,8 @@
import twistedcaldav.test.util
from twistedcaldav.sql import db_prefix
+from threading import Thread
+import time
import os
class SQL (twistedcaldav.test.util.TestCase):
@@ -62,6 +64,13 @@
"""
)
+ class TestDBPauseInInit(TestDB):
+
+ def _db_init(self, db_filename, q):
+
+ time.sleep(1)
+ super(SQL.TestDBPauseInInit, self)._db_init(db_filename, q)
+
def test_connect(self):
"""
Connect to database and create table
@@ -152,3 +161,26 @@
children = self.site.resource.listChildren()
self.assertTrue("test" in children)
self.assertFalse(db_prefix + "sqlite" in children)
+
+ def test_duplicate_create(self):
+ dbname = self.mktemp()
+
+ class DBThread(Thread):
+
+ def run(self):
+ try:
+ db = SQL.TestDBPauseInInit(dbname)
+ db._db()
+ self.result = True
+ except:
+ self.result = False
+
+ t1 = DBThread()
+ t2 = DBThread()
+ t1.start()
+ t2.start()
+ t1.join()
+ t2.join()
+ self.assertTrue(t1.result)
+ self.assertTrue(t2.result)
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20071114/b44cbc07/attachment-0001.html
More information about the calendarserver-changes
mailing list