00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00034 #include "config.h"
00035 #include "scheduler/schedule.h"
00036 #include "scheduler/task.h"
00037 #include "shared/allocator.h"
00038 #include "shared/duration.h"
00039 #include "shared/log.h"
00040
00041 #include <ldns/ldns.h>
00042
00043 static const char* schedule_str = "scheduler";
00044
00045
00050 schedule_type*
00051 schedule_create(allocator_type* allocator)
00052 {
00053 schedule_type* schedule;
00054 if (!allocator) {
00055 ods_log_error("[%s] unable to create: no allocator available",
00056 schedule_str);
00057 return NULL;
00058 }
00059 ods_log_assert(allocator);
00060
00061 schedule = (schedule_type*) allocator_alloc(allocator,
00062 sizeof(schedule_type));
00063 if (!schedule) {
00064 ods_log_error("[%s] unable to create: allocator failed", schedule_str);
00065 return NULL;
00066 }
00067 ods_log_assert(schedule);
00068
00069 schedule->allocator = allocator;
00070 schedule->loading = 0;
00071 schedule->flushcount = 0;
00072 schedule->tasks = ldns_rbtree_create(task_compare);
00073 lock_basic_init(&schedule->schedule_lock);
00074 return schedule;
00075 }
00076
00077
00082 void
00083 schedule_flush(schedule_type* schedule, task_id override)
00084 {
00085 ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00086 task_type* task = NULL;
00087
00088 ods_log_debug("[%s] flush all tasks", schedule_str);
00089 if (!schedule || !schedule->tasks) {
00090 return;
00091 }
00092 ods_log_assert(schedule);
00093 ods_log_assert(schedule->tasks);
00094
00095 node = ldns_rbtree_first(schedule->tasks);
00096 while (node && node != LDNS_RBTREE_NULL) {
00097 task = (task_type*) node->data;
00098 task->flush = 1;
00099 schedule->flushcount++;
00100 if (override != TASK_NONE) {
00101 task->what = override;
00102 }
00103 node = ldns_rbtree_next(node);
00104 }
00105 return;
00106 }
00107
00108
00113 static ldns_rbnode_t*
00114 task2node(task_type* task)
00115 {
00116 ldns_rbnode_t* node = (ldns_rbnode_t*) malloc(sizeof(ldns_rbnode_t));
00117 node->key = task;
00118 node->data = task;
00119 return node;
00120 }
00121
00122
00127 task_type*
00128 schedule_lookup_task(schedule_type* schedule, task_type* task)
00129 {
00130 ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00131 task_type* lookup = NULL;
00132
00133 if (!schedule || !task) {
00134 return NULL;
00135 }
00136 ods_log_assert(task);
00137 ods_log_assert(schedule);
00138 ods_log_assert(schedule->tasks);
00139
00140 node = ldns_rbtree_search(schedule->tasks, task);
00141 if (node && node != LDNS_RBTREE_NULL) {
00142 lookup = (task_type*) node->data;
00143 }
00144 return lookup;
00145 }
00146
00147
00152 ods_status
00153 schedule_task(schedule_type* schedule, task_type* task, int log)
00154 {
00155 ldns_rbnode_t* new_node = NULL;
00156 ldns_rbnode_t* ins_node = NULL;
00157
00158 if (!task) {
00159 ods_log_error("[%s] unable to schedule task: no task", schedule_str);
00160 return ODS_STATUS_ASSERT_ERR;
00161 }
00162 ods_log_assert(task);
00163 if (!schedule) {
00164 ods_log_error("[%s] unable to schedule task: no schedule",
00165 schedule_str);
00166 return ODS_STATUS_ASSERT_ERR;
00167 }
00168 ods_log_assert(schedule);
00169 ods_log_assert(schedule->tasks);
00170
00171 ods_log_debug("[%s] schedule task %s for zone %s", schedule_str,
00172 task_what2str(task->what), task_who2str(task->who));
00173 if (schedule_lookup_task(schedule, task) != NULL) {
00174 ods_log_error("[%s] unable to schedule task %s for zone %s: "
00175 " already present", schedule_str, task_what2str(task->what),
00176 task_who2str(task->who));
00177 return ODS_STATUS_ERR;
00178 }
00179 new_node = task2node(task);
00180 ins_node = ldns_rbtree_insert(schedule->tasks, new_node);
00181 if (!ins_node) {
00182 ods_log_error("[%s] unable to schedule task %s for zone %s: "
00183 " insert failed", schedule_str, task_what2str(task->what),
00184 task_who2str(task->who));
00185 free((void*)new_node);
00186 return ODS_STATUS_ERR;
00187 }
00188 if (task->flush) {
00189 schedule->flushcount++;
00190 }
00191 if (log) {
00192 task_log(task);
00193 }
00194 return ODS_STATUS_OK;
00195 }
00196
00197
00202 task_type*
00203 unschedule_task(schedule_type* schedule, task_type* task)
00204 {
00205 ldns_rbnode_t* del_node = LDNS_RBTREE_NULL;
00206 task_type* del_task = NULL;
00207
00208 if (!task) {
00209
00210 return NULL;
00211 }
00212 ods_log_assert(task);
00213 if (!schedule) {
00214 ods_log_error("[%s] unable to unschedule task: no schedule",
00215 schedule_str);
00216 return NULL;
00217 }
00218 ods_log_assert(schedule);
00219 ods_log_assert(schedule->tasks);
00220
00221 ods_log_debug("[%s] unschedule task %s for zone %s",
00222 schedule_str, task_what2str(task->what), task_who2str(task->who));
00223 del_node = ldns_rbtree_delete(schedule->tasks, (const void*) task);
00224 if (del_node) {
00225 del_task = (task_type*) del_node->data;
00226 free((void*)del_node);
00227 } else {
00228 ods_log_warning("[%s] unable to unschedule task %s for zone %s: not "
00229 "scheduled", schedule_str, task_what2str(task->what),
00230 task_who2str(task->who));
00231 return NULL;
00232 }
00233 if (del_task->flush) {
00234 del_task->flush = 0;
00235 schedule->flushcount--;
00236 }
00237 return del_task;
00238 }
00239
00240
00245 ods_status
00246 reschedule_task(schedule_type* schedule, task_type* task, task_id what,
00247 time_t when)
00248 {
00249 task_type* del_task = NULL;
00250
00251 if (!task) {
00252 return ODS_STATUS_ASSERT_ERR;
00253 }
00254
00255 del_task = unschedule_task(schedule, task);
00256 if (!del_task) {
00257 del_task = task;
00258 }
00259 del_task->what = what;
00260 del_task->when = when;
00261 return schedule_task(schedule, del_task, 1);
00262 }
00263
00264
00269 task_type*
00270 schedule_get_first_task(schedule_type* schedule)
00271 {
00272 ldns_rbnode_t* first_node = LDNS_RBTREE_NULL;
00273 ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00274 task_type* pop = NULL;
00275
00276 if (!schedule) {
00277 return NULL;
00278 }
00279 ods_log_assert(schedule);
00280 ods_log_assert(schedule->tasks);
00281
00282 first_node = ldns_rbtree_first(schedule->tasks);
00283 if (!first_node) {
00284 return NULL;
00285 }
00286
00287 if (schedule->flushcount > 0) {
00288
00289 node = first_node;
00290 while (node && node != LDNS_RBTREE_NULL) {
00291 pop = (task_type*) node->data;
00292 if (pop->flush) {
00293 return pop;
00294 }
00295 node = ldns_rbtree_next(node);
00296 }
00297
00298 ods_log_warning("[%s] unable to get first scheduled: could not "
00299 "find flush-task, while there should be %i flush-tasks left",
00300 schedule_str, schedule->flushcount);
00301 ods_log_info("[%s] reset flush count to 0", schedule_str);
00302 schedule->flushcount = 0;
00303 }
00304
00305 pop = (task_type*) first_node->data;
00306 return pop;
00307 }
00308
00309
00314 task_type*
00315 schedule_pop_task(schedule_type* schedule)
00316 {
00317 task_type* pop = NULL;
00318 time_t now = 0;
00319
00320 if (!schedule) {
00321 ods_log_error("[%s] unable to pop task: no schedule", schedule_str);
00322 return NULL;
00323 }
00324 ods_log_assert(schedule);
00325 ods_log_assert(schedule->tasks);
00326
00327 now = time_now();
00328 pop = schedule_get_first_task(schedule);
00329 if (pop && (pop->flush || pop->when <= now)) {
00330 if (pop->flush) {
00331 ods_log_debug("[%s] flush task for zone %s", schedule_str,
00332 pop->who?pop->who:"(null)");
00333 } else {
00334 ods_log_debug("[%s] pop task for zone %s", schedule_str,
00335 pop->who?pop->who:"(null)");
00336 }
00337 return unschedule_task(schedule, pop);
00338 }
00339 return NULL;
00340 }
00341
00342
00347 void
00348 schedule_print(FILE* out, schedule_type* schedule)
00349 {
00350 ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00351 task_type* task = NULL;
00352
00353 if (!out || !schedule || !schedule->tasks) {
00354 return;
00355 }
00356 ods_log_assert(out);
00357 ods_log_assert(schedule);
00358 ods_log_assert(schedule->tasks);
00359
00360 node = ldns_rbtree_first(schedule->tasks);
00361 while (node && node != LDNS_RBTREE_NULL) {
00362 task = (task_type*) node->data;
00363 task_print(out, task);
00364 node = ldns_rbtree_next(node);
00365 }
00366 fprintf(out, "\n");
00367 return;
00368 }
00369
00370
00375 static void
00376 task_delfunc(ldns_rbnode_t* elem)
00377 {
00378 task_type* task;
00379
00380 if (elem && elem != LDNS_RBTREE_NULL) {
00381 task = (task_type*) elem->data;
00382 task_delfunc(elem->left);
00383 task_delfunc(elem->right);
00384 task_cleanup(task);
00385 free((void*)elem);
00386 }
00387 return;
00388 }
00389
00390
00395 void
00396 schedule_cleanup(schedule_type* schedule)
00397 {
00398 allocator_type* allocator;
00399 lock_basic_type schedule_lock;
00400
00401 if (!schedule) {
00402 return;
00403 }
00404 ods_log_debug("[%s] cleanup schedule", schedule_str);
00405 if (schedule->tasks) {
00406 task_delfunc(schedule->tasks->root);
00407 ldns_rbtree_free(schedule->tasks);
00408 schedule->tasks = NULL;
00409 }
00410
00411 allocator = schedule->allocator;
00412 schedule_lock = schedule->schedule_lock;
00413
00414 allocator_deallocate(allocator, (void*) schedule);
00415 lock_basic_destroy(&schedule_lock);
00416 return;
00417 }