OpenDNSSEC-signer  1.4.1
schedule.c
Go to the documentation of this file.
1 /*
2  * $Id$
3  *
4  * Copyright (c) 2009 NLNet Labs. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
34 #include "config.h"
35 #include "scheduler/schedule.h"
36 #include "scheduler/task.h"
37 #include "shared/duration.h"
38 #include "shared/log.h"
39 
40 #include <ldns/ldns.h>
41 
42 static const char* schedule_str = "scheduler";
43 
44 
51 {
52  schedule_type* schedule;
53  if (!allocator) {
54  return NULL;
55  }
56  schedule = (schedule_type*) allocator_alloc(allocator,
57  sizeof(schedule_type));
58  if (!schedule) {
59  ods_log_error("[%s] unable to create schedule: allocator_alloc() "
60  "failed", schedule_str);
61  return NULL;
62  }
63  schedule->allocator = allocator;
64  schedule->loading = 0;
65  schedule->flushcount = 0;
66  schedule->tasks = ldns_rbtree_create(task_compare);
67  if (!schedule->tasks) {
68  ods_log_error("[%s] unable to create schedule: ldns_rbtree_create() "
69  "failed", schedule_str);
70  allocator_deallocate(allocator, (void*) schedule);
71  return NULL;
72  }
73  lock_basic_init(&schedule->schedule_lock);
74  return schedule;
75 }
76 
77 
82 void
83 schedule_flush(schedule_type* schedule, task_id override)
84 {
85  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
86  task_type* task = NULL;
87 
88  ods_log_debug("[%s] flush all tasks", schedule_str);
89  if (!schedule || !schedule->tasks) {
90  return;
91  }
92  node = ldns_rbtree_first(schedule->tasks);
93  while (node && node != LDNS_RBTREE_NULL) {
94  task = (task_type*) node->data;
95  task->flush = 1;
96  schedule->flushcount++;
97  if (override != TASK_NONE) {
98  task->what = override;
99  }
100  node = ldns_rbtree_next(node);
101  }
102  return;
103 }
104 
105 
110 static ldns_rbnode_t*
111 task2node(task_type* task)
112 {
113  ldns_rbnode_t* node = (ldns_rbnode_t*) malloc(sizeof(ldns_rbnode_t));
114  if (node) {
115  node->key = task;
116  node->data = task;
117  }
118  return node;
119 }
120 
121 
126 task_type*
128 {
129  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
130  task_type* lookup = NULL;
131  if (!schedule || !task) {
132  return NULL;
133  }
134  ods_log_assert(schedule->tasks);
135  node = ldns_rbtree_search(schedule->tasks, task);
136  if (node && node != LDNS_RBTREE_NULL) {
137  lookup = (task_type*) node->data;
138  }
139  return lookup;
140 }
141 
142 
148 schedule_task(schedule_type* schedule, task_type* task, int log)
149 {
150  ldns_rbnode_t* new_node = NULL;
151  ldns_rbnode_t* ins_node = NULL;
152  if (!task || !schedule || !schedule->tasks) {
153  return ODS_STATUS_ASSERT_ERR;
154  }
155  ods_log_debug("[%s] schedule task %s for zone %s", schedule_str,
156  task_what2str(task->what), task_who2str(task));
157  if (schedule_lookup_task(schedule, task) != NULL) {
158  ods_log_error("[%s] unable to schedule task %s for zone %s: "
159  " already present", schedule_str, task_what2str(task->what),
160  task_who2str(task));
161  return ODS_STATUS_ERR;
162  }
163  new_node = task2node(task);
164  if (!new_node) {
165  ods_log_error("[%s] unable to schedule task %s for zone %s: "
166  " task2node() failed", schedule_str, task_what2str(task->what),
167  task_who2str(task));
168  return ODS_STATUS_MALLOC_ERR;
169  }
170  ins_node = ldns_rbtree_insert(schedule->tasks, new_node);
171  if (!ins_node) {
172  ods_log_error("[%s] unable to schedule task %s for zone %s: "
173  " insert failed", schedule_str, task_what2str(task->what),
174  task_who2str(task));
175  free((void*)new_node);
176  return ODS_STATUS_ERR;
177  }
178  if (task->flush) {
179  schedule->flushcount++;
180  }
181  if (log) {
182  task_log(task);
183  }
184  return ODS_STATUS_OK;
185 }
186 
187 
192 task_type*
194 {
195  ldns_rbnode_t* del_node = LDNS_RBTREE_NULL;
196  task_type* del_task = NULL;
197  if (!task || !schedule || !schedule->tasks) {
198  return NULL;
199  }
200  ods_log_debug("[%s] unschedule task %s for zone %s",
201  schedule_str, task_what2str(task->what), task_who2str(task));
202  del_node = ldns_rbtree_delete(schedule->tasks, (const void*) task);
203  if (del_node) {
204  del_task = (task_type*) del_node->data;
205  free((void*)del_node);
206  } else {
207  ods_log_warning("[%s] unable to unschedule task %s for zone %s: not "
208  "scheduled", schedule_str, task_what2str(task->what),
209  task_who2str(task));
210  return NULL;
211  }
212  if (del_task->flush) {
213  del_task->flush = 0;
214  schedule->flushcount--;
215  }
216  return del_task;
217 }
218 
219 
226  time_t when)
227 {
228  task_type* del_task = NULL;
229  if (!task || !schedule || !schedule->tasks) {
230  return ODS_STATUS_ASSERT_ERR;
231  }
232  del_task = unschedule_task(schedule, task);
233  if (!del_task) {
234  del_task = task;
235  }
236  del_task->what = what;
237  del_task->when = when;
238  return schedule_task(schedule, del_task, 1);
239 }
240 
241 
246 task_type*
248 {
249  ldns_rbnode_t* first_node = LDNS_RBTREE_NULL;
250  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
251  task_type* pop = NULL;
252  if (!schedule || !schedule->tasks) {
253  return NULL;
254  }
255  first_node = ldns_rbtree_first(schedule->tasks);
256  if (!first_node) {
257  return NULL;
258  }
259  if (schedule->flushcount > 0) {
260  /* find remaining to be flushed tasks */
261  node = first_node;
262  while (node && node != LDNS_RBTREE_NULL) {
263  pop = (task_type*) node->data;
264  if (pop->flush) {
265  return pop;
266  }
267  node = ldns_rbtree_next(node);
268  }
269  /* no more to be flushed tasks found */
270  ods_log_warning("[%s] unable to get first scheduled task: could not "
271  "find flush-task, while there should be %i flush-tasks left",
272  schedule_str, schedule->flushcount);
273  ods_log_info("[%s] reset flush count to 0", schedule_str);
274  schedule->flushcount = 0;
275  }
276  /* no more tasks to be flushed, return first task in schedule */
277  pop = (task_type*) first_node->data;
278  return pop;
279 }
280 
281 
286 task_type*
288 {
289  task_type* pop = NULL;
290  time_t now = 0;
291  if (!schedule || !schedule->tasks) {
292  return NULL;
293  }
294  now = time_now();
295  pop = schedule_get_first_task(schedule);
296  if (pop && (pop->flush || pop->when <= now)) {
297  if (pop->flush) {
298  ods_log_debug("[%s] flush task for zone %s", schedule_str,
299  task_who2str(pop));
300  } else {
301  ods_log_debug("[%s] pop task for zone %s", schedule_str,
302  task_who2str(pop));
303  }
304  return unschedule_task(schedule, pop);
305  }
306  return NULL;
307 }
308 
309 
314 void
315 schedule_print(FILE* out, schedule_type* schedule)
316 {
317  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
318  task_type* task = NULL;
319 
320  if (!out || !schedule || !schedule->tasks) {
321  return;
322  }
323  node = ldns_rbtree_first(schedule->tasks);
324  while (node && node != LDNS_RBTREE_NULL) {
325  task = (task_type*) node->data;
326  task_print(out, task);
327  node = ldns_rbtree_next(node);
328  }
329  fprintf(out, "\n");
330  return;
331 }
332 
333 
338 static void
339 task_delfunc(ldns_rbnode_t* elem)
340 {
341  task_type* task;
342 
343  if (elem && elem != LDNS_RBTREE_NULL) {
344  task = (task_type*) elem->data;
345  task_delfunc(elem->left);
346  task_delfunc(elem->right);
347  task_cleanup(task);
348  free((void*)elem);
349  }
350  return;
351 }
352 
353 
358 void
360 {
361  allocator_type* allocator;
362  lock_basic_type schedule_lock;
363 
364  if (!schedule) {
365  return;
366  }
367  ods_log_debug("[%s] cleanup schedule", schedule_str);
368  if (schedule->tasks) {
369  task_delfunc(schedule->tasks->root);
370  ldns_rbtree_free(schedule->tasks);
371  schedule->tasks = NULL;
372  }
373  allocator = schedule->allocator;
374  schedule_lock = schedule->schedule_lock;
375  allocator_deallocate(allocator, (void*) schedule);
376  lock_basic_destroy(&schedule_lock);
377  return;
378 }
Definition: task.h:43
ods_status reschedule_task(schedule_type *schedule, task_type *task, task_id what, time_t when)
Definition: schedule.c:225
task_type * schedule_get_first_task(schedule_type *schedule)
Definition: schedule.c:247
void ods_log_debug(const char *format,...)
Definition: log.c:272
time_t when
Definition: task.h:61
#define lock_basic_destroy(lock)
Definition: locks.h:92
void * allocator_alloc(allocator_type *allocator, size_t size)
Definition: allocator.c:68
void task_log(task_type *task)
Definition: task.c:255
ods_status schedule_task(schedule_type *schedule, task_type *task, int log)
Definition: schedule.c:148
int flush
Definition: task.h:64
void ods_log_info(const char *format,...)
Definition: log.c:304
const char * task_who2str(task_type *task)
Definition: task.c:178
enum ods_enum_status ods_status
Definition: status.h:89
void schedule_flush(schedule_type *schedule, task_id override)
Definition: schedule.c:83
void ods_log_error(const char *format,...)
Definition: log.c:336
task_type * schedule_lookup_task(schedule_type *schedule, task_type *task)
Definition: schedule.c:127
enum task_id_enum task_id
Definition: task.h:50
void schedule_print(FILE *out, schedule_type *schedule)
Definition: schedule.c:315
int lock_basic_type
Definition: locks.h:90
task_type * schedule_pop_task(schedule_type *schedule)
Definition: schedule.c:287
void task_cleanup(task_type *task)
Definition: task.c:277
task_type * unschedule_task(schedule_type *schedule, task_type *task)
Definition: schedule.c:193
allocator_type * allocator
Definition: schedule.h:61
task_id what
Definition: task.h:58
#define lock_basic_init(lock)
Definition: locks.h:91
ldns_rbtree_t * tasks
Definition: schedule.h:62
void allocator_deallocate(allocator_type *allocator, void *data)
Definition: allocator.c:137
void schedule_cleanup(schedule_type *schedule)
Definition: schedule.c:359
int task_compare(const void *a, const void *b)
Definition: task.c:114
lock_basic_type schedule_lock
Definition: schedule.h:65
void task_print(FILE *out, task_type *task)
Definition: task.c:233
#define ods_log_assert(x)
Definition: log.h:156
schedule_type * schedule_create(allocator_type *allocator)
Definition: schedule.c:50
void ods_log_warning(const char *format,...)
Definition: log.c:320
const char * task_what2str(task_id what)
Definition: task.c:148
time_t time_now(void)
Definition: duration.c:507