[CalendarServer-changes] [7079] CalendarServer/trunk/txdav/common/datastore/sql.py

source_changes at macosforge.org source_changes at macosforge.org
Thu Feb 24 12:21:48 PST 2011


Revision: 7079
          http://trac.macosforge.org/projects/calendarserver/changeset/7079
Author:   cdaboo at apple.com
Date:     2011-02-24 12:21:46 -0800 (Thu, 24 Feb 2011)
Log Message:
-----------
Use savepoints instead of lock on calendar_home table.

Modified Paths:
--------------
    CalendarServer/trunk/txdav/common/datastore/sql.py

Modified: CalendarServer/trunk/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql.py	2011-02-24 18:06:02 UTC (rev 7078)
+++ CalendarServer/trunk/txdav/common/datastore/sql.py	2011-02-24 20:21:46 UTC (rev 7079)
@@ -470,31 +470,38 @@
         else:
             if not create:
                 returnValue(None)
-            # Need to lock to prevent race condition
 
-            # FIXME: this is an entire table lock - ideally we want a row lock
-            # but the row does not exist yet. However, the "exclusive" mode does
-            # allow concurrent reads so the only thing we block is other
-            # attempts to provision a home, which is not too bad
+            # Use savepoint so we can do a partial rollback if there is a race condition
+            # where this row has already been inserted
+            savepoint = SavepointAction("homeWithUID")
+            yield savepoint.acquire(txn)
 
-            # Also note that we must not cache the owner_uid->resource_id
-            # mapping in _cacher when creating as we don't want that to appear
-            # until AFTER the commit
-
-            yield Lock(cls._homeSchema, 'exclusive').on(txn)
-            # Now test again
-            exists = yield cls._resourceIDFromOwnerQuery.on(txn, ownerUID=uid)
-            if not exists:
+            try:
                 resourceid = (yield Insert(
                     {cls._homeSchema.OWNER_UID: uid},
                     Return=cls._homeSchema.RESOURCE_ID).on(txn))[0][0]
                 yield Insert(
                     {cls._homeMetaDataSchema.RESOURCE_ID: resourceid}).on(txn)
-            home = cls(txn, uid, notifiers)
-            home = (yield home.initFromStore(no_cache=not exists))
-            if not exists:
+            except Exception: # FIXME: Really want to trap the pg.DatabaseError but in a non-DB specific manner
+                yield savepoint.rollback(txn)
+                
+                # Retry the query - row may exist now, if not re-raise
+                homeObject = cls(txn, uid, notifiers)
+                homeObject = (yield homeObject.initFromStore())
+                if homeObject:
+                    returnValue(homeObject)
+                else:
+                    raise
+            else:
+                yield savepoint.release(txn)
+
+                # Note that we must not cache the owner_uid->resource_id
+                # mapping in _cacher when creating as we don't want that to appear
+                # until AFTER the commit
+                home = cls(txn, uid, notifiers)
+                home = (yield home.initFromStore(no_cache=True))
                 yield home.createdHome()
-            returnValue(home)
+                returnValue(home)
 
 
     @classmethod
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110224/b597acb1/attachment-0001.html>


More information about the calendarserver-changes mailing list