File indexing completed on 2024-12-01 04:33:15

0001 /* This file is part of the KDE project
0002 
0003    Copyright (C) 2005 Dario Massarin <nekkar@libero.it>
0004    Copyright (C) 2010 Matthias Fuchs <mat69@gmx.net>
0005 
0006    This program is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 */
0011 
0012 #ifndef SCHEDULER_H
0013 #define SCHEDULER_H
0014 
0015 #include <QMap>
0016 #include <QObject>
0017 #include <QTimerEvent>
0018 
0019 #include "core/job.h"
0020 #include "core/jobqueue.h"
0021 #include "kget_export.h"
0022 
0023 /**
0024  * @brief Scheduler class: what handle all the jobs in kget.
0025  *
0026  * This class handles all the jobs in kget. See job.h for further details.
0027  * When we want a job to be executed in kget, we have to add the queue
0028  * that owns the job in the scheduler calling the addQueue(JobQueue *) function.
0029  *
0030  */
0031 
0032 class KGET_EXPORT Scheduler : public QObject
0033 {
0034     Q_OBJECT
0035 
0036     friend class SchedulerTest;
0037 
0038 public:
0039     enum FailureStatus {
0040         None = 0,
0041         AboutToStall = 1,
0042         Stall = 2,
0043         StallTimeout = 3,
0044         Abort = 4,
0045         AbortTimeout = 5,
0046         Error = 6,
0047     };
0048 
0049     class JobFailure
0050     {
0051     public:
0052         JobFailure()
0053             : status(None)
0054             , time(-1)
0055             , count(0)
0056         {
0057         }
0058 
0059         bool isValid()
0060         {
0061             return ((status != None) && (time != -1));
0062         }
0063 
0064         FailureStatus status;
0065         int time;
0066         int count;
0067 
0068         bool operator==(JobFailure f) const
0069         {
0070             return ((status == f.status) && (time == f.time));
0071         }
0072         bool operator!=(JobFailure f) const
0073         {
0074             return ((status != f.status) || (time != f.time));
0075         }
0076     };
0077 
0078     Scheduler(QObject *parent = nullptr);
0079     ~Scheduler() override;
0080 
0081     /**
0082      * Starts globally the execution of the jobs
0083      *
0084      * @see stop()
0085      */
0086     void start();
0087 
0088     /**
0089      * Stops globally the execution of the jobs
0090      *
0091      * @see start()
0092      */
0093     void stop();
0094 
0095     /**
0096      * Can be used to suspend the scheduler before doing lenghty operations
0097      * and activating it later again
0098      *
0099      * NOTE does not stop running jobs, just prevents changes to jobs
0100      * HACK this is needed since the scheduler would constantly update the queue
0101      * when stopping starting multiple transfers, this slows down that operation a lot
0102      * and could result in transfers finishing before they are stopped etc.
0103      */
0104     void setIsSuspended(bool isSuspended);
0105 
0106     /**
0107      * The JobQueues will be informed of changes in the network connection
0108      * If there is no network connection then the Scheduler won't act on
0109      * the timerEvent or updateQueue
0110      */
0111     void setHasNetworkConnection(bool hasConnection);
0112 
0113     /**
0114      * Adds a queue to the scheduler.
0115      *
0116      * @param queue The queue that should be added
0117      */
0118     void addQueue(JobQueue *queue);
0119 
0120     /**
0121      * Deletes a queue from the scheduler.
0122      * If some jobs in the given queue are being executed, they are
0123      * first stopped, then removed from the scheduler.
0124      *
0125      * @param queue The queue that should be removed
0126      */
0127     void delQueue(JobQueue *queue);
0128 
0129     /**
0130      * @returns true if there is at least one Job in the Running state
0131      */
0132     bool hasRunningJobs() const;
0133 
0134     /**
0135      * @returns the number of jobs that are currently in a Running state
0136      */
0137     int countRunningJobs() const;
0138 
0139     /**
0140      * This function gets called by the KGet class whenever the settings
0141      * have changed.
0142      */
0143     void settingsChanged();
0144 
0145     // JobQueue notifications
0146     virtual void jobQueueChangedEvent(JobQueue *queue, JobQueue::Status status);
0147     virtual void jobQueueMovedJobEvent(JobQueue *queue, Job *job);
0148     virtual void jobQueueAddedJobEvent(JobQueue *queue, Job *job);
0149     virtual void jobQueueAddedJobsEvent(JobQueue *queue, const QList<Job *> jobs);
0150     virtual void jobQueueRemovedJobEvent(JobQueue *queue, Job *job);
0151     virtual void jobQueueRemovedJobsEvent(JobQueue *queue, const QList<Job *> jobs);
0152 
0153     // Job notifications
0154     virtual void jobChangedEvent(Job *job, Job::Status status);
0155     virtual void jobChangedEvent(Job *job, Job::Policy status);
0156     virtual void jobChangedEvent(Job *job, JobFailure failure);
0157 
0158 protected:
0159     /**
0160      * Updates the given queue, starting the jobs that come first in the queue
0161      * and stopping all the other
0162      *
0163      * @param queue the queue to update
0164      */
0165     void updateQueue(JobQueue *queue);
0166 
0167     /**
0168      * @return true if the given job should be running (and this depends
0169      * on the job policy and on its jobQueue status)
0170      *
0171      * @param job the job to evaluate
0172      */
0173     bool shouldBeRunning(Job *job);
0174 
0175 private:
0176     // Virtual QObject method
0177     void timerEvent(QTimerEvent *event) override;
0178 
0179     /**
0180      * Calls updateQueue for all queues
0181      * @see updateQueue
0182      */
0183     void updateAllQueues();
0184 
0185     bool shouldUpdate() const;
0186 
0187 private:
0188     QList<JobQueue *> m_queues;
0189     QMap<Job *, JobFailure> m_failedJobs;
0190 
0191     int m_failureCheckTimer;
0192 
0193     const int m_stallTime;
0194     int m_stallTimeout;
0195     int m_abortTimeout;
0196     bool m_isSuspended;
0197     bool m_hasConnection;
0198 };
0199 
0200 inline bool Scheduler::shouldUpdate() const
0201 {
0202     return !m_isSuspended && m_hasConnection;
0203 }
0204 #endif