[CalendarServer-changes] [11021] CalendarServer/trunk/twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Tue Apr 9 18:50:17 PDT 2013


Revision: 11021
          http://trac.calendarserver.org//changeset/11021
Author:   cdaboo at apple.com
Date:     2013-04-09 18:50:16 -0700 (Tue, 09 Apr 2013)
Log Message:
-----------
Make sure that sync-token in PROPFIND Depth:1 on home changes for sharer and sharee when event changes in shared calendar.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/cache.py
    CalendarServer/trunk/twistedcaldav/method/propfind.py
    CalendarServer/trunk/twistedcaldav/storebridge.py

Modified: CalendarServer/trunk/twistedcaldav/cache.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/cache.py	2013-04-10 01:42:06 UTC (rev 11020)
+++ CalendarServer/trunk/twistedcaldav/cache.py	2013-04-10 01:50:16 UTC (rev 11021)
@@ -20,7 +20,7 @@
 
 from zope.interface import implements
 
-from twisted.internet.defer import succeed, maybeDeferred, inlineCallbacks,\
+from twisted.internet.defer import succeed, maybeDeferred, inlineCallbacks, \
     returnValue
 from twext.web2.dav.util import allDataFromStream
 from twext.web2.http import Response
@@ -50,15 +50,15 @@
   - directoryToken - a hash of that principal's directory record
   - uriToken - a token for the request uri
   - childTokens - tokens for any child resources the request uri depends on (for depth:1)
-  
+
   The current principalToken, uriToken and childTokens values are themselves stored in the cache using the key prefix 'cacheToken:'.
 When the 'changeCache' api is called the cached value for the matching token is updated.
-  
+
 (4) When a request is being checked in the cache, the response cache entry key is first computed and any value extracted. The
 tokens in the value are then checked against the current set of tokens in the cache. If there is any mismatch between tokens, the
 cache entry is considered invalid and the cached response is not returned. If everything matches up, the cached response is returned
 to the caller and ultimately sent directly back to the client.
- 
+
 (5) Because of shared calendars/address books that can affect the calendar/address book homes of several different users at once, we
 need to keep track of the separate childTokens for each child resource. The tokens for shared resources are keyed of the sharer's uri,
 so sharee's homes use that token. That way a single token for all shared instances is used and changed just once.
@@ -72,18 +72,22 @@
     def __init__(self, *args, **kwargs):
         pass
 
+
     def changed(self):
         return succeed(None)
 
 
+
 class DisabledCache(object):
     def getResponseForRequest(self, request):
         return succeed(None)
 
+
     def cacheResponseForRequest(self, request, response):
         return succeed(response)
 
 
+
 class URINotFoundException(Exception):
     def __init__(self, uri):
         self.uri = uri
@@ -95,6 +99,7 @@
             self.uri)
 
 
+
 class MemcacheChangeNotifier(LoggingMixIn, CachePoolUserMixIn):
 
     def __init__(self, resource, cachePool=None, cacheHandle="Default"):
@@ -102,22 +107,31 @@
         self._cachePool = cachePool
         self._cachePoolHandle = cacheHandle
 
+
     def _newCacheToken(self):
         return str(uuid.uuid4())
 
+
     def changed(self):
         """
         Change the cache token for a resource
 
         return: A L{Deferred} that fires when the token has been changed.
         """
-        url = self._resource.url()
 
+        # For shared resources we use the owner URL as the cache key
+        if hasattr(self._resource, "owner_url"):
+            url = self._resource.owner_url()
+        else:
+            url = self._resource.url()
+
         self.log_debug("Changing Cache Token for %r" % (url,))
         return self.getCachePool().set(
             'cacheToken:%s' % (url,),
-            self._newCacheToken(), expireTime=config.ResponseCacheTimeout*60)
-            
+            self._newCacheToken(), expireTime=config.ResponseCacheTimeout * 60)
+
+
+
 class BaseResponseCache(LoggingMixIn):
     """
     A base class which provides some common operations
@@ -149,10 +163,10 @@
     def _canonicalizeURIForRequest(self, uri, request):
         """
         Always use canonicalized forms of the URIs for caching (i.e. __uids__ paths).
