87f9512745446d0f079ca6792fb12ce40168b1ca
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 metric_store->last_update,
788 };
789 metric.stores_num = 1;
790 }
791 return store_metric(&metric, SDB_OBJ(store));
792 } /* sdb_memstore_metric */
794 int
795 sdb_memstore_attribute(sdb_memstore_t *store, const char *hostname,
796 const char *key, const sdb_data_t *value,
797 sdb_time_t last_update, sdb_time_t interval)
798 {
799 sdb_store_attribute_t attr = {
800 NULL, SDB_HOST, hostname, key, SDB_DATA_INIT,
801 last_update, interval, NULL, 0,
802 };
803 if (value) {
804 attr.value = *value;
805 }
806 return store_attribute(&attr, SDB_OBJ(store));
807 } /* sdb_memstore_attribute */
809 int
810 sdb_memstore_service_attr(sdb_memstore_t *store, const char *hostname,
811 const char *service, const char *key, const sdb_data_t *value,
812 sdb_time_t last_update, sdb_time_t interval)
813 {
814 sdb_store_attribute_t attr = {
815 hostname, SDB_SERVICE, service, key, SDB_DATA_INIT,
816 last_update, interval, NULL, 0,
817 };
818 if (value) {
819 attr.value = *value;
820 }
821 return store_attribute(&attr, SDB_OBJ(store));
822 } /* sdb_memstore_service_attr */
824 int
825 sdb_memstore_metric_attr(sdb_memstore_t *store, const char *hostname,
826 const char *metric, const char *key, const sdb_data_t *value,
827 sdb_time_t last_update, sdb_time_t interval)
828 {
829 sdb_store_attribute_t attr = {
830 hostname, SDB_METRIC, metric, key, SDB_DATA_INIT,
831 last_update, interval, NULL, 0,
832 };
833 if (value) {
834 attr.value = *value;
835 }
836 return store_attribute(&attr, SDB_OBJ(store));
837 } /* sdb_memstore_metric_attr */
839 sdb_memstore_obj_t *
840 sdb_memstore_get_host(sdb_memstore_t *store, const char *name)
841 {
842 host_t *host;
844 if ((! store) || (! name))
845 return NULL;
847 host = HOST(sdb_avltree_lookup(store->hosts, name));
848 if (! host)
849 return NULL;
851 return STORE_OBJ(host);
852 } /* sdb_memstore_get_host */
854 sdb_memstore_obj_t *
855 sdb_memstore_get_child(sdb_memstore_obj_t *obj, int type, const char *name)
856 {
857 sdb_avltree_t *children = NULL;
859 if ((! obj) || (! name))
860 return NULL;
862 if (type & SDB_ATTRIBUTE)
863 children = get_obj_attrs(obj);
864 else if (obj->type == SDB_HOST)
865 children = get_host_children(HOST(obj), type);
866 if (! children)
867 return NULL;
868 return STORE_OBJ(sdb_avltree_lookup(children, name));
869 } /* sdb_memstore_get_child */
871 int
872 sdb_memstore_get_field(sdb_memstore_obj_t *obj, int field, sdb_data_t *res)
873 {
874 sdb_data_t tmp;
876 if (! obj)
877 return -1;
879 switch (field) {
880 case SDB_FIELD_NAME:
881 tmp.type = SDB_TYPE_STRING;
882 tmp.data.string = strdup(SDB_OBJ(obj)->name);
883 if (! tmp.data.string)
884 return -1;
885 break;
886 case SDB_FIELD_LAST_UPDATE:
887 tmp.type = SDB_TYPE_DATETIME;
888 tmp.data.datetime = obj->last_update;
889 break;
890 case SDB_FIELD_AGE:
891 tmp.type = SDB_TYPE_DATETIME;
892 tmp.data.datetime = sdb_gettime() - obj->last_update;
893 break;
894 case SDB_FIELD_INTERVAL:
895 tmp.type = SDB_TYPE_DATETIME;
896 tmp.data.datetime = obj->interval;
897 break;
898 case SDB_FIELD_BACKEND:
899 if (! res)
900 return 0;
901 tmp.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING;
902 tmp.data.array.length = obj->backends_num;
903 tmp.data.array.values = obj->backends;
904 return sdb_data_copy(res, &tmp);
905 case SDB_FIELD_VALUE:
906 if (obj->type != SDB_ATTRIBUTE)
907 return -1;
908 if (! res)
909 return 0;
910 return sdb_data_copy(res, &ATTR(obj)->value);
911 case SDB_FIELD_TIMESERIES:
912 if (obj->type != SDB_METRIC)
913 return -1;
914 tmp.type = SDB_TYPE_BOOLEAN;
915 tmp.data.boolean = METRIC(obj)->stores_num > 0;
916 default:
917 return -1;
918 }
919 if (res)
920 *res = tmp;
921 else
922 sdb_data_free_datum(&tmp);
923 return 0;
924 } /* sdb_memstore_get_field */
926 int
927 sdb_memstore_get_attr(sdb_memstore_obj_t *obj, const char *name, sdb_data_t *res,
928 sdb_memstore_matcher_t *filter)
929 {
930 sdb_memstore_obj_t *attr;
932 if ((! obj) || (! name))
933 return -1;
935 attr = STORE_OBJ(sdb_avltree_lookup(get_obj_attrs(obj), name));
936 if (! attr)
937 return -1;
938 if (filter && (! sdb_memstore_matcher_matches(filter, attr, NULL))) {
939 sdb_object_deref(SDB_OBJ(attr));
940 return -1;
941 }
943 assert(STORE_OBJ(attr)->type == SDB_ATTRIBUTE);
944 if (res)
945 sdb_data_copy(res, &ATTR(attr)->value);
946 sdb_object_deref(SDB_OBJ(attr));
947 return 0;
948 } /* sdb_memstore_get_attr */
950 int
951 sdb_memstore_scan(sdb_memstore_t *store, int type,
952 sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter,
953 sdb_memstore_lookup_cb cb, void *user_data)
954 {
955 sdb_avltree_iter_t *host_iter = NULL;
956 int status = 0;
958 if ((! store) || (! cb))
959 return -1;
961 if ((type != SDB_HOST) && (type != SDB_SERVICE) && (type != SDB_METRIC)) {
962 sdb_log(SDB_LOG_ERR, "memstore: Cannot scan objects of type %d", type);
963 return -1;
964 }
966 pthread_rwlock_rdlock(&store->host_lock);
967 host_iter = sdb_avltree_get_iter(store->hosts);
968 if (! host_iter)
969 status = -1;
971 /* has_next returns false if the iterator is NULL */
972 while (sdb_avltree_iter_has_next(host_iter)) {
973 sdb_memstore_obj_t *host;
974 sdb_avltree_iter_t *iter = NULL;
976 host = STORE_OBJ(sdb_avltree_iter_get_next(host_iter));
977 assert(host);
979 if (! sdb_memstore_matcher_matches(filter, host, NULL))
980 continue;
982 if (type == SDB_SERVICE)
983 iter = sdb_avltree_get_iter(HOST(host)->services);
984 else if (type == SDB_METRIC)
985 iter = sdb_avltree_get_iter(HOST(host)->metrics);
987 if (iter) {
988 while (sdb_avltree_iter_has_next(iter)) {
989 sdb_memstore_obj_t *obj;
990 obj = STORE_OBJ(sdb_avltree_iter_get_next(iter));
991 assert(obj);
993 if (sdb_memstore_matcher_matches(m, obj, filter)) {
994 if (cb(obj, filter, user_data)) {
995 sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
996 "an error while scanning");
997 status = -1;
998 break;
999 }
1000 }
1001 }
1002 }
1003 else if (sdb_memstore_matcher_matches(m, host, filter)) {
1004 if (cb(host, filter, user_data)) {
1005 sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
1006 "an error while scanning");
1007 status = -1;
1008 }
1009 }
1011 sdb_avltree_iter_destroy(iter);
1012 if (status)
1013 break;
1014 }
1016 sdb_avltree_iter_destroy(host_iter);
1017 pthread_rwlock_unlock(&store->host_lock);
1018 return status;
1019 } /* sdb_memstore_scan */
1021 int
1022 sdb_memstore_emit(sdb_memstore_obj_t *obj, sdb_store_writer_t *w, sdb_object_t *wd)
1023 {
1024 if ((! obj) || (! w))
1025 return -1;
1027 switch (obj->type) {
1028 case SDB_HOST:
1029 {
1030 sdb_store_host_t host = {
1031 obj->_name,
1032 obj->last_update,
1033 obj->interval,
1034 (const char * const *)obj->backends,
1035 obj->backends_num,
1036 };
1037 if (! w->store_host)
1038 return -1;
1039 return w->store_host(&host, wd);
1040 }
1041 case SDB_SERVICE:
1042 {
1043 sdb_store_service_t service = {
1044 obj->parent ? obj->parent->_name : NULL,
1045 obj->_name,
1046 obj->last_update,
1047 obj->interval,
1048 (const char * const *)obj->backends,
1049 obj->backends_num,
1050 };
1051 if (! w->store_service)
1052 return -1;
1053 return w->store_service(&service, wd);
1054 }
1055 case SDB_METRIC:
1056 {
1057 sdb_metric_store_t metric_stores[METRIC(obj)->stores_num];
1058 sdb_store_metric_t metric = {
1059 obj->parent ? obj->parent->_name : NULL,
1060 obj->_name,
1061 metric_stores,
1062 METRIC(obj)->stores_num,
1063 obj->last_update,
1064 obj->interval,
1065 (const char * const *)obj->backends,
1066 obj->backends_num,
1067 };
1068 size_t i;
1070 for (i = 0; i < METRIC(obj)->stores_num; ++i) {
1071 metric_stores[i].type = METRIC(obj)->stores[i].type;
1072 metric_stores[i].id = METRIC(obj)->stores[i].id;
1073 metric_stores[i].last_update = METRIC(obj)->stores[i].last_update;
1074 }
1076 if (! w->store_metric)
1077 return -1;
1078 return w->store_metric(&metric, wd);
1079 }
1080 case SDB_ATTRIBUTE:
1081 {
1082 sdb_store_attribute_t attr = {
1083 NULL,
1084 obj->parent ? obj->parent->type : 0,
1085 obj->parent ? obj->parent->_name : NULL,
1086 obj->_name,
1087 ATTR(obj)->value,
1088 obj->last_update,
1089 obj->interval,
1090 (const char * const *)obj->backends,
1091 obj->backends_num,
1092 };
1093 if (obj->parent && (obj->parent->type != SDB_HOST)
1094 && obj->parent->parent)
1095 attr.hostname = obj->parent->parent->_name;
1096 if (! w->store_attribute)
1097 return -1;
1098 return w->store_attribute(&attr, wd);
1099 }
1100 }
1102 return -1;
1103 } /* sdb_memstore_emit */
1105 int
1106 sdb_memstore_emit_full(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter,
1107 sdb_store_writer_t *w, sdb_object_t *wd)
1108 {
1109 sdb_avltree_t *trees[] = { NULL, NULL, NULL };
1110 size_t i;
1112 if (sdb_memstore_emit(obj, w, wd))
1113 return -1;
1115 if (obj->type == SDB_HOST) {
1116 trees[0] = HOST(obj)->attributes;
1117 trees[1] = HOST(obj)->metrics;
1118 trees[2] = HOST(obj)->services;
1119 }
1120 else if (obj->type == SDB_SERVICE)
1121 trees[0] = SVC(obj)->attributes;
1122 else if (obj->type == SDB_METRIC)
1123 trees[0] = METRIC(obj)->attributes;
1124 else if (obj->type == SDB_ATTRIBUTE)
1125 return 0;
1126 else
1127 return -1;
1129 for (i = 0; i < SDB_STATIC_ARRAY_LEN(trees); ++i) {
1130 sdb_avltree_iter_t *iter;
1132 if (! trees[i])
1133 continue;
1135 iter = sdb_avltree_get_iter(trees[i]);
1136 while (sdb_avltree_iter_has_next(iter)) {
1137 sdb_memstore_obj_t *child;
1138 child = STORE_OBJ(sdb_avltree_iter_get_next(iter));
1140 if (filter && (! sdb_memstore_matcher_matches(filter, child, NULL)))
1141 continue;
1143 if (sdb_memstore_emit_full(child, filter, w, wd)) {
1144 sdb_avltree_iter_destroy(iter);
1145 return -1;
1146 }
1147 }
1148 sdb_avltree_iter_destroy(iter);
1149 }
1150 return 0;
1151 } /* sdb_memstore_emit_full */
1153 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */