2 * collectd - src/utils_vl_lookup.c
3 * Copyright (C) 2012 Florian Forster
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 * Florian Forster <octo at collectd.org>
29 #include "utils_vl_lookup.h"
30 #include "utils_avltree.h"
33 # define sstrncpy strncpy
34 # define plugin_log(s, ...) do { \
35 printf ("[severity %i] ", s); \
36 printf (__VA_ARGS__); \
46 c_avl_tree_t *by_type_tree;
48 lookup_class_callback_t cb_user_class;
49 lookup_obj_callback_t cb_user_obj;
50 lookup_free_class_callback_t cb_free_class;
51 lookup_free_obj_callback_t cb_free_obj;
55 typedef struct user_obj_s user_obj_t;
68 user_obj_t *user_obj_list; /* list of user_obj */
70 typedef struct user_class_s user_class_t;
72 struct user_class_list_s;
73 typedef struct user_class_list_s user_class_list_t;
74 struct user_class_list_s
77 user_class_list_t *next;
80 struct by_type_entry_s
82 c_avl_tree_t *by_plugin_tree; /* plugin -> user_class_list_t */
83 user_class_list_t *wildcard_plugin_list;
85 typedef struct by_type_entry_s by_type_entry_t;
87 #define LU_IS_ANY(str) (strcmp (str, "/any/") == 0)
88 #define LU_IS_ALL(str) (strcmp (str, "/all/") == 0)
89 #define LU_IS_WILDCARD(str) (LU_IS_ANY(str) || LU_IS_ALL(str))
94 static void *lu_create_user_obj (lookup_t *obj, /* {{{ */
95 data_set_t const *ds, value_list_t const *vl,
96 user_class_t *user_class)
100 user_obj = malloc (sizeof (*user_obj));
101 if (user_obj == NULL)
103 ERROR ("utils_vl_lookup: malloc failed.");
106 memset (user_obj, 0, sizeof (*user_obj));
107 user_obj->next = NULL;
109 user_obj->user_obj = obj->cb_user_class (ds, vl, user_class->user_class);
110 if (user_obj->user_obj == NULL)
113 WARNING("utils_vl_lookup: User-provided constructor failed.");
117 sstrncpy (user_obj->ident.host,
118 LU_IS_ALL (user_class->ident.host) ? "/all/" : vl->host,
119 sizeof (user_obj->ident.host));
120 sstrncpy (user_obj->ident.plugin,
121 LU_IS_ALL (user_class->ident.plugin) ? "/all/" : vl->plugin,
122 sizeof (user_obj->ident.plugin));
123 sstrncpy (user_obj->ident.plugin_instance,
124 LU_IS_ALL (user_class->ident.plugin_instance) ? "/all/" : vl->plugin_instance,
125 sizeof (user_obj->ident.plugin_instance));
126 sstrncpy (user_obj->ident.type,
127 LU_IS_ALL (user_class->ident.type) ? "/all/" : vl->type,
128 sizeof (user_obj->ident.type));
129 sstrncpy (user_obj->ident.type_instance,
130 LU_IS_ALL (user_class->ident.type_instance) ? "/all/" : vl->type_instance,
131 sizeof (user_obj->ident.type_instance));
133 if (user_class->user_obj_list == NULL)
135 user_class->user_obj_list = user_obj;
139 user_obj_t *last = user_class->user_obj_list;
140 while (last->next != NULL)
142 last->next = user_obj;
146 } /* }}} void *lu_create_user_obj */
148 static user_obj_t *lu_find_user_obj (user_class_t *user_class, /* {{{ */
149 value_list_t const *vl)
153 for (ptr = user_class->user_obj_list;
157 if (!LU_IS_ALL (ptr->ident.host)
158 && (strcmp (ptr->ident.host, vl->host) != 0))
160 if (!LU_IS_ALL (ptr->ident.plugin_instance)
161 && (strcmp (ptr->ident.plugin_instance, vl->plugin_instance) != 0))
163 if (!LU_IS_ALL (ptr->ident.type_instance)
164 && (strcmp (ptr->ident.type_instance, vl->type_instance) != 0))
171 } /* }}} user_obj_t *lu_find_user_obj */
173 static int lu_handle_user_class (lookup_t *obj, /* {{{ */
174 data_set_t const *ds, value_list_t const *vl,
175 user_class_t *user_class)
177 user_obj_t *user_obj;
180 assert (strcmp (vl->type, user_class->ident.type) == 0);
181 assert (LU_IS_WILDCARD (user_class->ident.plugin)
182 || (strcmp (vl->plugin, user_class->ident.plugin) == 0));
184 /* When we get here, type and plugin already match the user class. Now check
185 * the rest of the fields. */
186 if (!LU_IS_WILDCARD (user_class->ident.type_instance)
187 && (strcmp (vl->type_instance, user_class->ident.type_instance) != 0))
189 if (!LU_IS_WILDCARD (user_class->ident.plugin_instance)
190 && (strcmp (vl->plugin_instance,
191 user_class->ident.plugin_instance) != 0))
193 if (!LU_IS_WILDCARD (user_class->ident.host)
194 && (strcmp (vl->host, user_class->ident.host) != 0))
197 user_obj = lu_find_user_obj (user_class, vl);
198 if (user_obj == NULL)
200 /* call lookup_class_callback_t() and insert into the list of user objects. */
201 user_obj = lu_create_user_obj (obj, ds, vl, user_class);
202 if (user_obj == NULL)
206 status = obj->cb_user_obj (ds, vl,
207 user_class->user_class, user_obj->user_obj);
210 ERROR ("utils_vl_lookup: The user object callback failed with status %i.",
212 /* Returning a negative value means: abort! */
220 } /* }}} int lu_handle_user_class */
222 static int lu_handle_user_class_list (lookup_t *obj, /* {{{ */
223 data_set_t const *ds, value_list_t const *vl,
224 user_class_list_t *user_class_list)
226 user_class_list_t *ptr;
229 for (ptr = user_class_list; ptr != NULL; ptr = ptr->next)
233 status = lu_handle_user_class (obj, ds, vl, &ptr->entry);
236 else if (status == 0)
241 } /* }}} int lu_handle_user_class_list */
243 static by_type_entry_t *lu_search_by_type (lookup_t *obj, /* {{{ */
244 char const *type, _Bool allocate_if_missing)
246 by_type_entry_t *by_type;
250 status = c_avl_get (obj->by_type_tree, type, (void *) &by_type);
254 if (!allocate_if_missing)
257 type_copy = strdup (type);
258 if (type_copy == NULL)
260 ERROR ("utils_vl_lookup: strdup failed.");
264 by_type = malloc (sizeof (*by_type));
267 ERROR ("utils_vl_lookup: malloc failed.");
271 memset (by_type, 0, sizeof (*by_type));
272 by_type->wildcard_plugin_list = NULL;
274 by_type->by_plugin_tree = c_avl_create ((void *) strcmp);
275 if (by_type->by_plugin_tree == NULL)
277 ERROR ("utils_vl_lookup: c_avl_create failed.");
283 status = c_avl_insert (obj->by_type_tree,
284 /* key = */ type_copy, /* value = */ by_type);
285 assert (status <= 0); /* >0 => entry exists => race condition. */
288 ERROR ("utils_vl_lookup: c_avl_insert failed.");
289 c_avl_destroy (by_type->by_plugin_tree);
296 } /* }}} by_type_entry_t *lu_search_by_type */
298 static int lu_add_by_plugin (by_type_entry_t *by_type, /* {{{ */
299 identifier_t const *ident, user_class_list_t *user_class_list)
301 user_class_list_t *ptr = NULL;
303 /* Lookup user_class_list from the per-plugin structure. If this is the first
304 * user_class to be added, the blocks return immediately. Otherwise they will
305 * set "ptr" to non-NULL. */
306 if (LU_IS_WILDCARD (ident->plugin))
308 if (by_type->wildcard_plugin_list == NULL)
310 by_type->wildcard_plugin_list = user_class_list;
314 ptr = by_type->wildcard_plugin_list;
315 } /* if (plugin is wildcard) */
316 else /* (plugin is not wildcard) */
320 status = c_avl_get (by_type->by_plugin_tree,
321 ident->plugin, (void *) &ptr);
323 if (status != 0) /* plugin not yet in tree */
325 char *plugin_copy = strdup (ident->plugin);
327 if (plugin_copy == NULL)
329 ERROR ("utils_vl_lookup: strdup failed.");
330 sfree (user_class_list);
334 status = c_avl_insert (by_type->by_plugin_tree,
335 plugin_copy, user_class_list);
338 ERROR ("utils_vl_lookup: c_avl_insert(\"%s\") failed with status %i.",
339 plugin_copy, status);
341 sfree (user_class_list);
348 } /* if (plugin not yet in tree) */
349 } /* if (plugin is not wildcard) */
351 assert (ptr != NULL);
353 while (ptr->next != NULL)
355 ptr->next = user_class_list;
358 } /* }}} int lu_add_by_plugin */
360 static void lu_destroy_user_obj (lookup_t *obj, /* {{{ */
361 user_obj_t *user_obj)
363 while (user_obj != NULL)
365 user_obj_t *next = user_obj->next;
367 if (obj->cb_free_obj != NULL)
368 obj->cb_free_obj (user_obj->user_obj);
369 user_obj->user_obj = NULL;
374 } /* }}} void lu_destroy_user_obj */
376 static void lu_destroy_user_class_list (lookup_t *obj, /* {{{ */
377 user_class_list_t *user_class_list)
379 while (user_class_list != NULL)
381 user_class_list_t *next = user_class_list->next;
383 if (obj->cb_free_class != NULL)
384 obj->cb_free_class (user_class_list->entry.user_class);
385 user_class_list->entry.user_class = NULL;
387 lu_destroy_user_obj (obj, user_class_list->entry.user_obj_list);
388 user_class_list->entry.user_obj_list = NULL;
390 sfree (user_class_list);
391 user_class_list = next;
393 } /* }}} void lu_destroy_user_class_list */
395 static void lu_destroy_by_type (lookup_t *obj, /* {{{ */
396 by_type_entry_t *by_type)
402 user_class_list_t *user_class_list = NULL;
405 status = c_avl_pick (by_type->by_plugin_tree,
406 (void *) &plugin, (void *) &user_class_list);
410 DEBUG ("utils_vl_lookup: lu_destroy_by_type: Destroying plugin \"%s\".",
413 lu_destroy_user_class_list (obj, user_class_list);
416 c_avl_destroy (by_type->by_plugin_tree);
417 by_type->by_plugin_tree = NULL;
419 lu_destroy_user_class_list (obj, by_type->wildcard_plugin_list);
420 by_type->wildcard_plugin_list = NULL;
423 } /* }}} int lu_destroy_by_type */
428 lookup_t *lookup_create (lookup_class_callback_t cb_user_class, /* {{{ */
429 lookup_obj_callback_t cb_user_obj,
430 lookup_free_class_callback_t cb_free_class,
431 lookup_free_obj_callback_t cb_free_obj)
433 lookup_t *obj = malloc (sizeof (*obj));
436 ERROR ("utils_vl_lookup: malloc failed.");
439 memset (obj, 0, sizeof (*obj));
441 obj->by_type_tree = c_avl_create ((void *) strcmp);
442 if (obj->by_type_tree == NULL)
444 ERROR ("utils_vl_lookup: c_avl_create failed.");
449 obj->cb_user_class = cb_user_class;
450 obj->cb_user_obj = cb_user_obj;
451 obj->cb_free_class = cb_free_class;
452 obj->cb_free_obj = cb_free_obj;
455 } /* }}} lookup_t *lookup_create */
457 void lookup_destroy (lookup_t *obj) /* {{{ */
467 by_type_entry_t *by_type = NULL;
469 status = c_avl_pick (obj->by_type_tree, (void *) &type, (void *) &by_type);
473 DEBUG ("utils_vl_lookup: lookup_destroy: Destroying type \"%s\".", type);
475 lu_destroy_by_type (obj, by_type);
478 c_avl_destroy (obj->by_type_tree);
479 obj->by_type_tree = NULL;
482 } /* }}} void lookup_destroy */
484 int lookup_add (lookup_t *obj, /* {{{ */
485 identifier_t const *ident, void *user_class)
487 by_type_entry_t *by_type = NULL;
488 user_class_list_t *user_class_obj;
490 by_type = lu_search_by_type (obj, ident->type, /* allocate = */ 1);
494 user_class_obj = malloc (sizeof (*user_class_obj));
495 if (user_class_obj == NULL)
497 ERROR ("utils_vl_lookup: malloc failed.");
500 memset (user_class_obj, 0, sizeof (*user_class_obj));
501 user_class_obj->entry.user_class = user_class;
502 memmove (&user_class_obj->entry.ident, ident, sizeof (*ident));
503 user_class_obj->entry.user_obj_list = NULL;
504 user_class_obj->next = NULL;
506 return (lu_add_by_plugin (by_type, ident, user_class_obj));
507 } /* }}} int lookup_add */
509 /* returns the number of successful calls to the callback function */
510 int lookup_search (lookup_t *obj, /* {{{ */
511 data_set_t const *ds, value_list_t const *vl)
513 by_type_entry_t *by_type = NULL;
514 user_class_list_t *user_class_list = NULL;
518 if ((obj == NULL) || (ds == NULL) || (vl == NULL))
521 by_type = lu_search_by_type (obj, vl->type, /* allocate = */ 0);
525 status = c_avl_get (by_type->by_plugin_tree,
526 vl->plugin, (void *) &user_class_list);
529 status = lu_handle_user_class_list (obj, ds, vl, user_class_list);
535 if (by_type->wildcard_plugin_list != NULL)
537 status = lu_handle_user_class_list (obj, ds, vl,
538 by_type->wildcard_plugin_list);
545 } /* }}} lookup_search */