-        
-        Do this without calling locateResource which may cause a query on the store. 
+
+        Do this without calling locateResource which may cause a query on the store.
         """
-        
+
         uribits = uri.split("/")
         if len(uribits) > 1 and uribits[1] in ("principals", "calendars", "addressbooks"):
             if uribits[2] == "__uids__":
@@ -166,8 +180,7 @@
                     uribits[2] = "__uids__"
                     uribits[3] = record.uid
                     return succeed("/".join(uribits))
-                
-            
+
         # Fall back to the locateResource approach
         try:
             return request.locateResource(uri).addCallback(
@@ -190,6 +203,7 @@
 
         return d
 
+
     @inlineCallbacks
     def _requestKey(self, request):
         """
@@ -201,7 +215,7 @@
             # Give it back to the request so it can be read again
             request.stream = MemoryStream(requestBody)
             request.stream.doStartReading = None
-            
+
             # Normalize the property order by doing a "dumb" sort on lines
             requestLines = requestBody.splitlines()
             requestLines.sort()
@@ -222,6 +236,7 @@
         return d1
 
 
+
 class MemcacheResponseCache(BaseResponseCache, CachePoolUserMixIn):
     def __init__(self, docroot, cachePool=None):
         self._docroot = docroot
@@ -238,6 +253,7 @@
         else:
             return self.getCachePool().get('cacheToken:%s' % (uri,))
 
+
     @inlineCallbacks
     def _tokenForRecord(self, uri, request):
         """
@@ -247,19 +263,21 @@
         record = (yield self._getRecordForURI(uri, request))
         returnValue(record.cacheToken())
 
+
     @inlineCallbacks
     def _tokensForChildren(self, rURI, request):
         """
         Create a dict of child resource tokens for any "recorded" during this request in the childCacheURIs attribute.
         """
-        
+
         if hasattr(request, "childCacheURIs"):
             tokens = dict([(uri, (yield self._tokenForURI(uri)),) for uri in request.childCacheURIs])
             returnValue(tokens)
         else:
             returnValue({})
-    
-    @inlineCallbacks 
+
+
+    @inlineCallbacks
     def _getTokens(self, request):
         """
         Tokens are a principal token, directory record token, resource token and list
@@ -296,19 +314,19 @@
         """
         try:
             key = (yield self._hashedRequestKey(request))
-    
+
             self.log_debug("Checking cache for: %r" % (key,))
             _ignore_flags, value = (yield self.getCachePool().get(key))
-    
+
             if value is None:
                 self.log_debug("Not in cache: %r" % (key,))
                 returnValue(None)
-    
+
             self.log_debug("Found in cache: %r = %r" % (key, value))
-    
+
             (principalToken, directoryToken, uriToken, childTokens, (code, headers, body)) = cPickle.loads(value)
             currentTokens = (yield self._getTokens(request))
-    
+
             if currentTokens[0] != principalToken:
                 self.log_debug(
                     "Principal token doesn't match for %r: %r != %r" % (
@@ -316,7 +334,7 @@
                         currentTokens[0],
                         principalToken))
                 returnValue(None)
-    
+
             if currentTokens[1] != directoryToken:
                 self.log_debug(
                     "Directory Record Token doesn't match for %r: %r != %r" % (
@@ -324,7 +342,7 @@
                         currentTokens[1],
                         directoryToken))
                 returnValue(None)
-    
+
             if currentTokens[2] != uriToken:
                 self.log_debug(
                     "URI token doesn't match for %r: %r != %r" % (
@@ -332,7 +350,7 @@
                         currentTokens[2],
                         uriToken))
                 returnValue(None)
-    
+
             for childuri, token in childTokens.items():
                 currentToken = (yield self._tokenForURI(childuri))
                 if currentToken != token:
@@ -343,19 +361,20 @@
                             currentToken,
                             token))
                     returnValue(None)
-                     
+
             r = Response(code,
                          stream=MemoryStream(body))
-    
+
             for key, value in headers.iteritems():
                 r.headers.setRawHeaders(key, value)
-    
+
             returnValue(r)
 
         except URINotFoundException, e:
             self.log_debug("Could not locate URI: %r" % (e,))
             returnValue(None)
 
+
     @inlineCallbacks
     def cacheResponseForRequest(self, request, response):
         """
