[CalendarServer-changes] [7185] CalendarServer/trunk/txdav
source_changes at macosforge.org
source_changes at macosforge.org
Fri Mar 11 13:10:33 PST 2011
Revision: 7185
http://trac.macosforge.org/projects/calendarserver/changeset/7185
Author: cdaboo at apple.com
Date: 2011-03-11 13:10:33 -0800 (Fri, 11 Mar 2011)
Log Message:
-----------
Prevent a race condition when creating direct shares.
Modified Paths:
--------------
CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
CalendarServer/trunk/txdav/common/datastore/sql_legacy.py
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py 2011-03-11 19:38:43 UTC (rev 7184)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py 2011-03-11 21:10:33 UTC (rev 7185)
@@ -41,6 +41,7 @@
from twistedcaldav import memcacher, caldavxml
from twistedcaldav.config import config
from twistedcaldav.dateops import datetimeMktime
+from twistedcaldav.sharing import SharedCollectionRecord
import datetime
@@ -573,3 +574,53 @@
rows = yield _allWithID.on(self.transactionUnderTest(), resourceID=resourceID)
self.assertEqual(len(tuple(rows)), 0)
yield self.commit()
+
+ @inlineCallbacks
+ def test_directShareCreateConcurrency(self):
+ """
+ Test that two concurrent attempts to create a direct shared calendar
+ work concurrently without an exception.
+ """
+
+ calendarStore = self._sqlCalendarStore
+
+ # Provision the home and calendar now
+ txn = calendarStore.newTransaction()
+ home = yield txn.homeWithUID(ECALENDARTYPE, "uid1", create=True)
+ self.assertNotEqual(home, None)
+ cal = yield home.calendarWithName("calendar")
+ self.assertNotEqual(cal, None)
+ yield txn.commit()
+
+ txn1 = calendarStore.newTransaction()
+ txn2 = calendarStore.newTransaction()
+
+ home1 = yield txn1.homeWithUID(ECALENDARTYPE, "uid1", create=True)
+ home2 = yield txn2.homeWithUID(ECALENDARTYPE, "uid1", create=True)
+
+ shares1 = yield home1.retrieveOldShares()
+ shares2 = yield home2.retrieveOldShares()
+
+ record = SharedCollectionRecord(
+ "abcd",
+ "D",
+ "/calendars/__uids__/uid2/calendar/",
+ "XYZ",
+ "Shared Wiki Calendar",
+ )
+
+ @inlineCallbacks
+ def _defer1():
+ yield shares1.addOrUpdateRecord(record)
+ yield txn1.commit()
+ d1 = _defer1()
+
+ @inlineCallbacks
+ def _defer2():
+ yield shares2.addOrUpdateRecord(record)
+ yield txn2.commit()
+ d2 = _defer2()
+
+ yield d1
+ yield d2
+
Modified: CalendarServer/trunk/txdav/common/datastore/sql_legacy.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_legacy.py 2011-03-11 19:38:43 UTC (rev 7184)
+++ CalendarServer/trunk/txdav/common/datastore/sql_legacy.py 2011-03-11 21:10:33 UTC (rev 7185)
@@ -44,7 +44,7 @@
from txdav.common.icommondatastore import (
IndexedSearchException, ReservationError)
-from twext.enterprise.dal.syntax import Update
+from twext.enterprise.dal.syntax import Update, SavepointAction
from twext.enterprise.dal.syntax import Insert
from twext.enterprise.dal.syntax import Select
from twext.enterprise.dal.syntax import Delete
@@ -621,15 +621,27 @@
homeID=self._home._resourceID, resourceID=collectionResourceID
)
elif record.sharetype == 'D':
- # There is no bind entry already so add one.
- yield self._acceptDirectShareQuery.on(
- self._txn, homeID=self._home._resourceID,
- resourceID=collectionResourceID, name=record.localname,
- message=record.summary
- )
+ # There is no bind entry already so add one - but be aware of possible race to create
- shareeCollection = yield self._home.sharedChildWithName(
- record.localname)
+ # Use savepoint so we can do a partial rollback if there is a race condition
+ # where this row has already been inserted
+ savepoint = SavepointAction("addOrUpdateRecord")
+ yield savepoint.acquire(self._txn)
+
+ try:
+ yield self._acceptDirectShareQuery.on(
+ self._txn, homeID=self._home._resourceID,
+ resourceID=collectionResourceID, name=record.localname,
+ message=record.summary
+ )
+ except Exception: # FIXME: Really want to trap the pg.DatabaseError but in a non-DB specific manner
+ yield savepoint.rollback(self._txn)
+
+ # For now we will assume that the insert already done is the winner - so nothing more to do here
+ else:
+ yield savepoint.release(self._txn)
+
+ shareeCollection = yield self._home.sharedChildWithName(record.localname)
yield shareeCollection._initSyncToken()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110311/ee637d27/attachment.html>
More information about the calendarserver-changes
mailing list