[CalendarServer-changes] [6741] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Sun Jan 16 19:24:11 PST 2011
Revision: 6741
http://trac.macosforge.org/projects/calendarserver/changeset/6741
Author: cdaboo at apple.com
Date: 2011-01-16 19:24:05 -0800 (Sun, 16 Jan 2011)
Log Message:
-----------
Make sure dropbox attachment mode is properly set. Minimise queries when doing dropbox operations.
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/storebridge.py
CalendarServer/trunk/txdav/caldav/datastore/file.py
CalendarServer/trunk/txdav/caldav/datastore/sql.py
CalendarServer/trunk/txdav/carddav/datastore/sql.py
CalendarServer/trunk/txdav/common/datastore/sql.py
CalendarServer/trunk/txdav/common/datastore/sql_schema_v1.sql
CalendarServer/trunk/txdav/common/datastore/sql_tables.py
Modified: CalendarServer/trunk/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/storebridge.py 2011-01-15 21:01:57 UTC (rev 6740)
+++ CalendarServer/trunk/twistedcaldav/storebridge.py 2011-01-17 03:24:05 UTC (rev 6741)
@@ -748,13 +748,8 @@
return davxml.ResourceType.dropboxhome #@UndefinedVariable
- @inlineCallbacks
def listChildren(self):
- l = []
- for everyCalendar in (yield self._newStoreHome.calendars()):
- for everyObject in (yield everyCalendar.calendarObjects()):
- l.append((yield everyObject.dropboxID()))
- returnValue(l)
+ return self._newStoreHome.getAllDropboxIDs()
@@ -894,9 +889,7 @@
),
)
- othersCanWrite = (
- yield self._newStoreCalendarObject.attendeesCanManageAttachments()
- )
+ othersCanWrite = self._newStoreCalendarObject.attendeesCanManageAttachments()
cuas = (yield self._newStoreCalendarObject.component()).getAttendees()
newACEs = []
for calendarUserAddress in cuas:
Modified: CalendarServer/trunk/txdav/caldav/datastore/file.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/file.py 2011-01-15 21:01:57 UTC (rev 6740)
+++ CalendarServer/trunk/txdav/caldav/datastore/file.py 2011-01-17 03:24:05 UTC (rev 6741)
@@ -138,6 +138,17 @@
returnValue(calendarObject)
+ @inlineCallbacks
+ def getAllDropboxIDs(self):
+
+ dropboxIDs = []
+ for calendar in self.calendars():
+ for calendarObject in calendar.calendarObjects():
+ dropboxID = (yield calendarObject.dropboxID())
+ dropboxIDs.append(dropboxID)
+
+ returnValue(dropboxIDs)
+
@property
def _calendarStore(self):
return self._dataStore
@@ -483,7 +494,7 @@
@inlineCallbacks
def attendeesCanManageAttachments(self):
- returnValue((yield self.component()).hasPropertyInAnyComponent("X-APPLE-DROPBOX"))
+ return self.component().hasPropertyInAnyComponent("X-APPLE-DROPBOX")
def dropboxID(self):
Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py 2011-01-15 21:01:57 UTC (rev 6740)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py 2011-01-17 03:24:05 UTC (rev 6741)
@@ -53,8 +53,10 @@
SQLLegacyCalendarShares, PostgresLegacyInboxIndexEmulator
from txdav.common.datastore.sql_tables import CALENDAR_TABLE,\
CALENDAR_BIND_TABLE, CALENDAR_OBJECT_REVISIONS_TABLE, CALENDAR_OBJECT_TABLE,\
- _ATTACHMENTS_MODE_WRITE, CALENDAR_HOME_TABLE, CALENDAR_HOME_METADATA_TABLE,\
- CALENDAR_AND_CALENDAR_BIND, CALENDAR_OBJECT_REVISIONS_AND_BIND_TABLE
+ _ATTACHMENTS_MODE_NONE, _ATTACHMENTS_MODE_READ, _ATTACHMENTS_MODE_WRITE,\
+ CALENDAR_HOME_TABLE, CALENDAR_HOME_METADATA_TABLE,\
+ CALENDAR_AND_CALENDAR_BIND, CALENDAR_OBJECT_REVISIONS_AND_BIND_TABLE,\
+ CALENDAR_OBJECT_AND_BIND_TABLE
from txdav.common.icommondatastore import IndexedSearchException
from vobject.icalendar import utc
@@ -91,16 +93,50 @@
@inlineCallbacks
def calendarObjectWithDropboxID(self, dropboxID):
"""
- Implement lookup with brute-force scanning.
+ Implement lookup via queries.
"""
- for calendar in (yield self.calendars()):
- for calendarObject in (yield calendar.calendarObjects()):
- dbid = yield calendarObject.dropboxID()
- if dropboxID == dbid:
- returnValue(calendarObject)
+ rows = (yield self._txn.execSQL("""
+ select %(OBJECT:name)s.%(OBJECT:column_PARENT_RESOURCE_ID)s, %(OBJECT:column_RESOURCE_ID)s
+ from %(OBJECT:name)s
+ left outer join %(BIND:name)s on (
+ %(OBJECT:name)s.%(OBJECT:column_PARENT_RESOURCE_ID)s = %(BIND:name)s.%(BIND:column_RESOURCE_ID)s
+ )
+ where
+ %(OBJECT:column_DROPBOX_ID)s = %%s and
+ %(BIND:name)s.%(BIND:column_HOME_RESOURCE_ID)s = %%s
+ """ % CALENDAR_OBJECT_AND_BIND_TABLE,
+ [dropboxID, self._resourceID,]
+ ))
+ if rows:
+ calendarID, objectID = rows[0]
+ calendar = (yield self.childWithID(calendarID))
+ if calendar:
+ calendarObject = (yield calendar.objectResourceWithID(objectID))
+ returnValue(calendarObject)
+
+ returnValue(None)
@inlineCallbacks
+ def getAllDropboxIDs(self):
+
+ rows = (yield self._txn.execSQL("""
+ select %(OBJECT:column_DROPBOX_ID)s
+ from %(OBJECT:name)s
+ left outer join %(BIND:name)s on (
+ %(OBJECT:name)s.%(OBJECT:column_PARENT_RESOURCE_ID)s = %(BIND:name)s.%(BIND:column_RESOURCE_ID)s
+ )
+ where
+ %(OBJECT:column_DROPBOX_ID)s is not null and
+ %(BIND:name)s.%(BIND:column_HOME_RESOURCE_ID)s = %%s
+ order by %(OBJECT:column_DROPBOX_ID)s
+ """ % CALENDAR_OBJECT_AND_BIND_TABLE,
+ [self._resourceID]
+ ))
+
+ returnValue([row[0] for row in rows])
+
+ @inlineCallbacks
def createdHome(self):
defaultCal = yield self.createCalendarWithName("calendar")
props = defaultCal.properties()
@@ -108,8 +144,6 @@
Opaque())
yield self.createCalendarWithName("inbox")
-
-
class Calendar(CommonHomeChild):
"""
File-based implementation of L{ICalendar}.
@@ -245,9 +279,9 @@
_objectTable = CALENDAR_OBJECT_TABLE
- def __init__(self, calendar, name, uid, metadata=None):
+ def __init__(self, calendar, name, uid, resourceID=None, metadata=None):
- super(CalendarObject, self).__init__(calendar, name, uid)
+ super(CalendarObject, self).__init__(calendar, name, uid, resourceID)
if metadata is None:
metadata = {}
@@ -271,6 +305,8 @@
%(column_UID)s,
%(column_MD5)s,
character_length(%(column_TEXT)s),
+ %(column_ATTACHMENTS_MODE)s,
+ %(column_DROPBOX_ID)s,
%(column_ACCESS)s,
%(column_SCHEDULE_OBJECT)s,
%(column_SCHEDULE_TAG)s,
@@ -290,6 +326,8 @@
self._uid,
self._md5,
self._size,
+ self._attachment,
+ self._dropboxID,
self._access,
self._schedule_object,
self._schedule_tag,
@@ -369,32 +407,48 @@
organizer = ""
# CALENDAR_OBJECT table update
+ self._uid = component.resourceUID()
self._md5 = hashlib.md5(componentText).hexdigest()
self._size = len(componentText)
+
+ # Determine attachment mode (ignore inbox's) - NB we have to do this
+ # after setting up other properties as UID at least is needed
+ self._attachment = _ATTACHMENTS_MODE_NONE
+ self._dropboxID = None
+ if self._parentCollection.name() != "inbox":
+ if component.hasPropertyInAnyComponent("X-APPLE-DROPBOX"):
+ self._attachment = _ATTACHMENTS_MODE_WRITE
+ self._dropboxID = (yield self.dropboxID())
+ elif component.hasPropertyInAnyComponent("ATTACH"):
+ # FIXME: really we ought to check to see if the ATTACH properties have URI values
+ # and if those are pointing to our server dropbox collections and only then set
+ # the read mode
+ self._attachment = _ATTACHMENTS_MODE_READ
+ self._dropboxID = (yield self.dropboxID())
+
if inserting:
self._resourceID, self._created, self._modified = (
yield self._txn.execSQL(
"""
insert into CALENDAR_OBJECT
(CALENDAR_RESOURCE_ID, RESOURCE_NAME, ICALENDAR_TEXT, ICALENDAR_UID, ICALENDAR_TYPE,
- ATTACHMENTS_MODE, ORGANIZER, RECURRANCE_MAX, ACCESS, SCHEDULE_OBJECT, SCHEDULE_TAG,
+ ATTACHMENTS_MODE, DROPBOX_ID, ORGANIZER, RECURRANCE_MAX, ACCESS, SCHEDULE_OBJECT, SCHEDULE_TAG,
SCHEDULE_ETAGS, PRIVATE_COMMENTS, MD5)
values
- (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
+ (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
returning
RESOURCE_ID,
CREATED,
MODIFIED
""",
- # FIXME: correct ATTACHMENTS_MODE based on X-APPLE-
- # DROPBOX
[
self._calendar._resourceID,
self._name,
componentText,
- component.resourceUID(),
+ self._uid,
component.resourceType(),
- _ATTACHMENTS_MODE_WRITE,
+ self._attachment,
+ self._dropboxID,
organizer,
normalizeForIndex(instances.limit) if instances.limit else None,
self._access,
@@ -410,21 +464,19 @@
"""
update CALENDAR_OBJECT set
(ICALENDAR_TEXT, ICALENDAR_UID, ICALENDAR_TYPE, ATTACHMENTS_MODE,
- ORGANIZER, RECURRANCE_MAX, ACCESS, SCHEDULE_OBJECT, SCHEDULE_TAG,
+ DROPBOX_ID, ORGANIZER, RECURRANCE_MAX, ACCESS, SCHEDULE_OBJECT, SCHEDULE_TAG,
SCHEDULE_ETAGS, PRIVATE_COMMENTS, MD5, MODIFIED)
=
- (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, timezone('UTC', CURRENT_TIMESTAMP))
+ (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, timezone('UTC', CURRENT_TIMESTAMP))
where RESOURCE_ID = %s
returning MODIFIED
""",
- # should really be filling out more fields: ORGANIZER,
- # ORGANIZER_OBJECT, a correct ATTACHMENTS_MODE based on X-APPLE-
- # DROPBOX
[
componentText,
- component.resourceUID(),
+ self._uid,
component.resourceType(),
- _ATTACHMENTS_MODE_WRITE,
+ self._attachment,
+ self._dropboxID,
organizer,
normalizeForIndex(instances.limit) if instances.limit else None,
self._access,
@@ -446,7 +498,6 @@
self._resourceID,
],
)
- self._uid = component.resourceUID()
# CALENDAR_OBJECT table update
@@ -630,11 +681,8 @@
attachment = (yield attachment.initFromStore())
returnValue(attachment)
- @inlineCallbacks
def attendeesCanManageAttachments(self):
- returnValue((yield self.component()).hasPropertyInAnyComponent(
- "X-APPLE-DROPBOX"
- ))
+ return self._attachment == _ATTACHMENTS_MODE_WRITE
dropboxID = dropboxIDFromCalendarObject
Modified: CalendarServer/trunk/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/sql.py 2011-01-15 21:01:57 UTC (rev 6740)
+++ CalendarServer/trunk/txdav/carddav/datastore/sql.py 2011-01-17 03:24:05 UTC (rev 6741)
@@ -172,9 +172,9 @@
_objectTable = ADDRESSBOOK_OBJECT_TABLE
- def __init__(self, addressbook, name, uid, metadata=None):
+ def __init__(self, addressbook, name, uid, resourceID=None, metadata=None):
- super(AddressBookObject, self).__init__(addressbook, name, uid)
+ super(AddressBookObject, self).__init__(addressbook, name, uid, resourceID)
@property
Modified: CalendarServer/trunk/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql.py 2011-01-15 21:01:57 UTC (rev 6740)
+++ CalendarServer/trunk/txdav/common/datastore/sql.py 2011-01-17 03:24:05 UTC (rev 6741)
@@ -417,7 +417,17 @@
"""
return self._childClass.objectWithName(self, name, owned=True)
+ @memoizedKey("resourceID", "_children")
+ def childWithID(self, resourceID):
+ """
+ Retrieve the child with the given C{resourceID} contained in this
+ home.
+ @param name: a string.
+ @return: an L{ICalendar} or C{None} if no such child exists.
+ """
+ return self._childClass.objectWithID(self, resourceID)
+
@memoizedKey("name", "_sharedChildren")
def sharedChildWithName(self, name):
"""
@@ -822,7 +832,6 @@
@param home: a L{CommonHome}.
@param name: a string.
@param owned: a boolean - whether or not to get a shared child
- @param mustExist: a boolean - if False return and empty object
@return: an L{CommonHomChild} or C{None} if no such child
exists.
"""
@@ -865,6 +874,38 @@
@classmethod
@inlineCallbacks
+ def objectWithID(cls, home, resourceID):
+ """
+ Retrieve the child with the given C{resourceID} contained in this
+ C{home}.
+
+ @param home: a L{CommonHome}.
+ @param resourceID: a string.
+ @return: an L{CommonHomChild} or C{None} if no such child
+ exists.
+ """
+
+ data = yield home._txn.execSQL("""
+ select %(column_RESOURCE_NAME)s from %(name)s
+ where
+ %(column_RESOURCE_ID)s = %%s and
+ %(column_HOME_RESOURCE_ID)s = %%s
+ """ % cls._bindTable,
+ [
+ resourceID,
+ home._resourceID,
+ ]
+ )
+
+ if not data:
+ returnValue(None)
+ name = data[0][0]
+ child = cls(home, name, resourceID)
+ yield child.initFromStore()
+ returnValue(child)
+
+ @classmethod
+ @inlineCallbacks
def create(cls, home, name):
child = (yield cls.objectWithName(home, name, owned=True))
@@ -1033,27 +1074,41 @@
if name in self._objects:
return succeed(self._objects[name])
else:
- return self._makeObjectResource(name, None)
+ return self._makeObjectResource(name=name)
def objectResourceWithUID(self, uid):
if uid in self._objects:
return succeed(self._objects[uid])
else:
- return self._makeObjectResource(None, uid)
+ return self._makeObjectResource(uid=uid)
+ def objectResourceWithID(self, resourceID):
+ if resourceID in self._objects:
+ return succeed(self._objects[resourceID])
+ else:
+ return self._makeObjectResource(resourceID=resourceID)
+
@inlineCallbacks
- def _makeObjectResource(self, name, uid):
+ def _makeObjectResource(self, name=None, uid=None, resourceID=None):
"""
We create the empty object first then have it initialize itself from the store
"""
- objectResource = (yield self._objectResourceClass.objectWithName(self, name, uid))
+
+ if resourceID:
+ objectResource = (yield self._objectResourceClass.objectWithID(self, resourceID))
+ else:
+ objectResource = (yield self._objectResourceClass.objectWithName(self, name, uid))
if objectResource:
self._objects[objectResource.name()] = objectResource
self._objects[objectResource.uid()] = objectResource
+ self._objects[objectResource._resourceID] = objectResource
else:
- self._objects[name if name else uid] = None
+ if resourceID:
+ self._objects[resourceID] = None
+ else:
+ self._objects[name if name else uid] = None
returnValue(objectResource)
@@ -1430,9 +1485,9 @@
_objectTable = None
- def __init__(self, parent, name, uid, metadata=None):
+ def __init__(self, parent, name, uid, resourceID=None, metadata=None):
self._parentCollection = parent
- self._resourceID = None
+ self._resourceID = resourceID
self._name = name
self._uid = uid
self._md5 = None
@@ -1483,10 +1538,15 @@
@classmethod
def objectWithName(cls, parent, name, uid):
- objectResource = cls(parent, name, uid)
+ objectResource = cls(parent, name, uid, None)
return objectResource.initFromStore()
@classmethod
+ def objectWithID(cls, parent, resourceID):
+ objectResource = cls(parent, None, None, resourceID)
+ return objectResource.initFromStore()
+
+ @classmethod
@inlineCallbacks
def create(cls, parent, name, component, metadata):
@@ -1497,7 +1557,7 @@
if name.startswith("."):
raise ObjectResourceNameNotAllowedError(name)
- objectResource = cls(parent, name, None, metadata)
+ objectResource = cls(parent, name, None, None, metadata=metadata)
yield objectResource.setComponent(component, inserting=True)
yield objectResource._loadPropertyStore(created=True)
@@ -1523,13 +1583,20 @@
""" % self._objectTable,
[self._name, self._parentCollection._resourceID]
)
- else:
+ elif self._uid:
rows = yield self._txn.execSQL(self._selectAllColumns() + """
from %(name)s
where %(column_UID)s = %%s and %(column_PARENT_RESOURCE_ID)s = %%s
""" % self._objectTable,
[self._uid, self._parentCollection._resourceID]
)
+ elif self._resourceID:
+ rows = yield self._txn.execSQL(self._selectAllColumns() + """
+ from %(name)s
+ where %(column_RESOURCE_ID)s = %%s and %(column_PARENT_RESOURCE_ID)s = %%s
+ """ % self._objectTable,
+ [self._resourceID, self._parentCollection._resourceID]
+ )
if rows:
self._initFromRow(tuple(rows[0]))
yield self._loadPropertyStore()
Modified: CalendarServer/trunk/txdav/common/datastore/sql_schema_v1.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema_v1.sql 2011-01-15 21:01:57 UTC (rev 6740)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema_v1.sql 2011-01-17 03:24:05 UTC (rev 6741)
@@ -168,7 +168,8 @@
ICALENDAR_TEXT text not null,
ICALENDAR_UID varchar(255) not null,
ICALENDAR_TYPE varchar(255) not null,
- ATTACHMENTS_MODE integer not null, -- enum CALENDAR_OBJECT_ATTACHMENTS_MODE
+ ATTACHMENTS_MODE integer default 0 not null, -- enum CALENDAR_OBJECT_ATTACHMENTS_MODE
+ DROPBOX_ID varchar(255),
ORGANIZER varchar(255),
ORGANIZER_OBJECT integer references CALENDAR_OBJECT,
RECURRANCE_MAX date, -- maximum date that recurrences have been expanded to.
@@ -193,9 +194,15 @@
create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID on
CALENDAR_OBJECT(CALENDAR_RESOURCE_ID);
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_AND_ICALENDAR_UID on
+ CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, ICALENDAR_UID);
+
create index CALENDAR_OBJECT_ORGANIZER_OBJECT on
CALENDAR_OBJECT(ORGANIZER_OBJECT);
+create index CALENDAR_OBJECT_DROPBOX_ID on
+ CALENDAR_OBJECT(DROPBOX_ID);
+
-- Enumeration of attachment modes
create table CALENDAR_OBJECT_ATTACHMENTS_MODE (
@@ -203,8 +210,9 @@
DESCRIPTION varchar(16) not null unique
);
-insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (0, 'read' );
-insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (1, 'write');
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (0, 'none' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (1, 'read' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (2, 'write');
-- Enumeration of calendar access types
Modified: CalendarServer/trunk/txdav/common/datastore/sql_tables.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_tables.py 2011-01-15 21:01:57 UTC (rev 6740)
+++ CalendarServer/trunk/txdav/common/datastore/sql_tables.py 2011-01-17 03:24:05 UTC (rev 6741)
@@ -125,6 +125,8 @@
"column_RESOURCE_NAME" : "RESOURCE_NAME",
"column_TEXT" : "ICALENDAR_TEXT",
"column_UID" : "ICALENDAR_UID",
+ "column_ATTACHMENTS_MODE" : "ATTACHMENTS_MODE",
+ "column_DROPBOX_ID" : "DROPBOX_ID",
"column_ACCESS" : "ACCESS",
"column_SCHEDULE_OBJECT" : "SCHEDULE_OBJECT",
"column_SCHEDULE_TAG" : "SCHEDULE_TAG",
@@ -150,12 +152,14 @@
# Various constants
-_BIND_STATUS_INVITED = 0
+_BIND_STATUS_INVITED = 0
_BIND_STATUS_ACCEPTED = 1
_BIND_STATUS_DECLINED = 2
-_BIND_STATUS_INVALID = 3
+_BIND_STATUS_INVALID = 3
-_ATTACHMENTS_MODE_WRITE = 1
+_ATTACHMENTS_MODE_NONE = 0
+_ATTACHMENTS_MODE_READ = 1
+_ATTACHMENTS_MODE_WRITE = 2
_BIND_MODE_OWN = 0
_BIND_MODE_READ = 1
@@ -167,6 +171,10 @@
CALENDAR_AND_CALENDAR_BIND.update([("CHILD:%s" % (k,), v) for k,v in CALENDAR_TABLE.items()])
CALENDAR_AND_CALENDAR_BIND.update([("BIND:%s" % (k,), v) for k,v in CALENDAR_BIND_TABLE.items()])
+CALENDAR_OBJECT_AND_BIND_TABLE = {}
+CALENDAR_OBJECT_AND_BIND_TABLE.update([("OBJECT:%s" % (k,), v) for k,v in CALENDAR_OBJECT_TABLE.items()])
+CALENDAR_OBJECT_AND_BIND_TABLE.update([("BIND:%s" % (k,), v) for k,v in CALENDAR_BIND_TABLE.items()])
+
CALENDAR_OBJECT_REVISIONS_AND_BIND_TABLE = {}
CALENDAR_OBJECT_REVISIONS_AND_BIND_TABLE.update([("REV:%s" % (k,), v) for k,v in CALENDAR_OBJECT_REVISIONS_TABLE.items()])
CALENDAR_OBJECT_REVISIONS_AND_BIND_TABLE.update([("BIND:%s" % (k,), v) for k,v in CALENDAR_BIND_TABLE.items()])
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110116/df3238f1/attachment-0001.html>
More information about the calendarserver-changes
mailing list