@@ -368,9 +387,9 @@
                 key = request.cacheKey
             else:
                 key = (yield self._hashedRequestKey(request))
-    
+
             key, responseBody = (yield self._getResponseBody(key, response))
-    
+
             response.headers.removeHeader('date')
             response.stream = MemoryStream(responseBody)
             pToken, dToken, uToken, cTokens = (yield self._getTokens(request))
@@ -388,30 +407,34 @@
             ))
             self.log_debug("Adding to cache: %r = %r" % (key, cacheEntry))
             yield self.getCachePool().set(key, cacheEntry,
-                expireTime=config.ResponseCacheTimeout*60)
+                expireTime=config.ResponseCacheTimeout * 60)
 
         except URINotFoundException, e:
             self.log_debug("Could not locate URI: %r" % (e,))
 
-        returnValue(response)            
+        returnValue(response)
 
 
+
 class _CachedResponseResource(object):
     implements(IResource)
 
     def __init__(self, response):
         self._response = response
 
+
     def renderHTTP(self, request):
         if not hasattr(request, "extendedLogItems"):
             request.extendedLogItems = {}
         request.extendedLogItems["cached"] = "1"
         return self._response
 
+
     def locateChild(self, request, segments):
         return self, []
 
 
+
 class PropfindCacheMixin(object):
     """
     A mixin that causes a resource's PROPFIND response to be cached. It also adds an api to change the
@@ -433,12 +456,15 @@
             d.addCallback(_getResponseCache)
         return d
 
+
     def changeCache(self):
         if hasattr(self, 'cacheNotifier'):
             return self.cacheNotifier.changed()
         else:
             self.log_debug("%r does not have a cacheNotifier but was changed" % (self,))
 
+
+
 class ResponseCacheMixin(object):
     """
     This is a mixin for a child resource that does not itself cache PROPFINDs, but needs to invalidate a parent
@@ -451,19 +477,25 @@
         else:
             self.log_debug("%r does not have a cacheNotifier but was changed" % (self,))
 
+
+
 class CacheStoreNotifier(object):
-    
+
     def __init__(self, resource):
         self.resource = resource
-    
+
+
     def notify(self, op="update"):
         self.resource.changeCache()
 
+
     def clone(self, label="default", id=None):
         return self
 
+
     def getID(self, label="default"):
         return None
 
+
     def nodeName(self, label="default"):
         return succeed(None)

Modified: CalendarServer/trunk/twistedcaldav/method/propfind.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/propfind.py	2013-04-10 01:42:06 UTC (rev 11020)
+++ CalendarServer/trunk/twistedcaldav/method/propfind.py	2013-04-10 01:50:16 UTC (rev 11021)
@@ -219,8 +219,11 @@
 
             # This needed for propfind cache tracking of children changes
             if depth == "1":
-                if resource != self and hasattr(resource, "url"):
-                    request.childCacheURIs.append(resource.url())
+                if resource != self:
+                    if hasattr(resource, "owner_url"):
+                        request.childCacheURIs.append(resource.owner_url())
+                    elif hasattr(resource, "url"):
+                        request.childCacheURIs.append(resource.url())
         else:
             xml_response = davxml.StatusResponse(davxml.HRef(uri), davxml.Status.fromResponseCode(responsecode.FORBIDDEN))
 

Modified: CalendarServer/trunk/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/storebridge.py	2013-04-10 01:42:06 UTC (rev 11020)
+++ CalendarServer/trunk/twistedcaldav/storebridge.py	2013-04-10 01:50:16 UTC (rev 11021)
@@ -265,6 +265,13 @@
         return joinURL(self._parentResource.url(), self._name, "/")
 
 
+    def owner_url(self):
+        if self.isShareeCollection():
+            return joinURL(self._share.url(), "/")
+        else:
+            return self.url()
+
+
     def parentResource(self):
         return self._parentResource
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130409/3e47f08e/attachment-0001.html>


More information about the calendarserver-changes mailing list