File indexing completed on 2025-01-05 04:47:04
0001 /****************************************************************************** 0002 * 0003 * File : preprocessorinstance.cpp 0004 * Creation date : Sat 18 Jul 2009 02:50:39 0005 * 0006 * SPDX-FileCopyrightText: 2009 Szymon Stefanek <s.stefanek at gmail dot com> 0007 * 0008 * SPDX-License-Identifier: LGPL-2.0-or-later 0009 * 0010 *****************************************************************************/ 0011 0012 #include "preprocessorinstance.h" 0013 #include "akonadiserver_debug.h" 0014 #include "preprocessorinterface.h" 0015 #include "preprocessormanager.h" 0016 0017 #include "entities.h" 0018 0019 #include "agentcontrolinterface.h" 0020 #include "agentmanagerinterface.h" 0021 0022 #include "tracer.h" 0023 0024 #include "private/dbus_p.h" 0025 0026 using namespace Akonadi; 0027 using namespace Akonadi::Server; 0028 0029 PreprocessorInstance::PreprocessorInstance(const QString &id, PreprocessorManager &manager, Tracer &tracer) 0030 : mManager(manager) 0031 , mTracer(tracer) 0032 , mId(id) 0033 { 0034 Q_ASSERT(!id.isEmpty()); 0035 } 0036 0037 PreprocessorInstance::~PreprocessorInstance() = default; 0038 0039 bool PreprocessorInstance::init() 0040 { 0041 Q_ASSERT(!mBusy); // must be called very early 0042 Q_ASSERT(!mInterface); 0043 0044 mInterface = new OrgFreedesktopAkonadiPreprocessorInterface(DBus::agentServiceName(mId, DBus::Preprocessor), 0045 QStringLiteral("/Preprocessor"), 0046 QDBusConnection::sessionBus(), 0047 this); 0048 0049 if (!mInterface || !mInterface->isValid()) { 0050 mTracer.warning( 0051 QStringLiteral("PreprocessorInstance"), 0052 QStringLiteral("Could not connect to pre-processor instance '%1': %2").arg(mId, mInterface ? mInterface->lastError().message() : QString())); 0053 delete mInterface; 0054 mInterface = nullptr; 0055 return false; 0056 } 0057 0058 QObject::connect(mInterface, &OrgFreedesktopAkonadiPreprocessorInterface::itemProcessed, this, &PreprocessorInstance::itemProcessed); 0059 0060 return true; 0061 } 0062 0063 void PreprocessorInstance::enqueueItem(qint64 itemId) 0064 { 0065 qCDebug(AKONADISERVER_LOG) << "PreprocessorInstance::enqueueItem(" << itemId << ")"; 0066 0067 mItemQueue.push_back(itemId); 0068 0069 // If the preprocessor is already busy processing another item then do nothing. 0070 if (mBusy) { 0071 // The "head" item is the one being processed and we have just added another one. 0072 Q_ASSERT(mItemQueue.size() > 1); 0073 return; 0074 } 0075 0076 // Not busy: handle the item. 0077 processHeadItem(); 0078 } 0079 0080 void PreprocessorInstance::processHeadItem() 0081 { 0082 // We shouldn't be called if there are no items in the queue 0083 Q_ASSERT(!mItemQueue.empty()); 0084 // We shouldn't be here with no interface 0085 Q_ASSERT(mInterface); 0086 0087 qint64 itemId = mItemQueue.front(); 0088 0089 // Fetch the actual item data (as it may have changed since it was enqueued) 0090 // The fetch will hit the cache if the item wasn't changed. 0091 0092 PimItem actualItem = PimItem::retrieveById(itemId); 0093 0094 while (!actualItem.isValid()) { 0095 // hum... item is gone ? 0096 mManager.preProcessorFinishedHandlingItem(this, itemId); 0097 0098 mItemQueue.pop_front(); 0099 if (mItemQueue.empty()) { 0100 // nothing more to process for this instance: jump out 0101 mBusy = false; 0102 return; 0103 } 0104 0105 // try the next one in the queue 0106 itemId = mItemQueue.front(); 0107 actualItem = PimItem::retrieveById(itemId); 0108 } 0109 0110 // Ok.. got a valid item to process: collection and mimetype is known. 0111 0112 qCDebug(AKONADISERVER_LOG) << "PreprocessorInstance::processHeadItem(): about to begin processing item " << itemId; 0113 0114 mBusy = true; 0115 0116 mItemProcessingStartDateTime = QDateTime::currentDateTime(); 0117 0118 // The beginProcessItem() D-Bus call is asynchronous (marked with NoReply attribute) 0119 mInterface->beginProcessItem(itemId, actualItem.collectionId(), actualItem.mimeType().name()); 0120 0121 qCDebug(AKONADISERVER_LOG) << "PreprocessorInstance::processHeadItem(): processing started for item " << itemId; 0122 } 0123 0124 qint64 PreprocessorInstance::currentProcessingTime() 0125 { 0126 if (!mBusy) { 0127 return -1; // nothing being processed 0128 } 0129 0130 return mItemProcessingStartDateTime.secsTo(QDateTime::currentDateTime()); 0131 } 0132 0133 bool PreprocessorInstance::abortProcessing() 0134 { 0135 Q_ASSERT_X(mBusy, "PreprocessorInstance::abortProcessing()", "You shouldn't call this method when isBusy() returns false"); 0136 0137 OrgFreedesktopAkonadiAgentControlInterface iface(DBus::agentServiceName(mId, DBus::Agent), QStringLiteral("/"), QDBusConnection::sessionBus(), this); 0138 0139 if (!iface.isValid()) { 0140 mTracer.warning(QStringLiteral("PreprocessorInstance"), 0141 QStringLiteral("Could not connect to pre-processor instance '%1': %2").arg(mId, iface.lastError().message())); 0142 return false; 0143 } 0144 0145 // We don't check the return value.. as this is a "warning" 0146 // The preprocessor manager will check again in a while and eventually 0147 // terminate the agent at all... 0148 iface.abort(); 0149 0150 return true; 0151 } 0152 0153 bool PreprocessorInstance::invokeRestart() 0154 { 0155 Q_ASSERT_X(mBusy, "PreprocessorInstance::invokeRestart()", "You shouldn't call this method when isBusy() returns false"); 0156 0157 OrgFreedesktopAkonadiAgentManagerInterface iface(DBus::serviceName(DBus::Control), QStringLiteral("/AgentManager"), QDBusConnection::sessionBus(), this); 0158 0159 if (!iface.isValid()) { 0160 mTracer.warning( 0161 QStringLiteral("PreprocessorInstance"), 0162 QStringLiteral("Could not connect to the AgentManager in order to restart pre-processor instance '%1': %2").arg(mId, iface.lastError().message())); 0163 return false; 0164 } 0165 0166 iface.restartAgentInstance(mId); 0167 0168 return true; 0169 } 0170 0171 void PreprocessorInstance::itemProcessed(qlonglong id) 0172 { 0173 qCDebug(AKONADISERVER_LOG) << "PreprocessorInstance::itemProcessed(" << id << ")"; 0174 0175 // We shouldn't be called if there are no items in the queue 0176 if (mItemQueue.empty()) { 0177 mTracer.warning(QStringLiteral("PreprocessorInstance"), 0178 QStringLiteral("Pre-processor instance '%1' emitted itemProcessed(%2) but we actually have no item in the queue").arg(mId).arg(id)); 0179 mBusy = false; 0180 return; // preprocessor is buggy (FIXME: What now ?) 0181 } 0182 0183 // We should be busy now: this is more likely our fault, not the preprocessor's one. 0184 Q_ASSERT(mBusy); 0185 0186 qlonglong itemId = mItemQueue.front(); 0187 0188 if (itemId != id) { 0189 mTracer.warning( 0190 QStringLiteral("PreprocessorInstance"), 0191 QStringLiteral("Pre-processor instance '%1' emitted itemProcessed(%2) but the head item in the queue has id %3").arg(mId).arg(id).arg(itemId)); 0192 0193 // FIXME: And what now ? 0194 } 0195 0196 mItemQueue.pop_front(); 0197 0198 mManager.preProcessorFinishedHandlingItem(this, itemId); 0199 0200 if (mItemQueue.empty()) { 0201 // Nothing more to do 0202 mBusy = false; 0203 return; 0204 } 0205 0206 // Stay busy and process next item in the queue 0207 processHeadItem(); 0208 } 0209 0210 #include "moc_preprocessorinstance.cpp"