commit 992096665110674e8e9bc5be6e91c5b78249266e Author: David Faure Date: Fri Jan 20 00:23:55 2012 +0100 New cleanup in "akonadictl fsck": clean up orphan resources from the DB The only way this can ever happen is when hacking agentsrc and removing resources from it (or removing the whole ~/.config). But then you get dead collection trees in kmail, always red, always unusable, and this is the only way to clean this up. diff --git a/server/src/storagejanitor.cpp b/server/src/storagejanitor.cpp index ea520a8..0e26596 100644 --- a/server/src/storagejanitor.cpp +++ b/server/src/storagejanitor.cpp @@ -21,6 +21,7 @@ #include "storage/datastore.h" #include "storage/selectquerybuilder.h" +#include "resourcemanager.h" #include #include @@ -29,6 +30,8 @@ #include #include +#include + #include #include #include @@ -70,8 +73,11 @@ StorageJanitor::~StorageJanitor() DataStore::self()->close(); } -void StorageJanitor::check() +void StorageJanitor::check() // implementation of `akonadictl fsck` { + inform( "Looking for resources in the DB not matching a configured resource..." ); + findOrphanedResources(); + inform( "Looking for collections not belonging to a valid resource..." ); findOrphanedCollections(); @@ -106,6 +112,43 @@ void StorageJanitor::check() inform( "Consistency check done." ); } +void StorageJanitor::findOrphanedResources() +{ + SelectQueryBuilder qbres; + OrgFreedesktopAkonadiAgentManagerInterface iface( + AkDBus::serviceName(AkDBus::Control), + QLatin1String( "/AgentManager" ), + QDBusConnection::sessionBus(), + this + ); + if (!iface.isValid()) { + inform( QString::fromLatin1("ERROR: Couldn't talk to %1").arg(AkDBus::Control) ); + return; + } + const QStringList knownResources = iface.agentInstances(); + if (knownResources.isEmpty()) { + inform( QString::fromLatin1("ERROR: no known resources. This must be a mistake?") ); + return; + } + akDebug() << "Known resources:" << knownResources; + qbres.addValueCondition( Resource::nameFullColumnName(), Query::NotIn, QVariant(knownResources) ); + qbres.addValueCondition( Resource::idFullColumnName(), Query::NotEquals, 1 ); // skip akonadi_search_resource + qbres.exec(); + //akDebug() << "SQL:" << qbres.query().lastQuery(); + const Resource::List orphanResources = qbres.result(); + if ( orphanResources.size() > 0 ) { + QStringList resourceNames; + foreach ( const Resource& resource, orphanResources ) { + resourceNames.append(resource.name()); + } + inform( QString::fromLatin1( "Found %1 orphan resources: %2" ).arg( orphanResources.size() ). arg( resourceNames.join(QLatin1String(",")) ) ); + foreach ( const QString& resourceName, resourceNames ) { + inform( QString::fromLatin1( "Removing resource %1" ).arg( resourceName ) ); + ResourceManager::self()->removeResourceInstance( resourceName ); + } + } +} + void StorageJanitor::findOrphanedCollections() { SelectQueryBuilder qb; @@ -137,7 +180,7 @@ void StorageJanitor::checkPathToRoot(const Akonadi::Collection& col) + QLatin1Literal( ") belongs to a different resource than its parent." ) ); // can/should we actually fix that? } - + checkPathToRoot( parent ); } diff --git a/server/src/storagejanitor.h b/server/src/storagejanitor.h index afc79c6..be3442e 100644 --- a/server/src/storagejanitor.h +++ b/server/src/storagejanitor.h @@ -63,6 +63,11 @@ class StorageJanitor : public QObject void inform( const QString &msg ); /** + * Look for resources in the DB not existing in reality. + */ + void findOrphanedResources(); + + /** * Look for collections belonging to non-existent resources. */ void findOrphanedCollections();