[CalendarServer-changes] [12178] CalendarServer/branches/users/cdaboo/cross-pod-sharing
source_changes at macosforge.org
source_changes at macosforge.org
Wed Mar 12 11:18:52 PDT 2014
Revision: 12178
http://trac.calendarserver.org//changeset/12178
Author: cdaboo at apple.com
Date: 2013-12-20 12:39:22 -0800 (Fri, 20 Dec 2013)
Log Message:
-----------
Checkpoint: cross-pod resource moves.
Modified Paths:
--------------
CalendarServer/branches/users/cdaboo/cross-pod-sharing/twistedcaldav/storebridge.py
CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/datastore/sql.py
CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/datastore/sql_external.py
CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/icalendarstore.py
CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/podding/conduit.py
CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/sql.py
CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/sql_external.py
Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/users/cdaboo/cross-pod-sharing/twistedcaldav/storebridge.py 2013-12-20 20:36:58 UTC (rev 12177)
+++ CalendarServer/branches/users/cdaboo/cross-pod-sharing/twistedcaldav/storebridge.py 2013-12-20 20:39:22 UTC (rev 12178)
@@ -2432,6 +2432,7 @@
try:
response = (yield self.storeMove(request, destinationparent, destination.name()))
+ self._newStoreObject = None
returnValue(response)
# Handle the various store errors
Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/datastore/sql.py 2013-12-20 20:36:58 UTC (rev 12177)
+++ CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/datastore/sql.py 2013-12-20 20:39:22 UTC (rev 12178)
@@ -1082,6 +1082,45 @@
self.viewerHome().removedCalendarResource(child.uid())
+ @inlineCallbacks
+ def moveObjectResourceHere(self, name, component):
+ """
+ Create a new child in this collection as part of a move operation. This needs to be split out because
+ behavior differs for sub-classes and cross-pod operations.
+
+ @param name: new name to use in new parent
+ @type name: C{str} or C{None} for existing name
+ @param component: data for new resource
+ @type component: L{Component}
+ """
+
+ # Cross-pod calls come in with component as str or unicode
+ if isinstance(component, str) or isinstance(component, unicode):
+ try:
+ component = self._objectResourceClass._componentClass.fromString(component)
+ except InvalidICalendarDataError as e:
+ raise InvalidComponentForStoreError(str(e))
+
+ yield self._createCalendarObjectWithNameInternal(name, component, internal_state=ComponentUpdateState.RAW)
+
+
+ @inlineCallbacks
+ def moveObjectResourceAway(self, rid, child=None):
+ """
+ Remove the child as the result of a move operation. This needs to be split out because
+ behavior differs for sub-classes and cross-pod operations.
+
+ @param rid: the child resource-id to move
+ @type rid: C{int}
+ @param child: the child resource to move - might be C{None} for cross-pod
+ @type child: L{CommonObjectResource}
+ """
+
+ if child is None:
+ child = yield self.objectResourceWithID(rid)
+ yield child._removeInternal(internal_state=ComponentRemoveState.INTERNAL)
+
+
def calendarObjectsInTimeRange(self, start, end, timeZone):
raise NotImplementedError()
@@ -2373,6 +2412,7 @@
Scheduling will be done automatically.
"""
+ # Cross-pod calls come in with component as str or unicode
if isinstance(component, str) or isinstance(component, unicode):
try:
component = self._componentClass.fromString(component)
@@ -2926,9 +2966,10 @@
yield NamedLock.acquire(self._txn, "ImplicitUIDLock:%s" % (hashlib.md5(calendar.resourceUID()).hexdigest(),))
# Need to also remove attachments
- if self._dropboxID:
- yield DropBoxAttachment.resourceRemoved(self._txn, self._resourceID, self._dropboxID)
- yield ManagedAttachment.resourceRemoved(self._txn, self._resourceID)
+ if internal_state != ComponentRemoveState.INTERNAL:
+ if self._dropboxID:
+ yield DropBoxAttachment.resourceRemoved(self._txn, self._resourceID, self._dropboxID)
+ yield ManagedAttachment.resourceRemoved(self._txn, self._resourceID)
yield super(CalendarObject, self).remove()
# Do scheduling
Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/datastore/sql_external.py
===================================================================
--- CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/datastore/sql_external.py 2013-12-20 20:36:58 UTC (rev 12177)
+++ CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/datastore/sql_external.py 2013-12-20 20:39:22 UTC (rev 12178)
@@ -23,6 +23,7 @@
from twext.python.log import Logger
from txdav.caldav.datastore.sql import CalendarHome, Calendar, CalendarObject
+from txdav.caldav.icalendarstore import ComponentUpdateState, ComponentRemoveState
from txdav.common.datastore.sql_external import CommonHomeExternal, CommonHomeChildExternal, \
CommonObjectResourceExternal
@@ -164,7 +165,18 @@
"""
SQL-based implementation of L{ICalendarObject}.
"""
- pass
+ @classmethod
+ def _createInternal(cls, parent, name, component, internal_state, options=None, split_details=None):
+ raise AssertionError("CalendarObjectExternal: not supported")
+
+ def _setComponentInternal(self, component, inserting=False, internal_state=ComponentUpdateState.NORMAL, smart_merge=False, split_details=None):
+ raise AssertionError("CalendarObjectExternal: not supported")
+
+
+ def _removeInternal(self, internal_state=ComponentRemoveState.NORMAL):
+ raise AssertionError("CalendarObjectExternal: not supported")
+
+
CalendarExternal._objectResourceClass = CalendarObjectExternal
Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/icalendarstore.py
===================================================================
--- CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/icalendarstore.py 2013-12-20 20:36:58 UTC (rev 12177)
+++ CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/icalendarstore.py 2013-12-20 20:39:22 UTC (rev 12178)
@@ -907,7 +907,7 @@
NORMAL_NO_IMPLICIT - this is an application layer (user) generated remove that deliberately turns
off implicit scheduling operations.
- INTERNAL - remove the resource without implicit scheduling.
+ INTERNAL - remove the resource without implicit scheduling or attachment processing.
"""
NORMAL = NamedConstant()
Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/podding/conduit.py
===================================================================
--- CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/podding/conduit.py 2013-12-20 20:36:58 UTC (rev 12177)
+++ CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/podding/conduit.py 2013-12-20 20:39:22 UTC (rev 12178)
@@ -709,10 +709,12 @@
# Calls on L{CommonHomeChild} objects
PoddingConduit._make_simple_homechild_action("countobjects", "countObjectResources")
PoddingConduit._make_simple_homechild_action("listobjects", "listObjectResources")
+PoddingConduit._make_simple_homechild_action("resourceuidforname", "resourceUIDForName")
+PoddingConduit._make_simple_homechild_action("resourcenameforuid", "resourceNameForUID")
+PoddingConduit._make_simple_homechild_action("movehere", "moveObjectResourceHere")
+PoddingConduit._make_simple_homechild_action("moveaway", "moveObjectResourceAway")
PoddingConduit._make_simple_homechild_action("synctoken", "syncToken")
PoddingConduit._make_simple_homechild_action("resourcenamessincerevision", "resourceNamesSinceRevision", transform_send=PoddingConduit._to_tuple)
-PoddingConduit._make_simple_homechild_action("resourceuidforname", "resourceUIDForName")
-PoddingConduit._make_simple_homechild_action("resourcenameforuid", "resourceNameForUID")
PoddingConduit._make_simple_homechild_action("search", "search")
# Calls on L{CommonObjectResource} objects
Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/sql.py 2013-12-20 20:36:58 UTC (rev 12177)
+++ CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/sql.py 2013-12-20 20:39:22 UTC (rev 12178)
@@ -4703,10 +4703,9 @@
@inlineCallbacks
- def moveObjectResource(self, child, newparent, newname=None):
+ def _validObjectResource(self, child, newparent, newname=None):
"""
- Move a child of this collection into another collection without actually removing/re-inserting the data.
- Make sure sync and cache details for both collections are updated.
+ Check that the move operation is valid
TODO: check that the resource name does not exist in the new parent, or that the UID
does not exist there too.
@@ -4720,7 +4719,6 @@
"""
name = child.name()
- uid = child.uid()
if newname is None:
newname = name
@@ -4739,6 +4737,30 @@
if child_count >= config.MaxResourcesPerCollection:
raise TooManyObjectResourcesError()
+ returnValue(newname)
+
+
+ @inlineCallbacks
+ def moveObjectResource(self, child, newparent, newname=None):
+ """
+ Move a child of this collection into another collection without actually removing/re-inserting the data.
+ Make sure sync and cache details for both collections are updated.
+
+ TODO: check that the resource name does not exist in the new parent, or that the UID
+ does not exist there too.
+
+ @param child: the child resource to move
+ @type child: L{CommonObjectResource}
+ @param newparent: the parent to move to
+ @type newparent: L{CommonHomeChild}
+ @param newname: new name to use in new parent
+ @type newname: C{str} or C{None} for existing name
+ """
+
+ name = child.name()
+ newname = yield self._validObjectResource(child, newparent, newname)
+ uid = child.uid()
+
# Clean this collections cache and signal sync change
self._objects.pop(name, None)
self._objects.pop(uid, None)
@@ -4778,6 +4800,63 @@
yield newparent.notifyChanged()
+ @inlineCallbacks
+ def moveObjectResourceCreateDelete(self, child, newparent, newname=None):
+ """
+ Move a child of this collection into another collection by doing a create/delete.
+
+ TODO: check that the resource name does not exist in the new parent, or that the UID
+ does not exist there too.
+
+ @param child: the child resource to move
+ @type child: L{CommonObjectResource}
+ @param newparent: the parent to move to
+ @type newparent: L{CommonHomeChild}
+ @param newname: new name to use in new parent
+ @type newname: C{str} or C{None} for existing name
+ """
+
+ name = child.name()
+ newname = yield self._validObjectResource(child, newparent, newname)
+
+ # Do a move as a create/delete
+ component = yield child.component()
+ yield newparent.moveObjectResourceHere(name, component)
+ yield self.moveObjectResourceAway(child.id(), child)
+
+
+ @inlineCallbacks
+ def moveObjectResourceHere(self, name, component):
+ """
+ Create a new child in this collection as part of a move operation. This needs to be split out because
+ behavior differs for sub-classes and cross-pod operations.
+
+ @param name: new name to use in new parent
+ @type name: C{str} or C{None} for existing name
+ @param component: data for new resource
+ @type component: L{Component}
+ """
+
+ yield self.createObjectResourceWithName(name, component)
+
+
+ @inlineCallbacks
+ def moveObjectResourceAway(self, rid, child=None):
+ """
+ Remove the child as the result of a move operation. This needs to be split out because
+ behavior differs for sub-classes and cross-pod operations.
+
+ @param rid: the child resource-id to move
+ @type rid: C{int}
+ @param child: the child resource to move - might be C{None} for cross-pod
+ @type child: L{CommonObjectResource}
+ """
+
+ if child is None:
+ child = yield self.objectResourceWithID(rid)
+ yield child.remove()
+
+
def objectResourcesHaveProperties(self):
return False
@@ -5513,9 +5592,15 @@
"""
yield self.moveValidation(destination, name)
- yield self._parentCollection.moveObjectResource(self, destination, name)
+ # If possible we do a "fast" move by simply fixing up the database information directly rather than
+ # re-writing any data. That is only possible when the source and destination are on this pod.
+ if not self._parentCollection.external() and not destination.external():
+ yield self._parentCollection.moveObjectResource(self, destination, name)
+ else:
+ yield self._parentCollection.moveObjectResourceCreateDelete(self, destination, name)
+
def moveValidation(self, destination, name):
raise NotImplementedError
Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/sql_external.py
===================================================================
--- CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/sql_external.py 2013-12-20 20:36:58 UTC (rev 12177)
+++ CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/sql_external.py 2013-12-20 20:39:22 UTC (rev 12178)
@@ -319,6 +319,46 @@
@inlineCallbacks
+ def moveObjectResourceHere(self, name, component):
+ """
+ Create a new child in this collection as part of a move operation. This needs to be split out because
+ behavior differs for sub-classes and cross-pod operations.
+
+ @param name: new name to use in new parent
+ @type name: C{str} or C{None} for existing name
+ @param component: data for new resource
+ @type component: L{Component}
+ """
+
+ try:
+ result = yield self._txn.store().conduit.send_movehere(self, name, str(component))
+ except NonExistentExternalShare:
+ yield self.fixNonExistentExternalShare()
+ raise ExternalShareFailed("External share does not exist")
+ returnValue(result)
+
+
+ @inlineCallbacks
+ def moveObjectResourceAway(self, rid, child=None):
+ """
+ Remove the child as the result of a move operation. This needs to be split out because
+ behavior differs for sub-classes and cross-pod operations.
+
+ @param rid: the child resource-id to move
+ @type rid: C{int}
+ @param child: the child resource to move - might be C{None} for cross-pod
+ @type child: L{CommonObjectResource}
+ """
+
+ try:
+ result = yield self._txn.store().conduit.send_moveaway(self, rid)
+ except NonExistentExternalShare:
+ yield self.fixNonExistentExternalShare()
+ raise ExternalShareFailed("External share does not exist")
+ returnValue(result)
+
+
+ @inlineCallbacks
def syncToken(self):
if self._syncTokenRevision is None:
try:
@@ -426,13 +466,5 @@
@inlineCallbacks
- def moveTo(self, destination, name=None):
- """
- Probably OK to leave this to the base implementation which calls up to the parent after some validation.
- """
- raise NotImplementedError
-
-
- @inlineCallbacks
def remove(self):
yield self._txn.store().conduit.send_remove(self.parentCollection(), self)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140312/a56af0a4/attachment.html>
More information about the calendarserver-changes
mailing list