[CalendarServer-changes] [5742] CalendarServer/branches/new-store
source_changes at macosforge.org
source_changes at macosforge.org
Tue Jun 15 14:03:31 PDT 2010
Revision: 5742
http://trac.macosforge.org/projects/calendarserver/changeset/5742
Author: glyph at apple.com
Date: 2010-06-15 14:03:29 -0700 (Tue, 15 Jun 2010)
Log Message:
-----------
Guard write operations against use outside transactions, and provide a back-door hook for scheduling processing to re-initialize a resource for deferred processing.
Modified Paths:
--------------
CalendarServer/branches/new-store/twistedcaldav/scheduling/processing.py
CalendarServer/branches/new-store/twistedcaldav/storebridge.py
CalendarServer/branches/new-store/txcaldav/calendarstore/file.py
Modified: CalendarServer/branches/new-store/twistedcaldav/scheduling/processing.py
===================================================================
--- CalendarServer/branches/new-store/twistedcaldav/scheduling/processing.py 2010-06-15 18:54:24 UTC (rev 5741)
+++ CalendarServer/branches/new-store/twistedcaldav/scheduling/processing.py 2010-06-15 21:03:29 UTC (rev 5742)
@@ -431,20 +431,27 @@
# refresh them. To prevent a race we need a lock.
lock = MemcacheLock("ImplicitUIDLock", calendar.resourceUID(), timeout=60.0)
+ # Note that this lock also protects the request, as this request is
+ # being re-used by potentially multiple transactions and should not be
+ # used concurrency (the locateResource cache needs to be cleared each
+ # time, by inNewTransaction). -glyph
try:
yield lock.acquire()
-
- # Send out a reply
- log.debug("ImplicitProcessing - recipient '%s' processing UID: '%s' - auto-reply: %s" % (self.recipient.cuaddr, self.uid, partstat))
- from twistedcaldav.scheduling.implicit import ImplicitScheduler
- scheduler = ImplicitScheduler()
- yield scheduler.sendAttendeeReply(self.request, resource, calendar, self.recipient)
-
except MemcacheLockTimeoutError:
-
# Just try again to get the lock
reactor.callLater(2.0, self.sendAttendeeAutoReply, *(calendar, resource, partstat))
-
+ else:
+ txn = resource.inNewTransaction(self.request)
+ try:
+ # Send out a reply
+ log.debug("ImplicitProcessing - recipient '%s' processing UID: '%s' - auto-reply: %s" % (self.recipient.cuaddr, self.uid, partstat))
+ from twistedcaldav.scheduling.implicit import ImplicitScheduler
+ scheduler = ImplicitScheduler()
+ yield scheduler.sendAttendeeReply(self.request, resource, calendar, self.recipient)
+ except:
+ txn.abort()
+ else:
+ txn.commit()
finally:
yield lock.clean()
Modified: CalendarServer/branches/new-store/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/new-store/twistedcaldav/storebridge.py 2010-06-15 18:54:24 UTC (rev 5741)
+++ CalendarServer/branches/new-store/twistedcaldav/storebridge.py 2010-06-15 21:03:29 UTC (rev 5742)
@@ -350,6 +350,31 @@
self._initializeWithObject(calendarObject)
+ def inNewTransaction(self, request):
+ """
+ Implicit auto-replies need to span multiple transactions. Clean out the
+ given request's resource-lookup mapping, transaction, and re-look-up my
+ calendar object in a new transaction.
+
+ Return the new transaction so it can be committed.
+ """
+ # FIXME: private names from 'file' implementation; maybe there should be
+ # a public way to do this? or maybe we should just have a real queue.
+ objectName = self._newStoreObject.name()
+ calendarName = self._newStoreObject._calendar.name()
+ homeUID = self._newStoreObject._calendar._calendarHome.uid()
+ store = self._newStoreObject._transaction._calendarStore
+ txn = store.newTransaction()
+ newObject = (txn.calendarHomeWithUID(homeUID)
+ .calendarWithName(calendarName)
+ .calendarObjectWithName(objectName))
+ request._newStoreTransaction = txn
+ request._resourcesByURL.clear()
+ request._urlsByResource.clear()
+ self._initializeWithObject(newObject)
+ return txn
+
+
def exists(self):
# FIXME: Tests
return True
Modified: CalendarServer/branches/new-store/txcaldav/calendarstore/file.py
===================================================================
--- CalendarServer/branches/new-store/txcaldav/calendarstore/file.py 2010-06-15 18:54:24 UTC (rev 5741)
+++ CalendarServer/branches/new-store/txcaldav/calendarstore/file.py 2010-06-15 21:03:29 UTC (rev 5742)
@@ -100,6 +100,17 @@
+def _writeOperation(thunk):
+ # FIXME: tests
+ def inner(self, *a, **kw):
+ if self._transaction._termination is not None:
+ raise RuntimeError(
+ "%s.%s is a write operation, but transaction already %s"
+ % (self, thunk.__name__, self._transaction._termination))
+ return thunk(self, *a, **kw)
+ return inner
+
+
class CalendarStore(LoggingMixIn):
"""
An implementation of L{ICalendarObject} backed by a
@@ -312,6 +323,7 @@
return None
+ @_writeOperation
def createCalendarWithName(self, name):
if name.startswith("."):
raise CalendarNameNotAllowedError(name)
@@ -362,7 +374,7 @@
# c.properties().participateInTxn(txn)
# FIXME: return c # maybe ?
-
+ @_writeOperation
def removeCalendarWithName(self, name):
if name.startswith(".") or name in self._removedCalendars:
raise NoSuchCalendarError(name)
@@ -469,6 +481,7 @@
_renamedName = None
+ @_writeOperation
def rename(self, name):
oldName = self.name()
self._renamedName = name
@@ -527,6 +540,7 @@
return obj
+ @_writeOperation
def createCalendarObjectWithName(self, name, component):
if name.startswith("."):
raise CalendarObjectNameNotAllowedError(name)
@@ -540,6 +554,7 @@
self._cachedCalendarObjects[name] = calendarObject
+ @_writeOperation
def removeCalendarObjectWithName(self, name):
if name.startswith("."):
raise NoSuchCalendarObjectError(name)
@@ -556,13 +571,16 @@
raise NoSuchCalendarObjectError(name)
+ @_writeOperation
def removeCalendarObjectWithUID(self, uid):
- self.removeCalendarObjectWithName(self.calendarObjectWithUID(uid)._path.basename())
+ self.removeCalendarObjectWithName(
+ self.calendarObjectWithUID(uid)._path.basename())
def syncToken(self):
raise NotImplementedError()
+
def _updateSyncToken(self, reset=False):
# FIXME: add locking a-la CalDAVFile.bumpSyncToken
# FIXME: tests for desired concurrency properties
@@ -588,6 +606,7 @@
raise NotImplementedError()
+ # FIXME: property writes should be a write operation
@_cached
def properties(self):
# FIXME: needs direct tests - only covered by calendar store tests
@@ -617,6 +636,7 @@
def __init__(self, name, calendar):
self._name = name
self._calendar = calendar
+ self._transaction = calendar._transaction
self._component = None
@@ -633,6 +653,7 @@
return self._path.basename()
+ @_writeOperation
def setComponent(self, component):
if not isinstance(component, VComponent):
raise TypeError(type(component))
@@ -673,7 +694,7 @@
else:
self._path.remove()
return undo
- self._calendar._transaction.addOperation(do)
+ self._transaction.addOperation(do)
# Mark all properties as dirty, so they will be re-added to the
# temporary file when the main file is deleted. NOTE: if there were a
# temporary file and a rename() as there should be, this should really
@@ -684,7 +705,7 @@
# happens _after_ the new file has been written. we may end up doing
# the work multiple times, and external callers to property-
# manipulation methods won't work.
- self._calendar._transaction.addOperation(self.properties().flush)
+ self._transaction.addOperation(self.properties().flush)
def component(self):
@@ -745,7 +766,7 @@
@_cached
def properties(self):
props = PropertyStore(self._path)
- self._calendar._transaction.addOperation(props.flush)
+ self._transaction.addOperation(props.flush)
return props
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100615/c37a01fe/attachment-0001.html>
More information about the calendarserver-changes
mailing list