[CalendarServer-changes] [8972] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Tue Apr 3 14:07:40 PDT 2012


Revision: 8972
          http://trac.macosforge.org/projects/calendarserver/changeset/8972
Author:   cdaboo at apple.com
Date:     2012-04-03 14:07:40 -0700 (Tue, 03 Apr 2012)
Log Message:
-----------
Do on-demand time range expansion in a separate transaction if possible.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/dateops.py
    CalendarServer/trunk/txdav/caldav/datastore/sql.py
    CalendarServer/trunk/txdav/common/datastore/sql.py
    CalendarServer/trunk/txdav/common/datastore/sql_legacy.py

Modified: CalendarServer/trunk/twistedcaldav/dateops.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/dateops.py	2012-04-03 18:15:08 UTC (rev 8971)
+++ CalendarServer/trunk/twistedcaldav/dateops.py	2012-04-03 21:07:40 UTC (rev 8972)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2006-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2006-2012 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.
@@ -262,6 +262,18 @@
     dt = datetime.datetime.strptime(ts[:19], "%Y-%m-%d %H:%M:%S")
     return PyCalendarDateTime(year=dt.year, month=dt.month, day=dt.day, hours=dt.hour, minutes=dt.minute, seconds=dt.second)
 
+def parseSQLDateToPyCalendar(ts):
+    """
+    Parse an SQL formated date into a PyCalendarDateTime
+    @param ts: the SQL date
+    @type ts: C{str}
+    
+    @return: L{PyCalendarDateTime} result
+    """
+    
+    dt = datetime.datetime.strptime(ts[:10], "%Y-%m-%d")
+    return PyCalendarDateTime(year=dt.year, month=dt.month, day=dt.day)
+
 def datetimeMktime(dt):
 
     assert isinstance(dt, datetime.date)

Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py	2012-04-03 18:15:08 UTC (rev 8971)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py	2012-04-03 21:07:40 UTC (rev 8972)
@@ -39,7 +39,7 @@
 from twistedcaldav.caldavxml import ScheduleCalendarTransp, Opaque
 from twistedcaldav.config import config
 from twistedcaldav.dateops import normalizeForIndex, datetimeMktime,\
-    parseSQLTimestamp, pyCalendarTodatetime
+    parseSQLTimestamp, pyCalendarTodatetime, parseSQLDateToPyCalendar
 from twistedcaldav.ical import Component, InvalidICalendarDataError
 from twistedcaldav.instance import InvalidOverriddenInstanceError
 from twistedcaldav.memcacher import Memcacher
@@ -1007,7 +1007,31 @@
         returnValue(component)
 
 
+    @classproperty
+    def _recurrenceMaxByIDQuery(cls): #@NoSelf
+        """
+        DAL query to load RECURRANCE_MAX via an object's resource ID.
+        """
+        co = schema.CALENDAR_OBJECT
+        return Select([co.RECURRANCE_MAX], From=co,
+                      Where=co.RESOURCE_ID == Parameter("resourceID"))
+
+
     @inlineCallbacks
+    def recurrenceMax(self):
+        """
+        Get the RECURRANCE_MAX value.
+    
+        @return: L{PyCalendarDateTime} result
+        """
+        rMax = (
+            yield self._recurrenceMaxByIDQuery.on(self._txn,
+                                         resourceID=self._resourceID)
+        )[0][0]
+        returnValue(parseSQLDateToPyCalendar(rMax))
+
+
+    @inlineCallbacks
     def organizer(self):
         returnValue((yield self.component()).getOrganizer())
 

Modified: CalendarServer/trunk/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql.py	2012-04-03 18:15:08 UTC (rev 8971)
+++ CalendarServer/trunk/txdav/common/datastore/sql.py	2012-04-03 21:07:40 UTC (rev 8972)
@@ -2694,9 +2694,10 @@
         self._created = None
         self._modified = None
         self._objectText = None
+        
+        self._overrideTxn = None
 
 
-
     @classproperty
     def _allColumnsWithParent(cls): #@NoSelf
         obj = cls._objectSchema
@@ -2902,11 +2903,25 @@
 
     @property
     def _txn(self):
-        return self._parentCollection._txn
+        return self._overrideTxn if self._overrideTxn else self._parentCollection._txn
 
     def transaction(self):
-        return self._parentCollection._txn
+        return self._overrideTxn if self._overrideTxn else self._parentCollection._txn
 
+    def useTxn(self, newTxn):
+        self._overrideTxn = newTxn
+
+    @classmethod
+    def _selectForUpdateQuery(cls, nowait): #@NoSelf
+        """
+        DAL statement to lock a L{CommonObjectResource} by its resource ID.
+        """
+        return Select(From=cls._objectSchema, ForUpdate=True, NoWait=nowait, Where=cls._objectSchema.RESOURCE_ID == Parameter("resourceID"))
+
+    @inlineCallbacks
+    def lock(self, nowait=False):
+        yield self._selectForUpdateQuery(nowait).on(self._txn, NoSuchObjectResourceError, resourceID=self._resourceID)
+
     def setComponent(self, component, inserting=False):
         raise NotImplementedError
 

Modified: CalendarServer/trunk/txdav/common/datastore/sql_legacy.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_legacy.py	2012-04-03 18:15:08 UTC (rev 8971)
+++ CalendarServer/trunk/txdav/common/datastore/sql_legacy.py	2012-04-03 21:07:40 UTC (rev 8972)
@@ -41,7 +41,7 @@
 from twistedcaldav.sharing import Invite
 
 from txdav.common.icommondatastore import (
-    IndexedSearchException, ReservationError)
+    IndexedSearchException, ReservationError, NoSuchObjectResourceError)
 
 from twext.enterprise.dal.syntax import Update, SavepointAction
 from twext.enterprise.dal.syntax import Insert
@@ -1156,11 +1156,40 @@
         with a longer expansion.
         """
         obj = yield self.calendar.calendarObjectWithName(name)
-        yield obj.updateDatabase(
-            (yield obj.component()), expand_until=expand_until, reCreate=True
-        )
+        
+        # Use a new transaction to do this update quickly without locking the row for too long. However, the original
+        # transaction may have the row locked, so use NOWAIT and if that fails, fakll back to using the original txn. 
+        
+        newTxn = obj.transaction().store().newTransaction()
+        obj.useTxn(newTxn)
+        try:
+            yield obj.lock(nowait=True)
+        except NoSuchObjectResourceError:
+            yield newTxn.commit()
+            obj.useTxn(None)
+            returnValue(None)
+        except:
+            yield newTxn.abort()
+            obj.useTxn(None)
+            newTxn = None
 
+        # Now do the re-expand using the appropriate transaction
+        try:
+            if newTxn is None:
+                rmax = None
+            else:
+                rmax = (yield obj.recurrenceMax())
 
+            if rmax is None or rmax < expand_until:
+                yield obj.updateDatabase(
+                    (yield obj.component()), expand_until=expand_until, reCreate=True
+                )
+        finally:
+            if newTxn is not None:
+                yield newTxn.commit()
+                obj.useTxn(None)
+
+
     @inlineCallbacks
     def testAndUpdateIndex(self, minDate):
         # Find out if the index is expanded far enough
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120403/8a85c936/attachment.html>


More information about the calendarserver-changes mailing list