OpenDNSSEC-signer  2.0.4
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 "duration.h"
36 #include "log.h"
37 
38 #include <ldns/ldns.h>
39 
40 static const char* schedule_str = "scheduler";
41 
42 
49 {
50  schedule_type* schedule;
51  CHECKALLOC(schedule = (schedule_type*) malloc(sizeof(schedule_type)));
52  if (!schedule) {
53  ods_log_error("[%s] unable to create schedule: allocator_alloc() "
54  "failed", schedule_str);
55  return NULL;
56  }
57  schedule->loading = 0;
58  schedule->flushcount = 0;
59  schedule->tasks = ldns_rbtree_create(task_compare);
60  if (!schedule->tasks) {
61  ods_log_error("[%s] unable to create schedule: ldns_rbtree_create() "
62  "failed", schedule_str);
63  free(schedule);
64  return NULL;
65  }
66  lock_basic_init(&schedule->schedule_lock);
67  return schedule;
68 }
69 
70 
75 void
76 schedule_flush(schedule_type* schedule, task_id override)
77 {
78  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
79  task_type* task = NULL;
80 
81  ods_log_debug("[%s] flush all tasks", schedule_str);
82  if (!schedule || !schedule->tasks) {
83  return;
84  }
85  node = ldns_rbtree_first(schedule->tasks);
86  while (node && node != LDNS_RBTREE_NULL) {
87  task = (task_type*) node->data;
88  task->flush = 1;
89  schedule->flushcount++;
90  if (override != TASK_NONE) {
91  task->what = override;
92  }
93  node = ldns_rbtree_next(node);
94  }
95 }
96 
97 
102 static ldns_rbnode_t*
103 task2node(task_type* task)
104 {
105  ldns_rbnode_t* node = (ldns_rbnode_t*) malloc(sizeof(ldns_rbnode_t));
106  if (node) {
107  node->key = task;
108  node->data = task;
109  }
110  return node;
111 }
112 
113 
118 task_type*
120 {
121  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
122  task_type* lookup = NULL;
123  if (!schedule || !task) {
124  return NULL;
125  }
126  ods_log_assert(schedule->tasks);
127  node = ldns_rbtree_search(schedule->tasks, task);
128  if (node && node != LDNS_RBTREE_NULL) {
129  lookup = (task_type*) node->data;
130  }
131  return lookup;
132 }
133 
134 
139 ods_status
140 schedule_task(schedule_type* schedule, task_type* task, int log)
141 {
142  ldns_rbnode_t* new_node = NULL;
143  ldns_rbnode_t* ins_node = NULL;
144  if (!task || !schedule || !schedule->tasks) {
145  return ODS_STATUS_ASSERT_ERR;
146  }
147  ods_log_debug("[%s] schedule task %s for zone %s", schedule_str,
148  task_what2str(task->what), task_who2str(task));
149  if (schedule_lookup_task(schedule, task) != NULL) {
150  ods_log_error("[%s] unable to schedule task %s for zone %s: "
151  " already present", schedule_str, task_what2str(task->what),
152  task_who2str(task));
153  return ODS_STATUS_ERR;
154  }
155  new_node = task2node(task);
156  if (!new_node) {
157  ods_log_error("[%s] unable to schedule task %s for zone %s: "
158  " task2node() failed", schedule_str, task_what2str(task->what),
159  task_who2str(task));
160  return ODS_STATUS_MALLOC_ERR;
161  }
162  ins_node = ldns_rbtree_insert(schedule->tasks, new_node);
163  if (!ins_node) {
164  ods_log_error("[%s] unable to schedule task %s for zone %s: "
165  " insert failed", schedule_str, task_what2str(task->what),
166  task_who2str(task));
167  free((void*)new_node);
168  return ODS_STATUS_ERR;
169  }
170  if (task->flush) {
171  schedule->flushcount++;
172  }
173  if (log) {
174  task_log(task);
175  }
176  return ODS_STATUS_OK;
177 }
178 
179 
184 task_type*
186 {
187  ldns_rbnode_t* del_node = LDNS_RBTREE_NULL;
188  task_type* del_task = NULL;
189  if (!task || !schedule || !schedule->tasks) {
190  return NULL;
191  }
192  ods_log_debug("[%s] unschedule task %s for zone %s",
193  schedule_str, task_what2str(task->what), task_who2str(task));
194  del_node = ldns_rbtree_delete(schedule->tasks, (const void*) task);
195  if (del_node) {
196  del_task = (task_type*) del_node->data;
197  free((void*)del_node);
198  } else {
199  ods_log_warning("[%s] unable to unschedule task %s for zone %s: not "
200  "scheduled", schedule_str, task_what2str(task->what),
201  task_who2str(task));
202  return NULL;
203  }
204  if (del_task->flush) {
205  del_task->flush = 0;
206  schedule->flushcount--;
207  }
208  return del_task;
209 }
210 
211 
216 task_type*
218 {
219  ldns_rbnode_t* first_node = LDNS_RBTREE_NULL;
220  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
221  task_type* pop = NULL;
222  if (!schedule || !schedule->tasks) {
223  return NULL;
224  }
225  first_node = ldns_rbtree_first(schedule->tasks);
226  if (!first_node) {
227  return NULL;
228  }
229  if (schedule->flushcount > 0) {
230  /* find remaining to be flushed tasks */
231  node = first_node;
232  while (node && node != LDNS_RBTREE_NULL) {
233  pop = (task_type*) node->data;
234  if (pop->flush) {
235  return pop;
236  }
237  node = ldns_rbtree_next(node);
238  }
239  /* no more to be flushed tasks found */
240  ods_log_warning("[%s] unable to get first scheduled task: could not "
241  "find flush-task, while there should be %i flush-tasks left",
242  schedule_str, schedule->flushcount);
243  ods_log_info("[%s] reset flush count to 0", schedule_str);
244  schedule->flushcount = 0;
245  }
246  /* no more tasks to be flushed, return first task in schedule */
247  pop = (task_type*) first_node->data;
248  return pop;
249 }
250 
251 
256 task_type*
258 {
259  task_type* pop = NULL;
260  time_t now = 0;
261  if (!schedule || !schedule->tasks) {
262  return NULL;
263  }
264  now = time_now();
265  pop = schedule_get_first_task(schedule);
266  if (pop && (pop->flush || pop->when <= now)) {
267  if (pop->flush) {
268  ods_log_debug("[%s] flush task for zone %s", schedule_str,
269  task_who2str(pop));
270  } else {
271  ods_log_debug("[%s] pop task for zone %s", schedule_str,
272  task_who2str(pop));
273  }
274  return unschedule_task(schedule, pop);
275  }
276  return NULL;
277 }
278 
279 
284 static void
285 task_delfunc(ldns_rbnode_t* elem)
286 {
287  task_type* task;
288 
289  if (elem && elem != LDNS_RBTREE_NULL) {
290  task = (task_type*) elem->data;
291  task_delfunc(elem->left);
292  task_delfunc(elem->right);
293  task_cleanup(task);
294  free((void*)elem);
295  }
296 }
297 
298 
303 void
305 {
306  if (!schedule) {
307  return;
308  }
309  ods_log_debug("[%s] cleanup schedule", schedule_str);
310  if (schedule->tasks) {
311  task_delfunc(schedule->tasks->root);
312  ldns_rbtree_free(schedule->tasks);
313  schedule->tasks = NULL;
314  }
315  lock_basic_destroy(&schedule->schedule_lock);
316  free(schedule);
317 }
Definition: task.h:39
schedule_type * schedule_create()
Definition: schedule.c:48
task_type * schedule_get_first_task(schedule_type *schedule)
Definition: schedule.c:217
time_t when
Definition: task.h:60
void task_log(task_type *task)
Definition: task.c:192
ods_status schedule_task(schedule_type *schedule, task_type *task, int log)
Definition: schedule.c:140
int flush
Definition: task.h:63
const char * task_who2str(task_type *task)
Definition: task.c:137
void schedule_flush(schedule_type *schedule, task_id override)
Definition: schedule.c:76
task_type * schedule_lookup_task(schedule_type *schedule, task_type *task)
Definition: schedule.c:119
enum task_id_enum task_id
Definition: task.h:46
task_type * schedule_pop_task(schedule_type *schedule)
Definition: schedule.c:257
void task_cleanup(task_type *task)
Definition: task.c:213
task_type * unschedule_task(schedule_type *schedule, task_type *task)
Definition: schedule.c:185
task_id what
Definition: task.h:57
ldns_rbtree_t * tasks
Definition: schedule.h:59
void schedule_cleanup(schedule_type *schedule)
Definition: schedule.c:304
int task_compare(const void *a, const void *b)
Definition: task.c:73
lock_basic_type schedule_lock
Definition: schedule.h:62
const char * task_what2str(task_id what)
Definition: task.c:107