• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdenetwork API Reference
  • KDE Home
  • Contact Us
 

kget

  • sources
  • kde-4.12
  • kdenetwork
  • kget
  • core
scheduler.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE project
2 
3  Copyright (C) 2004 Dario Massarin <nekkar@libero.it>
4  Coypright (C) 2010 Matthias Fuchs <mat69@gmx.net>
5 
6  This program is free software; you can redistribute it and/or
7  modify it under the terms of the GNU General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10 */
11 
12 #include "core/scheduler.h"
13 
14 #include "core/transferhandler.h"
15 #include "settings.h"
16 
17 #include <algorithm>
18 #include <boost/bind.hpp>
19 
20 #include <KDebug>
21 
22 Scheduler::Scheduler(QObject * parent)
23  : QObject(parent),
24  m_failureCheckTimer(0),
25  m_stallTime(5),
26  m_stallTimeout(Settings::reconnectDelay()),
27  m_abortTimeout(Settings::reconnectDelay()),
28  m_isSuspended(false),
29  m_hasConnection(true)
30 {
31 
32 }
33 
34 Scheduler::~Scheduler()
35 {
36 
37 }
38 
39 void Scheduler::setIsSuspended(bool isSuspended)
40 {
41  const bool changed = (isSuspended != m_isSuspended);
42  m_isSuspended = isSuspended;
43 
44  //update all the queues
45  if (changed && shouldUpdate()) {
46  updateAllQueues();
47  }
48 }
49 
50 void Scheduler::setHasNetworkConnection(bool hasConnection)
51 {
52  const bool changed = (hasConnection != m_hasConnection);
53  m_hasConnection = hasConnection;
54 
55  if (changed) {
56  if (hasConnection) {
57  if (!m_failureCheckTimer) {
58  m_failureCheckTimer = startTimer(1000);
59  }
60  updateAllQueues();
61  } else {
62  if (m_failureCheckTimer) {
63  killTimer(m_failureCheckTimer);
64  m_failureCheckTimer = 0;
65  }
66  foreach (JobQueue *queue, m_queues) {
67  std::for_each(queue->begin(), queue->end(), boost::bind(&Job::stop, _1));
68  }
69  }
70  }
71 }
72 
73 void Scheduler::addQueue(JobQueue * queue)
74 {
75  if(!m_queues.contains(queue))
76  m_queues.append(queue);
77 }
78 
79 void Scheduler::delQueue(JobQueue * queue)
80 {
81  m_queues.removeAll(queue);
82 }
83 
84 struct IsRunningJob
85 {
86  bool operator()(Job *job) const {return (job->status() == Job::Running);}
87 };
88 
89 bool Scheduler::hasRunningJobs() const
90 {
91  foreach (JobQueue *queue, m_queues) {
92  if (std::find_if(queue->begin(), queue->end(), IsRunningJob()) != queue->end()) {
93  return true;
94  }
95  }
96  return false;
97 }
98 
99 int Scheduler::countRunningJobs() const
100 {
101  int count = 0;
102  foreach(JobQueue * queue, m_queues) {
103  count += std::count_if(queue->begin(), queue->end(), IsRunningJob());
104  }
105 
106  return count;
107 }
108 
109 void Scheduler::settingsChanged()
110 {
111  m_stallTimeout = Settings::reconnectDelay();
112  m_abortTimeout = Settings::reconnectDelay();
113 
114  updateAllQueues();
115 }
116 
117 void Scheduler::jobQueueChangedEvent(JobQueue * queue, JobQueue::Status status)
118 {
119  if( status == JobQueue::Stopped )
120  {
121  JobQueue::iterator it = queue->begin();
122  JobQueue::iterator itEnd = queue->end();
123 
124  for ( ; it!=itEnd ; ++it)
125  {
126  if ((*it)->status() != Job::Stopped)
127  (*it)->stop();
128  }
129  }
130  else
131  updateQueue(queue);
132 }
133 
134 void Scheduler::jobQueueMovedJobEvent(JobQueue * queue, Job * job)
135 {
136  Q_UNUSED(job)
137 
138  updateQueue(queue);
139 }
140 
141 void Scheduler::jobQueueAddedJobEvent(JobQueue * queue, Job * job)
142 {
143  Q_UNUSED(job)
144 
145  updateQueue(queue);
146 }
147 
148 void Scheduler::jobQueueAddedJobsEvent(JobQueue *queue, const QList<Job*> jobs)
149 {
150  Q_UNUSED(jobs)
151 
152  updateQueue(queue);
153 }
154 
155 
156 void Scheduler::jobQueueRemovedJobEvent(JobQueue * queue, Job * job)
157 {
158  Q_UNUSED(job)
159 
160  updateQueue(queue);
161 }
162 
163 void Scheduler::jobQueueRemovedJobsEvent(JobQueue *queue, const QList<Job*> jobs)
164 {
165  Q_UNUSED(jobs)
166 
167  updateQueue(queue);
168 }
169 
170 void Scheduler::jobChangedEvent(Job * job, Job::Status status)
171 {
172  kDebug(5001) << "Scheduler::jobChangedEvent (job=" << job << " status=" << status << ")";
173 
174  if (!m_failureCheckTimer)
175  m_failureCheckTimer = startTimer(1000);
176 
177  if (status != Job::Running)
178  updateQueue( job->jobQueue() );
179 }
180 
181 void Scheduler::jobChangedEvent(Job * job, Job::Policy policy)
182 {
183  Q_UNUSED(policy)
184 
185  updateQueue( job->jobQueue() );
186 }
187 
188 void Scheduler::jobChangedEvent(Job * job, JobFailure failure)
189 {
190  switch(failure.status)
191  {
192  case None:
193  kDebug(5001) << "job = " << job << " failure (#" << failure.count << ") = None ";
194  break;
195  case AboutToStall:
196  kDebug(5001) << "job = " << job << " failure (#" << failure.count << ") = AboutToStall ";
197  break;
198  case Stall:
199  kDebug(5001) << "job = " << job << " failure (#" << failure.count << ") = Stall ";
200  break;
201  case StallTimeout:
202  kDebug(5001) << "job = " << job << " failure (#" << failure.count << ") = StallTimeout ";
203  break;
204  case Abort:
205  kDebug(5001) << "job = " << job << " failure (#" << failure.count << ") = Abort ";
206  break;
207  case AbortTimeout:
208  kDebug(5001) << "job = " << job << " failure (#" << failure.count << ") = AbortTimeout ";
209  break;
210  case Error:
211  kDebug(5001) << "job = " << job << " failure (#" << failure.count << ") = Error ";
212  break;
213  }
214 
215  if (failure.status == Error) {
216  static_cast<Transfer*>(job)->handler()->stop();
217  } else if (//If this happens the job just gets stopped
218  // Second condition: if count > reconnectRetries and Timeout happened trigger a stop/start BUT only if
219  // 10 timeouts have happened (9 of them without taking any action). This means every 10*Settings::reconnectDelay() (ex. 15s -> 150s)
220  (failure.count > Settings::reconnectRetries() && (failure.status == StallTimeout || failure.status == AbortTimeout)
221  && !((failure.count - Settings::reconnectRetries()) % 10)) )
222  {
223  //FIXME reenable once a connection limit per mirror is in place BUG:262098
224  //static_cast<Transfer*>(job)->handler()->stop();// This will trigger the changedEvent which will trigger an updateQueue call
225  job->stop();//FIXME remove once a connection limit per mirror is in place
226  } else if (failure.count <= Settings::reconnectRetries() && (failure.status == StallTimeout || failure.status == AbortTimeout)){
227  // First condition: if count <= reconnectRetries and Timeout happened trigger a stop/start
228  job->stop();//stops the job, it will be later restarted by updateQueue
229  }
230  else
231  updateQueue( job->jobQueue() );
232 }
233 
234 void Scheduler::start()
235 {
236  std::for_each(m_queues.begin(), m_queues.end(), boost::bind(&JobQueue::setStatus, _1, JobQueue::Running));
237 }
238 
239 void Scheduler::stop()
240 {
241  std::for_each(m_queues.begin(), m_queues.end(), boost::bind(&JobQueue::setStatus, _1, JobQueue::Stopped));
242 }
243 
244 void Scheduler::updateQueue( JobQueue * queue )
245 {
246  static bool updatingQueue = false;
247 
248  if (!shouldUpdate() || updatingQueue)
249  return;
250 
251  updatingQueue = true;
252 
253  int runningJobs = 0; //Jobs that are running (and not in the stallTimeout)
254  int waitingJobs = 0; //Jobs that we leave running but are in stallTimeout. We wait for them to start downloading, while we start other ones
255 
274  JobQueue::iterator it = queue->begin();
275  JobQueue::iterator itEnd = queue->end();
276 
277  for( int job=0 ; it!=itEnd ; ++it, ++job)
278  {
279  //kDebug(5001) << "MaxSimJobs " << queue->maxSimultaneousJobs();
280  kDebug(5001) << "Scheduler: Evaluating job " << job;
281 
282  JobFailure failure = m_failedJobs.value(*it);
283 
284  if( runningJobs < queue->maxSimultaneousJobs() && ((runningJobs + waitingJobs) < 2 * queue->maxSimultaneousJobs()) )
285  {
286  if( (*it)->status() == Job::Running || (*it)->status() == Job::FinishedKeepAlive )
287  {
288  if( !shouldBeRunning(*it) )
289  {
290  kDebug(5001) << "Scheduler: stopping job";
291  (*it)->stop();
292  }
293  else if(failure.status == None || failure.status == AboutToStall)
294  runningJobs++;
295  else
296  waitingJobs++;
297  }
298  else // != Job::Running
299  {
300  if( shouldBeRunning(*it) )
301  {
302  kDebug(5001) << "Scheduler: starting job";
303  (*it)->start();
304  if((failure.status == None || failure.status == AboutToStall) && (*it)->status() != Job::FinishedKeepAlive)
305  runningJobs++;
306  else
307  waitingJobs++;
308  }
309  }
310  }
311  else
312  {
313  //Stop all the other running downloads
314  kDebug(5001) << "Scheduler: stopping job over maxSimJobs limit";
315  (*it)->stop();
316  }
317  }
318 
319  updatingQueue = false;
320 }
321 
322 void Scheduler::updateAllQueues()
323 {
324  foreach (JobQueue *queue, m_queues) {
325  updateQueue(queue);
326  }
327 }
328 
329 bool Scheduler::shouldBeRunning( Job * job )
330 {
331  Job::Policy policy = job->policy();
332  Job::Status status = job->status();
333 
334  if( job->jobQueue()->status() == JobQueue::Stopped )
335  {
336  return ( (policy == Job::Start) &&
337  ((status != Job::Finished) &&
338  (status != Job::Aborted || job->error().type == Job::AutomaticRetry)));
339  }
340  else //JobQueue::Running
341  {
342  return ( (policy != Job::Stop) &&
343  ((status != Job::Finished) &&
344  (status != Job::Aborted || job->error().type == Job::AutomaticRetry)));
345  }
346 }
347 
348 void Scheduler::timerEvent( QTimerEvent * event )
349 {
350  Q_UNUSED(event)
351 // kDebug(5001);
352 
353  if (!shouldUpdate()) {
354  return;
355  }
356 
357  foreach(JobQueue * queue, m_queues)
358  {
359  JobQueue::iterator it = queue->begin();
360  JobQueue::iterator itEnd = queue->end();
361 
362  for( int job=0 ; it!=itEnd ; ++it, ++job)
363  {
364  JobFailure failure = m_failedJobs[*it];
365  JobFailure prevFailure = failure;
366 
367  if((*it)->isStalled()) // Stall status initialization
368  {
369  if(failure.status!=AboutToStall && failure.status!=Stall && failure.status!=StallTimeout)
370  {
371  failure.status = AboutToStall;
372  failure.time = 0;
373  failure.count = 0;
374  }
375  else
376  {
377  failure.time++;
378 
379  if(failure.time >= m_stallTime + m_stallTimeout)
380  {
381  failure.status = StallTimeout;
382  failure.count++;
383 
384  }
385  else if(failure.time >= m_stallTime)
386  failure.status = Stall;
387  else
388  failure.status = AboutToStall;
389 
390  if(failure.status == StallTimeout)
391  failure.time = m_stallTime;
392  }
393  }
394  else if((*it)->status() == Job::Aborted) // Abort status initialization
395  {
396  if ((*it)->error().type != Job::AutomaticRetry) {
397  failure.status = Error;
398  } else {
399  if(failure.status!=Abort)
400  {
401  failure.status = Abort;
402  failure.time = 0;
403  failure.count = 0;
404  }
405  else
406  {
407  failure.time++;
408  failure.count++;
409 
410  if(failure.time >= m_abortTimeout)
411  {
412  failure.status = AbortTimeout;
413  failure.count++;
414  }
415 
416  if(failure.status == AbortTimeout)
417  failure.time = 0;
418  }
419  }
420  }
421  else if ((*it)->isWorking())
422  {
423  failure = JobFailure();
424  }
425 
426  if(failure.isValid()) // A failure has been detected
427  m_failedJobs[*it] = failure;
428  else // No failure detected, remove it
429  m_failedJobs.remove(*it);
430 
431 // if(failure.isValid() || prevFailure.isValid())
432 // kDebug(5001) << "failure = " << failure.status << " T=" << failure.time << " prevFailure = " << prevFailure.status;
433 
434  if(failure.status != prevFailure.status)
435  jobChangedEvent(*it, failure); // Notify the scheduler
436  }
437  }
438 }
439 
440 #include "scheduler.moc"
Scheduler::stop
void stop()
Stops globally the execution of the jobs.
Definition: scheduler.cpp:239
Settings::reconnectRetries
static int reconnectRetries()
Get ReconnectRetries.
Definition: settings.h:715
Scheduler::None
Definition: scheduler.h:41
Scheduler::setIsSuspended
void setIsSuspended(bool isSuspended)
Can be used to suspend the scheduler before doing lenghty operations and activating it later again...
Definition: scheduler.cpp:39
Job::Finished
The job is stopped, but this also indicates that it stopped because an error occurred.
Definition: job.h:47
Scheduler::jobQueueRemovedJobsEvent
virtual void jobQueueRemovedJobsEvent(JobQueue *queue, const QList< Job * > jobs)
Definition: scheduler.cpp:163
Scheduler::delQueue
void delQueue(JobQueue *queue)
Deletes a queue from the scheduler.
Definition: scheduler.cpp:79
Job::AutomaticRetry
Definition: job.h:69
Job::error
Error error() const
Definition: job.h:96
Job::Status
Status
The status property describes the current job status.
Definition: job.h:42
Job::Stop
The scheduler should start this job even if its queue isn't in a Running status.
Definition: job.h:60
Scheduler::StallTimeout
Definition: scheduler.h:44
Scheduler::JobFailure
Definition: scheduler.h:50
Scheduler::jobQueueChangedEvent
virtual void jobQueueChangedEvent(JobQueue *queue, JobQueue::Status status)
Definition: scheduler.cpp:117
Job::FinishedKeepAlive
The job exited from its Running state successfully.
Definition: job.h:48
Scheduler::Abort
Definition: scheduler.h:45
Job::Error::type
ErrorType type
Definition: job.h:77
Job
Definition: job.h:35
Scheduler::countRunningJobs
int countRunningJobs() const
Definition: scheduler.cpp:99
JobQueue::Running
Definition: jobqueue.h:36
Scheduler::jobQueueAddedJobsEvent
virtual void jobQueueAddedJobsEvent(JobQueue *queue, const QList< Job * > jobs)
Definition: scheduler.cpp:148
Scheduler::Stall
Definition: scheduler.h:43
Scheduler::AbortTimeout
Definition: scheduler.h:46
QObject
JobQueue::Status
Status
Definition: jobqueue.h:36
Scheduler::updateQueue
void updateQueue(JobQueue *queue)
Updates the given queue, starting the jobs that come first in the queue and stopping all the other...
Definition: scheduler.cpp:244
Job::policy
Policy policy() const
Definition: job.h:95
Settings::reconnectDelay
static int reconnectDelay()
Get ReconnectDelay.
Definition: settings.h:734
Scheduler::JobFailure::count
int count
Definition: scheduler.h:60
scheduler.h
Scheduler::start
void start()
Starts globally the execution of the jobs.
Definition: scheduler.cpp:234
Scheduler::JobFailure::status
FailureStatus status
Definition: scheduler.h:58
Job::Running
Definition: job.h:43
Scheduler::addQueue
void addQueue(JobQueue *queue)
Adds a queue to the scheduler.
Definition: scheduler.cpp:73
Scheduler::jobQueueMovedJobEvent
virtual void jobQueueMovedJobEvent(JobQueue *queue, Job *job)
Definition: scheduler.cpp:134
Job::jobQueue
JobQueue * jobQueue()
Definition: job.h:86
Job::stop
virtual void stop()=0
Scheduler::AboutToStall
Definition: scheduler.h:42
JobQueue::begin
iterator begin()
Definition: jobqueue.h:57
Scheduler::jobChangedEvent
virtual void jobChangedEvent(Job *job, Job::Status status)
Definition: scheduler.cpp:170
Scheduler::setHasNetworkConnection
void setHasNetworkConnection(bool hasConnection)
The JobQueues will be informed of changes in the network connection If there is no network connection...
Definition: scheduler.cpp:50
Scheduler::Scheduler
Scheduler(QObject *parent=0)
Definition: scheduler.cpp:22
Job::Policy
Policy
The policy property describes how the scheduler should manage this job.
Definition: job.h:57
Scheduler::~Scheduler
~Scheduler()
Definition: scheduler.cpp:34
Settings
Definition: settings.h:10
Job::Aborted
The job is stopped.
Definition: job.h:45
transferhandler.h
Job::Stopped
The job is being executed.
Definition: job.h:44
JobQueue::Stopped
Definition: jobqueue.h:36
Scheduler::settingsChanged
void settingsChanged()
This function gets called by the KGet class whenever the settings have changed.
Definition: scheduler.cpp:109
JobQueue::status
Status status() const
Definition: jobqueue.h:52
settings.h
Job::status
Status status() const
Definition: job.h:93
JobQueue
Definition: jobqueue.h:32
Scheduler::jobQueueAddedJobEvent
virtual void jobQueueAddedJobEvent(JobQueue *queue, Job *job)
Definition: scheduler.cpp:141
Scheduler::jobQueueRemovedJobEvent
virtual void jobQueueRemovedJobEvent(JobQueue *queue, Job *job)
Definition: scheduler.cpp:156
JobQueue::setStatus
virtual void setStatus(Status queueStatus)
Sets the JobQueue status.
Definition: jobqueue.cpp:44
JobQueue::end
iterator end()
Definition: jobqueue.h:62
JobQueue::maxSimultaneousJobs
int maxSimultaneousJobs() const
Definition: jobqueue.cpp:71
Scheduler::Error
Definition: scheduler.h:47
Scheduler::shouldBeRunning
bool shouldBeRunning(Job *job)
Definition: scheduler.cpp:329
Scheduler::hasRunningJobs
bool hasRunningJobs() const
Definition: scheduler.cpp:89
Job::Start
Definition: job.h:58
Transfer
Definition: transfer.h:36
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:53:17 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kget

Skip menu "kget"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdenetwork API Reference

Skip menu "kdenetwork API Reference"
  • kget
  • kopete
  •   kopete
  •   libkopete
  • krdc
  • krfb

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal