[CalendarServer-changes] [9166] CalendarServer/trunk/txdav

source_changes at macosforge.org source_changes at macosforge.org
Fri Apr 20 14:54:48 PDT 2012


Revision: 9166
          http://trac.macosforge.org/projects/calendarserver/changeset/9166
Author:   sagen at apple.com
Date:     2012-04-20 14:54:48 -0700 (Fri, 20 Apr 2012)
Log Message:
-----------
Cache home-child meta data query, and updates postCommit( ) to take an "immediately" keyword arg indicating we want the operation to happen prior to the response being returned to the client.

Modified Paths:
--------------
    CalendarServer/trunk/txdav/base/datastore/file.py
    CalendarServer/trunk/txdav/base/datastore/util.py
    CalendarServer/trunk/txdav/caldav/datastore/sql.py
    CalendarServer/trunk/txdav/common/datastore/sql.py
    CalendarServer/trunk/txdav/idav.py

Modified: CalendarServer/trunk/txdav/base/datastore/file.py
===================================================================
--- CalendarServer/trunk/txdav/base/datastore/file.py	2012-04-20 20:47:07 UTC (rev 9165)
+++ CalendarServer/trunk/txdav/base/datastore/file.py	2012-04-20 21:54:48 UTC (rev 9166)
@@ -187,11 +187,11 @@
                         self.log_error("Cannot undo DataStoreTransaction")
                 raise
 
-        for operation in self._postCommitOperations:
+        for (operation, ignored) in self._postCommitOperations:
             operation()
 
-    def postCommit(self, operation):
-        self._postCommitOperations.append(operation)
+    def postCommit(self, operation, immediately=False):
+        self._postCommitOperations.append((operation, immediately))
 
     def postAbort(self, operation):
         self._postAbortOperations.append(operation)

Modified: CalendarServer/trunk/txdav/base/datastore/util.py
===================================================================
--- CalendarServer/trunk/txdav/base/datastore/util.py	2012-04-20 20:47:07 UTC (rev 9165)
+++ CalendarServer/trunk/txdav/base/datastore/util.py	2012-04-20 21:54:48 UTC (rev 9166)
@@ -59,43 +59,34 @@
         self.cacheExpireSeconds = cacheExpireSeconds
 
     def set(self, key, value):
-        super(QueryCacher, self).set(key, value, expireTime=self.cacheExpireSeconds)
+        return super(QueryCacher, self).set(key, value, expireTime=self.cacheExpireSeconds)
 
-    # Home child objects by name
+    def delete(self, key):
+        return super(QueryCacher, self).delete(key)
 
-    def keyForObjectWithName(self, homeResourceID, name):
-        return "objectWithName:%s:%s" % (homeResourceID, name)
 
-    def getObjectWithName(self, homeResourceID, name):
-        key = self.keyForObjectWithName(homeResourceID, name)
-        return self.get(key)
+    def setAfterCommit(self, transaction, key, value):
+        transaction.postCommit(lambda: self.set(key, value), immediately=True)
 
-    def setObjectWithName(self, transaction, homeResourceID, name, value):
-        key = self.keyForObjectWithName(homeResourceID, name)
-        transaction.postCommit(lambda:self.set(key, value))
+    def invalidateAfterCommit(self, transaction, key):
+        # Invalidate now (so that operations within this transaction see it)
+        # and *also* post-commit (because there could be a scheduled setAfterCommit
+        # for this key)
+        transaction.postCommit(lambda: self.delete(key), immediately=True)
+        return self.delete(key)
 
-    def invalidateObjectWithName(self, transaction, homeResourceID, name):
-        key = self.keyForObjectWithName(homeResourceID, name)
-        # Invalidate immediately and post-commit in case a calendar was created and deleted
-        # within the same transaction
-        self.delete(key)
-        transaction.postCommit(lambda:self.delete(key))
+    # Home child objects by name
 
+    def keyForObjectWithName(self, homeResourceID, name):
+        return "objectWithName:%s:%s" % (homeResourceID, name)
+
     # Home metadata (Created/Modified)
 
     def keyForHomeMetaData(self, homeResourceID):
         return "homeMetaData:%s" % (homeResourceID)
 
-    def getHomeMetaData(self, homeResourceID):
-        key = self.keyForHomeMetaData(homeResourceID)
-        return self.get(key)
+    # HomeChild metadata (Created/Modified (and SUPPORTED_COMPONENTS))
 
