File indexing completed on 2024-05-26 05:13:54

0001 /*
0002     SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include "agentbase.h"
0010 #include "collection.h"
0011 #include "item.h"
0012 #include "resourcebase.h"
0013 
0014 #include <QDBusMessage>
0015 #include <QObject>
0016 
0017 namespace Akonadi
0018 {
0019 class RecursiveMover;
0020 
0021 /// @cond PRIVATE
0022 
0023 /**
0024   @internal
0025 
0026   Manages synchronization and fetch requests for a resource.
0027 
0028   @todo Attach to the ResourceBase Monitor,
0029 */
0030 class ResourceScheduler : public QObject
0031 {
0032     Q_OBJECT
0033 
0034 public:
0035     // If you change this enum, keep s_taskTypes in sync in resourcescheduler.cpp
0036     enum TaskType {
0037         Invalid,
0038         SyncAll,
0039         SyncCollectionTree,
0040         SyncCollection,
0041         SyncCollectionAttributes,
0042         SyncTags,
0043         FetchItem,
0044         FetchItems,
0045         ChangeReplay,
0046         RecursiveMoveReplay,
0047         DeleteResourceCollection,
0048         InvalideCacheForCollection,
0049         SyncAllDone,
0050         SyncCollectionTreeDone,
0051         SyncRelations,
0052         Custom
0053     };
0054 
0055     class Task
0056     {
0057         static qint64 latestSerial;
0058 
0059     public:
0060         Task()
0061             : serial(++latestSerial)
0062             , type(Invalid)
0063         {
0064         }
0065         qint64 serial;
0066         TaskType type;
0067         Collection collection;
0068         QList<Item> items;
0069         QSet<QByteArray> itemParts;
0070         QList<QDBusMessage> dbusMsgs;
0071         QObject *receiver = nullptr;
0072         QByteArray methodName;
0073         QVariant argument;
0074 
0075         void sendDBusReplies(const QString &errorMsg);
0076 
0077         bool operator==(const Task &other) const
0078         {
0079             return type == other.type && (collection == other.collection || (!collection.isValid() && !other.collection.isValid())) && items == other.items
0080                 && itemParts == other.itemParts && receiver == other.receiver && methodName == other.methodName && argument == other.argument;
0081         }
0082     };
0083 
0084     explicit ResourceScheduler(QObject *parent = nullptr);
0085 
0086     /**
0087       Schedules a full synchronization.
0088     */
0089     void scheduleFullSync();
0090 
0091     /**
0092       Schedules a collection tree sync.
0093     */
0094     void scheduleCollectionTreeSync();
0095 
0096     /**
0097       Schedules the synchronization of a single collection.
0098       @param col The collection to synchronize.
0099     */
0100     void scheduleSync(const Collection &col);
0101 
0102     /**
0103       Schedules synchronizing the attributes of a single collection.
0104       @param collection The collection to synchronize attributes from.
0105     */
0106     void scheduleAttributesSync(const Collection &collection);
0107 
0108     void scheduleTagSync();
0109     void scheduleRelationSync();
0110 
0111     /**
0112       Schedules fetching of a single PIM item.
0113 
0114       This task is only ever used if the resource still uses the old deprecated
0115       retrieveItem() (instead of retrieveItems(Item::List)) method. This task has
0116       a special meaning to the scheduler and instead of replying to the DBus message
0117       after the single @p item is retrieved, the items are accumulated until all
0118       tasks from the same messages are fetched.
0119 
0120       @param items The items to fetch.
0121       @param parts List of names of the parts of the item to fetch.
0122       @param msg The associated D-Bus message.
0123       @param parentId ID of the original ItemsFetch task that this task was created from.
0124                       We can use this ID to group the tasks together
0125     */
0126     void scheduleItemFetch(const Item &item, const QSet<QByteArray> &parts, const QList<QDBusMessage> &msgs, const qint64 parentId);
0127 
0128     /**
0129       Schedules batch-fetching of PIM items.
0130       @param items The items to fetch.
0131       @param parts List of names of the parts of the item to fetch.
0132       @param msg The associated D-Bus message.
0133     */
0134     void scheduleItemsFetch(const Item::List &item, const QSet<QByteArray> &parts, const QDBusMessage &msg);
0135 
0136     /**
0137       Schedules deletion of the resource collection.
0138       This method is used to implement the ResourceBase::clearCache() functionality.
0139      */
0140     void scheduleResourceCollectionDeletion();
0141 
0142     /**
0143      * Schedule cache invalidation for @p collection.
0144      * @see ResourceBase::invalidateCache()
0145      */
0146     void scheduleCacheInvalidation(const Collection &collection);
0147 
0148     /**
0149       Insert synchronization completion marker into the task queue.
0150     */
0151     void scheduleFullSyncCompletion();
0152 
0153     /**
0154       Insert collection tree synchronization completion marker into the task queue.
0155     */
0156     void scheduleCollectionTreeSyncCompletion();
0157 
0158     /**
0159       Insert a custom task.
0160       @param methodName The method name, without signature, do not use the SLOT() macro
0161     */
0162     void
0163     scheduleCustomTask(QObject *receiver, const char *methodName, const QVariant &argument, ResourceBase::SchedulePriority priority = ResourceBase::Append);
0164 
0165     /**
0166      * Schedule a recursive move replay.
0167      */
0168     void scheduleMoveReplay(const Collection &movedCollection, RecursiveMover *mover);
0169 
0170     /**
0171       Returns true if no tasks are running or in the queue.
0172     */
0173     bool isEmpty();
0174 
0175     /**
0176       Returns the current task.
0177     */
0178     Task currentTask() const;
0179 
0180     Task &currentTask();
0181 
0182     /**
0183       Sets the online state.
0184     */
0185     void setOnline(bool state);
0186 
0187     /**
0188        Print debug output showing the state of the scheduler.
0189     */
0190     void dump() const;
0191     /**
0192        Print debug output showing the state of the scheduler.
0193     */
0194     QString dumpToString() const;
0195 
0196     /**
0197        Clear the state of the scheduler. Warning: this is intended to be
0198        used purely in debugging scenarios, as it might cause loss of uncommitted
0199        local changes.
0200     */
0201     void clear();
0202 
0203     /**
0204        Cancel everything the scheduler has still in queue. Keep the current task running though.
0205        It can be seen as a less aggressive clear() used when the user requested the resource to
0206        abort its activities. It properly cancel all the tasks in there.
0207     */
0208     void cancelQueues();
0209 
0210 public Q_SLOTS:
0211     /**
0212       Schedules replaying changes.
0213     */
0214     void scheduleChangeReplay();
0215 
0216     /**
0217       The current task has been finished
0218     */
0219     void taskDone();
0220 
0221     /**
0222       Like taskDone(), but special case for ItemFetch task
0223     */
0224     void itemFetchDone(const QString &msg);
0225 
0226     /**
0227       The current task can't be finished now and will be rescheduled later
0228     */
0229     void deferTask();
0230 
0231     /**
0232       Remove tasks that affect @p collection.
0233     */
0234     void collectionRemoved(const Akonadi::Collection &collection);
0235 
0236 Q_SIGNALS:
0237     void executeFullSync();
0238     void executeCollectionAttributesSync(const Akonadi::Collection &col);
0239     void executeCollectionSync(const Akonadi::Collection &col);
0240     void executeCollectionTreeSync();
0241     void executeTagSync();
0242     void executeRelationSync();
0243     void executeItemFetch(const Akonadi::Item &item, const QSet<QByteArray> &parts);
0244     void executeItemsFetch(const QList<Akonadi::Item> &items, const QSet<QByteArray> &parts);
0245     void executeResourceCollectionDeletion();
0246     void executeCacheInvalidation(const Akonadi::Collection &collection);
0247     void executeChangeReplay();
0248     void executeRecursiveMoveReplay(RecursiveMover *mover);
0249     void collectionTreeSyncComplete();
0250     void fullSyncComplete();
0251     void status(int status, const QString &message = QString());
0252 
0253 private Q_SLOTS:
0254     void scheduleNext();
0255     void executeNext();
0256 
0257 private:
0258     void signalTaskToTracker(const Task &task, const QByteArray &taskType, const QString &debugString = QString());
0259 
0260     // We have a number of task queues, by order of priority.
0261     // * PrependTaskQueue is for deferring the current task
0262     // * ChangeReplay must be first:
0263     //    change replays have to happen before we pull changes from the backend, otherwise
0264     //    we will overwrite our still unsaved local changes if the backend can't do
0265     //    incremental retrieval
0266     //
0267     // * then the stuff that is "immediately after change replay", like writeFile calls.
0268     // * then tasks which the user is waiting for, like ItemFetch (clicking on a mail) or
0269     //        SyncCollectionAttributes (folder properties dialog in kmail)
0270     // * then everything else (which includes the background email checking, which can take quite some time).
0271     enum QueueType {
0272         PrependTaskQueue,
0273         ChangeReplayQueue, // one task at most
0274         AfterChangeReplayQueue, // also one task at most, currently
0275         UserActionQueue,
0276         GenericTaskQueue,
0277         NQueueCount
0278     };
0279     using TaskList = QList<Task>;
0280 
0281     static QueueType queueTypeForTaskType(TaskType type);
0282     TaskList &queueForTaskType(TaskType type);
0283 
0284     TaskList mTaskList[NQueueCount];
0285 
0286     Task mCurrentTask;
0287     int mCurrentTasksQueue = -1; // queue mCurrentTask came from
0288     bool mOnline = false;
0289 };
0290 
0291 QDebug operator<<(QDebug, const ResourceScheduler::Task &task);
0292 QTextStream &operator<<(QTextStream &, const ResourceScheduler::Task &task);
0293 
0294 /// @endcond
0295 
0296 }