OpenDNSSEC-signer  1.3.9
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  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  ods_log_assert(schedule);
93  ods_log_assert(schedule->tasks);
94 
95  node = ldns_rbtree_first(schedule->tasks);
96  while (node && node != LDNS_RBTREE_NULL) {
97  task = (task_type*) node->data;
98  task->flush = 1;
99  schedule->flushcount++;
100  if (override != TASK_NONE) {
101  task->what = override;
102  }
103  node = ldns_rbtree_next(node);
104  }
105  return;
106 }
107 
108 
113 static ldns_rbnode_t*
114 task2node(task_type* task)
115 {
116  ldns_rbnode_t* node = (ldns_rbnode_t*) malloc(sizeof(ldns_rbnode_t));
117  node->key = task;
118  node->data = task;
119  return node;
120 }
121 
122 
127 task_type*
129 {
130  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
131  task_type* lookup = NULL;
132 
133  if (!schedule || !task) {
134  return NULL;
135  }
136  ods_log_assert(task);
137  ods_log_assert(schedule);
138  ods_log_assert(schedule->tasks);
139 
140  node = ldns_rbtree_search(schedule->tasks, task);
141  if (node && node != LDNS_RBTREE_NULL) {
142  lookup = (task_type*) node->data;
143  }
144  return lookup;
145 }
146 
147 
153 schedule_task(schedule_type* schedule, task_type* task, int log)
154 {
155  ldns_rbnode_t* new_node = NULL;
156  ldns_rbnode_t* ins_node = NULL;
157 
158  if (!task) {
159  ods_log_error("[%s] unable to schedule task: no task", schedule_str);
160  return ODS_STATUS_ASSERT_ERR;
161  }
162  ods_log_assert(task);
163  if (!schedule) {
164  ods_log_error("[%s] unable to schedule task: no schedule",
165  schedule_str);
166  return ODS_STATUS_ASSERT_ERR;
167  }
168  ods_log_assert(schedule);
169  ods_log_assert(schedule->tasks);
170 
171  ods_log_debug("[%s] schedule task %s for zone %s", schedule_str,
172  task_what2str(task->what), task_who2str(task->who));
173  if (schedule_lookup_task(schedule, task) != NULL) {
174  ods_log_error("[%s] unable to schedule task %s for zone %s: "
175  " already present", schedule_str, task_what2str(task->what),
176  task_who2str(task->who));
177  return ODS_STATUS_ERR;
178  }
179  new_node = task2node(task);
180  ins_node = ldns_rbtree_insert(schedule->tasks, new_node);
181  if (!ins_node) {
182  ods_log_error("[%s] unable to schedule task %s for zone %s: "
183  " insert failed", schedule_str, task_what2str(task->what),
184  task_who2str(task->who));
185  free((void*)new_node);
186  return ODS_STATUS_ERR;
187  }
188  if (task->flush) {
189  schedule->flushcount++;
190  }
191  if (log) {
192  task_log(task);
193  }
194  return ODS_STATUS_OK;
195 }
196 
197 
202 task_type*
204 {
205  ldns_rbnode_t* del_node = LDNS_RBTREE_NULL;
206  task_type* del_task = NULL;
207 
208  if (!task) {
209  /* we are done */
210  return NULL;
211  }
212  ods_log_assert(task);
213  if (!schedule) {
214  ods_log_error("[%s] unable to unschedule task: no schedule",
215  schedule_str);
216  return NULL;
217  }
218  ods_log_assert(schedule);
219  ods_log_assert(schedule->tasks);
220 
221  ods_log_debug("[%s] unschedule task %s for zone %s",
222  schedule_str, task_what2str(task->what), task_who2str(task->who));
223  del_node = ldns_rbtree_delete(schedule->tasks, (const void*) task);
224  if (del_node) {
225  del_task = (task_type*) del_node->data;
226  free((void*)del_node);
227  } else {
228  ods_log_warning("[%s] unable to unschedule task %s for zone %s: not "
229  "scheduled", schedule_str, task_what2str(task->what),
230  task_who2str(task->who));
231  return NULL;
232  }
233  if (del_task->flush) {
234  del_task->flush = 0;
235  schedule->flushcount--;
236  }
237  return del_task;
238 }
239 
240 
247  time_t when)
248 {
249  task_type* del_task = NULL;
250 
251  if (!task) {
252  return ODS_STATUS_ASSERT_ERR;
253  }
254 
255  del_task = unschedule_task(schedule, task);
256  if (!del_task) {
257  del_task = task;
258  }
259  del_task->what = what;
260  del_task->when = when;
261  return schedule_task(schedule, del_task, 1);
262 }
263 
264 
269 task_type*
271 {
272  ldns_rbnode_t* first_node = LDNS_RBTREE_NULL;
273  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
274  task_type* pop = NULL;
275 
276  if (!schedule) {
277  return NULL;
278  }
279  ods_log_assert(schedule);
280  ods_log_assert(schedule->tasks);
281 
282  first_node = ldns_rbtree_first(schedule->tasks);
283  if (!first_node) {
284  return NULL;
285  }
286 
287  if (schedule->flushcount > 0) {
288  /* find remaining to be flushed tasks */
289  node = first_node;
290  while (node && node != LDNS_RBTREE_NULL) {
291  pop = (task_type*) node->data;
292  if (pop->flush) {
293  return pop;
294  }
295  node = ldns_rbtree_next(node);
296  }
297  /* no more to be flushed tasks found */
298  ods_log_warning("[%s] unable to get first scheduled: could not "
299  "find flush-task, while there should be %i flush-tasks left",
300  schedule_str, schedule->flushcount);
301  ods_log_info("[%s] reset flush count to 0", schedule_str);
302  schedule->flushcount = 0;
303  }
304  /* no more tasks to be flushed, return first task in schedule */
305  pop = (task_type*) first_node->data;
306  return pop;
307 }
308 
309 
314 task_type*
316 {
317  task_type* pop = NULL;
318  time_t now = 0;
319 
320  if (!schedule) {
321  ods_log_error("[%s] unable to pop task: no schedule", schedule_str);
322  return NULL;
323  }
324  ods_log_assert(schedule);
325  ods_log_assert(schedule->tasks);
326 
327  now = time_now();
328  pop = schedule_get_first_task(schedule);
329  if (pop && (pop->flush || pop->when <= now)) {
330  if (pop->flush) {
331  ods_log_debug("[%s] flush task for zone %s", schedule_str,
332  pop->who?pop->who:"(null)");
333  } else {
334  ods_log_debug("[%s] pop task for zone %s", schedule_str,
335  pop->who?pop->who:"(null)");
336  }
337  return unschedule_task(schedule, pop);
338  }
339  return NULL;
340 }
341 
342 
347 void
348 schedule_print(FILE* out, schedule_type* schedule)
349 {
350  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
351  task_type* task = NULL;
352 
353  if (!out || !schedule || !schedule->tasks) {
354  return;
355  }
356  ods_log_assert(out);
357  ods_log_assert(schedule);
358  ods_log_assert(schedule->tasks);
359 
360  node = ldns_rbtree_first(schedule->tasks);
361  while (node && node != LDNS_RBTREE_NULL) {
362  task = (task_type*) node->data;
363  task_print(out, task);
364  node = ldns_rbtree_next(node);
365  }
366  fprintf(out, "\n");
367  return;
368 }
369 
370 
375 static void
376 task_delfunc(ldns_rbnode_t* elem)
377 {
378  task_type* task;
379 
380  if (elem && elem != LDNS_RBTREE_NULL) {
381  task = (task_type*) elem->data;
382  task_delfunc(elem->left);
383  task_delfunc(elem->right);
384  task_cleanup(task);
385  free((void*)elem);
386  }
387  return;
388 }
389 
390 
395 void
397 {
398  allocator_type* allocator;
399  lock_basic_type schedule_lock;
400 
401  if (!schedule) {
402  return;
403  }
404  ods_log_debug("[%s] cleanup schedule", schedule_str);
405  if (schedule->tasks) {
406  task_delfunc(schedule->tasks->root);
407  ldns_rbtree_free(schedule->tasks);
408  schedule->tasks = NULL;
409  }
410 
411  allocator = schedule->allocator;
412  schedule_lock = schedule->schedule_lock;
413 
414  allocator_deallocate(allocator, (void*) schedule);
415  lock_basic_destroy(&schedule_lock);
416  return;
417 }