-    def setHomeMetaData(self, transaction, homeResourceID, value):
-        key = self.keyForHomeMetaData(homeResourceID)
-        transaction.postCommit(lambda:self.set(key, value))
+    def keyForHomeChildMetaData(self, resourceID):
+        return "homeChildMetaData:%s" % (resourceID)
 
-    def invalidateHomeMetaData(self, transaction, homeResourceID):
-        key = self.keyForHomeMetaData(homeResourceID)
-        # Invalidate immediately and post-commit
-        self.delete(key)
-        transaction.postCommit(lambda:self.delete(key))

Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py	2012-04-20 20:47:07 UTC (rev 9165)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py	2012-04-20 21:54:48 UTC (rev 9166)
@@ -426,13 +426,14 @@
         """
         return self._name == "inbox"
 
+
     @inlineCallbacks
     def setSupportedComponents(self, supported_components):
         """
         Update the database column with the supported components. Technically this should only happen once
         on collection creation, but for migration we may need to change after the fact - hence a separate api.
         """
-        
+
         cal = self._homeChildMetaDataSchema
         yield Update(
             {
@@ -442,6 +443,11 @@
         ).on(self._txn)
         self._supportedComponents = supported_components
 
+        queryCacher = self._txn.store().queryCacher
+        if queryCacher is not None:
+            cacheKey = queryCacher.keyForHomeChildMetaData(self._resourceID)
+            yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+
     def getSupportedComponents(self):
         return self._supportedComponents
 

Modified: CalendarServer/trunk/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql.py	2012-04-20 20:47:07 UTC (rev 9165)
+++ CalendarServer/trunk/txdav/common/datastore/sql.py	2012-04-20 21:54:48 UTC (rev 9166)
@@ -513,11 +513,11 @@
         return self._apnSubscriptionsBySubscriberQuery.on(self, subscriberGUID=guid)
 
 
-    def postCommit(self, operation):
+    def postCommit(self, operation, immediately=False):
         """
         Run things after C{commit}.
         """
-        self._postCommitOperations.append(operation)
+        self._postCommitOperations.append((operation, immediately))
 
 
     def postAbort(self, operation):
@@ -659,10 +659,14 @@
         """
         Commit the transaction and execute any post-commit hooks.
         """
+        @inlineCallbacks
         def postCommit(ignored):
-            for operation in self._postCommitOperations:
-                operation()
-            return ignored
+            for operation, immediately in self._postCommitOperations:
+                if immediately:
+                    yield operation()
+                else:
+                    operation()
+            returnValue(ignored)
 
         if self._stats:
             s = StringIO()
@@ -884,16 +888,24 @@
 
         if result:
             self._resourceID = result[0][0]
+
             queryCacher = self._txn.store().queryCacher
             if queryCacher:
-                data = yield queryCacher.getHomeMetaData(self._resourceID)
-                if data is not None:
-                    self._created, self._modified = data
-                else:
-                    self._created, self._modified = (yield self._metaDataQuery.on(
-                        self._txn, resourceID=self._resourceID))[0]
-                    yield queryCacher.setHomeMetaData(self._txn, self._resourceID,
-                        (self._created, self._modified))
+                # Get cached copy
+                cacheKey = queryCacher.keyForHomeMetaData(self._resourceID)
+                data = yield queryCacher.get(cacheKey)
+            else:
+                data = None
+            if data is None:
+                # Don't have a cached copy
+                data = (yield self._metaDataQuery.on(
+                    self._txn, resourceID=self._resourceID))[0]
+                if queryCacher:
+                    # Cache the data
+                    yield queryCacher.setAfterCommit(self._txn, cacheKey, data)
+
+            self._created, self._modified = data
+
             yield self._loadPropertyStore()
             returnValue(self)
         else:
@@ -1452,7 +1464,8 @@
             self._modified = (yield self._txn.subtransaction(_bumpModified, retries=0, failureOK=True))[0][0]
             queryCacher = self._txn.store().queryCacher
             if queryCacher is not None:
-                yield queryCacher.invalidateHomeMetaData(self._txn, self._resourceID)
+                cacheKey = queryCacher.keyForHomeMetaData(self._resourceID)
+                yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
 
         except AllRetriesFailed:
             log.debug("CommonHome.bumpModified failed")
@@ -2045,9 +2058,12 @@
         # Only caching non-shared objects so that we don't need to invalidate
         # in sql_legacy
         if owned and queryCacher:
-            data = yield queryCacher.getObjectWithName(home._resourceID, name)
+            # Retrieve data from cache
+            cacheKey = queryCacher.keyForObjectWithName(home._resourceID, name)
+            data = yield queryCacher.get(cacheKey)
 
         if data is None:
+            # No cached copy
             if owned:
                 query = cls._resourceIDOwnedByHomeByName
             else:
@@ -2055,11 +2071,12 @@
             data = yield query.on(home._txn,
                                   objectName=name, homeID=home._resourceID)
             if owned and data and queryCacher:
-                queryCacher.setObjectWithName(home._txn, home._resourceID,
-                    name, data)
+                # Cache the result
+                queryCacher.setAfterCommit(home._txn, cacheKey, data)
 
         if not data:
             returnValue(None)
+
         resourceID = data[0][0]
         child = cls(home, name, resourceID, owned)
         yield child.initFromStore()
@@ -2193,9 +2210,22 @@
         resource ID. We read in and cache all the extra metadata from the DB to
         avoid having to do DB queries for those individually later.
         """
