Akonadi

preprocessormanager.h
1 /******************************************************************************
2  *
3  * File : preprocessormanager.h
4  * Creation date : Sat 18 Jul 2009 01:58:50
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 #pragma once
13 
14 #include <QHash>
15 #include <QList>
16 #include <QMutex>
17 #include <QObject>
18 
19 #include <deque>
20 
21 class QTimer;
22 
23 #include "preprocessorinstance.h"
24 
25 namespace Akonadi
26 {
27 namespace Server
28 {
29 class PimItem;
30 class DataStore;
31 class Tracer;
32 
33 /**
34  * \class PreprocessorManager
35  * \brief The manager for preprocessor agents
36  *
37  * This class takes care of synchronizing the preprocessor agents.
38  *
39  * The preprocessors see the incoming PimItem objects before the user
40  * can see them (as long as the UI applications honor the hidden attribute).
41  * The items are marked as hidden (by the Append and AkAppend
42  * handlers) and then enqueued to the preprocessor chain via this class.
43  * Once all the preprocessors have done their work the item is unhidden again.
44  *
45  * Preprocessing isn't designed for critical tasks. There may
46  * be circumstances under that the Akonadi server fails to push an item
47  * to all the preprocessors. Most notably after a server restart all
48  * the items for that preprocessing was interrupted are just unhidden
49  * without any attempt to resume the preprocessor jobs.
50  *
51  * The enqueue requests may or may not arrive from "inside" a database
52  * transaction. The uncommitted transaction would "hide" the newly created items
53  * from the preprocessor instances (which are separate processes).
54  * This class, then, takes care of holding the newly arrived items
55  * in a wait queue until their transaction is committed (or rolled back).
56  */
58 {
59  friend class PreprocessorInstance;
60 
61  Q_OBJECT
62  Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Akonadi.PreprocessorManager")
63 
64 protected:
65  /**
66  * The hashtable of transaction wait queues. There is one wait
67  * queue for each DataStore that is currently in a transaction.
68  */
70 
71  /**
72  * The preprocessor chain.
73  * The pointers inside the list are owned.
74  *
75  * In all the algorithms we assume that this list is actually very short
76  * (say 3-4 elements) and reverse lookup (pointer->index) is really fast.
77  */
79 
80  /**
81  * Is preprocessing enabled at all in this Akonadi server instance?
82  * This is true by default and can be set via setEnabled().
83  * Mainly used to disable preprocessing via configuration file.
84  */
85  bool mEnabled = false;
86 
87  /**
88  * The mutex used to protect the internals of this class (mainly
89  * the mPreprocessorChain member).
90  */
92 
93  /**
94  * The heartbeat timer. Used mainly to expire preprocessor jobs.
95  */
96  QTimer *mHeartbeatTimer = nullptr;
97 
98  Tracer &mTracer;
99 
100 public:
101  /**
102  * Creates an instance of PreprocessorManager
103  */
104  explicit PreprocessorManager(Tracer &tracer);
105 
106  /**
107  * Destroys the instance of PreprocessorManager
108  * and frees all the relevant resources
109  */
110  ~PreprocessorManager() override;
111 
112  /**
113  * Returns true if preprocessing is active in this Akonadi server.
114  * This means that we have at least one active preprocessor and
115  * preprocessing hasn't been explicitly disabled via configuration
116  * (so if isActive() returns true then also isEnabled() will return true).
117  *
118  * This function is thread-safe.
119  */
120  bool isActive();
121 
122  /**
123  * Returns true if this preprocessor hasn't been explicitly disabled
124  * via setEnabled( false ). This is used to disable preprocessing
125  * via configuration even if we have a valid chain of preprocessors.
126  *
127  * Please note that this flag doesn't tell if we actually have
128  * some registered preprocessors and thus we can do some meaningful job.
129  * You should use isActive() for this purpose.
130  */
131  bool isEnabled() const
132  {
133  return mEnabled;
134  }
135 
136  /**
137  * Explicitly enables or disables the preprocessing in this Akonadi server.
138  * The PreprocessorManager starts in enabled state but can be disabled
139  * at a later stage: this is mainly used to disable preprocessing via
140  * configuration.
141  *
142  * Please note that setting this to true doesn't interrupt the currently
143  * running preprocessing jobs. Anything that was enqueued will be processed
144  * anyway. However, in Akonadi this is only invoked very early,
145  * when no preprocessors are alive yet.
146  */
147  void setEnabled(bool enabled)
148  {
149  mEnabled = enabled;
150  }
151 
152  /**
153  * Trigger the preprocessor chain for the specified item.
154  * The item should have been added to the Akonadi database via
155  * the specified DataStore object. If the DataStore is in a
156  * transaction then this class will put the item in a wait
157  * queue until the transaction is committed. If the transaction
158  * is rolled back the whole wait queue will be discarded.
159  * If the DataStore is not in a transaction then the item
160  * will be pushed directly to the preprocessing chain.
161  *
162  * You should make sure that the preprocessor chain isActive()
163  * before calling this method. The items you pass to this method,
164  * also, should have the hidden attribute set.
165  *
166  * This function is thread-safe.
167  */
168  void beginHandleItem(const PimItem &item, const DataStore *dataStore);
169 
170  /**
171  * This is called via D-Bus from AgentManager to register a preprocessor instance.
172  *
173  * This function is thread-safe.
174  */
175  void registerInstance(const QString &id);
176 
177  /**
178  * This is called via D-Bus from AgentManager to unregister a preprocessor instance.
179  *
180  * This function is thread-safe.
181  */
182  void unregisterInstance(const QString &id);
183 
184 protected:
185  /**
186  * This is called by PreprocessorInstance to signal that a certain preprocessor has finished
187  * handling an item.
188  *
189  * This function is thread-safe.
190  */
191  void preProcessorFinishedHandlingItem(PreprocessorInstance *preProcessor, qint64 itemId);
192 
193 private:
194  /**
195  * Finds the preprocessor instance by its identifier.
196  *
197  * This must be called with mMutex locked.
198  */
199  PreprocessorInstance *lockedFindInstance(const QString &id);
200 
201  /**
202  * Pushes the specified item to the first preprocessor.
203  * The caller *MUST* make sure that there is at least one preprocessor in the chain.
204  */
205  void lockedActivateFirstPreprocessor(qint64 itemId);
206 
207  /**
208  * This is called internally to terminate the pre-processing
209  * chain for the specified Item. All the preprocessors have
210  * been triggered for it.
211  *
212  * This must be called with mMutex locked.
213  */
214  void lockedEndHandleItem(qint64 itemId);
215 
216  /**
217  * This is the unprotected core of the unregisterInstance() function above.
218  */
219  void lockedUnregisterInstance(const QString &id);
220 
221  /**
222  * Kill the wait queue for the specific DataStore object.
223  */
224  void lockedKillWaitQueue(const DataStore *dataStore, bool disconnectSlots);
225 
226 private Q_SLOTS:
227 
228  /**
229  * Connected to the mHeartbeatTimer. Triggered every minute or something like that :D
230  * Mainly used to expire preprocessor jobs.
231  */
232  void heartbeat();
233 
234  /**
235  * This is used to handle database transactions and wait queues.
236  * The call to this slot usually comes from a queued signal/slot connection
237  * (i.e. from the *Append handler thread).
238  */
239  void dataStoreDestroyed();
240 
241  /**
242  * This is used to handle database transactions and wait queues.
243  * The call to this slot usually comes from a queued signal/slot connection
244  * (i.e. from the *Append handler thread).
245  */
246  void dataStoreTransactionCommitted();
247 
248  /**
249  * This is used to handle database transactions and wait queues.
250  * The call to this slot usually comes from a queued signal/slot connection
251  * (i.e. from the *Append handler thread).
252  */
253  void dataStoreTransactionRolledBack();
254 
255 }; // class PreprocessorManager
256 
257 } // namespace Server
258 } // namespace Akonadi
259 
Q_OBJECTQ_OBJECT
QList< PreprocessorInstance * > mPreprocessorChain
The preprocessor chain.
This class handles all the database access.
Definition: datastore.h:94
QMutex mMutex
The mutex used to protect the internals of this class (mainly the mPreprocessorChain member).
Q_SLOTSQ_SLOTS
PreprocessorManager(Tracer &tracer)
Creates an instance of PreprocessorManager.
Q_CLASSINFO(Name, Value)
~PreprocessorManager() override
Destroys the instance of PreprocessorManager and frees all the relevant resources.
bool isEnabled() const
Returns true if this preprocessor hasn't been explicitly disabled via setEnabled( false ).
void unregisterInstance(const QString &id)
This is called via D-Bus from AgentManager to unregister a preprocessor instance.
The global tracer instance where all akonadi components can send their tracing information to.
Definition: tracer.h:37
Definition: item.h:32
QTimer * mHeartbeatTimer
The heartbeat timer.
QHash< const DataStore *, std::deque< qint64 > * > mTransactionWaitQueueHash
The hashtable of transaction wait queues.
bool mEnabled
Is preprocessing enabled at all in this Akonadi server instance? This is true by default and can be s...
void setEnabled(bool enabled)
Explicitly enables or disables the preprocessing in this Akonadi server.
A single preprocessor (agent) instance.
void beginHandleItem(const PimItem &item, const DataStore *dataStore)
Trigger the preprocessor chain for the specified item.
void registerInstance(const QString &id)
This is called via D-Bus from AgentManager to register a preprocessor instance.
void preProcessorFinishedHandlingItem(PreprocessorInstance *preProcessor, qint64 itemId)
This is called by PreprocessorInstance to signal that a certain preprocessor has finished handling an...
bool isActive()
Returns true if preprocessing is active in this Akonadi server.
Helper integration between Akonadi and Qt.
The manager for preprocessor agents.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Mon Jun 27 2022 04:01:07 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.