OpenDNSSEC-signer
1.3.4
|
00001 /* 00002 * $Id$ 00003 * 00004 * Copyright (c) 2009 NLNet Labs. All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 1. Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00016 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00017 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 00019 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00020 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00021 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 00023 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00024 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 00025 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 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 /* we are done */ 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 /* find remaining to be flushed tasks */ 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 /* no more to be flushed tasks found */ 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 /* no more tasks to be flushed, return first task in schedule */ 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 }