[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