kmail

jobscheduler.cpp
1 
29 #include "jobscheduler.h"
30 #include "kmfolder.h"
31 #include "folderstorage.h"
32 #include "kmfoldermgr.h"
33 #include <kdebug.h>
34 
35 using namespace KMail;
36 
37 JobScheduler::JobScheduler( TQObject* parent, const char* name )
38  : TQObject( parent, name ), mTimer( this, "mTimer" ),
39  mPendingImmediateTasks( 0 ),
40  mCurrentTask( 0 ), mCurrentJob( 0 )
41 {
42  connect( &mTimer, TQ_SIGNAL( timeout() ), TQ_SLOT( slotRunNextJob() ) );
43  // No need to start the internal timer yet, we wait for a task to be scheduled
44 }
45 
46 
47 JobScheduler::~JobScheduler()
48 {
49  // delete tasks in tasklist (no autodelete for TQValueList)
50  for( TaskList::Iterator it = mTaskList.begin(); it != mTaskList.end(); ++it ) {
51  delete (*it);
52  }
53  delete mCurrentTask;
54  delete mCurrentJob;
55 }
56 
58 {
59  bool immediate = task->isImmediate();
60  int typeId = task->taskTypeId();
61  if ( typeId ) {
62  KMFolder* folder = task->folder();
63  // Search for an identical task already scheduled
64  for( TaskList::Iterator it = mTaskList.begin(); it != mTaskList.end(); ++it ) {
65  if ( (*it)->taskTypeId() == typeId && (*it)->folder() == folder ) {
66 #ifdef DEBUG_SCHEDULER
67  kdDebug(5006) << "JobScheduler: already having task type " << typeId << " for folder " << folder->label() << endl;
68 #endif
69  delete task;
70  if ( !mCurrentTask && immediate ) {
71  ScheduledTask* task = *it;
72  removeTask( it );
73  runTaskNow( task );
74  }
75  return;
76  }
77  }
78  // Note that scheduling an identical task as the one currently running is allowed.
79  }
80  if ( !mCurrentTask && immediate )
81  runTaskNow( task );
82  else {
83 #ifdef DEBUG_SCHEDULER
84  kdDebug(5006) << "JobScheduler: adding task " << task << " (type " << task->taskTypeId()
85  << ") for folder " << task->folder() << " " << task->folder()->label() << endl;
86 #endif
87  mTaskList.append( task );
88  if ( immediate )
89  ++mPendingImmediateTasks;
90  if ( !mCurrentTask && !mTimer.isActive() )
91  restartTimer();
92  }
93 }
94 
95 void JobScheduler::removeTask( TaskList::Iterator& it )
96 {
97  if ( (*it)->isImmediate() )
98  --mPendingImmediateTasks;
99  mTaskList.remove( it );
100 }
101 
103 {
104  if ( mCurrentTask && mCurrentTask->folder() == folder ) {
105  if ( mCurrentJob->isOpeningFolder() ) { // set when starting a job for this folder
106 #ifdef DEBUG_SCHEDULER
107  kdDebug(5006) << "JobScheduler: got the opening-notification for " << folder->label() << " as expected." << endl;
108 #endif
109  } else {
110  // Jobs scheduled from here should always be cancellable.
111  // One exception though, is when ExpireJob does its final KMMoveCommand.
112  // Then that command shouldn't kill its own parent job just because it opens a folder...
113  if ( mCurrentJob->isCancellable() )
114  interruptCurrentTask();
115  }
116  }
117 }
118 
119 void JobScheduler::interruptCurrentTask()
120 {
121  Q_ASSERT( mCurrentTask );
122 #ifdef DEBUG_SCHEDULER
123  kdDebug(5006) << "JobScheduler: interrupting job " << mCurrentJob << " for folder " << mCurrentTask->folder()->label() << endl;
124 #endif
125  // File it again. This will either delete it or put it in mTaskList.
126  registerTask( mCurrentTask );
127  mCurrentTask = 0;
128  mCurrentJob->kill(); // This deletes the job and calls slotJobFinished!
129 }
130 
131 void JobScheduler::slotRunNextJob()
132 {
133  while ( !mCurrentJob ) {
134 #ifdef DEBUG_SCHEDULER
135  kdDebug(5006) << "JobScheduler: slotRunNextJob" << endl;
136 #endif
137  Q_ASSERT( mCurrentTask == 0 );
138  ScheduledTask* task = 0;
139  // Find a task suitable for being run
140  for( TaskList::Iterator it = mTaskList.begin(); it != mTaskList.end(); ++it ) {
141  // Remove if folder died
142  KMFolder* folder = (*it)->folder();
143  if ( folder == 0 ) {
144 #ifdef DEBUG_SCHEDULER
145  kdDebug(5006) << " folder for task " << (*it) << " was deleted" << endl;
146 #endif
147  removeTask( it );
148  if ( !mTaskList.isEmpty() )
149  slotRunNextJob(); // to avoid the mess with invalid iterators :)
150  else
151  mTimer.stop();
152  return;
153  }
154  // The condition is that the folder must be unused (not open)
155  // But first we ask search folders to release their access to it
156  kmkernel->searchFolderMgr()->tryReleasingFolder( folder );
157 #ifdef DEBUG_SCHEDULER
158  kdDebug(5006) << " looking at folder " << folder->label()
159  << " " << folder->location()
160  << " isOpened=" << (*it)->folder()->isOpened() << endl;
161 #endif
162  if ( !folder->isOpened() ) {
163  task = *it;
164  removeTask( it );
165  break;
166  }
167  }
168 
169  if ( !task ) // found nothing to run, i.e. folder was opened
170  return; // Timer keeps running, i.e. try again in 1 minute
171 
172  runTaskNow( task );
173  } // If nothing to do for that task, loop and find another one to run
174 }
175 
176 void JobScheduler::restartTimer()
177 {
178  if ( mPendingImmediateTasks > 0 )
179  slotRunNextJob();
180  else
181  {
182 #ifdef DEBUG_SCHEDULER
183  mTimer.start( 10000 ); // 10 seconds
184 #else
185  mTimer.start( 1 * 60000 ); // 1 minute
186 #endif
187  }
188 }
189 
190 void JobScheduler::runTaskNow( ScheduledTask* task )
191 {
192  Q_ASSERT( mCurrentTask == 0 );
193  if ( mCurrentTask ) {
194  interruptCurrentTask();
195  }
196  mCurrentTask = task;
197  mTimer.stop();
198  mCurrentJob = mCurrentTask->run();
199 #ifdef DEBUG_SCHEDULER
200  kdDebug(5006) << "JobScheduler: task " << mCurrentTask
201  << " (type " << mCurrentTask->taskTypeId() << ")"
202  << " for folder " << mCurrentTask->folder()->label()
203  << " returned job " << mCurrentJob << " "
204  << ( mCurrentJob?mCurrentJob->className():0 ) << endl;
205 #endif
206  if ( !mCurrentJob ) { // nothing to do, e.g. folder deleted
207  delete mCurrentTask;
208  mCurrentTask = 0;
209  if ( !mTaskList.isEmpty() )
210  restartTimer();
211  return;
212  }
213  // Register the job in the folder. This makes it autodeleted if the folder is deleted.
214  mCurrentTask->folder()->storage()->addJob( mCurrentJob );
215  connect( mCurrentJob, TQ_SIGNAL( finished() ), this, TQ_SLOT( slotJobFinished() ) );
216  mCurrentJob->start();
217 }
218 
219 void JobScheduler::slotJobFinished()
220 {
221  // Do we need to test for mCurrentJob->error()? What do we do then?
222 #ifdef DEBUG_SCHEDULER
223  kdDebug(5006) << "JobScheduler: slotJobFinished" << endl;
224 #endif
225  delete mCurrentTask;
226  mCurrentTask = 0;
227  mCurrentJob = 0;
228  if ( !mTaskList.isEmpty() )
229  restartTimer();
230 }
231 
232 // DCOP call to pause any background jobs
233 void JobScheduler::pause()
234 {
235  mPendingImmediateTasks = 0;
236  if ( mCurrentJob && mCurrentJob->isCancellable() )
237  interruptCurrentTask();
238  mTimer.stop();
239 }
240 
241 void JobScheduler::resume()
242 {
243  restartTimer();
244 }
245 
247 
248 KMail::ScheduledJob::ScheduledJob( KMFolder* folder, bool immediate )
249  : FolderJob( 0, tOther, folder ), mImmediate( immediate ),
250  mOpeningFolder( false )
251 {
252  mCancellable = true;
253  mSrcFolder = folder;
254 }
255 
256 #include "jobscheduler.moc"
void addJob(FolderJob *) const
Add job for this folder.
Mail folder.
Definition: kmfolder.h:69
bool isOpened() const
Test if folder is opened.
Definition: kmfolder.cpp:500
virtual TQString label() const
Returns the label of the folder for visualization.
Definition: kmfolder.cpp:581
TQString location() const
Returns full path to folder file.
Definition: kmfolder.cpp:243
void notifyOpeningFolder(KMFolder *folder)
Called by [implementations of] FolderStorage::open() Interrupt any running job for this folder and re...
void registerTask(ScheduledTask *task)
Register a task to be done for a given folder The ownership of the task is transferred to the JobSche...
A scheduled task is some information about a folder job that should be run later.
Definition: jobscheduler.h:54
KMFolder * folder() const
The folder which this task is about, 0 if it was deleted meanwhile.
Definition: jobscheduler.h:79
virtual int taskTypeId() const =0
An identifier for the type of task (a bit like TQListViewItem::rtti) This allows to automatically pre...
virtual ScheduledJob * run()=0
Run this task, i.e.
folderdiaquotatab.h
Definition: aboutdata.cpp:40