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

source_changes at macosforge.org source_changes at macosforge.org
Mon Oct 27 19:13:04 PDT 2008


Revision: 3242
          http://trac.macosforge.org/projects/calendarserver/changeset/3242
Author:   cdaboo at apple.com
Date:     2008-10-27 19:13:04 -0700 (Mon, 27 Oct 2008)
Log Message:
-----------
Use a global lock to protect access to scheduling object resources to ensure only one
client can cause a set of modifications to all matching components of the organizer and
attendees.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/method/delete.py
    CalendarServer/trunk/twistedcaldav/method/put_common.py
    CalendarServer/trunk/twistedcaldav/test/test_collectioncontents.py

Modified: CalendarServer/trunk/twistedcaldav/method/delete.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/delete.py	2008-10-28 00:53:13 UTC (rev 3241)
+++ CalendarServer/trunk/twistedcaldav/method/delete.py	2008-10-28 02:13:04 UTC (rev 3242)
@@ -23,7 +23,9 @@
 from twisted.internet.defer import inlineCallbacks, returnValue
 from twisted.web2 import responsecode
 from twisted.web2.dav.util import parentForURL
+from twisted.web2.http import HTTPError, StatusResponse
 
+from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
 from twistedcaldav.resource import isCalendarCollectionResource
 from twistedcaldav.scheduling.implicit import ImplicitScheduler
 
@@ -43,31 +45,49 @@
     calendar = None
     is_calendar_collection = False
     is_calendar_resource = False
+    _lock = None
     if self.exists():
         if isCalendarCollectionResource(parent):
             is_calendar_resource = True
             calendar = self.iCalendar()
+            _lock = MemcacheLock("ImplicitUIDLock", calendar.resourceUID(), timeout=60.0)
+            
         elif isCalendarCollectionResource(self):
             is_calendar_collection = True
 
-    response = (yield super(CalDAVFile, self).http_DELETE(request))
+    try:
+        if _lock:
+            yield _lock.acquire()
 
-    if response == responsecode.NO_CONTENT:
-        if is_calendar_resource:
+        response = (yield super(CalDAVFile, self).http_DELETE(request))
+    
+        if response == responsecode.NO_CONTENT:
+            if is_calendar_resource:
+    
+                index = parent.index()
+                index.deleteResource(self.fp.basename())
+    
+                # Change CTag on the parent calendar collection
+                yield parent.updateCTag()
+    
+                # Do scheduling
+                scheduler = ImplicitScheduler()
+                yield scheduler.doImplicitScheduling(request, self, calendar, True)
+     
+            elif is_calendar_collection:
+                
+                # Do some clean up
+                yield self.deletedCalendar(request)
+                
+        if _lock:
+            yield _lock.release()
 
-            index = parent.index()
-            index.deleteResource(self.fp.basename())
+    except MemcacheLockTimeoutError:
+        raise HTTPError(StatusResponse(responsecode.CONFLICT, "Resource: %s currently in use on the server." % (self.uri,)))
 
-            # Change CTag on the parent calendar collection
-            yield parent.updateCTag()
+    except Exception, e:
+        if _lock:
+            yield _lock.clean()
+        raise e
 
-            # Do scheduling
-            scheduler = ImplicitScheduler()
-            yield scheduler.doImplicitScheduling(request, self, calendar, True)
- 
-        elif is_calendar_collection:
-            
-            # Do some clean up
-            yield self.deletedCalendar(request)
-
     returnValue(response)

Modified: CalendarServer/trunk/twistedcaldav/method/put_common.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/put_common.py	2008-10-28 00:53:13 UTC (rev 3241)
+++ CalendarServer/trunk/twistedcaldav/method/put_common.py	2008-10-28 02:13:04 UTC (rev 3242)
@@ -20,6 +20,7 @@
 
 __all__ = ["StoreCalendarObjectResource"]
 
+import os
 import types
 
 from twisted.internet import reactor
@@ -56,6 +57,7 @@
 from twistedcaldav.index import ReservationError
 from twistedcaldav.instance import TooManyInstancesError
 from twistedcaldav.log import Logger
+from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
 from twistedcaldav.scheduling.implicit import ImplicitScheduler
 
 log = Logger()
@@ -141,7 +143,11 @@
 
     class UIDReservation(object):
         
-        def __init__(self, index, uid, uri):
+        def __init__(self, index, uid, uri, internal_request):
+            if internal_request:
+                self._lock = None
+            else:
+                self._lock = MemcacheLock("ImplicitUIDLock", uid, timeout=60.0)
             self.reserved = False
             self.index = index
             self.uid = uid
@@ -150,6 +156,13 @@
         @inlineCallbacks
         def reserve(self):
             
+            # Implicit lock
+            if self._lock:
+                try:
+                    yield self._lock.acquire()
+                except MemcacheLockTimeoutError:
+                    raise HTTPError(StatusResponse(responsecode.CONFLICT, "Resource: %s currently in use on the server." % (self.uri,)))
+
             # Lets use a deferred for this and loop a few times if we cannot reserve so that we give
             # time to whoever has the reservation to finish and release it.
             failure_count = 0
@@ -169,13 +182,17 @@
                 yield pause
             
             if self.uri and not self.reserved:
-                raise HTTPError(StatusResponse(responsecode.CONFLICT, "Resource: %s currently in use." % (self.uri,)))
+                if self._lock:
+                    yield self._lock.release()
+                raise HTTPError(StatusResponse(responsecode.CONFLICT, "Resource: %s currently in use in calendar." % (self.uri,)))
         
         @inlineCallbacks
         def unreserve(self):
             if self.reserved:
                 yield self.index.unreserveUID(self.uid)
                 self.reserved = False
+            if self._lock:
+                yield self._lock.clean()
 
     def __init__(
         self,
@@ -682,7 +699,7 @@
             if self.destinationcal:    
                 # Reserve UID
                 self.destination_index = self.destinationparent.index()
-                reservation = StoreCalendarObjectResource.UIDReservation(self.destination_index, self.uid, self.destination_uri)
+                reservation = StoreCalendarObjectResource.UIDReservation(self.destination_index, self.uid, self.destination_uri, self.internal_request or self.isiTIP)
                 yield reservation.reserve()
             
                 # UID conflict check - note we do this after reserving the UID to avoid a race condition where two requests

Modified: CalendarServer/trunk/twistedcaldav/test/test_collectioncontents.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_collectioncontents.py	2008-10-28 00:53:13 UTC (rev 3241)
+++ CalendarServer/trunk/twistedcaldav/test/test_collectioncontents.py	2008-10-28 02:13:04 UTC (rev 3242)
@@ -13,6 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
+from twistedcaldav.memcachelock import MemcacheLock
+from twistedcaldav.memcacher import Memcacher
 
 import os
 
@@ -32,6 +34,19 @@
     """
     data_dir = os.path.join(os.path.dirname(__file__), "data")
 
+    def setUp(self):
+        def _getFakeMemcacheProtocol(self):
+            
+            result = super(MemcacheLock, self)._getMemcacheProtocol()
+            if isinstance(result, Memcacher.nullCacher):
+                result = self._memcacheProtocol = Memcacher.memoryCacher()
+            
+            return result
+        
+        MemcacheLock._getMemcacheProtocol = _getFakeMemcacheProtocol
+
+        super(CollectionContents, self).setUp()
+
     def test_collection_in_calendar(self):
         """
         Make (regular) collection in calendar
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20081027/a31c2193/attachment-0001.html>


More information about the calendarserver-changes mailing list