Commit 606a973d authored by Daniel Vrátil's avatar Daniel Vrátil 🤖
Browse files

Desingletonize event more server classes

parent 403afb55
......@@ -46,7 +46,7 @@ private Q_SLOTS:
void shouldInitializeSyncIntervals()
{
// WHEN
FakeIntervalCheck sched;
FakeIntervalCheck sched(mAkonadi);
sched.waitForInit();
const TimePoint now(std::chrono::steady_clock::now());
// THEN
......@@ -66,7 +66,7 @@ private Q_SLOTS:
void shouldObeyMinimumInterval()
{
// GIVEN
FakeIntervalCheck sched;
FakeIntervalCheck sched(mAkonadi);
// WHEN
sched.setMinimumInterval(10);
sched.waitForInit();
......@@ -82,7 +82,7 @@ private Q_SLOTS:
void shouldRemoveAndAddCollectionFromSchedule()
{
// GIVEN
FakeIntervalCheck sched;
FakeIntervalCheck sched(mAkonadi);
sched.waitForInit();
const auto timeForRoot = sched.nextScheduledTime(1);
const auto timeForColB = sched.nextScheduledTime(3);
......@@ -112,7 +112,7 @@ private Q_SLOTS:
void shouldHonourIntervalChange()
{
// GIVEN
FakeIntervalCheck sched;
FakeIntervalCheck sched(mAkonadi);
sched.waitForInit();
const auto timeForColB = sched.nextScheduledTime(3);
Collection colA = Collection::retrieveByName(QStringLiteral("Collection A"));
......
......@@ -227,10 +227,10 @@ void FakeAkonadiServer::initFake()
mCollectionStats = std::make_unique<CollectionStatistics>();
if (!mDisableItemRetrievalManager) {
mRetrievalManager = std::make_unique<FakeItemRetrievalManager>();
mItemRetrieval = std::make_unique<FakeItemRetrievalManager>();
}
mIntervalCheck = std::make_unique<FakeIntervalCheck>();
mIntervalCheck = std::make_unique<FakeIntervalCheck>(*this);
qDebug() << "==== Fake Akonadi Server started ====";
}
......@@ -253,7 +253,10 @@ bool FakeAkonadiServer::quit()
mPreprocessorManager.reset();
mCollectionStats.reset();
(void)SearchManager::instance();
mSearchManager.reset();
mCollectionStats.reset();
mItemRetrieval.reset();
mIntervalCheck.reset();
if (mDataStore) {
mDataStore->close();
......
......@@ -114,10 +114,8 @@ private:
void initFake();
FakeDataStore *mDataStore = nullptr;
std::unique_ptr<FakeSearchManager> mSearchManager;
std::unique_ptr<FakeConnection> mConnection;
std::unique_ptr<FakeClient> mClient;
std::unique_ptr<FakeItemRetrievalManager> mRetrievalManager;
InspectableNotificationCollector *mNtfCollector = nullptr;
......
......@@ -18,11 +18,12 @@
*/
#include "fakeintervalcheck.h"
#include "fakeakonadiserver.h"
using namespace Akonadi::Server;
FakeIntervalCheck::FakeIntervalCheck(QObject *parent)
: IntervalCheck(parent)
FakeIntervalCheck::FakeIntervalCheck(FakeAkonadiServer &akonadi)
: IntervalCheck(akonadi)
{
}
......
......@@ -27,11 +27,13 @@
namespace Akonadi {
namespace Server {
class FakeAkonadiServer;
class FakeIntervalCheck : public IntervalCheck
{
Q_OBJECT
public:
FakeIntervalCheck(QObject *parent = nullptr);
FakeIntervalCheck(FakeAkonadiServer &akonadi);
void waitForInit();
protected:
......
......@@ -25,15 +25,10 @@ using namespace Akonadi::Server;
FakeItemRetrievalManager::FakeItemRetrievalManager()
: ItemRetrievalManager()
{
sInstance = this;
qRegisterMetaType<ItemRetrievalRequest*>("ItemRetrievalRequest*");
}
FakeItemRetrievalManager::~FakeItemRetrievalManager()
{
sInstance = nullptr;
}
FakeItemRetrievalManager::~FakeItemRetrievalManager() = default;
void FakeItemRetrievalManager::requestItemDelivery(ItemRetrievalRequest *request)
{
......
......@@ -151,15 +151,15 @@ using RequestedParts = QVector<QByteArray /* FQ name */>;
class ClientThread : public QThread
{
public:
ClientThread(Entity::Id itemId, const RequestedParts &requestedParts)
: m_itemId(itemId), m_requestedParts(requestedParts)
ClientThread(Entity::Id itemId, const RequestedParts &requestedParts, ItemRetrievalManager &manager)
: m_itemId(itemId), m_requestedParts(requestedParts), m_manager(manager)
{}
void run() override
{
// ItemRetriever should...
CommandContext context;
ItemRetriever retriever(nullptr, context);
ItemRetriever retriever(m_manager, nullptr, context);
retriever.setItem(m_itemId);
retriever.setRetrieveParts(m_requestedParts);
QSignalSpy spy(&retriever, &ItemRetriever::itemsRetrieved);
......@@ -188,6 +188,7 @@ public:
private:
const Entity::Id m_itemId;
const RequestedParts m_requestedParts;
ItemRetrievalManager &m_manager;
mutable QMutex m_mutex; // protects results below
Results m_results;
......@@ -215,7 +216,7 @@ private Q_SLOTS:
void testFullPayload()
{
CommandContext context;
ItemRetriever r1(nullptr, context);
ItemRetriever r1(mAkonadi.itemRetrievalManager(), nullptr, context);
r1.setRetrieveFullPayload(true);
QCOMPARE(r1.retrieveParts().size(), 1);
QCOMPARE(r1.retrieveParts().at(0), { "PLD:RFC822" });
......@@ -313,7 +314,7 @@ private Q_SLOTS:
}
if (step == 0) {
ClientThread thread(item.id(), requestedParts);
ClientThread thread(item.id(), requestedParts, mgr);
thread.run();
const ClientThread::Results results = thread.results();
......@@ -332,7 +333,7 @@ private Q_SLOTS:
} else {
QVector<ClientThread *> threads;
for (int i = 0; i < 20; ++i) {
threads.append(new ClientThread(item.id(), requestedParts));
threads.append(new ClientThread(item.id(), requestedParts, mgr));
}
for (int i = 0; i < threads.size(); ++i) {
threads.at(i)->start();
......
......@@ -224,7 +224,7 @@ bool AkonadiServer::init()
mCacheCleaner = std::make_unique<CacheCleaner>();
}
mIntervalCheck = std::make_unique<IntervalCheck>();
mIntervalCheck = std::make_unique<IntervalCheck>(*this);
mStorageJanitor = std::make_unique<StorageJanitor>(*this);
mItemRetrieval = std::make_unique<ItemRetrievalManager>();
mAgentSearchManager = std::make_unique<SearchTaskManager>();
......@@ -442,6 +442,11 @@ SearchManager &AkonadiServer::searchManager()
return *mSearchManager.get();
}
ItemRetrievalManager &AkonadiServer::itemRetrievalManager()
{
return *mItemRetrieval.get();
}
QString AkonadiServer::serverPath() const
{
return StandardDirs::saveDir("config");
......
......@@ -76,6 +76,8 @@ public:
SearchManager &searchManager();
ItemRetrievalManager &itemRetrievalManager();
/**
* Instance-aware server .config directory
*/
......
......@@ -19,6 +19,7 @@
#include "collectioncopyhandler.h"
#include "akonadi.h"
#include "connection.h"
#include "handler/itemcopyhandler.h"
#include "handlerhelper.h"
......@@ -99,7 +100,7 @@ bool CollectionCopyHandler::parseStream()
CacheCleanerInhibitor inhibitor(akonadi());
// retrieve all not yet cached items of the source
ItemRetriever retriever(connection(), connection()->context());
ItemRetriever retriever(akonadi().itemRetrievalManager(), connection(), connection()->context());
retriever.setCollection(source, true);
retriever.setRetrieveFullPayload(true);
if (!retriever.exec()) {
......
......@@ -57,7 +57,7 @@ bool CollectionModifyHandler::parseStream()
if (newParent.isValid() && collection.parentId() != newParent.id()
&& collection.resourceId() != newParent.resourceId()) {
inhibitor.inhibit();
ItemRetriever retriever(connection(), connection()->context());
ItemRetriever retriever(akonadi().itemRetrievalManager(), connection(), connection()->context());
retriever.setCollection(collection, true);
retriever.setRetrieveFullPayload(true);
if (!retriever.exec()) {
......@@ -288,7 +288,7 @@ bool CollectionModifyHandler::parseStream()
// Only request Search update AFTER committing the transaction to avoid
// transaction deadlock with SQLite
if (changes.contains(AKONADI_PARAM_PERSISTENTSEARCH)) {
SearchManager::instance()->updateSearch(collection);
akonadi().searchManager().updateSearch(collection);
}
}
......
......@@ -19,6 +19,7 @@
#include "collectionmovehandler.h"
#include "akonadi.h"
#include "handlerhelper.h"
#include "connection.h"
#include "cachecleaner.h"
......@@ -60,7 +61,7 @@ bool CollectionMoveHandler::parseStream()
CacheCleanerInhibitor inhibitor(akonadi());
// retrieve all not yet cached items of the source
ItemRetriever retriever(connection(), connection()->context());
ItemRetriever retriever(akonadi().itemRetrievalManager(), connection(), connection()->context());
retriever.setCollection(source, true);
retriever.setRetrieveFullPayload(true);
if (!retriever.exec()) {
......
......@@ -19,6 +19,7 @@
#include "itemcopyhandler.h"
#include "akonadi.h"
#include "connection.h"
#include "handlerhelper.h"
#include "cachecleaner.h"
......@@ -115,7 +116,7 @@ bool ItemCopyHandler::parseStream()
CacheCleanerInhibitor inhibitor(akonadi());
ItemRetriever retriever(connection(), connection()->context());
ItemRetriever retriever(akonadi().itemRetrievalManager(), connection(), connection()->context());
retriever.setItemSet(cmd.items().uidSet());
retriever.setRetrieveFullPayload(true);
QObject::connect(&retriever, &ItemRetriever::itemsRetrieved,
......
......@@ -335,7 +335,7 @@ bool ItemCreateHandler::sendResponse(const PimItem &item, Protocol::CreateItemCo
Scope scope;
scope.setUidSet(set);
ItemFetchHelper fetchHelper(connection(), scope, fetchScope, Protocol::TagFetchScope{});
ItemFetchHelper fetchHelper(connection(), scope, fetchScope, Protocol::TagFetchScope{}, akonadi());
if (!fetchHelper.fetchItems()) {
return failureResponse("Failed to retrieve item");
}
......@@ -405,16 +405,12 @@ void ItemCreateHandler::recoverFromMultipleMergeCandidates(const PimItem::List &
return;
}
// Schedule a new sync of the collection, one that will succeed
const auto resource = collection.resource().name();
QMetaObject::invokeMethod(ItemRetrievalManager::instance(), "triggerCollectionSync",
Qt::QueuedConnection,
Q_ARG(QString, resource), Q_ARG(qint64, collection.id()));
akonadi().itemRetrievalManager().triggerCollectionSync(collection.resource().name(), collection.id());
qCInfo(AKONADISERVER_LOG) << "Automatic multiple merge candidates recovery successful: conflicting items" << (items | Views::transform([](const auto &i) { return i.id(); }) | Actions::toQVector)
<< "in collection" << collection.name() << "(ID:" << collection.id() << ") were removed and a new sync was scheduled in the resource"
<< resource;
<< collection.resource().name();
}
bool ItemCreateHandler::parseStream()
......
......@@ -46,7 +46,7 @@ bool ItemFetchHandler::parseStream()
CacheCleanerInhibitor inhibitor(akonadi());
ItemFetchHelper fetchHelper(connection(), context, cmd.scope(), cmd.itemFetchScope(), cmd.tagFetchScope());
ItemFetchHelper fetchHelper(connection(), context, cmd.scope(), cmd.itemFetchScope(), cmd.tagFetchScope(), akonadi());
if (!fetchHelper.fetchItems()) {
return failureResponse(QStringLiteral("Failed to fetch items"));
}
......
......@@ -73,8 +73,9 @@ using namespace AkRanges;
ItemFetchHelper::ItemFetchHelper(Connection *connection, const Scope &scope,
const Protocol::ItemFetchScope &itemFetchScope,
const Protocol::TagFetchScope &tagFetchScope)
: ItemFetchHelper(connection, connection->context(), scope, itemFetchScope, tagFetchScope)
const Protocol::TagFetchScope &tagFetchScope,
AkonadiServer &akonadi)
: ItemFetchHelper(connection, connection->context(), scope, itemFetchScope, tagFetchScope, akonadi)
{
}
......@@ -82,12 +83,14 @@ ItemFetchHelper::ItemFetchHelper(Connection *connection, const Scope &scope,
ItemFetchHelper::ItemFetchHelper(Connection *connection, const CommandContext &context,
const Scope &scope,
const Protocol::ItemFetchScope &itemFetchScope,
const Protocol::TagFetchScope &tagFetchScope)
const Protocol::TagFetchScope &tagFetchScope,
AkonadiServer &akonadi)
: mConnection(connection)
, mContext(context)
, mScope(scope)
, mItemFetchScope(itemFetchScope)
, mTagFetchScope(tagFetchScope)
, mAkonadi(akonadi)
{
std::fill(mItemQueryColumnMap, mItemQueryColumnMap + ItemQueryColumnCount, -1);
}
......@@ -359,7 +362,7 @@ bool ItemFetchHelper::fetchItems(std::function<void(Protocol::FetchItemsResponse
// Prepare for a call to ItemRetriever::exec();
// From a resource perspective the only parts that can be fetched are payloads.
ItemRetriever retriever(mConnection, mContext);
ItemRetriever retriever(mAkonadi.itemRetrievalManager(), mConnection, mContext);
retriever.setScope(mScope);
retriever.setRetrieveParts(mItemFetchScope.requestedPayloads());
retriever.setRetrieveFullPayload(mItemFetchScope.fullPayload());
......
......@@ -42,16 +42,19 @@ namespace Server
class AggregatedItemFetchScope;
class Connection;
class AkonadiServer;
class ItemFetchHelper
{
public:
ItemFetchHelper(Connection *connection, const Scope &scope,
const Protocol::ItemFetchScope &itemFetchScope,
const Protocol::TagFetchScope &tagFagScope);
const Protocol::TagFetchScope &tagFagScope,
AkonadiServer &akonadi);
ItemFetchHelper(Connection *connection, const CommandContext &context, const Scope &scope,
const Protocol::ItemFetchScope &itemFetchScope,
const Protocol::TagFetchScope &tagFetchScope);
const Protocol::TagFetchScope &tagFetchScope,
AkonadiServer &akonadi);
bool fetchItems(std::function<void(Protocol::FetchItemsResponse &&)> &&callback = {});
......@@ -96,6 +99,7 @@ private:
Protocol::TagFetchScope mTagFetchScope;
int mItemQueryColumnMap[ItemQueryColumnCount];
bool mUpdateATimeEnabled = true;
AkonadiServer &mAkonadi;
friend class ::ItemFetchHelperTest;
};
......
......@@ -19,10 +19,12 @@
#include "itemmovehandler.h"
#include "akonadi.h"
#include "connection.h"
#include "handlerhelper.h"
#include "cachecleaner.h"
#include "storage/datastore.h"
#include "storage/itemretrievalmanager.h"
#include "storage/itemretriever.h"
#include "storage/itemqueryhelper.h"
#include "storage/selectquerybuilder.h"
......@@ -159,7 +161,7 @@ bool ItemMoveHandler::parseStream()
CacheCleanerInhibitor inhibitor(akonadi());
// make sure all the items we want to move are in the cache
ItemRetriever retriever(connection(), context);
ItemRetriever retriever(akonadi().itemRetrievalManager(), connection(), context);
retriever.setScope(cmd.items());
retriever.setRetrieveFullPayload(true);
QObject::connect(&retriever, &ItemRetriever::itemsRetrieved,
......
......@@ -20,6 +20,7 @@
#include "searchcreatehandler.h"
#include "akonadi.h"
#include "connection.h"
#include "handlerhelper.h"
#include "storage/datastore.h"
......@@ -83,7 +84,7 @@ bool SearchCreateHandler::parseStream()
return failureResponse("Unable to commit transaction");
}
SearchManager::instance()->updateSearch(col);
akonadi().searchManager().updateSearch(col);
sendResponse(HandlerHelper::fetchCollectionsResponse(akonadi(), col));
return successResponse<Protocol::StoreSearchResponse>();
......
......@@ -71,7 +71,7 @@ bool SearchHandler::parseStream()
mItemFetchScope = cmd.itemFetchScope();
mTagFetchScope = cmd.tagFetchScope();
SearchRequest request(connection()->sessionId(), akonadi().agentSearchManager());
SearchRequest request(connection()->sessionId(), akonadi());
request.setCollections(collections);
request.setMimeTypes(cmd.mimeTypes());
request.setQuery(cmd.query());
......@@ -104,6 +104,6 @@ void SearchHandler::processResults(const QSet<qint64> &results)
Scope scope;
scope.setUidSet(imapSet);
ItemFetchHelper fetchHelper(connection(), scope, mItemFetchScope, mTagFetchScope);
ItemFetchHelper fetchHelper(connection(), scope, mItemFetchScope, mTagFetchScope, akonadi());
fetchHelper.fetchItems();
}
......@@ -19,6 +19,7 @@
*/
#include "intervalcheck.h"
#include "akonadi.h"
#include "storage/datastore.h"
#include "storage/itemretrievalmanager.h"
#include "storage/entity.h"
......@@ -28,8 +29,9 @@ using namespace Akonadi::Server;
static const int MINIMUM_AUTOSYNC_INTERVAL = 5; // minutes
static const int MINIMUM_COLTREESYNC_INTERVAL = 5; // minutes
IntervalCheck::IntervalCheck(QObject *parent)
: CollectionScheduler(QStringLiteral("IntervalCheck"), QThread::IdlePriority, parent)
IntervalCheck::IntervalCheck(AkonadiServer &akonadi)
: CollectionScheduler(QStringLiteral("IntervalCheck"), QThread::IdlePriority)
, mAkonadi(akonadi)
{
}
......@@ -73,9 +75,7 @@ void IntervalCheck::collectionExpired(const Collection &collection)
const QDateTime lastExpectedCheck = now.addSecs(interval * -60);
if (!mLastCollectionTreeSyncs.contains(resourceName) || mLastCollectionTreeSyncs.value(resourceName) < lastExpectedCheck) {
mLastCollectionTreeSyncs.insert(resourceName, now);
QMetaObject::invokeMethod(ItemRetrievalManager::instance(), "triggerCollectionTreeSync",
Qt::QueuedConnection,
Q_ARG(QString, resourceName));
mAkonadi.itemRetrievalManager().triggerCollectionTreeSync(resourceName);
}
}
......@@ -87,8 +87,5 @@ void IntervalCheck::collectionExpired(const Collection &collection)
return;
}
mLastChecks.insert(collection.id(), now);
QMetaObject::invokeMethod(ItemRetrievalManager::instance(), "triggerCollectionSync",
Qt::QueuedConnection,
Q_ARG(QString, collection.resource().name()),
Q_ARG(qint64, collection.id()));
mAkonadi.itemRetrievalManager().triggerCollectionSync(collection.resource().name(), collection.id());
}
......@@ -30,6 +30,8 @@ namespace Akonadi
namespace Server
{
class AkonadiServer;
/**
Interval checking thread.
*/
......@@ -38,7 +40,7 @@ class IntervalCheck : public CollectionScheduler
Q_OBJECT
public:
explicit IntervalCheck(QObject *parent = nullptr);
explicit IntervalCheck(AkonadiServer &akonadi);
~IntervalCheck() override;
/**
......@@ -60,6 +62,7 @@ protected Q_SLOTS:
private:
QHash<int, QDateTime> mLastChecks;
QHash<QString, QDateTime> mLastCollectionTreeSyncs;
AkonadiServer &mAkonadi;
};
} // namespace Server
......
......@@ -48,8 +48,6 @@ Q_DECLARE_METATYPE(Akonadi::Server::NotificationCollector *)
using namespace Akonadi;
using namespace Akonadi::Server;
SearchManager *SearchManager::sInstance = nullptr;
Q_DECLARE_METATYPE(Collection)
SearchManager::SearchManager(const QStringList &searchEngines, AkonadiServer &akonadi)
......@@ -60,9 +58,6 @@ SearchManager::SearchManager(const QStringList &searchEngines, AkonadiServer &ak
{
qRegisterMetaType<Collection>();
Q_ASSERT(sInstance == nullptr);
sInstance = this;
// We load search plugins (as in QLibrary::load()) in the main thread so that
// static initialization happens in the QApplication thread
loadSearchPlugins();
......@@ -129,14 +124,6 @@ void SearchManager::quit()
SearchManager::~SearchManager()
{
quitThread();
sInstance = nullptr;
}
SearchManager *SearchManager::instance()
{
Q_ASSERT(sInstance);
return sInstance;
}
void SearchManager::registerInstance(const QString &id)
......@@ -311,7 +298,7 @@ void SearchManager::updateSearchImpl(const Collection &collection)
}
// Query all plugins for search results
SearchRequest request("searchUpdate-" + QByteArray::number(QDateTime::currentDateTimeUtc().toTime_t()), mAkonadi.agentSearchManager());
SearchRequest request("searchUpdate-" + QByteArray::number(QDateTime::currentDateTimeUtc().toTime_t()), mAkonadi);
request.setCollections(queryCollections);
request.setMimeTypes(queryMimeTypes);
request.setQuery(collection.queryString());
......
......@@ -57,11 +57,6 @@ public:
~SearchManager() override;
/**
* Returns a global instance of the search manager.
*/
static SearchManager *instance();
/**
* Updates the search query asynchronously. Returns immediately
*/
......@@ -112,8 +107,6 @@ private:
// Called from manager thread
void initSearchPlugins();
static SearchManager *sInstance;
AkonadiServer &mAkonadi;
QStringList mEngineNames;
QVector<QPluginLoader *> mPluginLoaders;
......
......@@ -20,6 +20,7 @@
#include "searchrequest.h"
#include "akonadi.h"
#include "searchtaskmanager.h"
#include "abstractsearchplugin.h"
#include "searchmanager.h"
......@@ -28,9 +29,9 @@
using namespace Akonadi::Server;
SearchRequest::SearchRequest(const QByteArray &connectionId, SearchTaskManager &searchTaskManager)
SearchRequest::SearchRequest(const QByteArray &connectionId, AkonadiServer &akonadi)
: mConnectionId(connectionId)
, mSearchTaskManager(searchTaskManager)
, mAkonadi(akonadi)
{
}
......@@ -103,7 +104,7 @@ void SearchRequest::emitResults(const QSet<qint64> &results)
void SearchRequest::searchPlugins()
{
const QVector<AbstractSearchPlugin *> plugins = SearchManager::instance()->searchPlugins();
const QVector<AbstractSearchPlugin *> plugins = mAkonadi.searchManager().searchPlugins();
for (AbstractSearchPlugin *plugin : plugins) {
const QSet<qint64> result = plugin->search(mQuery, mCollections, mMimeTypes);
emitResults(result);
......@@ -131,7 +132,7 @@ void SearchRequest::exec()
task.collections = mCollections;
task.complete = false;
mSearchTaskManager.addTask(&task);
mAkonadi.agentSearchManager().addTask(&task);