Commit 403afb55 authored by Daniel Vrátil's avatar Daniel Vrátil 🤖
Browse files

Get rid of the singleton pattern in most classes in Server

Instead added getters into the AkonadiServer class and
pass that around to everything that needs it. Not using
singletons makes dependency injection in tests much easier
(and it's also the right thing to do.
parent c897dfe5
......@@ -25,6 +25,7 @@
#include "fakeitemretrievalmanager.h"
#include "inspectablenotificationcollector.h"
#include "fakeintervalcheck.h"
#include "storage/collectionstatistics.h"
#include <QSettings>
#include <QCoreApplication>
......@@ -220,9 +221,10 @@ void FakeAkonadiServer::initFake()
throw FakeAkonadiServerException("Failed to initialize datastore");
}
PreprocessorManager::init();
PreprocessorManager::instance()->setEnabled(false);
mSearchManager = std::make_unique<FakeSearchManager>();
mPreprocessorManager = std::make_unique<PreprocessorManager>();
mPreprocessorManager->setEnabled(false);
mSearchManager = std::make_unique<FakeSearchManager>(*this);
mCollectionStats = std::make_unique<CollectionStatistics>();
if (!mDisableItemRetrievalManager) {
mRetrievalManager = std::make_unique<FakeItemRetrievalManager>();
......@@ -249,7 +251,8 @@ bool FakeAkonadiServer::quit()
qDebug() << "Skipping clean up of" << basePath();
}
PreprocessorManager::done();
mPreprocessorManager.reset();
mCollectionStats.reset();
(void)SearchManager::instance();
if (mDataStore) {
......
......@@ -18,13 +18,14 @@
*/
#include "fakesearchmanager.h"
#include "fakeakonadiserver.h"
#include "entities.h"
using namespace Akonadi::Server;
FakeSearchManager::FakeSearchManager(QObject *parent)
: SearchManager(QStringList(), parent)
FakeSearchManager::FakeSearchManager(FakeAkonadiServer &akonadi)
: SearchManager(QStringList(), akonadi)
{
}
......
......@@ -25,6 +25,8 @@
namespace Akonadi {
namespace Server {
class FakeAkonadiServer;
/**
* Subclass of SearchManager that does nothing.
*/
......@@ -33,7 +35,7 @@ class FakeSearchManager : public SearchManager
Q_OBJECT
public:
explicit FakeSearchManager(QObject *parent = nullptr);
explicit FakeSearchManager(FakeAkonadiServer &akonadi);
~FakeSearchManager() override;
void registerInstance(const QString &id) override;
......
......@@ -210,16 +210,14 @@ bool AkonadiServer::init()
Tracer::self();
new DebugInterface(this);
ResourceManager::self();
CollectionStatistics::self();
// Initialize the preprocessor manager
PreprocessorManager::init();
mResourceManager = std::make_unique<ResourceManager>();
mCollectionStats = std::make_unique<CollectionStatistics>();
mPreprocessorManager = std::make_unique<PreprocessorManager>();
// Forcibly disable it if configuration says so
if (settings.value(QStringLiteral("General/DisablePreprocessing"), false).toBool()) {
PreprocessorManager::instance()->setEnabled(false);
mPreprocessorManager->setEnabled(false);
}
if (settings.value(QStringLiteral("Cache/EnableCleaner"), true).toBool()) {
......@@ -227,13 +225,13 @@ bool AkonadiServer::init()
}
mIntervalCheck = std::make_unique<IntervalCheck>();
mStorageJanitor = std::make_unique<StorageJanitor>();
mStorageJanitor = std::make_unique<StorageJanitor>(*this);
mItemRetrieval = std::make_unique<ItemRetrievalManager>();
mAgentSearchManager = std::make_unique<SearchTaskManager>();
const QStringList searchManagers = settings.value(QStringLiteral("Search/Manager"),
QStringList() << QStringLiteral("Agent")).toStringList();
mSearchManager = std::make_unique<SearchManager>(searchManagers);
mSearchManager = std::make_unique<SearchManager>(searchManagers, *this);
new ServerAdaptor(this);
QDBusConnection::sessionBus().registerObject(QStringLiteral("/Server"), this);
......@@ -283,6 +281,7 @@ bool AkonadiServer::quit()
mConnections.clear();
qCDebug(AKONADISERVER_LOG) << "terminating service threads";
mResourceManager.reset();
mCacheCleaner.reset();
mIntervalCheck.reset();
mStorageJanitor.reset();
......@@ -290,10 +289,8 @@ bool AkonadiServer::quit()
mAgentSearchManager.reset();
mSearchManager.reset();
mNotificationManager.reset();
// Terminate the preprocessor manager before the database but after all connections are gone
PreprocessorManager::done();
CollectionStatistics::destroy();
mCollectionStats.reset();
mPreprocessorManager.reset();
if (DbConfig::isConfigured()) {
if (DataStore::hasDataStore()) {
......@@ -415,11 +412,36 @@ IntervalCheck *AkonadiServer::intervalChecker()
return mIntervalCheck.get();
}
ResourceManager &AkonadiServer::resourceManager()
{
return *mResourceManager.get();
}
NotificationManager *AkonadiServer::notificationManager()
{
return mNotificationManager.get();
}
CollectionStatistics &AkonadiServer::collectionStatistics()
{
return *mCollectionStats.get();
}
PreprocessorManager &AkonadiServer::preprocessorManager()
{
return *mPreprocessorManager.get();
}
SearchTaskManager &AkonadiServer::agentSearchManager()
{
return *mAgentSearchManager.get();
}
SearchManager &AkonadiServer::searchManager()
{
return *mSearchManager.get();
}
QString AkonadiServer::serverPath() const
{
return StandardDirs::saveDir("config");
......
......@@ -25,6 +25,8 @@
#include <memory>
#include <shared/akoptional.h>
class QProcess;
class QDBusServiceWatcher;
......@@ -42,6 +44,9 @@ class CacheCleaner;
class IntervalCheck;
class AkLocalServer;
class NotificationManager;
class ResourceManager;
class CollectionStatistics;
class PreprocessorManager;
class AkonadiServer : public QObject
{
......@@ -61,6 +66,16 @@ public:
*/
IntervalCheck *intervalChecker();
ResourceManager &resourceManager();
CollectionStatistics &collectionStatistics();
PreprocessorManager &preprocessorManager();
SearchTaskManager &agentSearchManager();
SearchManager &searchManager();
/**
* Instance-aware server .config directory
*/
......@@ -98,6 +113,9 @@ protected:
std::unique_ptr<AkLocalServer> mCmdServer;
std::unique_ptr<AkLocalServer> mNtfServer;
std::unique_ptr<ResourceManager> mResourceManager;
std::unique_ptr<CollectionStatistics> mCollectionStats;
std::unique_ptr<PreprocessorManager> mPreprocessorManager;
std::unique_ptr<NotificationManager> mNotificationManager;
std::unique_ptr<CacheCleaner> mCacheCleaner;
std::unique_ptr<IntervalCheck> mIntervalCheck;
......
......@@ -121,7 +121,7 @@ bool CollectionCreateHandler::parseStream()
db->activeCachePolicy(collection);
sendResponse<Protocol::FetchCollectionsResponse>(
HandlerHelper::fetchCollectionsResponse(collection));
HandlerHelper::fetchCollectionsResponse(akonadi(), collection));
return successResponse<Protocol::CreateCollectionResponse>();
}
......@@ -113,7 +113,7 @@ void CollectionFetchHandler::listCollection(const Collection &root,
Collection dummy = root;
storageBackend()->activeCachePolicy(dummy);
sendResponse(HandlerHelper::fetchCollectionsResponse(dummy, attributes, mIncludeStatistics,
sendResponse(HandlerHelper::fetchCollectionsResponse(akonadi(), dummy, attributes, mIncludeStatistics,
mAncestorDepth, ancestors,
ancestorAttributes,
mimeTypes));
......
......@@ -20,7 +20,9 @@
#include "collectionstatsfetchhandler.h"
#include "connection.h"
#include "global.h"
#include "handlerhelper.h"
#include "akonadi.h"
#include "storage/datastore.h"
#include "storage/collectionstatistics.h"
......@@ -42,7 +44,7 @@ bool CollectionStatsFetchHandler::parseStream()
return failureResponse(QStringLiteral("No status for this folder"));
}
const CollectionStatistics::Statistics stats = CollectionStatistics::self()->statistics(col);
const auto stats = akonadi().collectionStatistics().statistics(col);
if (stats.count == -1) {
return failureResponse(QStringLiteral("Failed to query statistics."));
}
......
......@@ -20,6 +20,7 @@
#include "itemcreatehandler.h"
#include "itemfetchhelper.h"
#include "akonadi.h"
#include "connection.h"
#include "preprocessormanager.h"
#include "handlerhelper.h"
......@@ -141,7 +142,7 @@ bool ItemCreateHandler::insertItem(const Protocol::CreateItemCommand &cmd, PimIt
}
// Preprocessing
if (PreprocessorManager::instance()->isActive()) {
if (akonadi().preprocessorManager().isActive()) {
Part hiddenAttribute;
hiddenAttribute.setPimItemId(item.id());
hiddenAttribute.setPartType(PartTypeHelper::fromFqName(QStringLiteral(AKONADI_ATTRIBUTE_HIDDEN)));
......@@ -346,9 +347,9 @@ bool ItemCreateHandler::notify(const PimItem &item, bool seen, const Collection
{
storageBackend()->notificationCollector()->itemAdded(item, seen, collection);
if (PreprocessorManager::instance()->isActive()) {
if (akonadi().preprocessorManager().isActive()) {
// enqueue the item for preprocessing
PreprocessorManager::instance()->beginHandleItem(item, storageBackend());
akonadi().preprocessorManager().beginHandleItem(item, storageBackend());
}
return true;
}
......
......@@ -85,6 +85,6 @@ bool SearchCreateHandler::parseStream()
SearchManager::instance()->updateSearch(col);
sendResponse(HandlerHelper::fetchCollectionsResponse(col));
sendResponse(HandlerHelper::fetchCollectionsResponse(akonadi(), col));
return successResponse<Protocol::StoreSearchResponse>();
}
......@@ -19,9 +19,11 @@
#include "searchhandler.h"
#include "akonadi.h"
#include "connection.h"
#include "itemfetchhelper.h"
#include "handlerhelper.h"
#include "search/agentsearchengine.h"
#include "searchhelper.h"
#include "search/searchrequest.h"
#include "search/searchmanager.h"
......@@ -69,7 +71,7 @@ bool SearchHandler::parseStream()
mItemFetchScope = cmd.itemFetchScope();
mTagFetchScope = cmd.tagFetchScope();
SearchRequest request(connection()->sessionId());
SearchRequest request(connection()->sessionId(), akonadi().agentSearchManager());
request.setCollections(collections);
request.setMimeTypes(cmd.mimeTypes());
request.setQuery(cmd.query());
......
......@@ -20,6 +20,7 @@
#include "searchresulthandler.h"
#include "connection.h"
#include "akonadi.h"
#include "storage/querybuilder.h"
#include "storage/itemqueryhelper.h"
#include "search/searchtaskmanager.h"
......@@ -67,13 +68,13 @@ bool SearchResultHandler::parseStream()
}
}
}
SearchTaskManager::instance()->pushResults(cmd.searchId(), ids, connection());
akonadi().agentSearchManager().pushResults(cmd.searchId(), ids, connection());
return successResponse<Protocol::SearchResultResponse>();
}
bool SearchResultHandler::fail(const QByteArray &searchId, const QString &error)
{
SearchTaskManager::instance()->pushResults(searchId, QSet<qint64>(), connection());
akonadi().agentSearchManager().pushResults(searchId, QSet<qint64>(), connection());
return failureResponse(error);
}
......@@ -28,6 +28,7 @@
#include "handler.h"
#include "connection.h"
#include "utils.h"
#include "akonadi.h"
#include <private/imapset_p.h>
#include <private/scope_p.h>
......@@ -94,7 +95,8 @@ Protocol::CachePolicy HandlerHelper::cachePolicyResponse(const Collection &col)
return cachePolicy;
}
Protocol::FetchCollectionsResponse HandlerHelper::fetchCollectionsResponse(const Collection &col)
Protocol::FetchCollectionsResponse HandlerHelper::fetchCollectionsResponse(
AkonadiServer &akonadi, const Collection &col)
{
QStringList mimeTypes;
mimeTypes.reserve(col.mimeTypes().size());
......@@ -102,11 +104,13 @@ Protocol::FetchCollectionsResponse HandlerHelper::fetchCollectionsResponse(const
mimeTypes << mt.name();
}
return fetchCollectionsResponse(col, col.attributes(), false, 0, QStack<Collection>(),
return fetchCollectionsResponse(akonadi, col, col.attributes(), false, 0, QStack<Collection>(),
QStack<CollectionAttribute::List>(), mimeTypes);
}
Protocol::FetchCollectionsResponse HandlerHelper::fetchCollectionsResponse(const Collection &col,
Protocol::FetchCollectionsResponse HandlerHelper::fetchCollectionsResponse(
AkonadiServer &akonadi,
const Collection &col,
const CollectionAttribute::List &attrs,
bool includeStatistics,
int ancestorDepth,
......@@ -125,7 +129,7 @@ Protocol::FetchCollectionsResponse HandlerHelper::fetchCollectionsResponse(const
response.setIsVirtual(col.isVirtual());
if (includeStatistics) {
const CollectionStatistics::Statistics stats = CollectionStatistics::self()->statistics(col);
const auto stats = akonadi.collectionStatistics().statistics(col);
if (stats.count > -1) {
Protocol::FetchCollectionStatsResponse statsResponse;
statsResponse.setCount(stats.count);
......
......@@ -49,6 +49,7 @@ namespace Server
class CommandContext;
class Connection;
class AkonadiServer;
/**
Helper functions for command handlers.
......@@ -77,14 +78,15 @@ public:
Make sure DataStore::activeCachePolicy() has been called before to include
the effective cache policy
*/
static Protocol::FetchCollectionsResponse fetchCollectionsResponse(const Collection &col);
static Protocol::FetchCollectionsResponse fetchCollectionsResponse(AkonadiServer &akonadi, const Collection &col);
/**
Returns the protocol representation of the given collection.
Make sure DataStore::activeCachePolicy() has been called before to include
the effective cache policy
*/
static Protocol::FetchCollectionsResponse fetchCollectionsResponse(const Collection &col,
static Protocol::FetchCollectionsResponse fetchCollectionsResponse(AkonadiServer &akonadi,
const Collection &col,
const CollectionAttribute::List &attributeList,
bool includeStatistics = false,
int ancestorDepth = 0,
......
......@@ -40,8 +40,9 @@
using namespace Akonadi;
using namespace Akonadi::Server;
PreprocessorInstance::PreprocessorInstance(const QString &id)
PreprocessorInstance::PreprocessorInstance(const QString &id, PreprocessorManager &manager)
: QObject()
, mManager(manager)
, mId(id)
{
Q_ASSERT(!id.isEmpty());
......@@ -111,8 +112,7 @@ void PreprocessorInstance::processHeadItem()
while (!actualItem.isValid()) {
// hum... item is gone ?
// FIXME: Signal to the manager that the item is no longer valid!
PreprocessorManager::instance()->preProcessorFinishedHandlingItem(this, itemId);
mManager.preProcessorFinishedHandlingItem(this, itemId);
mItemQueue.pop_front();
if (mItemQueue.empty()) {
......@@ -231,7 +231,7 @@ void PreprocessorInstance::itemProcessed(qlonglong id)
mItemQueue.pop_front();
PreprocessorManager::instance()->preProcessorFinishedHandlingItem(this, itemId);
mManager.preProcessorFinishedHandlingItem(this, itemId);
if (mItemQueue.empty()) {
// Nothing more to do
......
......@@ -37,6 +37,7 @@ namespace Akonadi
namespace Server
{
class PreprocessorManager;
class AgentInstance;
/**
......@@ -59,7 +60,7 @@ protected:
/**
* Create an instance of a PreprocessorInstance descriptor.
*/
PreprocessorInstance(const QString &id);
PreprocessorInstance(const QString &id, PreprocessorManager &manager);
public: // This is public only for qDeleteAll() called from PreprocessorManager
// ...for some reason couldn't convince gcc to have it as friend...
......@@ -70,6 +71,7 @@ public: // This is public only for qDeleteAll() called from PreprocessorManager
~PreprocessorInstance();
private:
PreprocessorManager &mManager;
/**
* The internal queue if item identifiers.
......
......@@ -55,14 +55,11 @@ const int gDeadlineItemProcessingTimeInSecs = 240;
using namespace Akonadi::Server;
// The one and only PreprocessorManager object
PreprocessorManager *PreprocessorManager::mSelf = nullptr;
PreprocessorManager::PreprocessorManager()
: QObject()
, mEnabled(true)
, mMutex(new QMutex())
{
mSelf = this; // just to have it set early
// Hook in our D-Bus interface "shell".
new PreprocessorManagerAdaptor(this);
......@@ -92,21 +89,6 @@ PreprocessorManager::~PreprocessorManager()
delete mMutex;
}
bool PreprocessorManager::init()
{
if (mSelf) {
return false;
}
mSelf = new PreprocessorManager();
return true;
}
void PreprocessorManager::done()
{
delete mSelf;
mSelf = nullptr;
}
bool PreprocessorManager::isActive()
{
QMutexLocker locker(mMutex);
......@@ -143,7 +125,7 @@ void PreprocessorManager::registerInstance(const QString &id)
// TODO: Maybe we need some kind of ordering here ?
// In that case we'll need to fiddle with the items that are currently enqueued for processing...
instance = new PreprocessorInstance(id);
instance = new PreprocessorInstance(id, *this);
if (!instance->init()) {
Tracer::self()->warning(
QStringLiteral("PreprocessorManager"),
......
......@@ -76,25 +76,6 @@ class PreprocessorManager : public QObject
Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Akonadi.PreprocessorManager")
protected:
/**
* Creates an instance of PreprocessorManager
*/
PreprocessorManager();
/**
* Destroys the instance of PreprocessorManager
* and frees all the relevant resources
*/
~PreprocessorManager();
protected:
/**
* The one and only instance pointer for the class PreprocessorManager
*/
static PreprocessorManager *mSelf;
/**
* The hashtable of transaction wait queues. There is one wait
* queue for each DataStore that is currently in a transaction.
......@@ -129,38 +110,16 @@ protected:
QTimer *mHeartbeatTimer = nullptr;
public:
/**
* Returns the one and only instance pointer for the class PreprocessorManager
* The returned pointer is valid only after a successful call to init().
*
* \sa init()
* \sa done()
*/
static PreprocessorManager *instance()
{
return mSelf;
}
/**
* Initializes this class singleton by creating its one and only instance.
* This is actually called in the AkonadiServer constructor.
*
* The instance is later available via the static instance() method.
* You must call done() when you've finished using this class services.
* Returns true upon successful initialisation and false when the initialization fails.
*
* \sa done()
* Creates an instance of PreprocessorManager
*/
static bool init();
explicit PreprocessorManager();
/**
* Deinitializes this class singleton (if it was initialized at all).
* This is actually called in the AkonadiServer::quit() method.
*
* \sa init()
* Destroys the instance of PreprocessorManager
* and frees all the relevant resources
*/
static void done();
~PreprocessorManager();
/**
* Returns true if preprocessing is active in this Akonadi server.
......
......@@ -31,10 +31,8 @@
using namespace Akonadi::Server;
using namespace AkRanges;
ResourceManager *ResourceManager::mSelf = nullptr;
ResourceManager::ResourceManager(QObject *parent)
: QObject(parent)
ResourceManager::ResourceManager()
: QObject()
{
new ResourceManagerAdaptor(this);
QDBusConnection::sessionBus().registerObject(QStringLiteral("/ResourceManager"), this);
......@@ -77,10 +75,3 @@ QStringList ResourceManager::resourceInstances() const
return Resource::retrieveAll() | Views::transform(&Resource::name) | Actions::toQList;
}
ResourceManager *ResourceManager::self()
{
if (!mSelf) {
mSelf = new ResourceManager();
}
return mSelf;
}
......@@ -36,18 +36,12 @@ class ResourceManager : public QObject
Q_OBJECT
public:
static ResourceManager *self();
private:
explicit ResourceManager(QObject *parent = nullptr);
explicit ResourceManager();
public Q_SLOTS:
void addResourceInstance(const QString &name, const QStringList &capabilities);
void removeResourceInstance(const QString &name);
QStringList resourceInstances() const;
private:
static ResourceManager *mSelf;
};
} // namespace Server
......
Markdown is supported
0% or .