Akonadi

preprocessorinstance.cpp
1/******************************************************************************
2 *
3 * File : preprocessorinstance.cpp
4 * Creation date : Sat 18 Jul 2009 02:50:39
5 *
6 * SPDX-FileCopyrightText: 2009 Szymon Stefanek <s.stefanek at gmail dot com>
7 *
8 * SPDX-License-Identifier: LGPL-2.0-or-later
9 *
10 *****************************************************************************/
11
12#include "preprocessorinstance.h"
13#include "akonadiserver_debug.h"
14#include "preprocessorinterface.h"
15#include "preprocessormanager.h"
16
17#include "entities.h"
18
19#include "agentcontrolinterface.h"
20#include "agentmanagerinterface.h"
21
22#include "tracer.h"
23
24#include "private/dbus_p.h"
25
26using namespace Akonadi;
27using namespace Akonadi::Server;
28
30 : mManager(manager)
31 , mTracer(tracer)
32 , mId(id)
33{
34 Q_ASSERT(!id.isEmpty());
35}
36
38
40{
41 Q_ASSERT(!mBusy); // must be called very early
42 Q_ASSERT(!mInterface);
43
44 mInterface = new OrgFreedesktopAkonadiPreprocessorInterface(DBus::agentServiceName(mId, DBus::Preprocessor),
45 QStringLiteral("/Preprocessor"),
47 this);
48
49 if (!mInterface || !mInterface->isValid()) {
50 mTracer.warning(
51 QStringLiteral("PreprocessorInstance"),
52 QStringLiteral("Could not connect to pre-processor instance '%1': %2").arg(mId, mInterface ? mInterface->lastError().message() : QString()));
53 delete mInterface;
54 mInterface = nullptr;
55 return false;
56 }
57
58 QObject::connect(mInterface, &OrgFreedesktopAkonadiPreprocessorInterface::itemProcessed, this, &PreprocessorInstance::itemProcessed);
59
60 return true;
61}
62
64{
65 qCDebug(AKONADISERVER_LOG) << "PreprocessorInstance::enqueueItem(" << itemId << ")";
66
67 mItemQueue.push_back(itemId);
68
69 // If the preprocessor is already busy processing another item then do nothing.
70 if (mBusy) {
71 // The "head" item is the one being processed and we have just added another one.
72 Q_ASSERT(mItemQueue.size() > 1);
73 return;
74 }
75
76 // Not busy: handle the item.
77 processHeadItem();
78}
79
80void PreprocessorInstance::processHeadItem()
81{
82 // We shouldn't be called if there are no items in the queue
83 Q_ASSERT(!mItemQueue.empty());
84 // We shouldn't be here with no interface
85 Q_ASSERT(mInterface);
86
87 qint64 itemId = mItemQueue.front();
88
89 // Fetch the actual item data (as it may have changed since it was enqueued)
90 // The fetch will hit the cache if the item wasn't changed.
91
92 PimItem actualItem = PimItem::retrieveById(itemId);
93
94 while (!actualItem.isValid()) {
95 // hum... item is gone ?
97
98 mItemQueue.pop_front();
99 if (mItemQueue.empty()) {
100 // nothing more to process for this instance: jump out
101 mBusy = false;
102 return;
103 }
104
105 // try the next one in the queue
106 itemId = mItemQueue.front();
107 actualItem = PimItem::retrieveById(itemId);
108 }
109
110 // Ok.. got a valid item to process: collection and mimetype is known.
111
112 qCDebug(AKONADISERVER_LOG) << "PreprocessorInstance::processHeadItem(): about to begin processing item " << itemId;
113
114 mBusy = true;
115
116 mItemProcessingStartDateTime = QDateTime::currentDateTime();
117
118 // The beginProcessItem() D-Bus call is asynchronous (marked with NoReply attribute)
119 mInterface->beginProcessItem(itemId, actualItem.collectionId(), actualItem.mimeType().name());
120
121 qCDebug(AKONADISERVER_LOG) << "PreprocessorInstance::processHeadItem(): processing started for item " << itemId;
122}
123
125{
126 if (!mBusy) {
127 return -1; // nothing being processed
128 }
129
130 return mItemProcessingStartDateTime.secsTo(QDateTime::currentDateTime());
131}
132
134{
135 Q_ASSERT_X(mBusy, "PreprocessorInstance::abortProcessing()", "You shouldn't call this method when isBusy() returns false");
136
137 OrgFreedesktopAkonadiAgentControlInterface iface(DBus::agentServiceName(mId, DBus::Agent), QStringLiteral("/"), QDBusConnection::sessionBus(), this);
138
139 if (!iface.isValid()) {
140 mTracer.warning(QStringLiteral("PreprocessorInstance"),
141 QStringLiteral("Could not connect to pre-processor instance '%1': %2").arg(mId, iface.lastError().message()));
142 return false;
143 }
144
145 // We don't check the return value.. as this is a "warning"
146 // The preprocessor manager will check again in a while and eventually
147 // terminate the agent at all...
148 iface.abort();
149
150 return true;
151}
152
154{
155 Q_ASSERT_X(mBusy, "PreprocessorInstance::invokeRestart()", "You shouldn't call this method when isBusy() returns false");
156
157 OrgFreedesktopAkonadiAgentManagerInterface iface(DBus::serviceName(DBus::Control), QStringLiteral("/AgentManager"), QDBusConnection::sessionBus(), this);
158
159 if (!iface.isValid()) {
160 mTracer.warning(
161 QStringLiteral("PreprocessorInstance"),
162 QStringLiteral("Could not connect to the AgentManager in order to restart pre-processor instance '%1': %2").arg(mId, iface.lastError().message()));
163 return false;
164 }
165
166 iface.restartAgentInstance(mId);
167
168 return true;
169}
170
171void PreprocessorInstance::itemProcessed(qlonglong id)
172{
173 qCDebug(AKONADISERVER_LOG) << "PreprocessorInstance::itemProcessed(" << id << ")";
174
175 // We shouldn't be called if there are no items in the queue
176 if (mItemQueue.empty()) {
177 mTracer.warning(QStringLiteral("PreprocessorInstance"),
178 QStringLiteral("Pre-processor instance '%1' emitted itemProcessed(%2) but we actually have no item in the queue").arg(mId).arg(id));
179 mBusy = false;
180 return; // preprocessor is buggy (FIXME: What now ?)
181 }
182
183 // We should be busy now: this is more likely our fault, not the preprocessor's one.
184 Q_ASSERT(mBusy);
185
186 qlonglong itemId = mItemQueue.front();
187
188 if (itemId != id) {
189 mTracer.warning(
190 QStringLiteral("PreprocessorInstance"),
191 QStringLiteral("Pre-processor instance '%1' emitted itemProcessed(%2) but the head item in the queue has id %3").arg(mId).arg(id).arg(itemId));
192
193 // FIXME: And what now ?
194 }
195
196 mItemQueue.pop_front();
197
199
200 if (mItemQueue.empty()) {
201 // Nothing more to do
202 mBusy = false;
203 return;
204 }
205
206 // Stay busy and process next item in the queue
207 processHeadItem();
208}
209
210#include "moc_preprocessorinstance.cpp"
PreprocessorInstance(const QString &id, PreprocessorManager &manager, Tracer &tracer)
Create an instance of a PreprocessorInstance descriptor.
qint64 currentProcessingTime()
Returns the time in seconds elapsed since the current item was submitted to the slave preprocessor in...
bool abortProcessing()
Attempts to abort the processing of the current item.
void enqueueItem(qint64 itemId)
This is called by PreprocessorManager to enqueue a PimItem for processing by this preprocessor instan...
~PreprocessorInstance() override
Destroy this instance of the PreprocessorInstance descriptor.
bool init()
This is called by PreprocessorManager just after the construction in order to connect to the preproce...
bool invokeRestart()
Attempts to invoke the preprocessor slave restart via AgentManager.
The manager for preprocessor agents.
void preProcessorFinishedHandlingItem(PreprocessorInstance *preProcessor, qint64 itemId)
This is called by PreprocessorInstance to signal that a certain preprocessor has finished handling an...
The global tracer instance where all akonadi components can send their tracing information to.
Definition tracer.h:38
void warning(const QString &componentName, const QString &msg) override
This method is called whenever a component wants to output a warning.
Definition tracer.cpp:117
Helper integration between Akonadi and Qt.
QDateTime currentDateTime()
qint64 secsTo(const QDateTime &other) const const
QDBusConnection sessionBus()
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T qobject_cast(QObject *object)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:38 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.