OpenDNSSEC-signer 1.3.0
/build/buildd/opendnssec-1.3.0/signer/src/scheduler/schedule.c
Go to the documentation of this file.
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 }