Akonadi

preprocessorinstance.cpp
1 /******************************************************************************
2  *
3  * File : preprocessorinstance.cpp
4  * Creation date : Sat 18 Jul 2009 02:50:39
5  *
6  * Copyright (c) 2009 Szymon Stefanek <s.stefanek at gmail dot com>
7  *
8  * This library is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Library General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or (at your
11  * option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
16  * License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB. If not, write to the
20  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21  * MA, 02110-1301, USA.
22  *
23  *****************************************************************************/
24 
25 #include "preprocessorinstance.h"
26 #include "preprocessorinterface.h"
27 #include "preprocessormanager.h"
28 #include "akonadiserver_debug.h"
29 
30 #include "entities.h"
31 
32 #include "agentcontrolinterface.h"
33 #include "agentmanagerinterface.h"
34 
35 #include "tracer.h"
36 
37 #include <private/dbus_p.h>
38 
39 
40 using namespace Akonadi;
41 using namespace Akonadi::Server;
42 
44  : QObject()
45  , mManager(manager)
46  , mTracer(tracer)
47  , mId(id)
48 {
49  Q_ASSERT(!id.isEmpty());
50 }
51 
53 {
54 }
55 
57 {
58  Q_ASSERT(!mBusy); // must be called very early
59  Q_ASSERT(!mInterface);
60 
61  mInterface = new OrgFreedesktopAkonadiPreprocessorInterface(
62  DBus::agentServiceName(mId, DBus::Preprocessor),
63  QStringLiteral("/Preprocessor"),
65  this);
66 
67  if (!mInterface || !mInterface->isValid()) {
68  mTracer.warning(
69  QStringLiteral("PreprocessorInstance"),
70  QStringLiteral("Could not connect to pre-processor instance '%1': %2")
71  .arg(mId,
72  mInterface ? mInterface->lastError().message() : QString()));
73  delete mInterface;
74  mInterface = nullptr;
75  return false;
76  }
77 
78  QObject::connect(mInterface, &OrgFreedesktopAkonadiPreprocessorInterface::itemProcessed, this, &PreprocessorInstance::itemProcessed);
79 
80  return true;
81 }
82 
84 {
85  qCDebug(AKONADISERVER_LOG) << "PreprocessorInstance::enqueueItem(" << itemId << ")";
86 
87  mItemQueue.push_back(itemId);
88 
89  // If the preprocessor is already busy processing another item then do nothing.
90  if (mBusy) {
91  // The "head" item is the one being processed and we have just added another one.
92  Q_ASSERT(mItemQueue.size() > 1);
93  return;
94  }
95 
96  // Not busy: handle the item.
97  processHeadItem();
98 }
99 
100 void PreprocessorInstance::processHeadItem()
101 {
102  // We shouldn't be called if there are no items in the queue
103  Q_ASSERT(!mItemQueue.empty());
104  // We shouldn't be here with no interface
105  Q_ASSERT(mInterface);
106 
107  qint64 itemId = mItemQueue.front();
108 
109  // Fetch the actual item data (as it may have changed since it was enqueued)
110  // The fetch will hit the cache if the item wasn't changed.
111 
112  PimItem actualItem = PimItem::retrieveById(itemId);
113 
114  while (!actualItem.isValid()) {
115  // hum... item is gone ?
116  mManager.preProcessorFinishedHandlingItem(this, itemId);
117 
118  mItemQueue.pop_front();
119  if (mItemQueue.empty()) {
120  // nothing more to process for this instance: jump out
121  mBusy = false;
122  return;
123  }
124 
125  // try the next one in the queue
126  itemId = mItemQueue.front();
127  actualItem = PimItem::retrieveById(itemId);
128  }
129 
130  // Ok.. got a valid item to process: collection and mimetype is known.
131 
132  qCDebug(AKONADISERVER_LOG) << "PreprocessorInstance::processHeadItem(): about to begin processing item " << itemId;
133 
134  mBusy = true;
135 
136  mItemProcessingStartDateTime = QDateTime::currentDateTime();
137 
138  // The beginProcessItem() D-Bus call is asynchronous (marked with NoReply attribute)
139  mInterface->beginProcessItem(itemId, actualItem.collectionId(), actualItem.mimeType().name());
140 
141  qCDebug(AKONADISERVER_LOG) << "PreprocessorInstance::processHeadItem(): processing started for item " << itemId;
142 }
143 
145 {
146  if (!mBusy) {
147  return -1; // nothing being processed
148  }
149 
150  return mItemProcessingStartDateTime.secsTo(QDateTime::currentDateTime());
151 }
152 
154 {
155  Q_ASSERT_X(mBusy, "PreprocessorInstance::abortProcessing()", "You shouldn't call this method when isBusy() returns false");
156 
157  OrgFreedesktopAkonadiAgentControlInterface iface(
158  DBus::agentServiceName(mId, DBus::Agent),
159  QStringLiteral("/"),
161  this);
162 
163  if (!iface.isValid()) {
164  mTracer.warning(
165  QStringLiteral("PreprocessorInstance"),
166  QStringLiteral("Could not connect to pre-processor instance '%1': %2")
167  .arg(mId, iface.lastError().message()));
168  return false;
169  }
170 
171  // We don't check the return value.. as this is a "warning"
172  // The preprocessor manager will check again in a while and eventually
173  // terminate the agent at all...
174  iface.abort();
175 
176  return true;
177 }
178 
180 {
181  Q_ASSERT_X(mBusy, "PreprocessorInstance::invokeRestart()", "You shouldn't call this method when isBusy() returns false");
182 
183  OrgFreedesktopAkonadiAgentManagerInterface iface(
184  DBus::serviceName(DBus::Control),
185  QStringLiteral("/AgentManager"),
187  this);
188 
189  if (!iface.isValid()) {
190  mTracer.warning(
191  QStringLiteral("PreprocessorInstance"),
192  QStringLiteral("Could not connect to the AgentManager in order to restart pre-processor instance '%1': %2")
193  .arg(mId, iface.lastError().message()));
194  return false;
195  }
196 
197  iface.restartAgentInstance(mId);
198 
199  return true;
200 }
201 
202 void PreprocessorInstance::itemProcessed(qlonglong id)
203 {
204  qCDebug(AKONADISERVER_LOG) << "PreprocessorInstance::itemProcessed(" << id << ")";
205 
206  // We shouldn't be called if there are no items in the queue
207  if (mItemQueue.empty()) {
208  mTracer.warning(
209  QStringLiteral("PreprocessorInstance"),
210  QStringLiteral("Pre-processor instance '%1' emitted itemProcessed(%2) but we actually have no item in the queue")
211  .arg(mId)
212  .arg(id));
213  mBusy = false;
214  return; // preprocessor is buggy (FIXME: What now ?)
215  }
216 
217  // We should be busy now: this is more likely our fault, not the preprocessor's one.
218  Q_ASSERT(mBusy);
219 
220  qlonglong itemId = mItemQueue.front();
221 
222  if (itemId != id) {
223  mTracer.warning(
224  QStringLiteral("PreprocessorInstance"),
225  QStringLiteral("Pre-processor instance '%1' emitted itemProcessed(%2) but the head item in the queue has id %3")
226  .arg(mId)
227  .arg(id)
228  .arg(itemId));
229 
230  // FIXME: And what now ?
231  }
232 
233  mItemQueue.pop_front();
234 
235  mManager.preProcessorFinishedHandlingItem(this, itemId);
236 
237  if (mItemQueue.empty()) {
238  // Nothing more to do
239  mBusy = false;
240  return;
241  }
242 
243  // Stay busy and process next item in the queue
244  processHeadItem();
245 }
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.
void preProcessorFinishedHandlingItem(PreprocessorInstance *preProcessor, qint64 itemId)
This is called by PreprocessorInstance to signal that a certain preprocessor has finished handling an...
QDBusConnection sessionBus()
The global tracer instance where all akonadi components can send their tracing information to...
Definition: tracer.h:53
PreprocessorInstance(const QString &id, PreprocessorManager &manager, Tracer &tracer)
Create an instance of a PreprocessorInstance descriptor.
The manager for preprocessor agents.
void warning(const QString &componentName, const QString &msg) override
This method is called whenever a component wants to output a warning.
Definition: tracer.cpp:124
bool abortProcessing()
Attempts to abort the processing of the current item.
~PreprocessorInstance()
Destroy this instance of the PreprocessorInstance descriptor.
QDateTime currentDateTime()
qint64 secsTo(const QDateTime &other) const const
Helper integration between Akonadi and Qt.
void enqueueItem(qint64 itemId)
This is called by PreprocessorManager to enqueue a PimItem for processing by this preprocessor instan...
qint64 currentProcessingTime()
Returns the time in seconds elapsed since the current item was submitted to the slave preprocessor in...
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Jun 5 2020 23:08:55 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.