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->stores = NULL;
220 sobj->stores_num = 0;
221 return 0;
222 } /* metric_init */
224 static void
225 metric_destroy(sdb_object_t *obj)
226 {
227 metric_t *sobj = METRIC(obj);
228 size_t i;
230 assert(obj);
231 store_obj_destroy(obj);
233 if (sobj->attributes)
234 sdb_avltree_destroy(sobj->attributes);
236 for (i = 0; i < sobj->stores_num; ++i) {
237 if (sobj->stores[i].type)
238 free(sobj->stores[i].type);
239 if (sobj->stores[i].id)
240 free(sobj->stores[i].id);
241 }
242 if (sobj->stores)
243 free(sobj->stores);
244 sobj->stores = NULL;
245 sobj->stores_num = 0;
246 } /* metric_destroy */
248 static int
249 attr_init(sdb_object_t *obj, va_list ap)
250 {
251 const sdb_data_t *value;
252 int ret;
254 /* this will consume the first argument (type) of ap */
255 ret = store_obj_init(obj, ap);
256 if (ret)
257 return ret;
258 value = va_arg(ap, const sdb_data_t *);
260 if (value)
261 if (sdb_data_copy(&ATTR(obj)->value, value))
262 return -1;
263 return 0;
264 } /* attr_init */
266 static void
267 attr_destroy(sdb_object_t *obj)
268 {
269 assert(obj);
271 store_obj_destroy(obj);
272 sdb_data_free_datum(&ATTR(obj)->value);
273 } /* attr_destroy */
275 static sdb_type_t store_type = {
276 /* size = */ sizeof(sdb_memstore_t),
277 /* init = */ store_init,
278 /* destroy = */ store_destroy,
279 };
281 static sdb_type_t host_type = {
282 /* size = */ sizeof(host_t),
283 /* init = */ host_init,
284 /* destroy = */ host_destroy
285 };
287 static sdb_type_t service_type = {
288 /* size = */ sizeof(service_t),
289 /* init = */ service_init,
290 /* destroy = */ service_destroy
291 };
293 static sdb_type_t metric_type = {
294 /* size = */ sizeof(metric_t),
295 /* init = */ metric_init,
296 /* destroy = */ metric_destroy
297 };
299 static sdb_type_t attribute_type = {
300 /* size = */ sizeof(attr_t),
301 /* init = */ attr_init,
302 /* destroy = */ attr_destroy
303 };
305 /*
306 * private helper functions
307 */
309 static int
310 record_backends(sdb_memstore_obj_t *obj,
311 const char * const *backends, size_t backends_num)
312 {
313 char **tmp;
314 size_t i;
316 for (i = 0; i < backends_num; i++) {
317 bool found = 0;
318 size_t j;
320 for (j = 0; j < obj->backends_num; ++j) {
321 if (!strcasecmp(obj->backends[j], backends[i])) {
322 found = 1;
323 break;
324 }
325 }
326 if (found)
327 continue;
329 tmp = realloc(obj->backends,
330 (obj->backends_num + 1) * sizeof(*obj->backends));
331 if (! tmp)
332 return -1;
334 obj->backends = tmp;
335 obj->backends[obj->backends_num] = strdup(backends[i]);
336 if (! obj->backends[obj->backends_num])
337 return -1;
339 ++obj->backends_num;
340 }
341 return 0;
342 } /* record_backends */
344 static int
345 store_obj(store_obj_t *obj, sdb_memstore_obj_t **updated_obj)
346 {
347 sdb_memstore_obj_t *old, *new;
348 int status = 0;
350 assert(obj->parent_tree);
352 old = STORE_OBJ(sdb_avltree_lookup(obj->parent_tree, obj->name));
353 if (old) {
354 new = old;
355 sdb_object_deref(SDB_OBJ(old));
356 }
357 else {
358 if (obj->type == SDB_ATTRIBUTE) {
359 /* the value will be updated by the caller */
360 new = STORE_OBJ(sdb_object_create(obj->name, attribute_type,
361 obj->type, NULL));
362 }
363 else {
364 sdb_type_t t;
365 t = obj->type == SDB_HOST
366 ? host_type
367 : obj->type == SDB_SERVICE
368 ? service_type
369 : metric_type;
370 new = STORE_OBJ(sdb_object_create(obj->name, t, obj->type));
371 }
373 if (new) {
374 status = sdb_avltree_insert(obj->parent_tree, SDB_OBJ(new));
376 /* pass control to the tree or destroy in case of an error */
377 sdb_object_deref(SDB_OBJ(new));
378 }
379 else {
380 char errbuf[1024];
381 sdb_log(SDB_LOG_ERR, "memstore: Failed to create %s '%s': %s",
382 SDB_STORE_TYPE_TO_NAME(obj->type), obj->name,
383 sdb_strerror(errno, errbuf, sizeof(errbuf)));
384 status = -1;
385 }
386 }
388 if (status < 0)
389 return status;
390 assert(new);
392 new->last_update = obj->last_update;
393 new->interval = obj->interval;
395 if (new->parent != obj->parent) {
396 // Avoid circular self-references which are not handled
397 // correctly by the ref-count based management layer.
398 //sdb_object_deref(SDB_OBJ(new->parent));
399 //sdb_object_ref(SDB_OBJ(obj->parent));
400 new->parent = obj->parent;
401 }
403 if (updated_obj)
404 *updated_obj = new;
406 if (record_backends(new, obj->backends, obj->backends_num))
407 return -1;
408 return status;
409 } /* store_obj */
411 static int
412 store_metric_update_store(metric_store_t *store,
413 const sdb_metric_store_t __attribute__((unused)) *s,
414 sdb_time_t last_update)
415 {
416 if (last_update <= store->last_update)
417 return 0;
418 store->last_update = last_update;
419 return 0;
420 } /* store_metric_update_store */
422 static int
423 store_metric_add_store(metric_t *metric, const sdb_metric_store_t *s,
424 sdb_time_t last_update)
425 {
426 char *type = strdup(s->type);
427 char *id = strdup(s->id);
429 metric_store_t *new;
431 if ((! type) || (! id)) {
432 if (type)
433 free(type);
434 if (id)
435 free(id);
436 return -1;
437 }
439 new = realloc(metric->stores,
440 (metric->stores_num + 1) * sizeof(*metric->stores));
441 if (! new) {
442 free(type);
443 free(id);
444 return -1;
445 }
447 metric->stores = new;
448 new = metric->stores + metric->stores_num;
449 metric->stores_num++;
451 new->type = type;
452 new->id = id;
453 new->last_update = last_update;
454 return 0;
455 } /* store_metric_add_store */
457 static int
458 store_metric_stores(metric_t *metric, sdb_store_metric_t *m)
459 {
460 size_t i;
462 if (! m->stores_num)
463 return 0;
465 for (i = 0; i < m->stores_num; ++i) {
466 sdb_time_t last_update = m->stores[i].last_update;
467 size_t j;
469 if (last_update < m->last_update)
470 last_update = m->last_update;
472 for (j = 0; j < metric->stores_num; ++j) {
473 if ((! strcasecmp(metric->stores[j].type, m->stores[i].type))
474 && (! strcasecmp(metric->stores[j].id, m->stores[i].id))) {
475 if (store_metric_update_store(metric->stores + j,
476 m->stores + i, last_update) < 0)
477 return -1;
478 break;
479 }
480 }
482 if (j >= metric->stores_num)
483 if (store_metric_add_store(metric, m->stores + i, last_update) < 0)
484 return -1;
485 }
486 return 0;
487 } /* store_metric_stores */
489 /* The store's host_lock has to be acquired before calling this function. */
490 static sdb_avltree_t *
491 get_host_children(host_t *host, int type)
492 {
493 if ((type != SDB_SERVICE) && (type != SDB_METRIC)
494 && (type != SDB_ATTRIBUTE))
495 return NULL;
497 if (! host)
498 return NULL;
500 if (type == SDB_ATTRIBUTE)
501 return host->attributes;
502 else if (type == SDB_METRIC)
503 return host->metrics;
504 else
505 return host->services;
506 } /* get_host_children */
508 static sdb_avltree_t *
509 get_obj_attrs(sdb_memstore_obj_t *obj)
510 {
511 if (obj->type == SDB_HOST)
512 return HOST(obj)->attributes;
513 else if (obj->type == SDB_SERVICE)
514 return SVC(obj)->attributes;
515 else if (obj->type == SDB_METRIC)
516 return METRIC(obj)->attributes;
517 return NULL;
518 } /* get_obj_attrs */
520 /*
521 * store writer API
522 */
524 static int
525 store_attribute(sdb_store_attribute_t *attr, sdb_object_t *user_data)
526 {
527 sdb_memstore_t *st = SDB_MEMSTORE(user_data);
528 store_obj_t obj = STORE_OBJ_INIT;
529 sdb_memstore_obj_t *new = NULL;
530 const char *hostname;
531 host_t *host;
533 sdb_avltree_t *children = NULL;
534 int status = 0;
536 if ((! attr) || (! attr->parent) || (! attr->key))
537 return -1;
539 hostname = attr->hostname;
540 if (attr->parent_type == SDB_HOST)
541 hostname = attr->parent;
542 if (! hostname)
543 return -1;
545 pthread_rwlock_wrlock(&st->host_lock);
546 host = HOST(sdb_avltree_lookup(st->hosts, hostname));
547 if (! host) {
548 sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - "
549 "host '%s' not found", attr->key, hostname);
550 status = -1;
551 }
553 switch (attr->parent_type) {
554 case SDB_HOST:
555 obj.parent = STORE_OBJ(host);
556 obj.parent_tree = get_host_children(host, SDB_ATTRIBUTE);
557 break;
558 case SDB_SERVICE:
559 case SDB_METRIC:
560 children = get_host_children(host, attr->parent_type);
561 break;
562 default:
563 status = -1;
564 break;
565 }
567 if (children) {
568 obj.parent = STORE_OBJ(sdb_avltree_lookup(children, attr->parent));
569 if (! obj.parent) {
570 sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - "
571 "%s '%s/%s' not found", attr->key,
572 SDB_STORE_TYPE_TO_NAME(attr->parent_type),
573 attr->hostname, attr->parent);
574 status = -1;
575 }
576 else
577 obj.parent_tree = attr->parent_type == SDB_SERVICE
578 ? SVC(obj.parent)->attributes
579 : METRIC(obj.parent)->attributes;
580 }
582 obj.type = SDB_ATTRIBUTE;
583 obj.name = attr->key;
584 obj.last_update = attr->last_update;
585 obj.interval = attr->interval;
586 obj.backends = attr->backends;
587 obj.backends_num = attr->backends_num;
588 if (! status)
589 status = store_obj(&obj, &new);
591 if (! status) {
592 assert(new);
593 /* update the value if it changed */
594 if (sdb_data_cmp(&ATTR(new)->value, &attr->value))
595 if (sdb_data_copy(&ATTR(new)->value, &attr->value))
596 status = -1;
597 }
599 if (obj.parent != STORE_OBJ(host))
600 sdb_object_deref(SDB_OBJ(obj.parent));
601 sdb_object_deref(SDB_OBJ(host));
602 pthread_rwlock_unlock(&st->host_lock);
604 return status;
605 } /* store_attribute */
607 static int
608 store_host(sdb_store_host_t *host, sdb_object_t *user_data)
609 {
610 sdb_memstore_t *st = SDB_MEMSTORE(user_data);
611 store_obj_t obj = { NULL, st->hosts, SDB_HOST, NULL, 0, 0, NULL, 0 };
612 int status = 0;
614 if ((! host) || (! host->name))
615 return -1;
617 obj.name = host->name;
618 obj.last_update = host->last_update;
619 obj.interval = host->interval;
620 obj.backends = host->backends;
621 obj.backends_num = host->backends_num;
622 pthread_rwlock_wrlock(&st->host_lock);
623 status = store_obj(&obj, NULL);
624 pthread_rwlock_unlock(&st->host_lock);
626 return status;
627 } /* store_host */
629 static int
630 store_service(sdb_store_service_t *service, sdb_object_t *user_data)
631 {
632 sdb_memstore_t *st = SDB_MEMSTORE(user_data);
633 store_obj_t obj = STORE_OBJ_INIT;
634 host_t *host;
636 int status = 0;
638 if ((! service) || (! service->hostname) || (! service->name))
639 return -1;
641 pthread_rwlock_wrlock(&st->host_lock);
642 host = HOST(sdb_avltree_lookup(st->hosts, service->hostname));
643 obj.parent = STORE_OBJ(host);
644 obj.parent_tree = get_host_children(host, SDB_SERVICE);
645 obj.type = SDB_SERVICE;
646 if (! obj.parent_tree) {
647 sdb_log(SDB_LOG_ERR, "memstore: Failed to store service '%s' - "
648 "host '%s' not found", service->name, service->hostname);
649 status = -1;
650 }
652 obj.name = service->name;
653 obj.last_update = service->last_update;
654 obj.interval = service->interval;
655 obj.backends = service->backends;
656 obj.backends_num = service->backends_num;
657 if (! status)
658 status = store_obj(&obj, NULL);
660 sdb_object_deref(SDB_OBJ(host));
661 pthread_rwlock_unlock(&st->host_lock);
662 return status;
663 } /* store_service */
665 static int
666 store_metric(sdb_store_metric_t *metric, sdb_object_t *user_data)
667 {
668 sdb_memstore_t *st = SDB_MEMSTORE(user_data);
669 store_obj_t obj = STORE_OBJ_INIT;
670 sdb_memstore_obj_t *new = NULL;
671 host_t *host;
673 int status = 0;
674 size_t i;
676 if ((! metric) || (! metric->hostname) || (! metric->name))
677 return -1;
679 for (i = 0; i < metric->stores_num; ++i)
680 if ((metric->stores[i].type == NULL) || (metric->stores[i].id == NULL))
681 return -1;
683 pthread_rwlock_wrlock(&st->host_lock);
684 host = HOST(sdb_avltree_lookup(st->hosts, metric->hostname));
685 obj.parent = STORE_OBJ(host);
686 obj.parent_tree = get_host_children(host, SDB_METRIC);
687 obj.type = SDB_METRIC;
688 if (! obj.parent_tree) {
689 sdb_log(SDB_LOG_ERR, "memstore: Failed to store metric '%s' - "
690 "host '%s' not found", metric->name, metric->hostname);
691 status = -1;
692 }
694 obj.name = metric->name;
695 obj.last_update = metric->last_update;
696 obj.interval = metric->interval;
697 obj.backends = metric->backends;
698 obj.backends_num = metric->backends_num;
699 if (! status)
700 status = store_obj(&obj, &new);
701 sdb_object_deref(SDB_OBJ(host));
703 if (status) {
704 pthread_rwlock_unlock(&st->host_lock);
705 return status;
706 }
708 assert(new);
709 if (store_metric_stores(METRIC(new), metric))
710 status = -1;
711 pthread_rwlock_unlock(&st->host_lock);
712 return status;
713 } /* store_metric */
715 sdb_store_writer_t sdb_memstore_writer = {
716 store_host, store_service, store_metric, store_attribute,
717 };
719 /*
720 * store query API
721 */
723 static sdb_object_t *
724 prepare_query(sdb_ast_node_t *ast,
725 sdb_strbuf_t __attribute__((unused)) *errbuf,
726 sdb_object_t __attribute__((unused)) *user_data)
727 {
728 return SDB_OBJ(sdb_memstore_query_prepare(ast));
729 } /* prepare_query */
731 static int
732 execute_query(sdb_object_t *q,
733 sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
734 sdb_object_t *user_data)
735 {
736 return sdb_memstore_query_execute(SDB_MEMSTORE(user_data),
737 QUERY(q), w, wd, errbuf);
738 } /* execute_query */
740 sdb_store_reader_t sdb_memstore_reader = {
741 prepare_query, execute_query,
742 };
744 /*
745 * public API
746 */
748 sdb_memstore_t *
749 sdb_memstore_create(void)
750 {
751 return SDB_MEMSTORE(sdb_object_create("memstore", store_type));
752 } /* sdb_memstore_create */
754 int
755 sdb_memstore_host(sdb_memstore_t *store, const char *name,
756 sdb_time_t last_update, sdb_time_t interval)
757 {
758 sdb_store_host_t host = {
759 name, last_update, interval, NULL, 0,
760 };
761 return store_host(&host, SDB_OBJ(store));
762 } /* sdb_memstore_host */
764 int
765 sdb_memstore_service(sdb_memstore_t *store, const char *hostname, const char *name,
766 sdb_time_t last_update, sdb_time_t interval)
767 {
768 sdb_store_service_t service = {
769 hostname, name, last_update, interval, NULL, 0,
770 };
771 return store_service(&service, SDB_OBJ(store));
772 } /* sdb_memstore_service */
774 int
775 sdb_memstore_metric(sdb_memstore_t *store, const char *hostname, const char *name,
776 sdb_metric_store_t *metric_store,
777 sdb_time_t last_update, sdb_time_t interval)
778 {
779 sdb_store_metric_t metric = {
780 hostname, name, /* stores */ NULL, 0,
781 last_update, interval, NULL, 0,
782 };
783 if (metric_store) {
784 metric.stores = &(const sdb_metric_store_t){
785 metric_store->type,
786 metric_store->id,
787 NULL,
788 metric_store->last_update,
789 };
790 metric.stores_num = 1;
791 }
792 return store_metric(&metric, SDB_OBJ(store));
793 } /* sdb_memstore_metric */
795 int
796 sdb_memstore_attribute(sdb_memstore_t *store, const char *hostname,
797 const char *key, const sdb_data_t *value,
798 sdb_time_t last_update, sdb_time_t interval)
799 {
800 sdb_store_attribute_t attr = {
801 NULL, SDB_HOST, hostname, key, SDB_DATA_INIT,
802 last_update, interval, NULL, 0,
803 };
804 if (value) {
805 attr.value = *value;
806 }
807 return store_attribute(&attr, SDB_OBJ(store));
808 } /* sdb_memstore_attribute */
810 int
811 sdb_memstore_service_attr(sdb_memstore_t *store, const char *hostname,
812 const char *service, const char *key, const sdb_data_t *value,
813 sdb_time_t last_update, sdb_time_t interval)
814 {
815 sdb_store_attribute_t attr = {
816 hostname, SDB_SERVICE, service, key, SDB_DATA_INIT,
817 last_update, interval, NULL, 0,
818 };
819 if (value) {
820 attr.value = *value;
821 }
822 return store_attribute(&attr, SDB_OBJ(store));
823 } /* sdb_memstore_service_attr */
825 int
826 sdb_memstore_metric_attr(sdb_memstore_t *store, const char *hostname,
827 const char *metric, const char *key, const sdb_data_t *value,
828 sdb_time_t last_update, sdb_time_t interval)
829 {
830 sdb_store_attribute_t attr = {
831 hostname, SDB_METRIC, metric, key, SDB_DATA_INIT,
832 last_update, interval, NULL, 0,
833 };
834 if (value) {
835 attr.value = *value;
836 }
837 return store_attribute(&attr, SDB_OBJ(store));
838 } /* sdb_memstore_metric_attr */
840 sdb_memstore_obj_t *
841 sdb_memstore_get_host(sdb_memstore_t *store, const char *name)
842 {
843 host_t *host;
845 if ((! store) || (! name))
846 return NULL;
848 host = HOST(sdb_avltree_lookup(store->hosts, name));
849 if (! host)
850 return NULL;
852 return STORE_OBJ(host);
853 } /* sdb_memstore_get_host */
855 sdb_memstore_obj_t *
856 sdb_memstore_get_child(sdb_memstore_obj_t *obj, int type, const char *name)
857 {
858 sdb_avltree_t *children = NULL;
860 if ((! obj) || (! name))
861 return NULL;
863 if (type & SDB_ATTRIBUTE)
864 children = get_obj_attrs(obj);
865 else if (obj->type == SDB_HOST)
866 children = get_host_children(HOST(obj), type);
867 if (! children)
868 return NULL;
869 return STORE_OBJ(sdb_avltree_lookup(children, name));
870 } /* sdb_memstore_get_child */
872 int
873 sdb_memstore_get_field(sdb_memstore_obj_t *obj, int field, sdb_data_t *res)
874 {
875 sdb_data_t tmp;
877 if (! obj)
878 return -1;
880 switch (field) {
881 case SDB_FIELD_NAME:
882 tmp.type = SDB_TYPE_STRING;
883 tmp.data.string = strdup(SDB_OBJ(obj)->name);
884 if (! tmp.data.string)
885 return -1;
886 break;
887 case SDB_FIELD_LAST_UPDATE:
888 tmp.type = SDB_TYPE_DATETIME;
889 tmp.data.datetime = obj->last_update;
890 break;
891 case SDB_FIELD_AGE:
892 tmp.type = SDB_TYPE_DATETIME;
893 tmp.data.datetime = sdb_gettime() - obj->last_update;
894 break;
895 case SDB_FIELD_INTERVAL:
896 tmp.type = SDB_TYPE_DATETIME;
897 tmp.data.datetime = obj->interval;
898 break;
899 case SDB_FIELD_BACKEND:
900 if (! res)
901 return 0;
902 tmp.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING;
903 tmp.data.array.length = obj->backends_num;
904 tmp.data.array.values = obj->backends;
905 return sdb_data_copy(res, &tmp);
906 case SDB_FIELD_VALUE:
907 if (obj->type != SDB_ATTRIBUTE)
908 return -1;
909 if (! res)
910 return 0;
911 return sdb_data_copy(res, &ATTR(obj)->value);
912 case SDB_FIELD_TIMESERIES:
913 if (obj->type != SDB_METRIC)
914 return -1;
915 tmp.type = SDB_TYPE_BOOLEAN;
916 tmp.data.boolean = METRIC(obj)->stores_num > 0;
917 default:
918 return -1;
919 }
920 if (res)
921 *res = tmp;
922 else
923 sdb_data_free_datum(&tmp);
924 return 0;
925 } /* sdb_memstore_get_field */
927 int
928 sdb_memstore_get_attr(sdb_memstore_obj_t *obj, const char *name, sdb_data_t *res,
929 sdb_memstore_matcher_t *filter)
930 {
931 sdb_memstore_obj_t *attr;
933 if ((! obj) || (! name))
934 return -1;
936 attr = STORE_OBJ(sdb_avltree_lookup(get_obj_attrs(obj), name));
937 if (! attr)
938 return -1;
939 if (filter && (! sdb_memstore_matcher_matches(filter, attr, NULL))) {
940 sdb_object_deref(SDB_OBJ(attr));
941 return -1;
942 }
944 assert(STORE_OBJ(attr)->type == SDB_ATTRIBUTE);
945 if (res)
946 sdb_data_copy(res, &ATTR(attr)->value);
947 sdb_object_deref(SDB_OBJ(attr));
948 return 0;
949 } /* sdb_memstore_get_attr */
951 int
952 sdb_memstore_scan(sdb_memstore_t *store, int type,
953 sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter,
954 sdb_memstore_lookup_cb cb, void *user_data)
955 {
956 sdb_avltree_iter_t *host_iter = NULL;
957 int status = 0;
959 if ((! store) || (! cb))
960 return -1;
962 if ((type != SDB_HOST) && (type != SDB_SERVICE) && (type != SDB_METRIC)) {
963 sdb_log(SDB_LOG_ERR, "memstore: Cannot scan objects of type %d", type);
964 return -1;
965 }
967 pthread_rwlock_rdlock(&store->host_lock);
968 host_iter = sdb_avltree_get_iter(store->hosts);
969 if (! host_iter)
970 status = -1;
972 /* has_next returns false if the iterator is NULL */
973 while (sdb_avltree_iter_has_next(host_iter)) {
974 sdb_memstore_obj_t *host;
975 sdb_avltree_iter_t *iter = NULL;
977 host = STORE_OBJ(sdb_avltree_iter_get_next(host_iter));
978 assert(host);
980 if (! sdb_memstore_matcher_matches(filter, host, NULL))
981 continue;
983 if (type == SDB_SERVICE)
984 iter = sdb_avltree_get_iter(HOST(host)->services);
985 else if (type == SDB_METRIC)
986 iter = sdb_avltree_get_iter(HOST(host)->metrics);
988 if (iter) {
989 while (sdb_avltree_iter_has_next(iter)) {
990 sdb_memstore_obj_t *obj;
991 obj = STORE_OBJ(sdb_avltree_iter_get_next(iter));
992 assert(obj);
994 if (sdb_memstore_matcher_matches(m, obj, filter)) {
995 if (cb(obj, filter, user_data)) {
996 sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
997 "an error while scanning");
998 status = -1;
999 break;
1000 }
1001 }
1002 }
1003 }
1004 else if (sdb_memstore_matcher_matches(m, host, filter)) {
1005 if (cb(host, filter, user_data)) {
1006 sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
1007 "an error while scanning");
1008 status = -1;
1009 }
1010 }
1012 sdb_avltree_iter_destroy(iter);
1013 if (status)
1014 break;
1015 }
1017 sdb_avltree_iter_destroy(host_iter);
1018 pthread_rwlock_unlock(&store->host_lock);
1019 return status;
1020 } /* sdb_memstore_scan */
1022 int
1023 sdb_memstore_emit(sdb_memstore_obj_t *obj, sdb_store_writer_t *w, sdb_object_t *wd)
1024 {
1025 if ((! obj) || (! w))
1026 return -1;
1028 switch (obj->type) {
1029 case SDB_HOST:
1030 {
1031 sdb_store_host_t host = {
1032 obj->_name,
1033 obj->last_update,
1034 obj->interval,
1035 (const char * const *)obj->backends,
1036 obj->backends_num,
1037 };
1038 if (! w->store_host)
1039 return -1;
1040 return w->store_host(&host, wd);
1041 }
1042 case SDB_SERVICE:
1043 {
1044 sdb_store_service_t service = {
1045 obj->parent ? obj->parent->_name : NULL,
1046 obj->_name,
1047 obj->last_update,
1048 obj->interval,
1049 (const char * const *)obj->backends,
1050 obj->backends_num,
1051 };
1052 if (! w->store_service)
1053 return -1;
1054 return w->store_service(&service, wd);
1055 }
1056 case SDB_METRIC:
1057 {
1058 sdb_metric_store_t metric_stores[METRIC(obj)->stores_num];
1059 sdb_store_metric_t metric = {
1060 obj->parent ? obj->parent->_name : NULL,
1061 obj->_name,
1062 metric_stores,
1063 METRIC(obj)->stores_num,
1064 obj->last_update,
1065 obj->interval,
1066 (const char * const *)obj->backends,
1067 obj->backends_num,
1068 };
1069 size_t i;
1071 for (i = 0; i < METRIC(obj)->stores_num; ++i) {
1072 metric_stores[i].type = METRIC(obj)->stores[i].type;
1073 metric_stores[i].id = METRIC(obj)->stores[i].id;
1074 metric_stores[i].last_update = METRIC(obj)->stores[i].last_update;
1075 }
1077 if (! w->store_metric)
1078 return -1;
1079 return w->store_metric(&metric, wd);
1080 }
1081 case SDB_ATTRIBUTE:
1082 {
1083 sdb_store_attribute_t attr = {
1084 NULL,
1085 obj->parent ? obj->parent->type : 0,
1086 obj->parent ? obj->parent->_name : NULL,
1087 obj->_name,
1088 ATTR(obj)->value,
1089 obj->last_update,
1090 obj->interval,
1091 (const char * const *)obj->backends,
1092 obj->backends_num,
1093 };
1094 if (obj->parent && (obj->parent->type != SDB_HOST)
1095 && obj->parent->parent)
1096 attr.hostname = obj->parent->parent->_name;
1097 if (! w->store_attribute)
1098 return -1;
1099 return w->store_attribute(&attr, wd);
1100 }
1101 }
1103 return -1;
1104 } /* sdb_memstore_emit */
1106 int
1107 sdb_memstore_emit_full(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter,
1108 sdb_store_writer_t *w, sdb_object_t *wd)
1109 {
1110 sdb_avltree_t *trees[] = { NULL, NULL, NULL };
1111 size_t i;
1113 if (sdb_memstore_emit(obj, w, wd))
1114 return -1;
1116 if (obj->type == SDB_HOST) {
1117 trees[0] = HOST(obj)->attributes;
1118 trees[1] = HOST(obj)->metrics;
1119 trees[2] = HOST(obj)->services;
1120 }
1121 else if (obj->type == SDB_SERVICE)
1122 trees[0] = SVC(obj)->attributes;
1123 else if (obj->type == SDB_METRIC)
1124 trees[0] = METRIC(obj)->attributes;
1125 else if (obj->type == SDB_ATTRIBUTE)
1126 return 0;
1127 else
1128 return -1;
1130 for (i = 0; i < SDB_STATIC_ARRAY_LEN(trees); ++i) {
1131 sdb_avltree_iter_t *iter;
1133 if (! trees[i])
1134 continue;
1136 iter = sdb_avltree_get_iter(trees[i]);
1137 while (sdb_avltree_iter_has_next(iter)) {
1138 sdb_memstore_obj_t *child;
1139 child = STORE_OBJ(sdb_avltree_iter_get_next(iter));
1141 if (filter && (! sdb_memstore_matcher_matches(filter, child, NULL)))
1142 continue;
1144 if (sdb_memstore_emit_full(child, filter, w, wd)) {
1145 sdb_avltree_iter_destroy(iter);
1146 return -1;
1147 }
1148 }
1149 sdb_avltree_iter_destroy(iter);
1150 }
1151 return 0;
1152 } /* sdb_memstore_emit_full */
1154 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */