aboutsummaryrefslogtreecommitdiff
path: root/src/stable/minicron.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/stable/minicron.h')
-rw-r--r--src/stable/minicron.h336
1 files changed, 336 insertions, 0 deletions
diff --git a/src/stable/minicron.h b/src/stable/minicron.h
new file mode 100644
index 0000000..0d1cb62
--- /dev/null
+++ b/src/stable/minicron.h
@@ -0,0 +1,336 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_MINICRON_H
9#define BU_MINICRON_H
10
11#include "bu/signals.h"
12#include "bu/heap.h"
13#include "bu/string.h"
14
15#include <time.h>
16
17namespace Bu
18{
19 /**
20 * A simple cron like system designed to be embedded in any program. This
21 * class creates a simple cron system that can run any number of jobs at
22 * customizable intervals or schedules. It does not support some of the
23 * more complex scheduling that some cron systems can do such as load
24 * balancing directly, but this could be done on the job side.
25 *
26 * This system is synchronous, it does not use any threads on it's own, but
27 * it is threadsafe, so a cron thread could be created if desired.
28 *
29 * The operation is fairly simple, jobs can be added at any time, and use
30 * any timer they would like, even custom timers. When it is time for a
31 * job to be run it signals the slot provided when the job was added. Every
32 * job slot recieves a handle to the job object so that it may control it's
33 * own lifetime and get information about itself. In addition, every job
34 * is assigned a unique ID that can be used to control it's operation
35 * at any time.
36 *
37 * By default a job will continually reschedule itself after being run
38 * unless it calls stop() on it's job object, it is removed using
39 * removeJob() on the cron object, or it is added with addJobOnce.
40 *
41 *@todo A minor change to the job execution system could allow a Timer to
42 * defer or reschedule execution instead of the job executing. This would,
43 * in effect, allow us to do every type of interesting scheduling that
44 * systems like fcron offer, including time constrained load-balanced
45 * execution.
46 */
47 class MiniCron
48 {
49 public:
50 class Job;
51 class Timer;
52 typedef Bu::Signal1<void, Bu::MiniCron::Job &> CronSignal;
53 typedef int JobId;
54
55 MiniCron();
56 virtual ~MiniCron();
57
58 /**
59 * Tells you if there are jobs registered in the MiniCron.
60 *@returns true if there are jobs, false otherwise.
61 */
62 virtual bool hasJobs();
63
64 /**
65 * If there are jobs, tells you the time the next one will execute.
66 *@returns The timestamp that the next job will execute at.
67 */
68 virtual time_t getNextRun();
69
70 /**
71 * Tells you the time the job matching jid will run next.
72 *@returns The timestamp that the job jid will next run.
73 */
74 virtual time_t getNextRun( JobId jid );
75
76 /**
77 * Call this regularly to execute all jobs that should be executed.
78 * This will loop until all jobs who's run time match the current time
79 * or are below the current time (we've missed them).
80 * If there is nothing to run, the runtime of this funcion is constant,
81 * it is very fast. Otherwise it executes at log(N) per job run,
82 * O(N*log(N)).
83 */
84 virtual void poll();
85
86 /**
87 * Add a job for repeated scheduling. Pass in a slot to signal, and a
88 * Timer object to use to do the scheduling. This function returns a
89 * JobId which can be used at a later time to control the execution of
90 * the job.
91 */
92 virtual JobId addJob( const Bu::String &sName, CronSignal sigJob,
93 const Timer &t );
94
95 /**
96 * Add a job for one time scheduling. Pass in a slot to signal, and a
97 * Timer object to use to schodule the one run of this job. This
98 * function returns a JobId which can be used at a later time to control
99 * the execution of the job.
100 */
101 virtual JobId addJobOnce( const Bu::String &sName, CronSignal sigJob,
102 const Timer &t );
103
104 /**
105 * Remove a job, preventing all future runs of the job. If there is no
106 * job matching the given JobId then nothing will happen. However, this
107 * function is relatively expensive compared to the others in this class
108 * and has a worse case runtime of 2*N*log(N), still not that bad, and
109 * a O(N*log(N)).
110 */
111 virtual void removeJob( JobId jid );
112
113 /**
114 * Executes the job specified right now. If bReschedule is true then
115 * the job is then removed from the queue and rescheduled as though
116 * it's time had come naturally to be run. Otherwise, it's run without
117 * interrupting the normal schedule.
118 */
119 virtual void runJob( JobId jid, bool bReschedule=false );
120
121 /**
122 * Executes the job specified right now. If bReschedule is true then
123 * the job is then removed from the queue and rescheduled as though
124 * it's time had come naturally to be run. Otherwise, it's run without
125 * interrupting the normal schedule.
126 */
127 virtual void runJob( const Bu::String &sName, bool bReschedule=false );
128
129 class JobInfo
130 {
131 public:
132 JobInfo( const Bu::String &sName, JobId jid, time_t tNext );
133 virtual ~JobInfo();
134
135 bool operator<( const JobInfo &rhs ) const;
136
137 Bu::String sName;
138 JobId jid;
139 time_t tNext;
140 };
141 typedef Bu::List<JobInfo> JobInfoList;
142
143 JobInfoList getJobInfo();
144
145 /**
146 * The baseclass for timer/schedulers for MiniCron jobs. Classes that
147 * inherit from this are used to determine when jobs will run and at
148 * what interval.
149 */
150 class Timer
151 {
152 public:
153 Timer();
154 virtual ~Timer();
155
156 /**
157 * Called by MiniCron when each job is run to determine the next
158 * time that a job should be run. When a job is run, this function
159 * is actually called before the job is executed again so that the
160 * job can tell when the next time it will be run will be.
161 */
162 virtual time_t nextTime()=0;
163
164 /**
165 * This function should return a copy of the child class.
166 */
167 virtual Timer *clone() const = 0;
168 };
169
170 /**
171 * Execute the job every tInterval seconds, also you can delay the
172 * first run by a different amount of time from the job's creation.
173 */
174 class TimerInterval : public Timer
175 {
176 public:
177 TimerInterval( time_t tFirst, time_t tInterval );
178 virtual ~TimerInterval();
179
180 virtual time_t nextTime();
181 virtual Timer *clone() const
182 { return new TimerInterval( *this ); }
183 private:
184 time_t tNext;
185 time_t tInterval;
186 };
187
188 /**
189 * A much more general timer class that can be used for much more
190 * "cron-like" functionality. The constructor takes a string that
191 * describes the times that the job should be run. At the moment the
192 * following schemes are understood:
193 *
194 * "daily [hour] [minute]"
195 * "hourly [minute]"
196 * "weekly [day] [hour] [minute]"
197 *
198 * In these examples each word in [brackets] represents a number that
199 * matches the data type in the brackets. [day] is the number of days
200 * since sunday, 0-6. You can also use lowercase three character
201 * abbreviations for the day names.
202 *
203 * Many more forms follow.
204 */
205 class TimerBasic : public Timer
206 {
207 public:
208 TimerBasic( const Bu::String &s );
209 virtual ~TimerBasic();
210
211 virtual time_t nextTime();
212 virtual Timer *clone() const
213 { return new TimerBasic( *this ); }
214
215 private:
216 enum Token
217 {
218 tokDaily,
219 tokHourly,
220 tokWeekly,
221 tokMonthly,
222 tokYearly,
223 valInt,
224 tokErr,
225 tokEos
226 };
227 Token lex( Bu::String::const_iterator &i );
228 int lexInt( Bu::String::const_iterator &i );
229 int iVal; //< A temp variable for parsing.
230 time_t tLast;
231 Bu::String sSpec;
232 };
233
234 /**
235 * Represents a MiniCron Job. This class is used for both internal
236 * job management as well as job slot interaction and control. Objects
237 * of this class are passed into the slots that are signaled when a job
238 * is executed.
239 */
240 class Job
241 {
242 friend class Bu::MiniCron;
243 private:
244 Job( const Bu::String &sName, JobId jid, bool bRepeat=true );
245 virtual ~Job();
246
247 public:
248
249 /**
250 * Execute this job once, increment the runcount and schedule the
251 * next occurance of it.
252 */
253 void run( bool bReschedule=true );
254
255 /**
256 * Get the time this job will next run.
257 */
258 time_t getNextRun() const;
259
260 /**
261 * Compute the time this job will next run.
262 */
263 void calcNextRun();
264
265 /**
266 * Replace the current job timer with a new one, this will trigger
267 * a re-schedule.
268 */
269 void setTimer( const Timer &t );
270
271 /**
272 * Stop execution of this job, never execute this job again.
273 */
274 void stop();
275
276 /**
277 * Undo a previous stop. This will cause a job that has been
278 * stopped or even added with addJobOnce to be set for repeated
279 * scheduling.
280 */
281 void resume();
282
283 /**
284 * Get the unique ID of this job.
285 */
286 JobId getId() const;
287
288 /**
289 * Get the timestamp this job was created.
290 */
291 time_t getTimeCreated() const;
292
293 /**
294 * Get the current run count of this job, how many times it has been
295 * executed. This is incremented before the slot is signaled.
296 */
297 int getRunCount() const;
298
299 /**
300 * Get the next time that this job will be run. Certain timers may
301 * have the ability to delay job executions, so this is the earliest
302 * time that the job may run.
303 */
304 time_t getNextRunTime() const;
305
306 /**
307 * Gets the name that was set when the job was created.
308 */
309 Bu::String getName() const;
310
311 private:
312 Bu::String sName;
313 CronSignal sigJob;
314 time_t tNextRun;
315 Timer *pTimer;
316 bool bContinue;
317 JobId jid;
318 time_t tAdded;
319 int iRunCount;
320 };
321
322 private:
323 struct JobPtrCmp
324 {
325 bool operator()( const Job *pLeft, const Job *pRight )
326 {
327 return pLeft->tNextRun < pRight->tNextRun;
328 }
329 };
330 typedef Bu::Heap<Job *, JobPtrCmp> JobHeap;
331 JobHeap hJobs;
332 JobId jidNext;
333 };
334};
335
336#endif