1 /*
2 * SysDB - src/core/memstore.c
3 * Copyright (C) 2012-2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
4 * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 #if HAVE_CONFIG_H
29 # include "config.h"
30 #endif /* HAVE_CONFIG_H */
32 #include "sysdb.h"
33 #include "core/memstore-private.h"
34 #include "core/plugin.h"
35 #include "utils/avltree.h"
36 #include "utils/error.h"
38 #include <assert.h>
40 #include <errno.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <strings.h>
47 #include <pthread.h>
49 /*
50 * private types
51 */
53 struct sdb_memstore {
54 sdb_object_t super;
56 /* hosts are the top-level entries and
57 * reference everything else */
58 sdb_avltree_t *hosts;
59 pthread_rwlock_t host_lock;
60 };
62 /* internal representation of a to-be-stored object */
63 typedef struct {
64 sdb_memstore_obj_t *parent;
65 sdb_avltree_t *parent_tree;
66 int type;
67 const char *name;
68 sdb_time_t last_update;
69 sdb_time_t interval;
70 const char * const *backends;
71 size_t backends_num;
72 } store_obj_t;
73 #define STORE_OBJ_INIT { NULL, NULL, 0, NULL, 0, 0, NULL, 0 }
75 static sdb_type_t host_type;
76 static sdb_type_t service_type;
77 static sdb_type_t metric_type;
78 static sdb_type_t attribute_type;
80 static int
81 store_init(sdb_object_t *obj, va_list __attribute__((unused)) ap)
82 {
83 int err;
84 if (! (SDB_MEMSTORE(obj)->hosts = sdb_avltree_create()))
85 return -1;
86 if ((err = pthread_rwlock_init(&SDB_MEMSTORE(obj)->host_lock,
87 /* attr = */ NULL))) {
88 char errbuf[128];
89 sdb_log(SDB_LOG_ERR, "memstore: Failed to initialize lock: %s",
90 sdb_strerror(err, errbuf, sizeof(errbuf)));
91 return -1;
92 }
93 return 0;
94 } /* store_init */
96 static void
97 store_destroy(sdb_object_t *obj)
98 {
99 int err;
100 if ((err = pthread_rwlock_destroy(&SDB_MEMSTORE(obj)->host_lock))) {
101 char errbuf[128];
102 sdb_log(SDB_LOG_ERR, "memstore: Failed to destroy lock: %s",
103 sdb_strerror(err, errbuf, sizeof(errbuf)));
104 return;
105 }
106 sdb_avltree_destroy(SDB_MEMSTORE(obj)->hosts);
107 SDB_MEMSTORE(obj)->hosts = NULL;
108 } /* store_destroy */
110 static int
111 store_obj_init(sdb_object_t *obj, va_list ap)
112 {
113 sdb_memstore_obj_t *sobj = STORE_OBJ(obj);
114 sobj->type = va_arg(ap, int);
115 return 0;
116 } /* store_obj_init */
118 static void
119 store_obj_destroy(sdb_object_t *obj)
120 {
121 sdb_memstore_obj_t *sobj = STORE_OBJ(obj);
122 size_t i;
124 for (i = 0; i < sobj->backends_num; ++i)
125 free(sobj->backends[i]);
126 free(sobj->backends);
127 sobj->backends = NULL;
128 sobj->backends_num = 0;
130 // We don't currently keep an extra reference for parent objects to
131 // avoid circular self-references which are not handled correctly by
132 // the ref-count base management layer.
133 //sdb_object_deref(SDB_OBJ(sobj->parent));
134 } /* store_obj_destroy */
136 static int
137 host_init(sdb_object_t *obj, va_list ap)
138 {
139 host_t *sobj = HOST(obj);
140 int ret;
142 /* this will consume the first argument (type) of ap */
143 ret = store_obj_init(obj, ap);
144 if (ret)
145 return ret;
147 sobj->services = sdb_avltree_create();
148 if (! sobj->services)
149 return -1;
150 sobj->metrics = sdb_avltree_create();
151 if (! sobj->metrics)
152 return -1;
153 sobj->attributes = sdb_avltree_create();
154 if (! sobj->attributes)
155 return -1;
156 return 0;
157 } /* host_init */
159 static void
160 host_destroy(sdb_object_t *obj)
161 {
162 host_t *sobj = HOST(obj);
163 assert(obj);
165 store_obj_destroy(obj);
167 if (sobj->services)
168 sdb_avltree_destroy(sobj->services);
169 if (sobj->metrics)
170 sdb_avltree_destroy(sobj->metrics);
171 if (sobj->attributes)
172 sdb_avltree_destroy(sobj->attributes);
173 } /* host_destroy */
175 static int
176 service_init(sdb_object_t *obj, va_list ap)
177 {
178 service_t *sobj = SVC(obj);
179 int ret;
181 /* this will consume the first argument (type) of ap */
182 ret = store_obj_init(obj, ap);
183 if (ret)
184 return ret;
186 sobj->attributes = sdb_avltree_create();
187 if (! sobj->attributes)
188 return -1;
189 return 0;
190 } /* service_init */
192 static void
193 service_destroy(sdb_object_t *obj)
194 {
195 service_t *sobj = SVC(obj);
196 assert(obj);
198 store_obj_destroy(obj);
200 if (sobj->attributes)
201 sdb_avltree_destroy(sobj->attributes);
202 } /* service_destroy */
204 static int
205 metric_init(sdb_object_t *obj, va_list ap)
206 {
207 metric_t *sobj = METRIC(obj);
208 int ret;
210 /* this will consume the first argument (type) of ap */
211 ret = store_obj_init(obj, ap);
212 if (ret)
213 return ret;
215 sobj->attributes = sdb_avltree_create();
216 if (! sobj->attributes)
217 return -1;
219 sobj->store.type = sobj->store.id = NULL;
220 return 0;
221 } /* metric_init */
223 static void
224 metric_destroy(sdb_object_t *obj)
225 {
226 metric_t *sobj = METRIC(obj);
227 assert(obj);
229 store_obj_destroy(obj);
231 if (sobj->attributes)
232 sdb_avltree_destroy(sobj->attributes);
234 if (sobj->store.type)
235 free(sobj->store.type);
236 if (sobj->store.id)
237 free(sobj->store.id);
238 } /* metric_destroy */
240 static int
241 attr_init(sdb_object_t *obj, va_list ap)
242 {
243 const sdb_data_t *value;
244 int ret;
246 /* this will consume the first argument (type) of ap */
247 ret = store_obj_init(obj, ap);
248 if (ret)
249 return ret;
250 value = va_arg(ap, const sdb_data_t *);
252 if (value)
253 if (sdb_data_copy(&ATTR(obj)->value, value))
254 return -1;
255 return 0;
256 } /* attr_init */
258 static void
259 attr_destroy(sdb_object_t *obj)
260 {
261 assert(obj);
263 store_obj_destroy(obj);
264 sdb_data_free_datum(&ATTR(obj)->value);
265 } /* attr_destroy */
267 static sdb_type_t store_type = {
268 /* size = */ sizeof(sdb_memstore_t),
269 /* init = */ store_init,
270 /* destroy = */ store_destroy,
271 };
273 static sdb_type_t host_type = {
274 /* size = */ sizeof(host_t),
275 /* init = */ host_init,
276 /* destroy = */ host_destroy
277 };
279 static sdb_type_t service_type = {
280 /* size = */ sizeof(service_t),
281 /* init = */ service_init,
282 /* destroy = */ service_destroy
283 };
285 static sdb_type_t metric_type = {
286 /* size = */ sizeof(metric_t),
287 /* init = */ metric_init,
288 /* destroy = */ metric_destroy
289 };
291 static sdb_type_t attribute_type = {
292 /* size = */ sizeof(attr_t),
293 /* init = */ attr_init,
294 /* destroy = */ attr_destroy
295 };
297 /*
298 * private helper functions
299 */
301 static int
302 record_backends(sdb_memstore_obj_t *obj,
303 const char * const *backends, size_t backends_num)
304 {
305 char **tmp;
306 size_t i;
308 for (i = 0; i < backends_num; i++) {
309 bool found = 0;
310 size_t j;
312 for (j = 0; j < obj->backends_num; ++j) {
313 if (!strcasecmp(obj->backends[j], backends[i])) {
314 found = 1;
315 break;
316 }
317 }
318 if (found)
319 continue;
321 tmp = realloc(obj->backends,
322 (obj->backends_num + 1) * sizeof(*obj->backends));
323 if (! tmp)
324 return -1;
326 obj->backends = tmp;
327 obj->backends[obj->backends_num] = strdup(backends[i]);
328 if (! obj->backends[obj->backends_num])
329 return -1;
331 ++obj->backends_num;
332 }
333 return 0;
334 } /* record_backends */
336 static int
337 store_obj(store_obj_t *obj, sdb_memstore_obj_t **updated_obj)
338 {
339 sdb_memstore_obj_t *old, *new;
340 int status = 0;
342 assert(obj->parent_tree);
344 old = STORE_OBJ(sdb_avltree_lookup(obj->parent_tree, obj->name));
345 if (old) {
346 new = old;
347 sdb_object_deref(SDB_OBJ(old));
348 }
349 else {
350 if (obj->type == SDB_ATTRIBUTE) {
351 /* the value will be updated by the caller */
352 new = STORE_OBJ(sdb_object_create(obj->name, attribute_type,
353 obj->type, NULL));
354 }
355 else {
356 sdb_type_t t;
357 t = obj->type == SDB_HOST
358 ? host_type
359 : obj->type == SDB_SERVICE
360 ? service_type
361 : metric_type;
362 new = STORE_OBJ(sdb_object_create(obj->name, t, obj->type));
363 }
365 if (new) {
366 status = sdb_avltree_insert(obj->parent_tree, SDB_OBJ(new));
368 /* pass control to the tree or destroy in case of an error */
369 sdb_object_deref(SDB_OBJ(new));
370 }
371 else {
372 char errbuf[1024];
373 sdb_log(SDB_LOG_ERR, "memstore: Failed to create %s '%s': %s",
374 SDB_STORE_TYPE_TO_NAME(obj->type), obj->name,
375 sdb_strerror(errno, errbuf, sizeof(errbuf)));
376 status = -1;
377 }
378 }
380 if (status < 0)
381 return status;
382 assert(new);
384 new->last_update = obj->last_update;
385 new->interval = obj->interval;
387 if (new->parent != obj->parent) {
388 // Avoid circular self-references which are not handled
389 // correctly by the ref-count based management layer.
390 //sdb_object_deref(SDB_OBJ(new->parent));
391 //sdb_object_ref(SDB_OBJ(obj->parent));
392 new->parent = obj->parent;
393 }
395 if (updated_obj)
396 *updated_obj = new;
398 if (record_backends(new, obj->backends, obj->backends_num))
399 return -1;
400 return status;
401 } /* store_obj */
403 static int
404 store_metric_store(metric_t *metric, sdb_store_metric_t *m)
405 {
406 char *type = metric->store.type;
407 char *id = metric->store.id;
409 if (! m->store.last_update)
410 m->store.last_update = metric->store.last_update;
411 else if (m->store.last_update < metric->store.last_update)
412 return 0;
414 if ((! metric->store.type) || strcasecmp(metric->store.type, m->store.type)) {
415 if (! (type = strdup(m->store.type)))
416 return -1;
417 }
418 if ((! metric->store.id) || strcasecmp(metric->store.id, m->store.id)) {
419 if (! (id = strdup(m->store.id))) {
420 if (type != metric->store.type)
421 free(type);
422 return -1;
423 }
424 }
426 if (type != metric->store.type) {
427 if (metric->store.type)
428 free(metric->store.type);
429 metric->store.type = type;
430 }
431 if (id != metric->store.id) {
432 if (metric->store.id)
433 free(metric->store.id);
434 metric->store.id = id;
435 }
436 metric->store.last_update = m->store.last_update;
437 return 0;
438 } /* store_metric_store */
440 /* The store's host_lock has to be acquired before calling this function. */
441 static sdb_avltree_t *
442 get_host_children(host_t *host, int type)
443 {
444 if ((type != SDB_SERVICE) && (type != SDB_METRIC)
445 && (type != SDB_ATTRIBUTE))
446 return NULL;
448 if (! host)
449 return NULL;
451 if (type == SDB_ATTRIBUTE)
452 return host->attributes;
453 else if (type == SDB_METRIC)
454 return host->metrics;
455 else
456 return host->services;
457 } /* get_host_children */
459 static sdb_avltree_t *
460 get_obj_attrs(sdb_memstore_obj_t *obj)
461 {
462 if (obj->type == SDB_HOST)
463 return HOST(obj)->attributes;
464 else if (obj->type == SDB_SERVICE)
465 return SVC(obj)->attributes;
466 else if (obj->type == SDB_METRIC)
467 return METRIC(obj)->attributes;
468 return NULL;
469 } /* get_obj_attrs */
471 /*
472 * store writer API
473 */
475 static int
476 store_attribute(sdb_store_attribute_t *attr, sdb_object_t *user_data)
477 {
478 sdb_memstore_t *st = SDB_MEMSTORE(user_data);
479 store_obj_t obj = STORE_OBJ_INIT;
480 sdb_memstore_obj_t *new = NULL;
481 const char *hostname;
482 host_t *host;
484 sdb_avltree_t *children = NULL;
485 int status = 0;
487 if ((! attr) || (! attr->parent) || (! attr->key))
488 return -1;
490 hostname = attr->hostname;
491 if (attr->parent_type == SDB_HOST)
492 hostname = attr->parent;
493 if (! hostname)
494 return -1;
496 pthread_rwlock_wrlock(&st->host_lock);
497 host = HOST(sdb_avltree_lookup(st->hosts, hostname));
498 if (! host) {
499 sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - "
500 "host '%s' not found", attr->key, hostname);
501 status = -1;
502 }
504 switch (attr->parent_type) {
505 case SDB_HOST:
506 obj.parent = STORE_OBJ(host);
507 obj.parent_tree = get_host_children(host, SDB_ATTRIBUTE);
508 break;
509 case SDB_SERVICE:
510 case SDB_METRIC:
511 children = get_host_children(host, attr->parent_type);
512 break;
513 default:
514 status = -1;
515 break;
516 }
518 if (children) {
519 obj.parent = STORE_OBJ(sdb_avltree_lookup(children, attr->parent));
520 if (! obj.parent) {
521 sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - "
522 "%s '%s/%s' not found", attr->key,
523 SDB_STORE_TYPE_TO_NAME(attr->parent_type),
524 attr->hostname, attr->parent);
525 status = -1;
526 }
527 else
528 obj.parent_tree = attr->parent_type == SDB_SERVICE
529 ? SVC(obj.parent)->attributes
530 : METRIC(obj.parent)->attributes;
531 }
533 obj.type = SDB_ATTRIBUTE;
534 obj.name = attr->key;
535 obj.last_update = attr->last_update;
536 obj.interval = attr->interval;
537 obj.backends = attr->backends;
538 obj.backends_num = attr->backends_num;
539 if (! status)
540 status = store_obj(&obj, &new);
542 if (! status) {
543 assert(new);
544 /* update the value if it changed */
545 if (sdb_data_cmp(&ATTR(new)->value, &attr->value))
546 if (sdb_data_copy(&ATTR(new)->value, &attr->value))
547 status = -1;
548 }
550 if (obj.parent != STORE_OBJ(host))
551 sdb_object_deref(SDB_OBJ(obj.parent));
552 sdb_object_deref(SDB_OBJ(host));
553 pthread_rwlock_unlock(&st->host_lock);
555 return status;
556 } /* store_attribute */
558 static int
559 store_host(sdb_store_host_t *host, sdb_object_t *user_data)
560 {
561 sdb_memstore_t *st = SDB_MEMSTORE(user_data);
562 store_obj_t obj = { NULL, st->hosts, SDB_HOST, NULL, 0, 0, NULL, 0 };
563 int status = 0;
565 if ((! host) || (! host->name))
566 return -1;
568 obj.name = host->name;
569 obj.last_update = host->last_update;
570 obj.interval = host->interval;
571 obj.backends = host->backends;
572 obj.backends_num = host->backends_num;
573 pthread_rwlock_wrlock(&st->host_lock);
574 status = store_obj(&obj, NULL);
575 pthread_rwlock_unlock(&st->host_lock);
577 return status;
578 } /* store_host */
580 static int
581 store_service(sdb_store_service_t *service, sdb_object_t *user_data)
582 {
583 sdb_memstore_t *st = SDB_MEMSTORE(user_data);
584 store_obj_t obj = STORE_OBJ_INIT;
585 host_t *host;
587 int status = 0;
589 if ((! service) || (! service->hostname) || (! service->name))
590 return -1;
592 pthread_rwlock_wrlock(&st->host_lock);
593 host = HOST(sdb_avltree_lookup(st->hosts, service->hostname));
594 obj.parent = STORE_OBJ(host);
595 obj.parent_tree = get_host_children(host, SDB_SERVICE);
596 obj.type = SDB_SERVICE;
597 if (! obj.parent_tree) {
598 sdb_log(SDB_LOG_ERR, "memstore: Failed to store service '%s' - "
599 "host '%s' not found", service->name, service->hostname);
600 status = -1;
601 }
603 obj.name = service->name;
604 obj.last_update = service->last_update;
605 obj.interval = service->interval;
606 obj.backends = service->backends;
607 obj.backends_num = service->backends_num;
608 if (! status)
609 status = store_obj(&obj, NULL);
611 sdb_object_deref(SDB_OBJ(host));
612 pthread_rwlock_unlock(&st->host_lock);
613 return status;
614 } /* store_service */
616 static int
617 store_metric(sdb_store_metric_t *metric, sdb_object_t *user_data)
618 {
619 sdb_memstore_t *st = SDB_MEMSTORE(user_data);
620 store_obj_t obj = STORE_OBJ_INIT;
621 sdb_memstore_obj_t *new = NULL;
622 host_t *host;
624 int status = 0;
626 if ((! metric) || (! metric->hostname) || (! metric->name))
627 return -1;
629 if ((metric->store.type != NULL) != (metric->store.id != NULL))
630 return -1;
632 pthread_rwlock_wrlock(&st->host_lock);
633 host = HOST(sdb_avltree_lookup(st->hosts, metric->hostname));
634 obj.parent = STORE_OBJ(host);
635 obj.parent_tree = get_host_children(host, SDB_METRIC);
636 obj.type = SDB_METRIC;
637 if (! obj.parent_tree) {
638 sdb_log(SDB_LOG_ERR, "memstore: Failed to store metric '%s' - "
639 "host '%s' not found", metric->name, metric->hostname);
640 status = -1;
641 }
643 obj.name = metric->name;
644 obj.last_update = metric->last_update;
645 obj.interval = metric->interval;
646 obj.backends = metric->backends;
647 obj.backends_num = metric->backends_num;
648 if (! status)
649 status = store_obj(&obj, &new);
650 sdb_object_deref(SDB_OBJ(host));
652 if (status) {
653 pthread_rwlock_unlock(&st->host_lock);
654 return status;
655 }
657 assert(new);
658 if (metric->store.type && metric->store.id)
659 if (store_metric_store(METRIC(new), metric))
660 status = -1;
661 pthread_rwlock_unlock(&st->host_lock);
662 return status;
663 } /* store_metric */
665 sdb_store_writer_t sdb_memstore_writer = {
666 store_host, store_service, store_metric, store_attribute,
667 };
669 /*
670 * store query API
671 */
673 static sdb_object_t *
674 prepare_query(sdb_ast_node_t *ast,
675 sdb_strbuf_t __attribute__((unused)) *errbuf,
676 sdb_object_t __attribute__((unused)) *user_data)
677 {
678 return SDB_OBJ(sdb_memstore_query_prepare(ast));
679 } /* prepare_query */
681 static int
682 execute_query(sdb_object_t *q,
683 sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
684 sdb_object_t *user_data)
685 {
686 return sdb_memstore_query_execute(SDB_MEMSTORE(user_data),
687 QUERY(q), w, wd, errbuf);
688 } /* execute_query */
690 sdb_store_reader_t sdb_memstore_reader = {
691 prepare_query, execute_query,
692 };
694 /*
695 * public API
696 */
698 sdb_memstore_t *
699 sdb_memstore_create(void)
700 {
701 return SDB_MEMSTORE(sdb_object_create("memstore", store_type));
702 } /* sdb_memstore_create */
704 int
705 sdb_memstore_host(sdb_memstore_t *store, const char *name,
706 sdb_time_t last_update, sdb_time_t interval)
707 {
708 sdb_store_host_t host = {
709 name, last_update, interval, NULL, 0,
710 };
711 return store_host(&host, SDB_OBJ(store));
712 } /* sdb_memstore_host */
714 int
715 sdb_memstore_service(sdb_memstore_t *store, const char *hostname, const char *name,
716 sdb_time_t last_update, sdb_time_t interval)
717 {
718 sdb_store_service_t service = {
719 hostname, name, last_update, interval, NULL, 0,
720 };
721 return store_service(&service, SDB_OBJ(store));
722 } /* sdb_memstore_service */
724 int
725 sdb_memstore_metric(sdb_memstore_t *store, const char *hostname, const char *name,
726 sdb_metric_store_t *metric_store,
727 sdb_time_t last_update, sdb_time_t interval)
728 {
729 sdb_store_metric_t metric = {
730 hostname, name,
731 { NULL, NULL, 0 },
732 last_update, interval, NULL, 0,
733 };
734 if (metric_store) {
735 metric.store.type = metric_store->type;
736 metric.store.id = metric_store->id;
737 metric.store.last_update = metric_store->last_update;
738 }
739 return store_metric(&metric, SDB_OBJ(store));
740 } /* sdb_memstore_metric */
742 int
743 sdb_memstore_attribute(sdb_memstore_t *store, const char *hostname,
744 const char *key, const sdb_data_t *value,
745 sdb_time_t last_update, sdb_time_t interval)
746 {
747 sdb_store_attribute_t attr = {
748 NULL, SDB_HOST, hostname, key, SDB_DATA_INIT,
749 last_update, interval, NULL, 0,
750 };
751 if (value) {
752 attr.value = *value;
753 }
754 return store_attribute(&attr, SDB_OBJ(store));
755 } /* sdb_memstore_attribute */
757 int
758 sdb_memstore_service_attr(sdb_memstore_t *store, const char *hostname,
759 const char *service, const char *key, const sdb_data_t *value,
760 sdb_time_t last_update, sdb_time_t interval)
761 {
762 sdb_store_attribute_t attr = {
763 hostname, SDB_SERVICE, service, key, SDB_DATA_INIT,
764 last_update, interval, NULL, 0,
765 };
766 if (value) {
767 attr.value = *value;
768 }
769 return store_attribute(&attr, SDB_OBJ(store));
770 } /* sdb_memstore_service_attr */
772 int
773 sdb_memstore_metric_attr(sdb_memstore_t *store, const char *hostname,
774 const char *metric, const char *key, const sdb_data_t *value,
775 sdb_time_t last_update, sdb_time_t interval)
776 {
777 sdb_store_attribute_t attr = {
778 hostname, SDB_METRIC, metric, key, SDB_DATA_INIT,
779 last_update, interval, NULL, 0,
780 };
781 if (value) {
782 attr.value = *value;
783 }
784 return store_attribute(&attr, SDB_OBJ(store));
785 } /* sdb_memstore_metric_attr */
787 sdb_memstore_obj_t *
788 sdb_memstore_get_host(sdb_memstore_t *store, const char *name)
789 {
790 host_t *host;
792 if ((! store) || (! name))
793 return NULL;
795 host = HOST(sdb_avltree_lookup(store->hosts, name));
796 if (! host)
797 return NULL;
799 return STORE_OBJ(host);
800 } /* sdb_memstore_get_host */
802 sdb_memstore_obj_t *
803 sdb_memstore_get_child(sdb_memstore_obj_t *obj, int type, const char *name)
804 {
805 sdb_avltree_t *children = NULL;
807 if ((! obj) || (! name))
808 return NULL;
810 if (type & SDB_ATTRIBUTE)
811 children = get_obj_attrs(obj);
812 else if (obj->type == SDB_HOST)
813 children = get_host_children(HOST(obj), type);
814 if (! children)
815 return NULL;
816 return STORE_OBJ(sdb_avltree_lookup(children, name));
817 } /* sdb_memstore_get_child */
819 int
820 sdb_memstore_get_field(sdb_memstore_obj_t *obj, int field, sdb_data_t *res)
821 {
822 sdb_data_t tmp;
824 if (! obj)
825 return -1;
827 switch (field) {
828 case SDB_FIELD_NAME:
829 tmp.type = SDB_TYPE_STRING;
830 tmp.data.string = strdup(SDB_OBJ(obj)->name);
831 if (! tmp.data.string)
832 return -1;
833 break;
834 case SDB_FIELD_LAST_UPDATE:
835 tmp.type = SDB_TYPE_DATETIME;
836 tmp.data.datetime = obj->last_update;
837 break;
838 case SDB_FIELD_AGE:
839 tmp.type = SDB_TYPE_DATETIME;
840 tmp.data.datetime = sdb_gettime() - obj->last_update;
841 break;
842 case SDB_FIELD_INTERVAL:
843 tmp.type = SDB_TYPE_DATETIME;
844 tmp.data.datetime = obj->interval;
845 break;
846 case SDB_FIELD_BACKEND:
847 if (! res)
848 return 0;
849 tmp.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING;
850 tmp.data.array.length = obj->backends_num;
851 tmp.data.array.values = obj->backends;
852 return sdb_data_copy(res, &tmp);
853 case SDB_FIELD_VALUE:
854 if (obj->type != SDB_ATTRIBUTE)
855 return -1;
856 if (! res)
857 return 0;
858 return sdb_data_copy(res, &ATTR(obj)->value);
859 case SDB_FIELD_TIMESERIES:
860 if (obj->type != SDB_METRIC)
861 return -1;
862 tmp.type = SDB_TYPE_BOOLEAN;
863 tmp.data.boolean = METRIC(obj)->store.type != NULL;
864 default:
865 return -1;
866 }
867 if (res)
868 *res = tmp;
869 else
870 sdb_data_free_datum(&tmp);
871 return 0;
872 } /* sdb_memstore_get_field */
874 int
875 sdb_memstore_get_attr(sdb_memstore_obj_t *obj, const char *name, sdb_data_t *res,
876 sdb_memstore_matcher_t *filter)
877 {
878 sdb_memstore_obj_t *attr;
880 if ((! obj) || (! name))
881 return -1;
883 attr = STORE_OBJ(sdb_avltree_lookup(get_obj_attrs(obj), name));
884 if (! attr)
885 return -1;
886 if (filter && (! sdb_memstore_matcher_matches(filter, attr, NULL))) {
887 sdb_object_deref(SDB_OBJ(attr));
888 return -1;
889 }
891 assert(STORE_OBJ(attr)->type == SDB_ATTRIBUTE);
892 if (res)
893 sdb_data_copy(res, &ATTR(attr)->value);
894 sdb_object_deref(SDB_OBJ(attr));
895 return 0;
896 } /* sdb_memstore_get_attr */
898 int
899 sdb_memstore_scan(sdb_memstore_t *store, int type,
900 sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter,
901 sdb_memstore_lookup_cb cb, void *user_data)
902 {
903 sdb_avltree_iter_t *host_iter = NULL;
904 int status = 0;
906 if ((! store) || (! cb))
907 return -1;
909 if ((type != SDB_HOST) && (type != SDB_SERVICE) && (type != SDB_METRIC)) {
910 sdb_log(SDB_LOG_ERR, "memstore: Cannot scan objects of type %d", type);
911 return -1;
912 }
914 pthread_rwlock_rdlock(&store->host_lock);
915 host_iter = sdb_avltree_get_iter(store->hosts);
916 if (! host_iter)
917 status = -1;
919 /* has_next returns false if the iterator is NULL */
920 while (sdb_avltree_iter_has_next(host_iter)) {
921 sdb_memstore_obj_t *host;
922 sdb_avltree_iter_t *iter = NULL;
924 host = STORE_OBJ(sdb_avltree_iter_get_next(host_iter));
925 assert(host);
927 if (! sdb_memstore_matcher_matches(filter, host, NULL))
928 continue;
930 if (type == SDB_SERVICE)
931 iter = sdb_avltree_get_iter(HOST(host)->services);
932 else if (type == SDB_METRIC)
933 iter = sdb_avltree_get_iter(HOST(host)->metrics);
935 if (iter) {
936 while (sdb_avltree_iter_has_next(iter)) {
937 sdb_memstore_obj_t *obj;
938 obj = STORE_OBJ(sdb_avltree_iter_get_next(iter));
939 assert(obj);
941 if (sdb_memstore_matcher_matches(m, obj, filter)) {
942 if (cb(obj, filter, user_data)) {
943 sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
944 "an error while scanning");
945 status = -1;
946 break;
947 }
948 }
949 }
950 }
951 else if (sdb_memstore_matcher_matches(m, host, filter)) {
952 if (cb(host, filter, user_data)) {
953 sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
954 "an error while scanning");
955 status = -1;
956 }
957 }
959 sdb_avltree_iter_destroy(iter);
960 if (status)
961 break;
962 }
964 sdb_avltree_iter_destroy(host_iter);
965 pthread_rwlock_unlock(&store->host_lock);
966 return status;
967 } /* sdb_memstore_scan */
969 int
970 sdb_memstore_emit(sdb_memstore_obj_t *obj, sdb_store_writer_t *w, sdb_object_t *wd)
971 {
972 if ((! obj) || (! w))
973 return -1;
975 switch (obj->type) {
976 case SDB_HOST:
977 {
978 sdb_store_host_t host = {
979 obj->_name,
980 obj->last_update,
981 obj->interval,
982 (const char * const *)obj->backends,
983 obj->backends_num,
984 };
985 if (! w->store_host)
986 return -1;
987 return w->store_host(&host, wd);
988 }
989 case SDB_SERVICE:
990 {
991 sdb_store_service_t service = {
992 obj->parent ? obj->parent->_name : NULL,
993 obj->_name,
994 obj->last_update,
995 obj->interval,
996 (const char * const *)obj->backends,
997 obj->backends_num,
998 };
999 if (! w->store_service)
1000 return -1;
1001 return w->store_service(&service, wd);
1002 }
1003 case SDB_METRIC:
1004 {
1005 sdb_store_metric_t metric = {
1006 obj->parent ? obj->parent->_name : NULL,
1007 obj->_name,
1008 {
1009 METRIC(obj)->store.type,
1010 METRIC(obj)->store.id,
1011 METRIC(obj)->store.last_update,
1012 },
1013 obj->last_update,
1014 obj->interval,
1015 (const char * const *)obj->backends,
1016 obj->backends_num,
1017 };
1018 if (! w->store_metric)
1019 return -1;
1020 return w->store_metric(&metric, wd);
1021 }
1022 case SDB_ATTRIBUTE:
1023 {
1024 sdb_store_attribute_t attr = {
1025 NULL,
1026 obj->parent ? obj->parent->type : 0,
1027 obj->parent ? obj->parent->_name : NULL,
1028 obj->_name,
1029 ATTR(obj)->value,
1030 obj->last_update,
1031 obj->interval,
1032 (const char * const *)obj->backends,
1033 obj->backends_num,
1034 };
1035 if (obj->parent && (obj->parent->type != SDB_HOST)
1036 && obj->parent->parent)
1037 attr.hostname = obj->parent->parent->_name;
1038 if (! w->store_attribute)
1039 return -1;
1040 return w->store_attribute(&attr, wd);
1041 }
1042 }
1044 return -1;
1045 } /* sdb_memstore_emit */
1047 int
1048 sdb_memstore_emit_full(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter,
1049 sdb_store_writer_t *w, sdb_object_t *wd)
1050 {
1051 sdb_avltree_t *trees[] = { NULL, NULL, NULL };
1052 size_t i;
1054 if (sdb_memstore_emit(obj, w, wd))
1055 return -1;
1057 if (obj->type == SDB_HOST) {
1058 trees[0] = HOST(obj)->attributes;
1059 trees[1] = HOST(obj)->metrics;
1060 trees[2] = HOST(obj)->services;
1061 }
1062 else if (obj->type == SDB_SERVICE)
1063 trees[0] = SVC(obj)->attributes;
1064 else if (obj->type == SDB_METRIC)
1065 trees[0] = METRIC(obj)->attributes;
1066 else if (obj->type == SDB_ATTRIBUTE)
1067 return 0;
1068 else
1069 return -1;
1071 for (i = 0; i < SDB_STATIC_ARRAY_LEN(trees); ++i) {
1072 sdb_avltree_iter_t *iter;
1074 if (! trees[i])
1075 continue;
1077 iter = sdb_avltree_get_iter(trees[i]);
1078 while (sdb_avltree_iter_has_next(iter)) {
1079 sdb_memstore_obj_t *child;
1080 child = STORE_OBJ(sdb_avltree_iter_get_next(iter));
1082 if (filter && (! sdb_memstore_matcher_matches(filter, child, NULL)))
1083 continue;
1085 if (sdb_memstore_emit_full(child, filter, w, wd)) {
1086 sdb_avltree_iter_destroy(iter);
1087 return -1;
1088 }
1089 }
1090 sdb_avltree_iter_destroy(iter);
1091 }
1092 return 0;
1093 } /* sdb_memstore_emit_full */
1095 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */