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