diff options
Diffstat (limited to 'src/stable/minicron.h')
-rw-r--r-- | src/stable/minicron.h | 336 |
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 | |||
17 | namespace 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 | ||