[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