Mailcommon

jobscheduler.cpp
1/**
2 * SPDX-FileCopyrightText: 2004 David Faure <faure@kde.org>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "jobscheduler.h"
8using namespace MailCommon;
9
11 : mCurrentFolder(folder)
12 , mImmediate(immediate)
13{
14}
15
17{
18 return mCurrentFolder;
19}
20
21bool ScheduledTask::isImmediate() const
22{
23 return mImmediate;
24}
25
26ScheduledTask::~ScheduledTask() = default;
27
28JobScheduler::JobScheduler(QObject *parent)
29 : QObject(parent)
30 , mTimer(this)
31{
32 connect(&mTimer, &QTimer::timeout, this, &JobScheduler::slotRunNextJob);
33 // No need to start the internal timer yet, we wait for a task to be scheduled
34}
35
36JobScheduler::~JobScheduler()
37{
38 qDeleteAll(mTaskList);
39 mTaskList.clear();
40 delete mCurrentTask;
41 mCurrentTask = nullptr;
42 delete mCurrentJob;
43}
44
46{
47 bool immediate = task->isImmediate();
48 int typeId = task->taskTypeId();
49 if (typeId) {
50 const Akonadi::Collection folder = task->folder();
51 // Search for an identical task already scheduled
52 TaskList::Iterator end(mTaskList.end());
53 for (TaskList::Iterator it = mTaskList.begin(); it != end; ++it) {
54 if ((*it)->taskTypeId() == typeId && (*it)->folder() == folder) {
55#ifdef DEBUG_SCHEDULER
56 qCDebug(MAILCOMMON_LOG) << "JobScheduler: already having task type" << typeId << "for folder" << folder->label();
57#endif
58 delete task;
59 if (!mCurrentTask && immediate) {
60 ScheduledTask *task = *it;
61 removeTask(it);
62 runTaskNow(task);
63 }
64 return;
65 }
66 }
67 // Note that scheduling an identical task as the one currently running is allowed.
68 }
69 if (!mCurrentTask && immediate) {
70 runTaskNow(task);
71 } else {
72#ifdef DEBUG_SCHEDULER
73 qCDebug(MAILCOMMON_LOG) << "JobScheduler: adding task" << task << "(type" << task->taskTypeId() << ") for folder" << task->folder()
74 << task->folder().name();
75#endif
76 mTaskList.append(task);
77 if (immediate) {
78 ++mPendingImmediateTasks;
79 }
80 if (!mCurrentTask && !mTimer.isActive()) {
81 restartTimer();
82 }
83 }
84}
85
86void JobScheduler::removeTask(TaskList::Iterator &it)
87{
88 if ((*it)->isImmediate()) {
89 --mPendingImmediateTasks;
90 }
91 mTaskList.erase(it);
92}
93
94void JobScheduler::interruptCurrentTask()
95{
96 Q_ASSERT(mCurrentTask);
97#ifdef DEBUG_SCHEDULER
98 qCDebug(MAILCOMMON_LOG) << "JobScheduler: interrupting job" << mCurrentJob << "for folder" << mCurrentTask->folder()->label();
99#endif
100 // File it again. This will either delete it or put it in mTaskList.
101 registerTask(mCurrentTask);
102 mCurrentTask = nullptr;
103 mCurrentJob->kill(); // This deletes the job and calls slotJobFinished!
104}
105
106void JobScheduler::slotRunNextJob()
107{
108 while (!mCurrentJob) {
109#ifdef DEBUG_SCHEDULER
110 qCDebug(MAILCOMMON_LOG) << "JobScheduler: slotRunNextJob";
111#endif
112 Q_ASSERT(mCurrentTask == nullptr);
113 ScheduledTask *task = nullptr;
114 // Find a task suitable for being run
115 TaskList::Iterator end(mTaskList.end());
116 for (TaskList::Iterator it = mTaskList.begin(); it != end; ++it) {
117 // Remove if folder died
118 const Akonadi::Collection folder = (*it)->folder();
119 if (!folder.isValid()) {
120#ifdef DEBUG_SCHEDULER
121 qCDebug(MAILCOMMON_LOG) << " folder for task" << (*it) << "was deleted";
122#endif
123 removeTask(it);
124 if (!mTaskList.isEmpty()) {
125 slotRunNextJob(); // to avoid the mess with invalid iterators :)
126 } else {
127 mTimer.stop();
128 }
129 return;
130 }
131#ifdef DEBUG_SCHEDULER
132 qCDebug(MAILCOMMON_LOG) << " looking at folder" << folder.name();
133#endif
134 task = *it;
135 removeTask(it);
136 break;
137 }
138
139 if (!task) { // found nothing to run, i.e. folder was opened
140 return; // Timer keeps running, i.e. try again in 1 minute
141 }
142
143 runTaskNow(task);
144 } // If nothing to do for that task, loop and find another one to run
145}
146
147void JobScheduler::restartTimer()
148{
149 if (mPendingImmediateTasks > 0) {
150 slotRunNextJob();
151 } else {
152#ifdef DEBUG_SCHEDULER
153 mTimer.start(10000); // 10 seconds
154#else
155 mTimer.start(1 * 60000); // 1 minute
156#endif
157 }
158}
159
160void JobScheduler::runTaskNow(ScheduledTask *task)
161{
162 Q_ASSERT(mCurrentTask == nullptr);
163 if (mCurrentTask) {
164 interruptCurrentTask();
165 }
166 mCurrentTask = task;
167 mTimer.stop();
168 mCurrentJob = mCurrentTask->run();
169#ifdef DEBUG_SCHEDULER
170 qCDebug(MAILCOMMON_LOG) << "JobScheduler: task" << mCurrentTask << "(type" << mCurrentTask->taskTypeId() << ")"
171 << "for folder" << mCurrentTask->folder()->label() << "returned job" << mCurrentJob << (mCurrentJob ? mCurrentJob->className() : 0);
172#endif
173 if (!mCurrentJob) { // nothing to do, e.g. folder deleted
174 delete mCurrentTask;
175 mCurrentTask = nullptr;
176 if (!mTaskList.isEmpty()) {
177 restartTimer();
178 }
179 return;
180 }
181 // Register the job in the folder. This makes it autodeleted if the folder is deleted.
182#if 0
183 mCurrentTask->folder()->storage()->addJob(mCurrentJob);
184#endif
185 connect(mCurrentJob, &ScheduledJob::finished, this, &JobScheduler::slotJobFinished);
186 mCurrentJob->start();
187}
188
189void JobScheduler::slotJobFinished()
190{
191 // Do we need to test for mCurrentJob->error()? What do we do then?
192#ifdef DEBUG_SCHEDULER
193 qCDebug(MAILCOMMON_LOG) << "JobScheduler: slotJobFinished";
194#endif
195 delete mCurrentTask;
196 mCurrentTask = nullptr;
197 mCurrentJob = nullptr;
198 if (!mTaskList.isEmpty()) {
199 restartTimer();
200 }
201}
202
203// D-Bus call to pause any background jobs
204void JobScheduler::pause()
205{
206 mPendingImmediateTasks = 0;
207 if (mCurrentJob && mCurrentJob->isCancellable()) {
208 interruptCurrentTask();
209 }
210 mTimer.stop();
211}
212
213void JobScheduler::resume()
214{
215 restartTimer();
216}
217
218////
219
220ScheduledJob::ScheduledJob(const Akonadi::Collection &folder, bool immediate)
221 : mImmediate(immediate)
222{
223 mCancellable = true;
224 mSrcFolder = folder;
225}
226
227ScheduledJob::~ScheduledJob() = default;
228
229#include "moc_jobscheduler.cpp"
bool isValid() const
QString name() const
bool isCancellable() const
Definition folderjob.cpp:48
virtual void kill()
Interrupt the job.
Definition folderjob.cpp:37
void start()
Start the job.
Definition folderjob.cpp:28
void finished()
Emitted when the job finishes all processing.
void registerTask(ScheduledTask *task)
Register a task to be done for a given folder.
A scheduled task is some information about a folder job that should be run later.
virtual int taskTypeId() const =0
An identifier for the type of task (a bit like QListViewItem::rtti).
virtual ScheduledJob * run()=0
Run this task, i.e.
ScheduledTask(const Akonadi::Collection &folder, bool immediate)
Creates a scheduled task for a given folder.
Akonadi::Collection folder() const
The folder which this task is supposed to handle, 0 if it was deleted meanwhile.
const QList< QKeySequence > & end()
The filter dialog.
void append(QList< T > &&value)
iterator begin()
void clear()
iterator end()
iterator erase(const_iterator begin, const_iterator end)
bool isEmpty() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QTaskBuilder< Task > task(Task &&task)
bool isActive() const const
void start()
void stop()
void timeout()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:01 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.