Warning, file /pim/mailcommon/src/job/jobscheduler.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /** 0002 * SPDX-FileCopyrightText: 2004 David Faure <faure@kde.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "jobscheduler.h" 0008 using namespace MailCommon; 0009 0010 ScheduledTask::ScheduledTask(const Akonadi::Collection &folder, bool immediate) 0011 : mCurrentFolder(folder) 0012 , mImmediate(immediate) 0013 { 0014 } 0015 0016 Akonadi::Collection ScheduledTask::folder() const 0017 { 0018 return mCurrentFolder; 0019 } 0020 0021 bool ScheduledTask::isImmediate() const 0022 { 0023 return mImmediate; 0024 } 0025 0026 ScheduledTask::~ScheduledTask() = default; 0027 0028 JobScheduler::JobScheduler(QObject *parent) 0029 : QObject(parent) 0030 , mTimer(this) 0031 { 0032 connect(&mTimer, &QTimer::timeout, this, &JobScheduler::slotRunNextJob); 0033 // No need to start the internal timer yet, we wait for a task to be scheduled 0034 } 0035 0036 JobScheduler::~JobScheduler() 0037 { 0038 qDeleteAll(mTaskList); 0039 mTaskList.clear(); 0040 delete mCurrentTask; 0041 mCurrentTask = nullptr; 0042 delete mCurrentJob; 0043 } 0044 0045 void JobScheduler::registerTask(ScheduledTask *task) 0046 { 0047 bool immediate = task->isImmediate(); 0048 int typeId = task->taskTypeId(); 0049 if (typeId) { 0050 const Akonadi::Collection folder = task->folder(); 0051 // Search for an identical task already scheduled 0052 TaskList::Iterator end(mTaskList.end()); 0053 for (TaskList::Iterator it = mTaskList.begin(); it != end; ++it) { 0054 if ((*it)->taskTypeId() == typeId && (*it)->folder() == folder) { 0055 #ifdef DEBUG_SCHEDULER 0056 qCDebug(MAILCOMMON_LOG) << "JobScheduler: already having task type" << typeId << "for folder" << folder->label(); 0057 #endif 0058 delete task; 0059 if (!mCurrentTask && immediate) { 0060 ScheduledTask *task = *it; 0061 removeTask(it); 0062 runTaskNow(task); 0063 } 0064 return; 0065 } 0066 } 0067 // Note that scheduling an identical task as the one currently running is allowed. 0068 } 0069 if (!mCurrentTask && immediate) { 0070 runTaskNow(task); 0071 } else { 0072 #ifdef DEBUG_SCHEDULER 0073 qCDebug(MAILCOMMON_LOG) << "JobScheduler: adding task" << task << "(type" << task->taskTypeId() << ") for folder" << task->folder() 0074 << task->folder().name(); 0075 #endif 0076 mTaskList.append(task); 0077 if (immediate) { 0078 ++mPendingImmediateTasks; 0079 } 0080 if (!mCurrentTask && !mTimer.isActive()) { 0081 restartTimer(); 0082 } 0083 } 0084 } 0085 0086 void JobScheduler::removeTask(TaskList::Iterator &it) 0087 { 0088 if ((*it)->isImmediate()) { 0089 --mPendingImmediateTasks; 0090 } 0091 mTaskList.erase(it); 0092 } 0093 0094 void JobScheduler::interruptCurrentTask() 0095 { 0096 Q_ASSERT(mCurrentTask); 0097 #ifdef DEBUG_SCHEDULER 0098 qCDebug(MAILCOMMON_LOG) << "JobScheduler: interrupting job" << mCurrentJob << "for folder" << mCurrentTask->folder()->label(); 0099 #endif 0100 // File it again. This will either delete it or put it in mTaskList. 0101 registerTask(mCurrentTask); 0102 mCurrentTask = nullptr; 0103 mCurrentJob->kill(); // This deletes the job and calls slotJobFinished! 0104 } 0105 0106 void JobScheduler::slotRunNextJob() 0107 { 0108 while (!mCurrentJob) { 0109 #ifdef DEBUG_SCHEDULER 0110 qCDebug(MAILCOMMON_LOG) << "JobScheduler: slotRunNextJob"; 0111 #endif 0112 Q_ASSERT(mCurrentTask == nullptr); 0113 ScheduledTask *task = nullptr; 0114 // Find a task suitable for being run 0115 TaskList::Iterator end(mTaskList.end()); 0116 for (TaskList::Iterator it = mTaskList.begin(); it != end; ++it) { 0117 // Remove if folder died 0118 const Akonadi::Collection folder = (*it)->folder(); 0119 if (!folder.isValid()) { 0120 #ifdef DEBUG_SCHEDULER 0121 qCDebug(MAILCOMMON_LOG) << " folder for task" << (*it) << "was deleted"; 0122 #endif 0123 removeTask(it); 0124 if (!mTaskList.isEmpty()) { 0125 slotRunNextJob(); // to avoid the mess with invalid iterators :) 0126 } else { 0127 mTimer.stop(); 0128 } 0129 return; 0130 } 0131 #ifdef DEBUG_SCHEDULER 0132 qCDebug(MAILCOMMON_LOG) << " looking at folder" << folder.name(); 0133 #endif 0134 task = *it; 0135 removeTask(it); 0136 break; 0137 } 0138 0139 if (!task) { // found nothing to run, i.e. folder was opened 0140 return; // Timer keeps running, i.e. try again in 1 minute 0141 } 0142 0143 runTaskNow(task); 0144 } // If nothing to do for that task, loop and find another one to run 0145 } 0146 0147 void JobScheduler::restartTimer() 0148 { 0149 if (mPendingImmediateTasks > 0) { 0150 slotRunNextJob(); 0151 } else { 0152 #ifdef DEBUG_SCHEDULER 0153 mTimer.start(10000); // 10 seconds 0154 #else 0155 mTimer.start(1 * 60000); // 1 minute 0156 #endif 0157 } 0158 } 0159 0160 void JobScheduler::runTaskNow(ScheduledTask *task) 0161 { 0162 Q_ASSERT(mCurrentTask == nullptr); 0163 if (mCurrentTask) { 0164 interruptCurrentTask(); 0165 } 0166 mCurrentTask = task; 0167 mTimer.stop(); 0168 mCurrentJob = mCurrentTask->run(); 0169 #ifdef DEBUG_SCHEDULER 0170 qCDebug(MAILCOMMON_LOG) << "JobScheduler: task" << mCurrentTask << "(type" << mCurrentTask->taskTypeId() << ")" 0171 << "for folder" << mCurrentTask->folder()->label() << "returned job" << mCurrentJob << (mCurrentJob ? mCurrentJob->className() : 0); 0172 #endif 0173 if (!mCurrentJob) { // nothing to do, e.g. folder deleted 0174 delete mCurrentTask; 0175 mCurrentTask = nullptr; 0176 if (!mTaskList.isEmpty()) { 0177 restartTimer(); 0178 } 0179 return; 0180 } 0181 // Register the job in the folder. This makes it autodeleted if the folder is deleted. 0182 #if 0 0183 mCurrentTask->folder()->storage()->addJob(mCurrentJob); 0184 #endif 0185 connect(mCurrentJob, &ScheduledJob::finished, this, &JobScheduler::slotJobFinished); 0186 mCurrentJob->start(); 0187 } 0188 0189 void JobScheduler::slotJobFinished() 0190 { 0191 // Do we need to test for mCurrentJob->error()? What do we do then? 0192 #ifdef DEBUG_SCHEDULER 0193 qCDebug(MAILCOMMON_LOG) << "JobScheduler: slotJobFinished"; 0194 #endif 0195 delete mCurrentTask; 0196 mCurrentTask = nullptr; 0197 mCurrentJob = nullptr; 0198 if (!mTaskList.isEmpty()) { 0199 restartTimer(); 0200 } 0201 } 0202 0203 // D-Bus call to pause any background jobs 0204 void JobScheduler::pause() 0205 { 0206 mPendingImmediateTasks = 0; 0207 if (mCurrentJob && mCurrentJob->isCancellable()) { 0208 interruptCurrentTask(); 0209 } 0210 mTimer.stop(); 0211 } 0212 0213 void JobScheduler::resume() 0214 { 0215 restartTimer(); 0216 } 0217 0218 //// 0219 0220 ScheduledJob::ScheduledJob(const Akonadi::Collection &folder, bool immediate) 0221 : mImmediate(immediate) 0222 { 0223 mCancellable = true; 0224 mSrcFolder = folder; 0225 } 0226 0227 ScheduledJob::~ScheduledJob() = default; 0228 0229 #include "moc_jobscheduler.cpp"