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