OpenDNSSEC-signer  1.3.14
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/allocator.h"
38 #include "shared/duration.h"
39 #include "shared/log.h"
40 
41 #include <ldns/ldns.h>
42 
43 static const char* schedule_str = "scheduler";
44 
45 
52 {
53  schedule_type* schedule;
54  if (!allocator) {
55  ods_log_error("[%s] unable to create: no allocator available",
56  schedule_str);
57  return NULL;
58  }
59  ods_log_assert(allocator);
60 
61  schedule = (schedule_type*) allocator_alloc(allocator,
62  sizeof(schedule_type));
63  if (!schedule) {
64  ods_log_error("[%s] unable to create: allocator failed", schedule_str);
65  return NULL;
66  }
67  ods_log_assert(schedule);
68 
69  schedule->allocator = allocator;
70  schedule->loading = 0;
71  schedule->flushcount = 0;
72  schedule->tasks = ldns_rbtree_create(task_compare);
73  lock_basic_init(&schedule->schedule_lock);
74  schedule->schedule_locked = 0;
75  return schedule;
76 }
77 
78 
83 void
84 schedule_flush(schedule_type* schedule, task_id override)
85 {
86  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
87  task_type* task = NULL;
88 
89  ods_log_debug("[%s] flush all tasks", schedule_str);
90  if (!schedule || !schedule->tasks) {
91  return;
92  }
93  ods_log_assert(schedule);
94  ods_log_assert(schedule->tasks);
95 
96  node = ldns_rbtree_first(schedule->tasks);
97  while (node && node != LDNS_RBTREE_NULL) {
98  task = (task_type*) node->data;
99  task->flush = 1;
100  schedule->flushcount++;
101  if (override != TASK_NONE) {
102  task->what = override;
103  }
104  node = ldns_rbtree_next(node);
105  }
106  return;
107 }
108 
109 
114 static ldns_rbnode_t*
115 task2node(task_type* task)
116 {
117  ldns_rbnode_t* node = (ldns_rbnode_t*) malloc(sizeof(ldns_rbnode_t));
118  node->key = task;
119  node->data = task;
120  return node;
121 }
122 
123 
128 task_type*
130 {
131  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
132  task_type* lookup = NULL;
133 
134  if (!schedule || !task) {
135  return NULL;
136  }
137  ods_log_assert(task);
138  ods_log_assert(schedule);
139  ods_log_assert(schedule->tasks);
140 
141  node = ldns_rbtree_search(schedule->tasks, task);
142  if (node && node != LDNS_RBTREE_NULL) {
143  lookup = (task_type*) node->data;
144  }
145  return lookup;
146 }
147 
148 
154 schedule_task(schedule_type* schedule, task_type* task, int log)
155 {
156  ldns_rbnode_t* new_node = NULL;
157  ldns_rbnode_t* ins_node = NULL;
158 
159  if (!task) {
160  ods_log_error("[%s] unable to schedule task: no task", schedule_str);
161  return ODS_STATUS_ASSERT_ERR;
162  }
163  ods_log_assert(task);
164  if (!schedule) {
165  ods_log_error("[%s] unable to schedule task: no schedule",
166  schedule_str);
167  return ODS_STATUS_ASSERT_ERR;
168  }
169  ods_log_assert(schedule);
170  ods_log_assert(schedule->tasks);
171 
172  ods_log_debug("[%s] schedule task %s for zone %s", schedule_str,
173  task_what2str(task->what), task_who2str(task->who));
174  if (schedule_lookup_task(schedule, task) != NULL) {
175  ods_log_error("[%s] unable to schedule task %s for zone %s: "
176  " already present", schedule_str, task_what2str(task->what),
177  task_who2str(task->who));
178  return ODS_STATUS_ERR;
179  }
180  new_node = task2node(task);
181  ins_node = ldns_rbtree_insert(schedule->tasks, new_node);
182  if (!ins_node) {
183  ods_log_error("[%s] unable to schedule task %s for zone %s: "
184  " insert failed", schedule_str, task_what2str(task->what),
185  task_who2str(task->who));
186  free((void*)new_node);
187  return ODS_STATUS_ERR;
188  }
189  if (task->flush) {
190  schedule->flushcount++;
191  }
192  if (log) {
193  task_log(task);
194  }
195  return ODS_STATUS_OK;
196 }
197 
198 
203 task_type*
205 {
206  ldns_rbnode_t* del_node = LDNS_RBTREE_NULL;
207  task_type* del_task = NULL;
208 
209  if (!task) {
210  /* we are done */
211  return NULL;
212  }
213  ods_log_assert(task);
214  if (!schedule) {
215  ods_log_error("[%s] unable to unschedule task: no schedule",
216  schedule_str);
217  return NULL;
218  }
219  ods_log_assert(schedule);
220  ods_log_assert(schedule->tasks);
221 
222  ods_log_debug("[%s] unschedule task %s for zone %s",
223  schedule_str, task_what2str(task->what), task_who2str(task->who));
224  del_node = ldns_rbtree_delete(schedule->tasks, (const void*) task);
225  if (del_node) {
226  del_task = (task_type*) del_node->data;
227  free((void*)del_node);
228  } else {
229  ods_log_warning("[%s] unable to unschedule task %s for zone %s: not "
230  "scheduled", schedule_str, task_what2str(task->what),
231  task_who2str(task->who));
232  return NULL;
233  }
234  if (del_task->flush) {
235  del_task->flush = 0;
236  schedule->flushcount--;
237  }
238  return del_task;
239 }
240 
241 
248  time_t when)
249 {
250  task_type* del_task = NULL;
251 
252  if (!task) {
253  return ODS_STATUS_ASSERT_ERR;
254  }
255 
256  del_task = unschedule_task(schedule, task);
257  if (!del_task) {
258  del_task = task;
259  }
260  del_task->what = what;
261  del_task->when = when;
262  return schedule_task(schedule, del_task, 1);
263 }
264 
265 
270 task_type*
272 {
273  ldns_rbnode_t* first_node = LDNS_RBTREE_NULL;
274  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
275  task_type* pop = NULL;
276 
277  if (!schedule) {
278  return NULL;
279  }
280  ods_log_assert(schedule);
281  ods_log_assert(schedule->tasks);
282 
283  first_node = ldns_rbtree_first(schedule->tasks);
284  if (!first_node) {
285  return NULL;
286  }
287 
288  if (schedule->flushcount > 0) {
289  /* find remaining to be flushed tasks */
290  node = first_node;
291  while (node && node != LDNS_RBTREE_NULL) {
292  pop = (task_type*) node->data;
293  if (pop->flush) {
294  return pop;
295  }
296  node = ldns_rbtree_next(node);
297  }
298  /* no more to be flushed tasks found */
299  ods_log_warning("[%s] unable to get first scheduled: could not "
300  "find flush-task, while there should be %i flush-tasks left",
301  schedule_str, schedule->flushcount);
302  ods_log_info("[%s] reset flush count to 0", schedule_str);
303  schedule->flushcount = 0;
304  }
305  /* no more tasks to be flushed, return first task in schedule */
306  pop = (task_type*) first_node->data;
307  return pop;
308 }
309 
310 
315 task_type*
317 {
318  task_type* pop = NULL;
319  time_t now = 0;
320 
321  if (!schedule) {
322  ods_log_error("[%s] unable to pop task: no schedule", schedule_str);
323  return NULL;
324  }
325  ods_log_assert(schedule);
326  ods_log_assert(schedule->tasks);
327 
328  now = time_now();
329  pop = schedule_get_first_task(schedule);
330  if (pop && (pop->flush || pop->when <= now)) {
331  if (pop->flush) {
332  ods_log_debug("[%s] flush task for zone %s", schedule_str,
333  pop->who?pop->who:"(null)");
334  } else {
335  ods_log_debug("[%s] pop task for zone %s", schedule_str,
336  pop->who?pop->who:"(null)");
337  }
338  return unschedule_task(schedule, pop);
339  } else if (pop) {
340  ods_log_debug("[%s] not popping task for zone %s: not ready (when %u "
341  "< now %u, flush=%u)", schedule_str, pop->who?pop->who:"(null)",
342  pop->when, now, pop->flush);
343  } else {
344  ods_log_debug("[%s] not popping task: no task", schedule_str);
345  }
346  return NULL;
347 }
348 
349 
354 void
355 schedule_print(FILE* out, schedule_type* schedule)
356 {
357  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
358  task_type* task = NULL;
359 
360  if (!out || !schedule || !schedule->tasks) {
361  return;
362  }
363  ods_log_assert(out);
364  ods_log_assert(schedule);
365  ods_log_assert(schedule->tasks);
366 
367  node = ldns_rbtree_first(schedule->tasks);
368  while (node && node != LDNS_RBTREE_NULL) {
369  task = (task_type*) node->data;
370  task_print(out, task);
371  node = ldns_rbtree_next(node);
372  }
373  fprintf(out, "\n");
374  return;
375 }
376 
377 
382 static void
383 task_delfunc(ldns_rbnode_t* elem)
384 {
385  task_type* task;
386 
387  if (elem && elem != LDNS_RBTREE_NULL) {
388  task = (task_type*) elem->data;
389  task_delfunc(elem->left);
390  task_delfunc(elem->right);
391  task_cleanup(task);
392  free((void*)elem);
393  }
394  return;
395 }
396 
397 
402 void
404 {
405  allocator_type* allocator;
406  lock_basic_type schedule_lock;
407 
408  if (!schedule) {
409  return;
410  }
411  ods_log_debug("[%s] cleanup schedule", schedule_str);
412  if (schedule->tasks) {
413  task_delfunc(schedule->tasks->root);
414  ldns_rbtree_free(schedule->tasks);
415  schedule->tasks = NULL;
416  }
417 
418  allocator = schedule->allocator;
419  schedule_lock = schedule->schedule_lock;
420 
421  allocator_deallocate(allocator, (void*) schedule);
422  lock_basic_destroy(&schedule_lock);
423  return;
424 }