Mercurial > hg > orthanc
annotate Core/JobsEngine/JobsRegistry.cpp @ 2589:a3fdfb6979ed jobs
getting rid of ReusableDicomConnection in REST API
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 15 May 2018 16:10:03 +0200 |
parents | 1b6a6d80b6f2 |
children | 140a539b4eba |
rev | line source |
---|---|
2569 | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2018 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU General Public License as | |
9 * published by the Free Software Foundation, either version 3 of the | |
10 * License, or (at your option) any later version. | |
11 * | |
12 * In addition, as a special exception, the copyright holders of this | |
13 * program give permission to link the code of its release with the | |
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
15 * that use the same license as the "OpenSSL" library), and distribute | |
16 * the linked executables. You must obey the GNU General Public License | |
17 * in all respects for all of the code used other than "OpenSSL". If you | |
18 * modify file(s) with this exception, you may extend this exception to | |
19 * your version of the file(s), but you are not obligated to do so. If | |
20 * you do not wish to do so, delete this exception statement from your | |
21 * version. If you delete this exception statement from all source files | |
22 * in the program, then also delete it here. | |
23 * | |
24 * This program is distributed in the hope that it will be useful, but | |
25 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
27 * General Public License for more details. | |
28 * | |
29 * You should have received a copy of the GNU General Public License | |
30 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
31 **/ | |
32 | |
33 | |
34 #include "../PrecompiledHeaders.h" | |
35 #include "JobsRegistry.h" | |
36 | |
37 #include "../Logging.h" | |
38 #include "../OrthancException.h" | |
39 #include "../Toolbox.h" | |
40 | |
41 namespace Orthanc | |
42 { | |
43 class JobsRegistry::JobHandler : public boost::noncopyable | |
44 { | |
45 private: | |
46 std::string id_; | |
47 JobState state_; | |
48 std::auto_ptr<IJob> job_; | |
49 int priority_; // "+inf()" means highest priority | |
50 boost::posix_time::ptime creationTime_; | |
51 boost::posix_time::ptime lastStateChangeTime_; | |
52 boost::posix_time::time_duration runtime_; | |
53 boost::posix_time::ptime retryTime_; | |
54 bool pauseScheduled_; | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
55 bool cancelScheduled_; |
2569 | 56 JobStatus lastStatus_; |
57 | |
58 void Touch() | |
59 { | |
60 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); | |
61 | |
62 if (state_ == JobState_Running) | |
63 { | |
64 runtime_ += (now - lastStateChangeTime_); | |
65 } | |
66 | |
67 lastStateChangeTime_ = now; | |
68 } | |
69 | |
70 void SetStateInternal(JobState state) | |
71 { | |
72 state_ = state; | |
73 pauseScheduled_ = false; | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
74 cancelScheduled_ = false; |
2569 | 75 Touch(); |
76 } | |
77 | |
78 public: | |
79 JobHandler(IJob* job, | |
80 int priority) : | |
81 id_(Toolbox::GenerateUuid()), | |
82 state_(JobState_Pending), | |
83 job_(job), | |
84 priority_(priority), | |
85 creationTime_(boost::posix_time::microsec_clock::universal_time()), | |
86 lastStateChangeTime_(creationTime_), | |
87 runtime_(boost::posix_time::milliseconds(0)), | |
88 retryTime_(creationTime_), | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
89 pauseScheduled_(false), |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
90 cancelScheduled_(false) |
2569 | 91 { |
92 if (job == NULL) | |
93 { | |
94 throw OrthancException(ErrorCode_NullPointer); | |
95 } | |
96 | |
97 lastStatus_ = JobStatus(ErrorCode_Success, *job); | |
2570
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
98 job->Start(); |
2569 | 99 } |
100 | |
101 const std::string& GetId() const | |
102 { | |
103 return id_; | |
104 } | |
105 | |
106 IJob& GetJob() const | |
107 { | |
108 assert(job_.get() != NULL); | |
109 return *job_; | |
110 } | |
111 | |
112 void SetPriority(int priority) | |
113 { | |
114 priority_ = priority; | |
115 } | |
116 | |
117 int GetPriority() const | |
118 { | |
119 return priority_; | |
120 } | |
121 | |
122 JobState GetState() const | |
123 { | |
124 return state_; | |
125 } | |
126 | |
127 void SetState(JobState state) | |
128 { | |
129 if (state == JobState_Retry) | |
130 { | |
131 // Use "SetRetryState()" | |
132 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
133 } | |
134 else | |
135 { | |
136 SetStateInternal(state); | |
137 } | |
138 } | |
139 | |
140 void SetRetryState(unsigned int timeout) | |
141 { | |
142 if (state_ == JobState_Running) | |
143 { | |
144 SetStateInternal(JobState_Retry); | |
145 retryTime_ = (boost::posix_time::microsec_clock::universal_time() + | |
146 boost::posix_time::milliseconds(timeout)); | |
147 } | |
148 else | |
149 { | |
150 // Only valid for running jobs | |
151 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
152 } | |
153 } | |
154 | |
155 void SchedulePause() | |
156 { | |
157 if (state_ == JobState_Running) | |
158 { | |
159 pauseScheduled_ = true; | |
160 } | |
161 else | |
162 { | |
163 // Only valid for running jobs | |
164 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
165 } | |
166 } | |
167 | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
168 void ScheduleCancel() |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
169 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
170 if (state_ == JobState_Running) |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
171 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
172 cancelScheduled_ = true; |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
173 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
174 else |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
175 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
176 // Only valid for running jobs |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
177 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
178 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
179 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
180 |
2569 | 181 bool IsPauseScheduled() |
182 { | |
183 return pauseScheduled_; | |
184 } | |
185 | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
186 bool IsCancelScheduled() |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
187 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
188 return cancelScheduled_; |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
189 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
190 |
2569 | 191 bool IsRetryReady(const boost::posix_time::ptime& now) const |
192 { | |
193 if (state_ != JobState_Retry) | |
194 { | |
195 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
196 } | |
197 else | |
198 { | |
199 return retryTime_ <= now; | |
200 } | |
201 } | |
202 | |
203 const boost::posix_time::ptime& GetCreationTime() const | |
204 { | |
205 return creationTime_; | |
206 } | |
207 | |
208 const boost::posix_time::ptime& GetLastStateChangeTime() const | |
209 { | |
210 return lastStateChangeTime_; | |
211 } | |
212 | |
213 const boost::posix_time::time_duration& GetRuntime() const | |
214 { | |
215 return runtime_; | |
216 } | |
217 | |
218 const JobStatus& GetLastStatus() const | |
219 { | |
220 return lastStatus_; | |
221 } | |
222 | |
223 void SetLastStatus(const JobStatus& status) | |
224 { | |
225 lastStatus_ = status; | |
226 Touch(); | |
227 } | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
228 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
229 void SetLastErrorCode(ErrorCode code) |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
230 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
231 lastStatus_.SetErrorCode(code); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
232 } |
2569 | 233 }; |
234 | |
235 | |
236 bool JobsRegistry::PriorityComparator::operator() (JobHandler*& a, | |
237 JobHandler*& b) const | |
238 { | |
239 return a->GetPriority() < b->GetPriority(); | |
240 } | |
241 | |
242 | |
243 #if defined(NDEBUG) | |
244 void JobsRegistry::CheckInvariants() const | |
245 { | |
246 } | |
247 | |
248 #else | |
249 bool JobsRegistry::IsPendingJob(const JobHandler& job) const | |
250 { | |
251 PendingJobs copy = pendingJobs_; | |
252 while (!copy.empty()) | |
253 { | |
254 if (copy.top() == &job) | |
255 { | |
256 return true; | |
257 } | |
258 | |
259 copy.pop(); | |
260 } | |
261 | |
262 return false; | |
263 } | |
264 | |
265 bool JobsRegistry::IsCompletedJob(JobHandler& job) const | |
266 { | |
267 for (CompletedJobs::const_iterator it = completedJobs_.begin(); | |
268 it != completedJobs_.end(); ++it) | |
269 { | |
270 if (*it == &job) | |
271 { | |
272 return true; | |
273 } | |
274 } | |
275 | |
276 return false; | |
277 } | |
278 | |
279 bool JobsRegistry::IsRetryJob(JobHandler& job) const | |
280 { | |
281 return retryJobs_.find(&job) != retryJobs_.end(); | |
282 } | |
283 | |
284 void JobsRegistry::CheckInvariants() const | |
285 { | |
286 { | |
287 PendingJobs copy = pendingJobs_; | |
288 while (!copy.empty()) | |
289 { | |
290 assert(copy.top()->GetState() == JobState_Pending); | |
291 copy.pop(); | |
292 } | |
293 } | |
294 | |
295 assert(completedJobs_.size() <= maxCompletedJobs_); | |
296 | |
297 for (CompletedJobs::const_iterator it = completedJobs_.begin(); | |
298 it != completedJobs_.end(); ++it) | |
299 { | |
300 assert((*it)->GetState() == JobState_Success || | |
301 (*it)->GetState() == JobState_Failure); | |
302 } | |
303 | |
304 for (RetryJobs::const_iterator it = retryJobs_.begin(); | |
305 it != retryJobs_.end(); ++it) | |
306 { | |
307 assert((*it)->GetState() == JobState_Retry); | |
308 } | |
309 | |
310 for (JobsIndex::const_iterator it = jobsIndex_.begin(); | |
311 it != jobsIndex_.end(); ++it) | |
312 { | |
313 JobHandler& job = *it->second; | |
314 | |
315 assert(job.GetId() == it->first); | |
316 | |
317 switch (job.GetState()) | |
318 { | |
319 case JobState_Pending: | |
320 assert(!IsRetryJob(job) && IsPendingJob(job) && !IsCompletedJob(job)); | |
321 break; | |
322 | |
323 case JobState_Success: | |
324 case JobState_Failure: | |
325 assert(!IsRetryJob(job) && !IsPendingJob(job) && IsCompletedJob(job)); | |
326 break; | |
327 | |
328 case JobState_Retry: | |
329 assert(IsRetryJob(job) && !IsPendingJob(job) && !IsCompletedJob(job)); | |
330 break; | |
331 | |
332 case JobState_Running: | |
333 case JobState_Paused: | |
334 assert(!IsRetryJob(job) && !IsPendingJob(job) && !IsCompletedJob(job)); | |
335 break; | |
336 | |
337 default: | |
338 throw OrthancException(ErrorCode_InternalError); | |
339 } | |
340 } | |
341 } | |
342 #endif | |
343 | |
344 | |
345 void JobsRegistry::ForgetOldCompletedJobs() | |
346 { | |
347 if (maxCompletedJobs_ != 0) | |
348 { | |
349 while (completedJobs_.size() > maxCompletedJobs_) | |
350 { | |
351 assert(completedJobs_.front() != NULL); | |
352 | |
353 std::string id = completedJobs_.front()->GetId(); | |
354 assert(jobsIndex_.find(id) != jobsIndex_.end()); | |
355 | |
356 jobsIndex_.erase(id); | |
357 delete(completedJobs_.front()); | |
358 completedJobs_.pop_front(); | |
359 } | |
360 } | |
361 } | |
362 | |
363 | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
364 void JobsRegistry::SetCompletedJob(JobHandler& job, |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
365 bool success) |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
366 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
367 job.SetState(success ? JobState_Success : JobState_Failure); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
368 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
369 completedJobs_.push_back(&job); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
370 ForgetOldCompletedJobs(); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
371 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
372 someJobComplete_.notify_all(); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
373 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
374 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
375 |
2569 | 376 void JobsRegistry::MarkRunningAsCompleted(JobHandler& job, |
377 bool success) | |
378 { | |
379 LOG(INFO) << "Job has completed with " << (success ? "success" : "failure") | |
380 << ": " << job.GetId(); | |
381 | |
382 CheckInvariants(); | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
383 |
2569 | 384 assert(job.GetState() == JobState_Running); |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
385 SetCompletedJob(job, success); |
2570
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
386 |
2569 | 387 CheckInvariants(); |
388 } | |
389 | |
390 | |
391 void JobsRegistry::MarkRunningAsRetry(JobHandler& job, | |
392 unsigned int timeout) | |
393 { | |
394 LOG(INFO) << "Job scheduled for retry in " << timeout << "ms: " << job.GetId(); | |
395 | |
396 CheckInvariants(); | |
397 | |
398 assert(job.GetState() == JobState_Running && | |
399 retryJobs_.find(&job) == retryJobs_.end()); | |
400 | |
401 retryJobs_.insert(&job); | |
402 job.SetRetryState(timeout); | |
403 | |
404 CheckInvariants(); | |
405 } | |
406 | |
407 | |
408 void JobsRegistry::MarkRunningAsPaused(JobHandler& job) | |
409 { | |
410 LOG(INFO) << "Job paused: " << job.GetId(); | |
411 | |
412 CheckInvariants(); | |
413 assert(job.GetState() == JobState_Running); | |
414 | |
415 job.SetState(JobState_Paused); | |
416 | |
417 CheckInvariants(); | |
418 } | |
419 | |
420 | |
2570
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
421 bool JobsRegistry::GetStateInternal(JobState& state, |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
422 const std::string& id) |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
423 { |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
424 CheckInvariants(); |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
425 |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
426 JobsIndex::const_iterator it = jobsIndex_.find(id); |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
427 if (it == jobsIndex_.end()) |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
428 { |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
429 return false; |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
430 } |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
431 else |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
432 { |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
433 state = it->second->GetState(); |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
434 return true; |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
435 } |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
436 } |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
437 |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
438 |
2569 | 439 JobsRegistry::~JobsRegistry() |
440 { | |
441 for (JobsIndex::iterator it = jobsIndex_.begin(); it != jobsIndex_.end(); ++it) | |
442 { | |
443 assert(it->second != NULL); | |
444 delete it->second; | |
445 } | |
446 } | |
447 | |
448 | |
449 void JobsRegistry::SetMaxCompletedJobs(size_t i) | |
450 { | |
451 boost::mutex::scoped_lock lock(mutex_); | |
452 CheckInvariants(); | |
453 | |
454 maxCompletedJobs_ = i; | |
455 ForgetOldCompletedJobs(); | |
456 | |
457 CheckInvariants(); | |
458 } | |
459 | |
460 | |
461 void JobsRegistry::ListJobs(std::set<std::string>& target) | |
462 { | |
463 boost::mutex::scoped_lock lock(mutex_); | |
464 CheckInvariants(); | |
465 | |
466 for (JobsIndex::const_iterator it = jobsIndex_.begin(); | |
467 it != jobsIndex_.end(); ++it) | |
468 { | |
469 target.insert(it->first); | |
470 } | |
471 } | |
472 | |
473 | |
474 bool JobsRegistry::GetJobInfo(JobInfo& target, | |
475 const std::string& id) | |
476 { | |
477 boost::mutex::scoped_lock lock(mutex_); | |
478 CheckInvariants(); | |
479 | |
480 JobsIndex::const_iterator found = jobsIndex_.find(id); | |
481 | |
482 if (found == jobsIndex_.end()) | |
483 { | |
484 return false; | |
485 } | |
486 else | |
487 { | |
488 const JobHandler& handler = *found->second; | |
489 target = JobInfo(handler.GetId(), | |
490 handler.GetPriority(), | |
491 handler.GetState(), | |
492 handler.GetLastStatus(), | |
493 handler.GetCreationTime(), | |
494 handler.GetLastStateChangeTime(), | |
495 handler.GetRuntime()); | |
496 return true; | |
497 } | |
498 } | |
499 | |
500 | |
501 void JobsRegistry::Submit(std::string& id, | |
502 IJob* job, // Takes ownership | |
503 int priority) | |
504 { | |
505 std::auto_ptr<JobHandler> handler(new JobHandler(job, priority)); | |
506 | |
507 boost::mutex::scoped_lock lock(mutex_); | |
508 CheckInvariants(); | |
509 | |
510 id = handler->GetId(); | |
511 | |
512 pendingJobs_.push(handler.get()); | |
513 pendingJobAvailable_.notify_one(); | |
514 | |
515 jobsIndex_.insert(std::make_pair(id, handler.release())); | |
516 | |
517 LOG(INFO) << "New job submitted with priority " << priority << ": " << id; | |
518 | |
519 CheckInvariants(); | |
520 } | |
521 | |
522 | |
523 void JobsRegistry::Submit(IJob* job, // Takes ownership | |
524 int priority) | |
525 { | |
526 std::string id; | |
527 Submit(id, job, priority); | |
528 } | |
529 | |
530 | |
2570
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
531 bool JobsRegistry::SubmitAndWait(IJob* job, // Takes ownership |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
532 int priority) |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
533 { |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
534 std::string id; |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
535 Submit(id, job, priority); |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
536 |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
537 JobState state; |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
538 |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
539 { |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
540 boost::mutex::scoped_lock lock(mutex_); |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
541 |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
542 while (GetStateInternal(state, id) && |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
543 state != JobState_Success && |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
544 state != JobState_Failure) |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
545 { |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
546 someJobComplete_.wait(lock); |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
547 } |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
548 } |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
549 |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
550 return (state == JobState_Success); |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
551 } |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
552 |
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
553 |
2573
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
554 bool JobsRegistry::SetPriority(const std::string& id, |
2569 | 555 int priority) |
556 { | |
557 LOG(INFO) << "Changing priority to " << priority << " for job: " << id; | |
558 | |
559 boost::mutex::scoped_lock lock(mutex_); | |
560 CheckInvariants(); | |
561 | |
562 JobsIndex::iterator found = jobsIndex_.find(id); | |
563 | |
564 if (found == jobsIndex_.end()) | |
565 { | |
566 LOG(WARNING) << "Unknown job: " << id; | |
2573
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
567 return false; |
2569 | 568 } |
569 else | |
570 { | |
571 found->second->SetPriority(priority); | |
572 | |
573 if (found->second->GetState() == JobState_Pending) | |
574 { | |
575 // If the job is pending, we need to reconstruct the | |
576 // priority queue, as the heap condition has changed | |
577 | |
578 PendingJobs copy; | |
579 std::swap(copy, pendingJobs_); | |
580 | |
581 assert(pendingJobs_.empty()); | |
582 while (!copy.empty()) | |
583 { | |
584 pendingJobs_.push(copy.top()); | |
585 copy.pop(); | |
586 } | |
587 } | |
2573
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
588 |
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
589 CheckInvariants(); |
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
590 return true; |
2569 | 591 } |
592 } | |
593 | |
594 | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
595 void JobsRegistry::RemovePendingJob(const std::string& id) |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
596 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
597 // If the job is pending, we need to reconstruct the priority |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
598 // queue to remove it |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
599 PendingJobs copy; |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
600 std::swap(copy, pendingJobs_); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
601 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
602 assert(pendingJobs_.empty()); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
603 while (!copy.empty()) |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
604 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
605 if (copy.top()->GetId() != id) |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
606 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
607 pendingJobs_.push(copy.top()); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
608 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
609 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
610 copy.pop(); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
611 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
612 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
613 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
614 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
615 void JobsRegistry::RemoveRetryJob(JobHandler* handler) |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
616 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
617 RetryJobs::iterator item = retryJobs_.find(handler); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
618 assert(item != retryJobs_.end()); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
619 retryJobs_.erase(item); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
620 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
621 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
622 |
2573
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
623 bool JobsRegistry::Pause(const std::string& id) |
2569 | 624 { |
625 LOG(INFO) << "Pausing job: " << id; | |
626 | |
627 boost::mutex::scoped_lock lock(mutex_); | |
628 CheckInvariants(); | |
629 | |
630 JobsIndex::iterator found = jobsIndex_.find(id); | |
631 | |
632 if (found == jobsIndex_.end()) | |
633 { | |
634 LOG(WARNING) << "Unknown job: " << id; | |
2573
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
635 return false; |
2569 | 636 } |
637 else | |
638 { | |
639 switch (found->second->GetState()) | |
640 { | |
641 case JobState_Pending: | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
642 RemovePendingJob(id); |
2569 | 643 found->second->SetState(JobState_Paused); |
644 break; | |
645 | |
646 case JobState_Retry: | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
647 RemoveRetryJob(found->second); |
2569 | 648 found->second->SetState(JobState_Paused); |
649 break; | |
650 | |
651 case JobState_Paused: | |
652 case JobState_Success: | |
653 case JobState_Failure: | |
654 // Nothing to be done | |
655 break; | |
656 | |
657 case JobState_Running: | |
658 found->second->SchedulePause(); | |
659 break; | |
660 | |
661 default: | |
662 throw OrthancException(ErrorCode_InternalError); | |
663 } | |
2573
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
664 |
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
665 CheckInvariants(); |
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
666 return true; |
2569 | 667 } |
668 } | |
669 | |
670 | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
671 bool JobsRegistry::Cancel(const std::string& id) |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
672 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
673 LOG(INFO) << "Canceling job: " << id; |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
674 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
675 boost::mutex::scoped_lock lock(mutex_); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
676 CheckInvariants(); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
677 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
678 JobsIndex::iterator found = jobsIndex_.find(id); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
679 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
680 if (found == jobsIndex_.end()) |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
681 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
682 LOG(WARNING) << "Unknown job: " << id; |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
683 return false; |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
684 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
685 else |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
686 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
687 switch (found->second->GetState()) |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
688 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
689 case JobState_Pending: |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
690 RemovePendingJob(id); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
691 SetCompletedJob(*found->second, false); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
692 found->second->SetLastErrorCode(ErrorCode_CanceledJob); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
693 break; |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
694 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
695 case JobState_Retry: |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
696 RemoveRetryJob(found->second); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
697 SetCompletedJob(*found->second, false); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
698 found->second->SetLastErrorCode(ErrorCode_CanceledJob); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
699 break; |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
700 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
701 case JobState_Paused: |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
702 SetCompletedJob(*found->second, false); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
703 found->second->SetLastErrorCode(ErrorCode_CanceledJob); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
704 break; |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
705 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
706 case JobState_Success: |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
707 case JobState_Failure: |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
708 // Nothing to be done |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
709 break; |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
710 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
711 case JobState_Running: |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
712 found->second->ScheduleCancel(); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
713 break; |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
714 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
715 default: |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
716 throw OrthancException(ErrorCode_InternalError); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
717 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
718 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
719 CheckInvariants(); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
720 return true; |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
721 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
722 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
723 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
724 |
2573
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
725 bool JobsRegistry::Resume(const std::string& id) |
2569 | 726 { |
727 LOG(INFO) << "Resuming job: " << id; | |
728 | |
729 boost::mutex::scoped_lock lock(mutex_); | |
730 CheckInvariants(); | |
731 | |
732 JobsIndex::iterator found = jobsIndex_.find(id); | |
733 | |
734 if (found == jobsIndex_.end()) | |
735 { | |
736 LOG(WARNING) << "Unknown job: " << id; | |
2573
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
737 return false; |
2569 | 738 } |
739 else if (found->second->GetState() != JobState_Paused) | |
740 { | |
741 LOG(WARNING) << "Cannot resume a job that is not paused: " << id; | |
2573
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
742 return false; |
2569 | 743 } |
744 else | |
745 { | |
746 found->second->SetState(JobState_Pending); | |
747 pendingJobs_.push(found->second); | |
748 pendingJobAvailable_.notify_one(); | |
2573
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
749 CheckInvariants(); |
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
750 return true; |
2569 | 751 } |
752 } | |
753 | |
754 | |
2573
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
755 bool JobsRegistry::Resubmit(const std::string& id) |
2569 | 756 { |
757 LOG(INFO) << "Resubmitting failed job: " << id; | |
758 | |
759 boost::mutex::scoped_lock lock(mutex_); | |
760 CheckInvariants(); | |
761 | |
762 JobsIndex::iterator found = jobsIndex_.find(id); | |
763 | |
764 if (found == jobsIndex_.end()) | |
765 { | |
766 LOG(WARNING) << "Unknown job: " << id; | |
2573
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
767 return false; |
2569 | 768 } |
769 else if (found->second->GetState() != JobState_Failure) | |
770 { | |
771 LOG(WARNING) << "Cannot resubmit a job that has not failed: " << id; | |
2573
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
772 return false; |
2569 | 773 } |
774 else | |
775 { | |
2583
1b6a6d80b6f2
OrthancPeerStoreJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2581
diff
changeset
|
776 found->second->GetJob().SignalResubmit(); |
1b6a6d80b6f2
OrthancPeerStoreJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2581
diff
changeset
|
777 |
2569 | 778 bool ok = false; |
779 for (CompletedJobs::iterator it = completedJobs_.begin(); | |
780 it != completedJobs_.end(); ++it) | |
781 { | |
782 if (*it == found->second) | |
783 { | |
784 ok = true; | |
785 completedJobs_.erase(it); | |
786 break; | |
787 } | |
788 } | |
789 | |
790 assert(ok); | |
791 | |
792 found->second->SetState(JobState_Pending); | |
793 pendingJobs_.push(found->second); | |
794 pendingJobAvailable_.notify_one(); | |
2573
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
795 |
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
796 CheckInvariants(); |
3372c5255333
StoreScuJob, Orthanc Explorer for jobs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2570
diff
changeset
|
797 return true; |
2569 | 798 } |
799 } | |
800 | |
801 | |
802 void JobsRegistry::ScheduleRetries() | |
803 { | |
804 boost::mutex::scoped_lock lock(mutex_); | |
805 CheckInvariants(); | |
806 | |
807 RetryJobs copy; | |
808 std::swap(copy, retryJobs_); | |
809 | |
810 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); | |
811 | |
812 assert(retryJobs_.empty()); | |
813 for (RetryJobs::iterator it = copy.begin(); it != copy.end(); ++it) | |
814 { | |
815 if ((*it)->IsRetryReady(now)) | |
816 { | |
817 LOG(INFO) << "Retrying job: " << (*it)->GetId(); | |
818 (*it)->SetState(JobState_Pending); | |
819 pendingJobs_.push(*it); | |
820 pendingJobAvailable_.notify_one(); | |
821 } | |
822 else | |
823 { | |
824 retryJobs_.insert(*it); | |
825 } | |
826 } | |
827 | |
828 CheckInvariants(); | |
829 } | |
830 | |
831 | |
832 bool JobsRegistry::GetState(JobState& state, | |
833 const std::string& id) | |
834 { | |
835 boost::mutex::scoped_lock lock(mutex_); | |
2570
2e879c796ec7
JobsRegistry::SubmitAndWait(), StoreScuJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2569
diff
changeset
|
836 return GetStateInternal(state, id); |
2569 | 837 } |
838 | |
839 | |
840 JobsRegistry::RunningJob::RunningJob(JobsRegistry& registry, | |
841 unsigned int timeout) : | |
842 registry_(registry), | |
843 handler_(NULL), | |
844 targetState_(JobState_Failure), | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
845 targetRetryTimeout_(0), |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
846 canceled_(false) |
2569 | 847 { |
848 { | |
849 boost::mutex::scoped_lock lock(registry_.mutex_); | |
850 | |
851 while (registry_.pendingJobs_.empty()) | |
852 { | |
853 if (timeout == 0) | |
854 { | |
855 registry_.pendingJobAvailable_.wait(lock); | |
856 } | |
857 else | |
858 { | |
859 bool success = registry_.pendingJobAvailable_.timed_wait | |
860 (lock, boost::posix_time::milliseconds(timeout)); | |
861 if (!success) | |
862 { | |
863 // No pending job | |
864 return; | |
865 } | |
866 } | |
867 } | |
868 | |
869 handler_ = registry_.pendingJobs_.top(); | |
870 registry_.pendingJobs_.pop(); | |
871 | |
872 assert(handler_->GetState() == JobState_Pending); | |
873 handler_->SetState(JobState_Running); | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
874 handler_->SetLastErrorCode(ErrorCode_Success); |
2569 | 875 |
876 job_ = &handler_->GetJob(); | |
877 id_ = handler_->GetId(); | |
878 priority_ = handler_->GetPriority(); | |
879 } | |
880 } | |
881 | |
882 | |
883 JobsRegistry::RunningJob::~RunningJob() | |
884 { | |
885 if (IsValid()) | |
886 { | |
887 boost::mutex::scoped_lock lock(registry_.mutex_); | |
888 | |
889 switch (targetState_) | |
890 { | |
891 case JobState_Failure: | |
892 registry_.MarkRunningAsCompleted(*handler_, false); | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
893 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
894 if (canceled_) |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
895 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
896 handler_->SetLastErrorCode(ErrorCode_CanceledJob); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
897 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
898 |
2569 | 899 break; |
900 | |
901 case JobState_Success: | |
902 registry_.MarkRunningAsCompleted(*handler_, true); | |
903 break; | |
904 | |
905 case JobState_Paused: | |
906 registry_.MarkRunningAsPaused(*handler_); | |
907 break; | |
908 | |
909 case JobState_Retry: | |
910 registry_.MarkRunningAsRetry(*handler_, targetRetryTimeout_); | |
911 break; | |
912 | |
913 default: | |
914 assert(0); | |
915 } | |
916 } | |
917 } | |
918 | |
919 | |
920 bool JobsRegistry::RunningJob::IsValid() const | |
921 { | |
922 return (handler_ != NULL && | |
923 job_ != NULL); | |
924 } | |
925 | |
926 | |
927 const std::string& JobsRegistry::RunningJob::GetId() const | |
928 { | |
929 if (!IsValid()) | |
930 { | |
931 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
932 } | |
933 else | |
934 { | |
935 return id_; | |
936 } | |
937 } | |
938 | |
939 | |
940 int JobsRegistry::RunningJob::GetPriority() const | |
941 { | |
942 if (!IsValid()) | |
943 { | |
944 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
945 } | |
946 else | |
947 { | |
948 return priority_; | |
949 } | |
950 } | |
951 | |
952 | |
953 IJob& JobsRegistry::RunningJob::GetJob() | |
954 { | |
955 if (!IsValid()) | |
956 { | |
957 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
958 } | |
959 else | |
960 { | |
961 return *job_; | |
962 } | |
963 } | |
964 | |
965 | |
966 bool JobsRegistry::RunningJob::IsPauseScheduled() | |
967 { | |
968 if (!IsValid()) | |
969 { | |
970 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
971 } | |
972 else | |
973 { | |
974 boost::mutex::scoped_lock lock(registry_.mutex_); | |
975 registry_.CheckInvariants(); | |
976 assert(handler_->GetState() == JobState_Running); | |
977 | |
978 return handler_->IsPauseScheduled(); | |
979 } | |
980 } | |
981 | |
982 | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
983 bool JobsRegistry::RunningJob::IsCancelScheduled() |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
984 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
985 if (!IsValid()) |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
986 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
987 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
988 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
989 else |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
990 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
991 boost::mutex::scoped_lock lock(registry_.mutex_); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
992 registry_.CheckInvariants(); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
993 assert(handler_->GetState() == JobState_Running); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
994 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
995 return handler_->IsCancelScheduled(); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
996 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
997 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
998 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
999 |
2569 | 1000 void JobsRegistry::RunningJob::MarkSuccess() |
1001 { | |
1002 if (!IsValid()) | |
1003 { | |
1004 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
1005 } | |
1006 else | |
1007 { | |
1008 targetState_ = JobState_Success; | |
1009 } | |
1010 } | |
1011 | |
1012 | |
1013 void JobsRegistry::RunningJob::MarkFailure() | |
1014 { | |
1015 if (!IsValid()) | |
1016 { | |
1017 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
1018 } | |
1019 else | |
1020 { | |
1021 targetState_ = JobState_Failure; | |
1022 } | |
1023 } | |
1024 | |
1025 | |
2581
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
1026 void JobsRegistry::RunningJob::MarkCanceled() |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
1027 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
1028 if (!IsValid()) |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
1029 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
1030 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
1031 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
1032 else |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
1033 { |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
1034 targetState_ = JobState_Failure; |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
1035 canceled_ = true; |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
1036 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
1037 } |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
1038 |
8da2cffc2378
JobsRegistry::Cancel()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2573
diff
changeset
|
1039 |
2569 | 1040 void JobsRegistry::RunningJob::MarkPause() |
1041 { | |
1042 if (!IsValid()) | |
1043 { | |
1044 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
1045 } | |
1046 else | |
1047 { | |
1048 targetState_ = JobState_Paused; | |
1049 } | |
1050 } | |
1051 | |
1052 | |
1053 void JobsRegistry::RunningJob::MarkRetry(unsigned int timeout) | |
1054 { | |
1055 if (!IsValid()) | |
1056 { | |
1057 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
1058 } | |
1059 else | |
1060 { | |
1061 targetState_ = JobState_Retry; | |
1062 targetRetryTimeout_ = timeout; | |
1063 } | |
1064 } | |
1065 | |
1066 | |
1067 void JobsRegistry::RunningJob::UpdateStatus(ErrorCode code) | |
1068 { | |
1069 if (!IsValid()) | |
1070 { | |
1071 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
1072 } | |
1073 else | |
1074 { | |
1075 JobStatus status(code, *job_); | |
1076 | |
1077 boost::mutex::scoped_lock lock(registry_.mutex_); | |
1078 registry_.CheckInvariants(); | |
1079 assert(handler_->GetState() == JobState_Running); | |
1080 | |
1081 handler_->SetLastStatus(status); | |
1082 } | |
1083 } | |
1084 } |