[CalendarServer-changes] [9911] CalendarServer/branches/users/gaya/sharedgroups/txdav/common/ datastore/sql.py
source_changes at macosforge.org
source_changes at macosforge.org
Tue Oct 9 13:13:47 PDT 2012
Revision: 9911
http://trac.calendarserver.org//changeset/9911
Author: gaya at apple.com
Date: 2012-10-09 13:13:47 -0700 (Tue, 09 Oct 2012)
Log Message:
-----------
merge in changeset/9910 from trunk
Modified Paths:
--------------
CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py
Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py 2012-10-09 20:11:51 UTC (rev 9910)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py 2012-10-09 20:13:47 UTC (rev 9911)
@@ -217,6 +217,7 @@
self._migrating = state
self._enableNotifications = not state
+
def setUpgrading(self, state):
"""
Set the "upgrading" state
@@ -224,6 +225,7 @@
self._enableNotifications = not state
+
class TransactionStatsCollector(object):
"""
Used to log each SQL query and statistics about that query during the course of a single transaction.
@@ -235,6 +237,7 @@
self.logFileName = logFileName
self.statements = []
+
def startStatement(self, sql, args):
"""
Called prior to an SQL query being run.
@@ -243,7 +246,7 @@
@type sql: C{str}
@param args: the arguments (binds) to the SQL statement
@type args: C{list}
-
+
@return: C{tuple} containing the index in the statement list for this statement, and the start time
"""
args = ["%s" % (arg,) for arg in args]
@@ -251,6 +254,7 @@
self.statements.append(["%s %s" % (sql, args,), 0, 0])
return len(self.statements) - 1, time.time()
+
def endStatement(self, context, rows):
"""
Called after an SQL query has executed.
@@ -264,6 +268,7 @@
self.statements[index][1] = len(rows) if rows else 0
self.statements[index][2] = time.time() - tstamp
+
def printReport(self):
"""
Print a report of all the SQL statements executed to date.
@@ -289,6 +294,8 @@
else:
log.error(toFile.getvalue())
+
+
class CommonStoreTransactionMonitor(object):
"""
Object that monitors the state of a transaction over time and logs or times out
@@ -310,6 +317,7 @@
self._installLogTimer()
self._installTimeout()
+
def _cleanTxn(self):
self.txn = None
if self.delayedLog:
@@ -319,6 +327,7 @@
self.delayedTimeout.cancel()
self.delayedTimeout = None
+
def _installLogTimer(self):
def _logTransactionWait():
if self.txn is not None:
@@ -328,6 +337,7 @@
if self.logTimerSeconds:
self.delayedLog = self.callLater(self.logTimerSeconds, _logTransactionWait)
+
def _installTimeout(self):
def _forceAbort():
if self.txn is not None:
@@ -444,6 +454,7 @@
Where=cs.NAME == Parameter('name'),
)
+
@inlineCallbacks
def calendarserverValue(self, key):
result = yield self._calendarserver.on(self, name=key)
@@ -507,6 +518,7 @@
"""
return NotificationCollection.notificationsWithUID(self, uid, create)
+
@classproperty
def _insertAPNSubscriptionQuery(cls): #@NoSelf
apn = schema.APN_SUBSCRIPTIONS
@@ -648,9 +660,11 @@
def isNotifiedAlready(self, obj):
return obj in self._notifiedAlready
+
def notificationAddedForObject(self, obj):
self._notifiedAlready.add(obj)
+
def isBumpedAlready(self, obj):
"""
Indicates whether or not bumpAddedForObject has already been
@@ -659,6 +673,7 @@
"""
return obj in self._bumpedAlready
+
def bumpAddedForObject(self, obj):
"""
Records the fact that a bumpModified( ) call has already been
@@ -754,13 +769,14 @@
# caller shouldn't be paying attention anyway.
block.end()
+
@inlineCallbacks
def execSQL(self, *a, **kw):
"""
Execute some SQL (delegate to L{IAsyncTransaction}).
"""
if self._stats:
- statsContext = self._stats.startStatement(a[0], a[1])
+ statsContext = self._stats.startStatement(a[0], a[1] if len(a) > 1 else ())
self.currentStatement = a[0]
if self._store.logTransactionWaits and a[0].split(" ", 1)[0].lower() in ("insert", "update", "delete",):
self.iudCount += 1
@@ -777,14 +793,15 @@
self._stats.endStatement(statsContext, results)
returnValue(results)
+
@inlineCallbacks
def execSQLBlock(self, sql):
"""
Execute a block of SQL by parsing it out into individual statements and execute
each of those.
-
+
FIXME: temporary measure for handling large schema upgrades. This should NOT be used
- for regular SQL operations - only upgrades.
+ for regular SQL operations - only upgrades.
"""
parsed = parse(sql)
for stmt in parsed:
@@ -795,6 +812,7 @@
stmt = str(stmt).rstrip(";")
yield self.execSQL(stmt)
+
def commit(self):
"""
Commit the transaction and execute any post-commit hooks.
@@ -816,7 +834,7 @@
co = schema.CALENDAR_OBJECT
cb = schema.CALENDAR_BIND
tr = schema.TIME_RANGE
- kwds = { }
+ kwds = {}
if limited:
kwds["Limit"] = Parameter("batchSize")
return Select(
@@ -864,7 +882,7 @@
if cutoff < truncateLowerLimit:
raise ValueError("Cannot query events older than %s" % (truncateLowerLimit.getText(),))
- kwds = { "CutOff" : pyCalendarTodatetime(cutoff) }
+ kwds = {"CutOff": pyCalendarTodatetime(cutoff)}
if batchSize is not None:
kwds["batchSize"] = batchSize
query = self._oldEventsLimited
@@ -948,15 +966,22 @@
returnValue(count)
+
class _EmptyCacher(object):
+
def set(self, key, value):
return succeed(True)
+
+
def get(self, key, withIdentifier=False):
return succeed(None)
+
+
def delete(self, key):
return succeed(True)
+
class CommonHome(LoggingMixIn):
# All these need to be initialized by derived classes for each store type
@@ -1017,6 +1042,7 @@
return Select([home.RESOURCE_ID],
From=home, Where=home.OWNER_UID == Parameter("ownerUID"))
+
@classproperty
def _ownerFromResourceID(cls): #@NoSelf
home = cls._homeSchema
@@ -1024,6 +1050,7 @@
From=home,
Where=home.RESOURCE_ID == Parameter("resourceID"))
+
@classproperty
def _metaDataQuery(cls): #@NoSelf
metadata = cls._homeMetaDataSchema
@@ -1031,6 +1058,7 @@
From=metadata,
Where=metadata.RESOURCE_ID == Parameter("resourceID"))
+
@inlineCallbacks
def initFromStore(self, no_cache=False):
"""
@@ -1183,6 +1211,7 @@
self._childrenLoaded = True
returnValue(results)
+
def listChildren(self):
"""
Retrieve the names of the children in this home.
@@ -1216,6 +1245,7 @@
"""
return self._childClass.objectWithName(self, name)
+
@memoizedKey("resourceID", "_children")
def childWithID(self, resourceID):
"""
@@ -1227,6 +1257,7 @@
"""
return self._childClass.objectWithID(self, resourceID)
+
def invitedChildWithName(self, name):
"""
Retrieve the invited child with the given C{name} contained in this
@@ -1237,6 +1268,7 @@
"""
return self._childClass.invitedObjectWithName(self, name)
+
@inlineCallbacks
def createChildWithName(self, name):
if name.startswith("."):
@@ -1246,6 +1278,7 @@
child = (yield self.childWithName(name))
returnValue(child)
+
@inlineCallbacks
def removeChildWithName(self, name):
child = yield self.childWithName(name)
@@ -1575,6 +1608,7 @@
else:
returnValue(None)
+
@classproperty
def _lockLastModifiedQuery(cls): #@NoSelf
meta = cls._homeMetaDataSchema
@@ -1585,6 +1619,7 @@
NoWait=True
)
+
@classproperty
def _changeLastModifiedQuery(cls): #@NoSelf
meta = cls._homeMetaDataSchema
@@ -1592,6 +1627,7 @@
Where=meta.RESOURCE_ID == Parameter("resourceID"),
Return=meta.MODIFIED)
+
@inlineCallbacks
def bumpModified(self):
"""
@@ -1625,6 +1661,7 @@
except AllRetriesFailed:
log.debug("CommonHome.bumpModified failed")
+
@inlineCallbacks
def notifyChanged(self):
"""
@@ -1677,6 +1714,7 @@
_ignore_uuid, revision = token.split("_", 1)
return int(revision)
+
@inlineCallbacks
def syncToken(self):
if self._syncTokenRevision is None:
@@ -1715,7 +1753,7 @@
(yield self._objectNamesSinceRevisionQuery.on(
self._txn, revision=token, resourceID=self._resourceID))
]
- results.sort(key=lambda x:x[1])
+ results.sort(key=lambda x: x[1])
changed = []
deleted = []
@@ -2034,6 +2072,7 @@
cls._homeChildMetaDataSchema.MODIFIED,
)
+
@classmethod
def metadataAttributes(cls):
"""
@@ -2049,6 +2088,7 @@
"_modified",
)
+
@classmethod
@inlineCallbacks
def listObjects(cls, home):
@@ -2070,6 +2110,7 @@
return cls._bindFor((bind.HOME_RESOURCE_ID == Parameter("homeID"))
.And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED))
+
@classmethod
@inlineCallbacks
def listInvitedObjects(cls, home):
@@ -2112,11 +2153,11 @@
def _updateBindColumnsQuery(cls, columnMap): #@NoSelf
bind = cls._bindSchema
return Update(columnMap,
- Where=
- (bind.RESOURCE_ID == Parameter("resourceID"))
+ Where=(bind.RESOURCE_ID == Parameter("resourceID"))
.And(bind.HOME_RESOURCE_ID == Parameter("homeID")),
Return=bind.RESOURCE_NAME)
+
@classproperty
def _updateBindQuery(cls): #@NoSelf
bind = cls._bindSchema
@@ -2235,7 +2276,7 @@
if shareeView._bindStatus == _BIND_STATUS_ACCEPTED:
yield shareeView._initSyncToken()
elif shareeView._bindStatus == _BIND_STATUS_DECLINED:
- shareeView._deletedSyncToken(sharedRemoval=True);
+ shareeView._deletedSyncToken(sharedRemoval=True)
if message:
shareeView._bindMessage = columnMap[bind.MESSAGE]
@@ -2253,7 +2294,6 @@
returnValue(shareeView._name)
-
@inlineCallbacks
def unshareWith(self, shareeHome):
"""
@@ -2268,19 +2308,18 @@
@return: a L{Deferred} which will fire with the previously-used name.
"""
-
#remove sync tokens
shareeChildren = yield shareeHome.children()
for shareeChild in shareeChildren:
if not shareeChild.owned() and shareeChild._resourceID == self._resourceID:
- shareeChild._deletedSyncToken(sharedRemoval=True);
+ shareeChild._deletedSyncToken(sharedRemoval=True)
queryCacher = self._txn._queryCacher
if queryCacher:
cacheKey = queryCacher.keyForObjectWithName(shareeHome._resourceID, shareeChild._name)
queryCacher.invalidateAfterCommit(self._txn, cacheKey)
- break;
+ break
bind = self._bindSchema
rows = yield Delete(
@@ -2308,30 +2347,35 @@
"""
return self._bindMode
+
def owned(self):
"""
@see: L{ICalendar.owned}
"""
return self._bindMode == _BIND_MODE_OWN
+
def shareStatus(self):
"""
@see: L{ICalendar.shareStatus}
"""
return self._bindStatus
+
def shareMessage(self):
"""
@see: L{ICalendar.shareMessage}
"""
return self._bindMessage
+
def shareUID(self):
"""
@see: L{ICalendar.shareUID}
"""
return self.name()
+
@inlineCallbacks
def unshare(self, homeType):
"""
@@ -2366,6 +2410,7 @@
Where=condition
)
+
@classproperty
def _sharedBindForResourceID(cls): #@NoSelf
bind = cls._bindSchema
@@ -2375,7 +2420,6 @@
)
-
@inlineCallbacks
def asShared(self):
"""
@@ -2420,6 +2464,7 @@
.And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
)
+
@inlineCallbacks
def asInvited(self):
"""
@@ -2573,6 +2618,7 @@
.And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
)
+
@classmethod
@inlineCallbacks
def objectWithName(cls, home, name):
@@ -2602,7 +2648,7 @@
if rows:
bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
- # get ownerHomeID
+ # get ownerHomeID
if bindMode == _BIND_MODE_OWN:
ownerHomeID = homeID
else:
@@ -3164,6 +3210,7 @@
raise NoSuchObjectResourceError
yield self._removeObjectResource(child)
+
@inlineCallbacks
def _removeObjectResource(self, child):
name = child.name()
@@ -3176,6 +3223,7 @@
yield self._deleteRevision(name)
yield self.notifyChanged()
+
@classproperty
def _moveParentUpdateQuery(cls): #@NoSelf
"""
@@ -3187,6 +3235,7 @@
Where=obj.RESOURCE_ID == Parameter("resourceID")
)
+
def _movedObjectResource(self, child, newparent):
"""
Method that subclasses can override to do an extra DB adjustments when a resource
@@ -3194,12 +3243,13 @@
"""
return succeed(True)
+
@inlineCallbacks
def moveObjectResource(self, child, newparent):
"""
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.
@@ -3232,6 +3282,7 @@
yield newparent._insertRevision(name)
yield newparent.notifyChanged()
+
def objectResourcesHaveProperties(self):
return False
@@ -3261,6 +3312,7 @@
@param props: the L{PropertyStore} from C{properties()}.
"""
+ pass
# IDataStoreObject
@@ -3289,12 +3341,14 @@
self._notifiers = ()
self._notifiers += (notifier,)
+
def notifierID(self, label="default"):
if self._notifiers:
return self._notifiers[0].getID(label)
else:
return None
+
@inlineCallbacks
def nodeName(self, label="default"):
if self._notifiers:
@@ -3305,6 +3359,7 @@
else:
returnValue(None)
+
@classproperty
def _lockLastModifiedQuery(cls): #@NoSelf
schema = cls._homeChildMetaDataSchema
@@ -3315,6 +3370,7 @@
NoWait=True
)
+
@classproperty
def _changeLastModifiedQuery(cls): #@NoSelf
schema = cls._homeChildMetaDataSchema
@@ -3353,6 +3409,7 @@
except AllRetriesFailed:
log.debug("CommonHomeChild.bumpModified failed")
+
@inlineCallbacks
def notifyChanged(self):
"""
@@ -3370,6 +3427,7 @@
self._txn.notificationAddedForObject(self)
+
class CommonObjectResource(LoggingMixIn, FancyEqMixin):
"""
Base class for object resources.
@@ -3447,6 +3505,7 @@
returnValue(results)
+
@classmethod
def _allColumnsWithParentAndNames(cls, names): #@NoSelf
obj = cls._objectSchema
@@ -3470,6 +3529,7 @@
returnValue(results)
+
@classmethod
@inlineCallbacks
def _loadAllObjectsWithNames(cls, parent, names):
@@ -3519,11 +3579,13 @@
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):
@@ -3700,7 +3762,7 @@
@type wait: C{bool}
@param txn: alternative transaction to use
@type txn: L{CommonStoreTransaction}
-
+
@raise: L{NoSuchObjectResourceError} if resource does not exist, other L{Exception}
if already locked and NOWAIT is used.
"""
@@ -3722,6 +3784,7 @@
def componentType(self):
returnValue((yield self.component()).mainType())
+
@classproperty
def _deleteQuery(cls): #@NoSelf
"""
@@ -3746,6 +3809,7 @@
self._modified = None
self._objectText = None
+
def uid(self):
return self._uid
@@ -3754,7 +3818,6 @@
return self._name
-
# IDataStoreObject
def contentType(self):
raise NotImplementedError()
@@ -3842,12 +3905,10 @@
notifiers = None
self._notifiers = notifiers
-
_resourceIDFromUIDQuery = Select(
[_homeSchema.RESOURCE_ID], From=_homeSchema,
Where=_homeSchema.OWNER_UID == Parameter("uid"))
-
_provisionNewNotificationsQuery = Insert(
{_homeSchema.OWNER_UID: Parameter("uid")},
Return=_homeSchema.RESOURCE_ID
@@ -3951,7 +4012,6 @@
self._notificationNames = sorted([result.name() for result in results])
returnValue(results)
-
_notificationUIDsForHomeQuery = Select(
[schema.NOTIFICATION.NOTIFICATION_UID], From=schema.NOTIFICATION,
Where=schema.NOTIFICATION.NOTIFICATION_HOME_RESOURCE_ID ==
@@ -4009,7 +4069,6 @@
def removeNotificationObjectWithName(self, name):
return self.removeNotificationObjectWithUID(self._nameToUID(name))
-
_removeByUIDQuery = Delete(
From=schema.NOTIFICATION,
Where=(schema.NOTIFICATION.NOTIFICATION_UID == Parameter("uid")).And(
@@ -4024,7 +4083,6 @@
self._notifications.pop(uid, None)
yield self._deleteRevision("%s.xml" % (uid,))
-
_initSyncTokenQuery = Insert(
{
_revisionsSchema.HOME_RESOURCE_ID : Parameter("resourceID"),
@@ -4040,7 +4098,6 @@
self._syncTokenRevision = (yield self._initSyncTokenQuery.on(
self._txn, resourceID=self._resourceID))[0][0]
-
_syncTokenQuery = Select(
[Max(_revisionsSchema.REVISION)], From=_revisionsSchema,
Where=_revisionsSchema.HOME_RESOURCE_ID == Parameter("resourceID")
@@ -4066,6 +4123,7 @@
self._notifiers = ()
self._notifiers += (notifier,)
+
def notifierID(self, label="default"):
if self._notifiers:
return self._notifiers[0].getID(label)
@@ -4121,7 +4179,7 @@
"""
# Delete NOTIFICATION rows
no = schema.NOTIFICATION
- kwds = { "ResourceID" : self._resourceID }
+ kwds = {"ResourceID": self._resourceID}
yield Delete(
From=no,
Where=(
@@ -4139,6 +4197,7 @@
).on(self._txn, **kwds)
+
class NotificationObject(LoggingMixIn, FancyEqMixin):
implements(INotificationObject)
@@ -4348,7 +4407,6 @@
self._modified = rows[0][0]
self._objectText = xmldata
-
_xmlDataFromID = Select(
[_objectSchema.XML_DATA], From=_objectSchema,
Where=_objectSchema.RESOURCE_ID == Parameter("resourceID"))
@@ -4377,6 +4435,7 @@
def size(self):
return self._size
+
def xmlType(self):
# NB This is the NotificationType property element
if isinstance(self._xmlType, str):
@@ -4385,6 +4444,7 @@
return self._xmlType
+
def created(self):
return datetimeMktime(parseSQLTimestamp(self._created))
@@ -4744,6 +4804,3 @@
# obscure bug.
else:
yield t.commit()
-
-
-
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20121009/f05fce91/attachment-0001.html>
More information about the calendarserver-changes
mailing list