[CalendarServer-changes] [10308] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Thu Jan 17 14:19:50 PST 2013
Revision: 10308
http://trac.calendarserver.org//changeset/10308
Author: cdaboo at apple.com
Date: 2013-01-17 14:19:49 -0800 (Thu, 17 Jan 2013)
Log Message:
-----------
Dropbox -> managed attachments migration.
Modified Paths:
--------------
CalendarServer/trunk/calendarserver/tap/caldav.py
CalendarServer/trunk/twistedcaldav/ical.py
CalendarServer/trunk/txdav/caldav/datastore/sql.py
CalendarServer/trunk/txdav/caldav/datastore/test/test_attachments.py
CalendarServer/trunk/txdav/common/datastore/sql.py
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/__init__.py
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrade.py
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/__init__.py
Added Paths:
-----------
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/others/
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/others/__init__.py
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/others/attachment_migration.py
Modified: CalendarServer/trunk/calendarserver/tap/caldav.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/caldav.py 2013-01-16 00:03:16 UTC (rev 10307)
+++ CalendarServer/trunk/calendarserver/tap/caldav.py 2013-01-17 22:19:49 UTC (rev 10308)
@@ -64,7 +64,7 @@
from txdav.common.datastore.sql_tables import schema
from txdav.common.datastore.upgrade.sql.upgrade import (
- UpgradeDatabaseSchemaService, UpgradeDatabaseDataService,
+ UpgradeDatabaseSchemaService, UpgradeDatabaseDataService, UpgradeDatabaseOtherService,
)
from txdav.common.datastore.upgrade.migrate import UpgradeToDatabaseService
@@ -1123,7 +1123,10 @@
UpgradeDatabaseDataService.wrapService(
UpgradeToDatabaseService.wrapService(
CachingFilePath(config.DocumentRoot),
- postImport,
+ UpgradeDatabaseOtherService.wrapService(
+ postImport,
+ store, uid=overrideUID, gid=overrideGID,
+ ),
store, uid=overrideUID, gid=overrideGID,
spawner=spawner, merge=config.MergeUpgrades,
parallel=parallel
@@ -2051,6 +2054,8 @@
return None
+
+
def getSystemIDs(userName, groupName):
"""
Return the system ID numbers corresponding to either:
@@ -2069,7 +2074,7 @@
try:
uid = getpwnam(userName).pw_uid
except KeyError:
- raise ConfigurationError("Invalid user name: %s" % (userName,))
+ raise ConfigurationError("Invalid user name: %s" % (userName,))
else:
uid = getuid()
Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py 2013-01-16 00:03:16 UTC (rev 10307)
+++ CalendarServer/trunk/twistedcaldav/ical.py 2013-01-17 22:19:49 UTC (rev 10308)
@@ -954,18 +954,21 @@
self._markAsDirty()
- def removePropertiesWithName(self, pname):
+ def removeAllPropertiesWithName(self, pname):
"""
- Remove all properties with the given name from this component.
+ Remove all properties with the given name from all components.
- @param pname: the property name to remove from this component.
+ @param pname: the property name to remove from all components.
@type pname: C{str}
"""
for property in self.properties(pname):
self.removeProperty(property)
+ for component in self.subcomponents():
+ component.removeAllPropertiesWithName(pname)
+
def replaceProperty(self, property):
"""
Add or replace a property in this component.
Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py 2013-01-16 00:03:16 UTC (rev 10307)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py 2013-01-17 22:19:49 UTC (rev 10308)
@@ -37,6 +37,7 @@
from twext.python.clsprop import classproperty
from twext.python.filepath import CachingFilePath
+from twext.python.log import Logger
from twext.python.vcomponent import VComponent
from twext.web2.http_headers import MimeType, generateContentType
from twext.web2.stream import readStream
@@ -91,6 +92,8 @@
import tempfile
import uuid
+log = Logger()
+
class CalendarStoreFeatures(object):
"""
Manages store-wide operations specific to calendars.
@@ -105,10 +108,30 @@
@inlineCallbacks
- def upgradeToManagedAttachments(self, txn, batchSize=10):
+ def hasDropboxAttachments(self, txn):
"""
+ Determine whether any dropbox attachments are present.
+
+ @param txn: the transaction to run under
+ @type txn: L{txdav.common.datastore.sql.CommonStoreTransaction}
+ """
+
+ at = schema.ATTACHMENT
+ rows = (yield Select(
+ (at.DROPBOX_ID,),
+ From=at,
+ Where=at.DROPBOX_ID != ".",
+ Limit=1,
+ ).on(txn))
+ returnValue(len(rows) != 0)
+
+
+ @inlineCallbacks
+ def upgradeToManagedAttachments(self, batchSize=10):
+ """
Upgrade the calendar server from old-style dropbox attachments to the new
- managed attachments. This is a one-way, one-time migration step.
+ managed attachments. This is a one-way, one-time migration step. This method
+ creates its own transactions as needed (possibly multiple when batching).
Things to do:
@@ -122,32 +145,63 @@
TODO: parallelize this as much as possible as it will have to touch a lot of data.
"""
- # Clear out unused CALENDAR_OBJECT.DROPBOX_IDs
- co = schema.CALENDAR_OBJECT
- at = schema.ATTACHMENT
- yield Update(
- {co.DROPBOX_ID: None},
- Where=co.RESOURCE_ID.In(Select(
- (co.RESOURCE_ID,),
- From=co.join(at, co.DROPBOX_ID == at.DROPBOX_ID, "left outer"),
- Where=(co.DROPBOX_ID != None).And(at.DROPBOX_ID == None),
- )),
- ).on(txn)
+ txn = self._store.newTransaction("CalendarStoreFeatures.upgradeToManagedAttachments - preliminary work")
+ try:
+ # Clear out unused CALENDAR_OBJECT.DROPBOX_IDs
+ co = schema.CALENDAR_OBJECT
+ at = schema.ATTACHMENT
+ yield Update(
+ {co.DROPBOX_ID: None},
+ Where=co.RESOURCE_ID.In(Select(
+ (co.RESOURCE_ID,),
+ From=co.join(at, co.DROPBOX_ID == at.DROPBOX_ID, "left outer"),
+ Where=(co.DROPBOX_ID != None).And(at.DROPBOX_ID == None),
+ )),
+ ).on(txn)
- # For each remaining attachment
- while True:
+ # Count number to process so we can display progress
rows = (yield Select(
- (at.DROPBOX_ID,),
+ (Count(at.DROPBOX_ID),),
From=at,
Where=at.DROPBOX_ID != ".",
+ GroupBy=at.DROPBOX_ID,
Limit=batchSize,
).on(txn))
- if len(rows) == 0:
- break
- for dropbox_id in rows:
- (yield self._upgradeDropbox(txn, dropbox_id))
+ total = rows[0][0]
+ count = 0
+ log.warn("%d dropbox ids to migrate" % (total,))
+ except RuntimeError:
+ yield txn.abort()
+ raise
+ else:
+ yield txn.commit()
+ # For each remaining attachment
+ rows = -1
+ while rows:
+ txn = self._store.newTransaction("CalendarStoreFeatures.upgradeToManagedAttachments - attachment loop count: %d" % (count,))
+ try:
+ dropbox_id = "Batched select"
+ rows = (yield Select(
+ (at.DROPBOX_ID,),
+ From=at,
+ Where=at.DROPBOX_ID != ".",
+ Limit=batchSize,
+ Distinct=True,
+ ).on(txn))
+ if len(rows) > 0:
+ for dropbox_id in rows:
+ (yield self._upgradeDropbox(txn, dropbox_id))
+ count += len(rows)
+ log.warn("%d of %d dropbox ids migrated" % (count, total,))
+ except RuntimeError, e:
+ log.error("Dropbox migration failed for '%s': %s" % (dropbox_id, e,))
+ yield txn.abort()
+ raise
+ else:
+ yield txn.commit()
+
@inlineCallbacks
def _upgradeDropbox(self, txn, dropbox_id):
"""
@@ -161,8 +215,11 @@
@type dropbox_id: C{str}
"""
+ log.debug("Processing dropbox id: %s" % (dropbox_id,))
+
# Get all affected calendar objects
cobjs = (yield self._loadCalendarObjectsForDropboxID(txn, dropbox_id))
+ log.debug(" %d affected calendar objects" % (len(cobjs),))
# Get names of each matching attachment
at = schema.ATTACHMENT
@@ -171,9 +228,12 @@
From=at,
Where=at.DROPBOX_ID == dropbox_id,
).on(txn))
+ log.debug(" %d associated attachment objects" % (len(names),))
# For each attachment, update each calendar object
for name in names:
+ name = name[0]
+ log.debug(" processing attachment object: %s" % (name,))
attachment = (yield DropBoxAttachment.load(txn, dropbox_id, name))
# Find owner objects and group all by UID
@@ -183,26 +243,34 @@
if cobj._parentCollection.ownerHome()._resourceID == attachment._ownerHomeID:
owners.append(cobj)
cobj_by_UID[cobj.uid()].append(cobj)
+ log.debug(" %d owner calendar objects" % (len(owners),))
+ log.debug(" %d UIDs" % (len(cobj_by_UID),))
+ log.debug(" %d total calendar objects" % (sum([len(items) for items in cobj_by_UID.values()]),))
if owners:
# Create the managed attachment without references to calendar objects.
managed = (yield attachment.convertToManaged())
+ log.debug(" converted attachment: %r" % (attachment,))
# Do conversion for each owner object
for owner_obj in owners:
# Add a reference to the managed attachment
mattachment = (yield managed.newReference(owner_obj._resourceID))
+ log.debug(" added reference for: %r" % (owner_obj,))
# Rewrite calendar data
for cobj in cobj_by_UID[owner_obj.uid()]:
(yield cobj.convertAttachments(attachment, mattachment))
+ log.debug(" re-wrote calendar object: %r" % (cobj,))
else:
# TODO: look for cobjs that were not changed and remove their ATTACH properties.
# These could happen if the owner object no longer exists.
pass
+ log.debug(" finished dropbox id: %s" % (dropbox_id,))
+
@inlineCallbacks
def _loadCalendarObjectsForDropboxID(self, txn, dropbox_id):
"""
@@ -1745,18 +1813,14 @@
for component in cal.subcomponents():
attachments = component.properties("ATTACH")
removed = False
- still_contains_dropbox = False
for attachment in tuple(attachments):
if attachment.value().endswith("/dropbox/%s/%s" % (oldattachment.dropboxID(), oldattachment.name(),)):
component.removeProperty(attachment)
removed = True
- elif attachment.value().find("/dropbox/") != -1:
- still_contains_dropbox = True
if removed:
attach, _ignore_location = (yield newattachment.attachProperty())
component.addProperty(attach)
- if not still_contains_dropbox:
- component.removePropertiesWithName("X-APPLE-DROPBOX")
+ component.removeAllPropertiesWithName("X-APPLE-DROPBOX")
# Write the component back (and no need to re-index as we have not
# changed any timing properties in the calendar data).
@@ -2029,6 +2093,10 @@
self._justCreated = justCreated
+ def __repr__(self):
+ return "<%s: %s>" % (self.__class__.__name__, self._attachmentID)
+
+
def _attachmentPathRoot(self):
return self._txn._store.attachmentsPath
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_attachments.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_attachments.py 2013-01-16 00:03:16 UTC (rev 10307)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_attachments.py 2013-01-17 22:19:49 UTC (rev 10308)
@@ -471,11 +471,7 @@
home = (yield txn.calendarHomeWithUID("home1"))
calendar = (yield home.calendarWithName("calendar1"))
event = (yield calendar.calendarObjectWithName("1.2.ics"))
- component = (yield event.component()).mainComponent()
- # Still has X-APPLE-DROPBOX
- self.assertTrue(component.hasProperty("X-APPLE-DROPBOX"))
-
# Check that one managed-id and one dropbox ATTACH exist
attachments = (yield event.component()).mainComponent().properties("ATTACH")
dropbox_count = 0
@@ -611,10 +607,8 @@
yield self._addAllAttachments()
- txn = self._sqlCalendarStore.newTransaction()
calstore = CalendarStoreFeatures(self._sqlCalendarStore)
- yield calstore.upgradeToManagedAttachments(txn, 2)
- yield txn.commit()
+ yield calstore.upgradeToManagedAttachments(2)
yield self._verifyConversion("home1", "calendar1", "1.2.ics", ("attach_1_2_1.txt", "attach_1_2_2.txt",))
yield self._verifyConversion("home1", "calendar1", "1.3.ics", ("attach_1_3.txt",))
Modified: CalendarServer/trunk/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql.py 2013-01-16 00:03:16 UTC (rev 10307)
+++ CalendarServer/trunk/txdav/common/datastore/sql.py 2013-01-17 22:19:49 UTC (rev 10308)
@@ -181,7 +181,12 @@
else:
self.queryCacher = None
+ # Always import these here to trigger proper "registration" of the calendar and address book
+ # home classes
+ __import__("txdav.caldav.datastore.sql")
+ __import__("txdav.carddav.datastore.sql")
+
@inlineCallbacks
def _withEachHomeDo(self, homeTable, homeFromTxn, action, batchSize):
"""
@@ -427,7 +432,6 @@
self._primaryHomeType = EADDRESSBOOKTYPE
directlyProvides(self, *extraInterfaces)
- self._circularImportHack()
self._sqlTxn = sqlTxn
self.paramstyle = sqlTxn.paramstyle
self.dialect = sqlTxn.dialect
@@ -441,20 +445,6 @@
self.currentStatement = None
- @classmethod
- def _circularImportHack(cls):
- """
- This method is run when the first L{CommonStoreTransaction} is
- instantiated, to populate class-scope (in other words, global) state
- that requires importing modules which depend on this one.
-
- @see: L{CommonHome._register}
- """
- if not cls._homeClass:
- __import__("txdav.caldav.datastore.sql")
- __import__("txdav.carddav.datastore.sql")
-
-
def enqueue(self, workItem, **kw):
"""
Enqueue a L{twext.enterprise.queue.WorkItem} for later execution.
Modified: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/__init__.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/__init__.py 2013-01-16 00:03:16 UTC (rev 10307)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/__init__.py 2013-01-17 22:19:49 UTC (rev 10308)
@@ -13,4 +13,3 @@
# See the License for the specific language governing permissions and
# limitations under the License.
##
-
Added: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/others/__init__.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/others/__init__.py (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/others/__init__.py 2013-01-17 22:19:49 UTC (rev 10308)
@@ -0,0 +1,15 @@
+##
+# Copyright (c) 2013 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
Added: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/others/attachment_migration.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/others/attachment_migration.py (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/others/attachment_migration.py 2013-01-17 22:19:49 UTC (rev 10308)
@@ -0,0 +1,44 @@
+##
+# Copyright (c) 2013 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from twisted.internet.defer import inlineCallbacks
+from txdav.caldav.datastore.sql import CalendarStoreFeatures
+
+"""
+Upgrader that checks for any dropbox attachments, and upgrades them all to managed attachments.
+"""
+
+ at inlineCallbacks
+def doUpgrade(upgrader):
+ """
+ Do the required upgrade steps.
+ """
+
+ storeWrapper = CalendarStoreFeatures(upgrader.sqlStore)
+ txn = upgrader.sqlStore.newTransaction("attachment_migration.doUpgrade")
+ try:
+ needUpgrade = (yield storeWrapper.hasDropboxAttachments(txn))
+ if needUpgrade:
+ upgrader.log_warn("Starting dropbox migration")
+ yield storeWrapper.upgradeToManagedAttachments(batchSize=10)
+ upgrader.log_warn("Finished dropbox migration")
+ else:
+ upgrader.log_warn("No dropbox migration needed")
+ except RuntimeError:
+ yield txn.abort()
+ raise
+ else:
+ yield txn.commit()
Modified: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrade.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrade.py 2013-01-16 00:03:16 UTC (rev 10307)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrade.py 2013-01-17 22:19:49 UTC (rev 10308)
@@ -30,6 +30,8 @@
from twisted.python.modules import getModule
from twisted.python.reflect import namedObject
+from txdav.common.datastore.upgrade.sql.others import attachment_migration
+
class UpgradeDatabaseCoreService(Service, LoggingMixIn, object):
"""
Base class for either schema or data upgrades on the database.
@@ -73,6 +75,7 @@
"""
return cls(store, service, uid=uid, gid=gid,)
+
def __init__(self, sqlStore, service, uid=None, gid=None):
"""
Initialize the service.
@@ -83,25 +86,27 @@
self.gid = gid
self.schemaLocation = getModule(__name__).filePath.parent().parent().sibling("sql_schema")
self.pyLocation = getModule(__name__).filePath.parent()
-
+
self.versionKey = None
self.versionDescriptor = ""
self.upgradeFileSuffix = ""
self.defaultKeyValue = None
-
+
+
def startService(self):
"""
Start the service.
"""
self.databaseUpgrade()
+
@inlineCallbacks
def databaseUpgrade(self):
"""
Do a database schema upgrade.
"""
self.log_warn("Beginning database %s check." % (self.versionDescriptor,))
-
+
# Retrieve information from schema and database
dialect, required_version, actual_version = yield self.getVersions()
@@ -117,13 +122,14 @@
self.sqlStore.setUpgrading(True)
yield self.upgradeVersion(actual_version, required_version, dialect)
self.sqlStore.setUpgrading(False)
-
+
self.log_warn("Database %s check complete." % (self.versionDescriptor,))
# see http://twistedmatrix.com/trac/ticket/4649
if self.wrappedService is not None:
reactor.callLater(0, self.wrappedService.setServiceParent, self.parent)
-
+
+
@inlineCallbacks
def getVersions(self):
"""
@@ -141,7 +147,7 @@
else:
required_version = int(found.group(1))
self.log_warn("Required database key %s: %s." % (self.versionKey, required_version,))
-
+
# Get the schema version in the current database
sqlTxn = self.sqlStore.newTransaction()
dialect = sqlTxn.dialect
@@ -161,6 +167,7 @@
returnValue((dialect, required_version, actual_version,))
+
@inlineCallbacks
def upgradeVersion(self, fromVersion, toVersion, dialect):
"""
@@ -169,10 +176,10 @@
"""
self.log_warn("Starting %s upgrade from version %d to %d." % (self.versionDescriptor, fromVersion, toVersion,))
-
+
# Scan for all possible upgrade files - returned sorted
files = self.scanForUpgradeFiles(dialect)
-
+
# Determine upgrade sequence and run each upgrade
upgrades = self.determineUpgradeSequence(fromVersion, toVersion, files, dialect)
@@ -186,17 +193,19 @@
self.log_warn("%s upgraded from version %d to %d." % (self.versionDescriptor.capitalize(), fromVersion, toVersion,))
+
def getPathToUpgrades(self, dialect):
"""
- Return the path where appropriate upgrade files can be found.
+ Return the path where appropriate upgrade files can be found.
"""
raise NotImplementedError
+
def scanForUpgradeFiles(self, dialect):
"""
Scan for upgrade files with the require name.
"""
-
+
fp = self.getPathToUpgrades(dialect)
upgrades = []
regex = re.compile("upgrade_from_(\d+)_to_(\d+)%s" % (self.upgradeFileSuffix,))
@@ -206,10 +215,11 @@
fromV = int(matched.group(1))
toV = int(matched.group(2))
upgrades.append((fromV, toV, child))
-
- upgrades.sort(key=lambda x:(x[0], x[1]))
+
+ upgrades.sort(key=lambda x: (x[0], x[1]))
return upgrades
+
def determineUpgradeSequence(self, fromVersion, toVersion, files, dialect):
"""
Determine the upgrade_from_X_to_Y(.sql|.py) files that cover the full range of upgrades.
@@ -224,7 +234,7 @@
for fromV, toV, fp in files:
if fromV not in filesByFromVersion or filesByFromVersion[fromV][1] < toV:
filesByFromVersion[fromV] = fromV, toV, fp
-
+
upgrades = []
nextVersion = fromVersion
while nextVersion != toVersion:
@@ -235,15 +245,18 @@
else:
upgrades.append(filesByFromVersion[nextVersion][2])
nextVersion = filesByFromVersion[nextVersion][1]
-
+
return upgrades
+
def applyUpgrade(self, fp):
"""
Apply the supplied upgrade to the database. Always return an L{Deferred"
"""
raise NotImplementedError
-
+
+
+
class UpgradeDatabaseSchemaService(UpgradeDatabaseCoreService):
"""
Checks and upgrades the database schema. This assumes there are a bunch of
@@ -265,19 +278,21 @@
def __init__(self, sqlStore, service, uid=None, gid=None):
"""
Initialize the service.
-
+
@param sqlStore: The store to operate on. Can be C{None} when doing unit tests.
@param service: Wrapped service. Can be C{None} when doing unit tests.
"""
super(UpgradeDatabaseSchemaService, self).__init__(sqlStore, service, uid, gid)
-
+
self.versionKey = "VERSION"
self.versionDescriptor = "schema"
self.upgradeFileSuffix = ".sql"
+
def getPathToUpgrades(self, dialect):
return self.schemaLocation.child("upgrades").child(dialect)
+
@inlineCallbacks
def applyUpgrade(self, fp):
"""
@@ -293,6 +308,8 @@
yield sqlTxn.abort()
raise
+
+
class UpgradeDatabaseDataService(UpgradeDatabaseCoreService):
"""
Checks and upgrades the database data. This assumes there are a bunch of
@@ -314,25 +331,27 @@
def __init__(self, sqlStore, service, uid=None, gid=None):
"""
Initialize the service.
-
+
@param sqlStore: The store to operate on. Can be C{None} when doing unit tests.
@param service: Wrapped service. Can be C{None} when doing unit tests.
"""
super(UpgradeDatabaseDataService, self).__init__(sqlStore, service, uid, gid)
-
+
self.versionKey = "CALENDAR-DATAVERSION"
self.versionDescriptor = "data"
self.upgradeFileSuffix = ".py"
+
def getPathToUpgrades(self, dialect):
return self.pyLocation.child("upgrades")
+
@inlineCallbacks
def applyUpgrade(self, fp):
"""
Apply the data upgrade .py files to the database.
"""
-
+
# Find the module function we need to execute
try:
module = getModule(__name__)
@@ -345,3 +364,51 @@
self.log_warn("Applying data upgrade: %s" % (module,))
yield doUpgrade(self.sqlStore)
+
+
+
+class UpgradeDatabaseOtherService(UpgradeDatabaseCoreService):
+ """
+ Do any other upgrade behaviors once all the schema, data, file migration upgraders
+ are done.
+
+ @ivar sqlStore: The store to operate on.
+ @type sqlStore: L{txdav.idav.IDataStore}
+
+ @ivar wrappedService: Wrapped L{IService} that will be started after this
+ L{UpgradeDatabaseOtherService}'s work is done
+ @type wrappedService: L{IService} or C{NoneType}
+ """
+
+ def __init__(self, sqlStore, service, uid=None, gid=None):
+ """
+ Initialize the service.
+
+ @param sqlStore: The store to operate on. Can be C{None} when doing unit tests.
+ @param service: Wrapped service. Can be C{None} when doing unit tests.
+ """
+ super(UpgradeDatabaseOtherService, self).__init__(sqlStore, service, uid, gid)
+
+ self.versionDescriptor = "other upgrades"
+
+
+ @inlineCallbacks
+ def databaseUpgrade(self):
+ """
+ Do upgrades.
+ """
+ self.log_warn("Beginning database %s check." % (self.versionDescriptor,))
+
+ # Do each upgrade in our own predefined order
+ self.sqlStore.setUpgrading(True)
+
+ # Migration from dropbox to managed attachments
+ yield attachment_migration.doUpgrade(self)
+
+ self.sqlStore.setUpgrading(False)
+
+ self.log_warn("Database %s check complete." % (self.versionDescriptor,))
+
+ # see http://twistedmatrix.com/trac/ticket/4649
+ if self.wrappedService is not None:
+ reactor.callLater(0, self.wrappedService.setServiceParent, self.parent)
Modified: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/__init__.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/__init__.py 2013-01-16 00:03:16 UTC (rev 10307)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/__init__.py 2013-01-17 22:19:49 UTC (rev 10308)
@@ -13,4 +13,3 @@
# See the License for the specific language governing permissions and
# limitations under the License.
##
-
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130117/5c84b66a/attachment-0001.html>
More information about the calendarserver-changes
mailing list