File indexing completed on 2024-06-16 04:50:33
0001 /****************************************************************************** 0002 * 0003 * File : preprocessormanager.h 0004 * Creation date : Sat 18 Jul 2009 01:58:50 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 #pragma once 0013 0014 #include <QHash> 0015 #include <QList> 0016 #include <QMutex> 0017 #include <QObject> 0018 0019 #include <deque> 0020 0021 class QTimer; 0022 0023 #include "preprocessorinstance.h" 0024 0025 namespace Akonadi 0026 { 0027 namespace Server 0028 { 0029 class PimItem; 0030 class DataStore; 0031 class Tracer; 0032 0033 /** 0034 * \class PreprocessorManager 0035 * \brief The manager for preprocessor agents 0036 * 0037 * This class takes care of synchronizing the preprocessor agents. 0038 * 0039 * The preprocessors see the incoming PimItem objects before the user 0040 * can see them (as long as the UI applications honor the hidden attribute). 0041 * The items are marked as hidden (by the Append and AkAppend 0042 * handlers) and then enqueued to the preprocessor chain via this class. 0043 * Once all the preprocessors have done their work the item is unhidden again. 0044 * 0045 * Preprocessing isn't designed for critical tasks. There may 0046 * be circumstances under that the Akonadi server fails to push an item 0047 * to all the preprocessors. Most notably after a server restart all 0048 * the items for that preprocessing was interrupted are just unhidden 0049 * without any attempt to resume the preprocessor jobs. 0050 * 0051 * The enqueue requests may or may not arrive from "inside" a database 0052 * transaction. The uncommitted transaction would "hide" the newly created items 0053 * from the preprocessor instances (which are separate processes). 0054 * This class, then, takes care of holding the newly arrived items 0055 * in a wait queue until their transaction is committed (or rolled back). 0056 */ 0057 class PreprocessorManager : public QObject 0058 { 0059 friend class PreprocessorInstance; 0060 0061 Q_OBJECT 0062 Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Akonadi.PreprocessorManager") 0063 0064 protected: 0065 /** 0066 * The hashtable of transaction wait queues. There is one wait 0067 * queue for each DataStore that is currently in a transaction. 0068 */ 0069 QHash<const DataStore *, std::deque<qint64> *> mTransactionWaitQueueHash; 0070 0071 /** 0072 * The preprocessor chain. 0073 * The pointers inside the list are owned. 0074 * 0075 * In all the algorithms we assume that this list is actually very short 0076 * (say 3-4 elements) and reverse lookup (pointer->index) is really fast. 0077 */ 0078 QList<PreprocessorInstance *> mPreprocessorChain; 0079 0080 /** 0081 * Is preprocessing enabled at all in this Akonadi server instance? 0082 * This is true by default and can be set via setEnabled(). 0083 * Mainly used to disable preprocessing via configuration file. 0084 */ 0085 bool mEnabled = false; 0086 0087 /** 0088 * The mutex used to protect the internals of this class (mainly 0089 * the mPreprocessorChain member). 0090 */ 0091 QMutex mMutex; 0092 0093 /** 0094 * The heartbeat timer. Used mainly to expire preprocessor jobs. 0095 */ 0096 QTimer *mHeartbeatTimer = nullptr; 0097 0098 Tracer &mTracer; 0099 0100 public: 0101 /** 0102 * Creates an instance of PreprocessorManager 0103 */ 0104 explicit PreprocessorManager(Tracer &tracer); 0105 0106 /** 0107 * Destroys the instance of PreprocessorManager 0108 * and frees all the relevant resources 0109 */ 0110 ~PreprocessorManager() override; 0111 0112 /** 0113 * Returns true if preprocessing is active in this Akonadi server. 0114 * This means that we have at least one active preprocessor and 0115 * preprocessing hasn't been explicitly disabled via configuration 0116 * (so if isActive() returns true then also isEnabled() will return true). 0117 * 0118 * This function is thread-safe. 0119 */ 0120 bool isActive(); 0121 0122 /** 0123 * Returns true if this preprocessor hasn't been explicitly disabled 0124 * via setEnabled( false ). This is used to disable preprocessing 0125 * via configuration even if we have a valid chain of preprocessors. 0126 * 0127 * Please note that this flag doesn't tell if we actually have 0128 * some registered preprocessors and thus we can do some meaningful job. 0129 * You should use isActive() for this purpose. 0130 */ 0131 bool isEnabled() const 0132 { 0133 return mEnabled; 0134 } 0135 0136 /** 0137 * Explicitly enables or disables the preprocessing in this Akonadi server. 0138 * The PreprocessorManager starts in enabled state but can be disabled 0139 * at a later stage: this is mainly used to disable preprocessing via 0140 * configuration. 0141 * 0142 * Please note that setting this to true doesn't interrupt the currently 0143 * running preprocessing jobs. Anything that was enqueued will be processed 0144 * anyway. However, in Akonadi this is only invoked very early, 0145 * when no preprocessors are alive yet. 0146 */ 0147 void setEnabled(bool enabled) 0148 { 0149 mEnabled = enabled; 0150 } 0151 0152 /** 0153 * Trigger the preprocessor chain for the specified item. 0154 * The item should have been added to the Akonadi database via 0155 * the specified DataStore object. If the DataStore is in a 0156 * transaction then this class will put the item in a wait 0157 * queue until the transaction is committed. If the transaction 0158 * is rolled back the whole wait queue will be discarded. 0159 * If the DataStore is not in a transaction then the item 0160 * will be pushed directly to the preprocessing chain. 0161 * 0162 * You should make sure that the preprocessor chain isActive() 0163 * before calling this method. The items you pass to this method, 0164 * also, should have the hidden attribute set. 0165 * 0166 * This function is thread-safe. 0167 */ 0168 void beginHandleItem(const PimItem &item, const DataStore *dataStore); 0169 0170 /** 0171 * This is called via D-Bus from AgentManager to register a preprocessor instance. 0172 * 0173 * This function is thread-safe. 0174 */ 0175 void registerInstance(const QString &id); 0176 0177 /** 0178 * This is called via D-Bus from AgentManager to unregister a preprocessor instance. 0179 * 0180 * This function is thread-safe. 0181 */ 0182 void unregisterInstance(const QString &id); 0183 0184 protected: 0185 /** 0186 * This is called by PreprocessorInstance to signal that a certain preprocessor has finished 0187 * handling an item. 0188 * 0189 * This function is thread-safe. 0190 */ 0191 void preProcessorFinishedHandlingItem(PreprocessorInstance *preProcessor, qint64 itemId); 0192 0193 private: 0194 /** 0195 * Finds the preprocessor instance by its identifier. 0196 * 0197 * This must be called with mMutex locked. 0198 */ 0199 PreprocessorInstance *lockedFindInstance(const QString &id); 0200 0201 /** 0202 * Pushes the specified item to the first preprocessor. 0203 * The caller *MUST* make sure that there is at least one preprocessor in the chain. 0204 */ 0205 void lockedActivateFirstPreprocessor(qint64 itemId); 0206 0207 /** 0208 * This is called internally to terminate the pre-processing 0209 * chain for the specified Item. All the preprocessors have 0210 * been triggered for it. 0211 * 0212 * This must be called with mMutex locked. 0213 */ 0214 void lockedEndHandleItem(qint64 itemId); 0215 0216 /** 0217 * This is the unprotected core of the unregisterInstance() function above. 0218 */ 0219 void lockedUnregisterInstance(const QString &id); 0220 0221 /** 0222 * Kill the wait queue for the specific DataStore object. 0223 */ 0224 void lockedKillWaitQueue(const DataStore *dataStore, bool disconnectSlots); 0225 0226 private Q_SLOTS: 0227 0228 /** 0229 * Connected to the mHeartbeatTimer. Triggered every minute or something like that :D 0230 * Mainly used to expire preprocessor jobs. 0231 */ 0232 void heartbeat(); 0233 0234 /** 0235 * This is used to handle database transactions and wait queues. 0236 * The call to this slot usually comes from a queued signal/slot connection 0237 * (i.e. from the *Append handler thread). 0238 */ 0239 void dataStoreDestroyed(); 0240 0241 /** 0242 * This is used to handle database transactions and wait queues. 0243 * The call to this slot usually comes from a queued signal/slot connection 0244 * (i.e. from the *Append handler thread). 0245 */ 0246 void dataStoreTransactionCommitted(); 0247 0248 /** 0249 * This is used to handle database transactions and wait queues. 0250 * The call to this slot usually comes from a queued signal/slot connection 0251 * (i.e. from the *Append handler thread). 0252 */ 0253 void dataStoreTransactionRolledBack(); 0254 0255 }; // class PreprocessorManager 0256 0257 } // namespace Server 0258 } // namespace Akonadi