-        dataRows = (
-            yield self._metadataByIDQuery.on(self._txn,
-                                          resourceID=self._resourceID))[0]
+        queryCacher = self._txn.store().queryCacher
+        if queryCacher:
+            # Retrieve from cache
+            cacheKey = queryCacher.keyForHomeChildMetaData(self._resourceID)
+            dataRows = yield queryCacher.get(cacheKey)
+        else:
+            dataRows = None
+        if dataRows is None:
+            # No cached copy
+            dataRows = (
+                yield self._metadataByIDQuery.on(self._txn,
+                    resourceID=self._resourceID))[0]
+            if queryCacher:
+                # Cache the results
+                yield queryCacher.setAfterCommit(self._txn, cacheKey, dataRows)
+
         for attr, value in zip(self.metadataAttributes(), dataRows):
             setattr(self, attr, value)
         yield self._loadPropertyStore()
@@ -2256,8 +2286,8 @@
 
         queryCacher = self._home._txn.store().queryCacher
         if queryCacher:
-            queryCacher.invalidateObjectWithName(self._home._txn,
-                self._home._resourceID, oldName)
+            cacheKey = queryCacher.keyForObjectWithName(self._home._resourceID, oldName)
+            yield queryCacher.invalidateAfterCommit(self._home._txn, cacheKey)
 
         yield self._renameQuery.on(self._txn, name=name,
                                    resourceID=self._resourceID,
@@ -2289,8 +2319,8 @@
 
         queryCacher = self._home._txn.store().queryCacher
         if queryCacher:
-            queryCacher.invalidateObjectWithName(self._home._txn,
-                self._home._resourceID, self._name)
+            cacheKey = queryCacher.keyForObjectWithName(self._home._resourceID, self._name)
+            yield queryCacher.invalidateAfterCommit(self._home._txn, cacheKey)
 
         yield self._deletedSyncToken()
         yield self._deleteQuery.on(self._txn, NoSuchHomeChildError,
@@ -2677,6 +2707,7 @@
                       Where=schema.RESOURCE_ID == Parameter("resourceID"),
                       Return=schema.MODIFIED)
 
+
     @inlineCallbacks
     def bumpModified(self):
         """
@@ -2695,6 +2726,11 @@
             
         try:
             self._modified = (yield self._txn.subtransaction(_bumpModified, retries=0, failureOK=True))[0][0]
+
+            queryCacher = self._txn.store().queryCacher
+            if queryCacher is not None:
+                cacheKey = queryCacher.keyForHomeChildMetaData(self._resourceID)
+                yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
         except AllRetriesFailed:
             log.debug("CommonHomeChild.bumpModified failed")
         

Modified: CalendarServer/trunk/txdav/idav.py
===================================================================
--- CalendarServer/trunk/txdav/idav.py	2012-04-20 20:47:07 UTC (rev 9165)
+++ CalendarServer/trunk/txdav/idav.py	2012-04-20 21:54:48 UTC (rev 9166)
@@ -207,7 +207,7 @@
         """
 
 
-    def postCommit(operation):
+    def postCommit(operation, immediately=False):
         """
         Registers an operation to be executed after the transaction is
         committed.
@@ -216,6 +216,8 @@
         in the order which they were registered.
 
         @param operation: a callable.
+        @param immediately: a boolean; True means finish this operation *before* the
+            commit( ) call completes, defaults to False.
         """
 
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120420/bc2f5213/attachment-0001.html>


More information about the calendarserver-changes mailing list