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>
46 #include <pthread.h>
48 /*
49 * private types
50 */
52 struct sdb_memstore {
53 sdb_object_t super;
55 /* hosts are the top-level entries and
56 * reference everything else */
57 sdb_avltree_t *hosts;
58 pthread_rwlock_t host_lock;
59 };
61 /* internal representation of a to-be-stored object */
62 typedef struct {
63 sdb_memstore_obj_t *parent;
64 sdb_avltree_t *parent_tree;
65 int type;
66 const char *name;
67 sdb_time_t last_update;
68 sdb_time_t interval;
69 const char * const *backends;
70 size_t backends_num;
71 } store_obj_t;
72 #define STORE_OBJ_INIT { NULL, NULL, 0, NULL, 0, 0, NULL, 0 }
74 static sdb_type_t host_type;
75 static sdb_type_t service_type;
76 static sdb_type_t metric_type;
77 static sdb_type_t attribute_type;
79 static int
80 store_init(sdb_object_t *obj, va_list __attribute__((unused)) ap)
81 {
82 int err;
83 if (! (SDB_MEMSTORE(obj)->hosts = sdb_avltree_create()))
84 return -1;
85 if ((err = pthread_rwlock_init(&SDB_MEMSTORE(obj)->host_lock,
86 /* attr = */ NULL))) {
87 char errbuf[128];
88 sdb_log(SDB_LOG_ERR, "memstore: Failed to initialize lock: %s",
89 sdb_strerror(err, errbuf, sizeof(errbuf)));
90 return -1;
91 }
92 return 0;
93 } /* store_init */
95 static void
96 store_destroy(sdb_object_t *obj)
97 {
98 int err;
99 if ((err = pthread_rwlock_destroy(&SDB_MEMSTORE(obj)->host_lock))) {
100 char errbuf[128];
101 sdb_log(SDB_LOG_ERR, "memstore: Failed to destroy lock: %s",
102 sdb_strerror(err, errbuf, sizeof(errbuf)));
103 return;
104 }
105 sdb_avltree_destroy(SDB_MEMSTORE(obj)->hosts);
106 SDB_MEMSTORE(obj)->hosts = NULL;
107 } /* store_destroy */
109 static int
110 store_obj_init(sdb_object_t *obj, va_list ap)
111 {
112 sdb_memstore_obj_t *sobj = STORE_OBJ(obj);
113 sobj->type = va_arg(ap, int);
114 return 0;
115 } /* store_obj_init */
117 static void
118 store_obj_destroy(sdb_object_t *obj)
119 {
120 sdb_memstore_obj_t *sobj = STORE_OBJ(obj);
121 size_t i;
123 for (i = 0; i < sobj->backends_num; ++i)
124 free(sobj->backends[i]);
125 free(sobj->backends);
126 sobj->backends = NULL;
127 sobj->backends_num = 0;
129 // We don't currently keep an extra reference for parent objects to
130 // avoid circular self-references which are not handled correctly by
131 // the ref-count base management layer.
132 //sdb_object_deref(SDB_OBJ(sobj->parent));
133 } /* store_obj_destroy */
135 static int
136 host_init(sdb_object_t *obj, va_list ap)
137 {
138 host_t *sobj = HOST(obj);
139 int ret;
141 /* this will consume the first argument (type) of ap */
142 ret = store_obj_init(obj, ap);
143 if (ret)
144 return ret;
146 sobj->services = sdb_avltree_create();
147 if (! sobj->services)
148 return -1;
149 sobj->metrics = sdb_avltree_create();
150 if (! sobj->metrics)
151 return -1;
152 sobj->attributes = sdb_avltree_create();
153 if (! sobj->attributes)
154 return -1;
155 return 0;
156 } /* host_init */
158 static void
159 host_destroy(sdb_object_t *obj)
160 {
161 host_t *sobj = HOST(obj);
162 assert(obj);
164 store_obj_destroy(obj);
166 if (sobj->services)
167 sdb_avltree_destroy(sobj->services);
168 if (sobj->metrics)
169 sdb_avltree_destroy(sobj->metrics);
170 if (sobj->attributes)
171 sdb_avltree_destroy(sobj->attributes);
172 } /* host_destroy */
174 static int
175 service_init(sdb_object_t *obj, va_list ap)
176 {
177 service_t *sobj = SVC(obj);
178 int ret;
180 /* this will consume the first argument (type) of ap */
181 ret = store_obj_init(obj, ap);
182 if (ret)
183 return ret;
185 sobj->attributes = sdb_avltree_create();
186 if (! sobj->attributes)
187 return -1;
188 return 0;
189 } /* service_init */
191 static void
192 service_destroy(sdb_object_t *obj)
193 {
194 service_t *sobj = SVC(obj);
195 assert(obj);
197 store_obj_destroy(obj);
199 if (sobj->attributes)
200 sdb_avltree_destroy(sobj->attributes);
201 } /* service_destroy */
203 static int
204 metric_init(sdb_object_t *obj, va_list ap)
205 {
206 metric_t *sobj = METRIC(obj);
207 int ret;
209 /* this will consume the first argument (type) of ap */
210 ret = store_obj_init(obj, ap);
211 if (ret)
212 return ret;
214 sobj->attributes = sdb_avltree_create();
215 if (! sobj->attributes)
216 return -1;
218 sobj->store.type = sobj->store.id = NULL;
219 return 0;
220 } /* metric_init */
222 static void
223 metric_destroy(sdb_object_t *obj)
224 {
225 metric_t *sobj = METRIC(obj);
226 assert(obj);
228 store_obj_destroy(obj);
230 if (sobj->attributes)
231 sdb_avltree_destroy(sobj->attributes);
233 if (sobj->store.type)
234 free(sobj->store.type);
235 if (sobj->store.id)
236 free(sobj->store.id);
237 } /* metric_destroy */
239 static int
240 attr_init(sdb_object_t *obj, va_list ap)
241 {
242 const sdb_data_t *value;
243 int ret;
245 /* this will consume the first argument (type) of ap */
246 ret = store_obj_init(obj, ap);
247 if (ret)
248 return ret;
249 value = va_arg(ap, const sdb_data_t *);
251 if (value)
252 if (sdb_data_copy(&ATTR(obj)->value, value))
253 return -1;
254 return 0;
255 } /* attr_init */
257 static void
258 attr_destroy(sdb_object_t *obj)
259 {
260 assert(obj);
262 store_obj_destroy(obj);
263 sdb_data_free_datum(&ATTR(obj)->value);
264 } /* attr_destroy */
266 static sdb_type_t store_type = {
267 /* size = */ sizeof(sdb_memstore_t),
268 /* init = */ store_init,
269 /* destroy = */ store_destroy,
270 };
272 static sdb_type_t host_type = {
273 /* size = */ sizeof(host_t),
274 /* init = */ host_init,
275 /* destroy = */ host_destroy
276 };
278 static sdb_type_t service_type = {
279 /* size = */ sizeof(service_t),
280 /* init = */ service_init,
281 /* destroy = */ service_destroy
282 };
284 static sdb_type_t metric_type = {
285 /* size = */ sizeof(metric_t),
286 /* init = */ metric_init,
287 /* destroy = */ metric_destroy
288 };
290 static sdb_type_t attribute_type = {
291 /* size = */ sizeof(attr_t),
292 /* init = */ attr_init,
293 /* destroy = */ attr_destroy
294 };
296 /*
297 * private helper functions
298 */
300 static int
301 record_backends(sdb_memstore_obj_t *obj,
302 const char * const *backends, size_t backends_num)
303 {
304 char **tmp;
305 size_t i;
307 for (i = 0; i < backends_num; i++) {
308 bool found = 0;
309 size_t j;
311 for (j = 0; j < obj->backends_num; ++j) {
312 if (!strcasecmp(obj->backends[j], backends[i])) {
313 found = 1;
314 break;
315 }
316 }
317 if (found)
318 continue;
320 tmp = realloc(obj->backends,
321 (obj->backends_num + 1) * sizeof(*obj->backends));
322 if (! tmp)
323 return -1;
325 obj->backends = tmp;
326 obj->backends[obj->backends_num] = strdup(backends[i]);
327 if (! obj->backends[obj->backends_num])
328 return -1;
330 ++obj->backends_num;
331 }
332 return 0;
333 } /* record_backends */
335 static int
336 store_obj(store_obj_t *obj, sdb_memstore_obj_t **updated_obj)
337 {
338 sdb_memstore_obj_t *old, *new;
339 int status = 0;
341 assert(obj->parent_tree);
343 old = STORE_OBJ(sdb_avltree_lookup(obj->parent_tree, obj->name));
344 if (old) {
345 new = old;
346 sdb_object_deref(SDB_OBJ(old));
347 }
348 else {
349 if (obj->type == SDB_ATTRIBUTE) {
350 /* the value will be updated by the caller */
351 new = STORE_OBJ(sdb_object_create(obj->name, attribute_type,
352 obj->type, NULL));
353 }
354 else {
355 sdb_type_t t;
356 t = obj->type == SDB_HOST
357 ? host_type
358 : obj->type == SDB_SERVICE
359 ? service_type
360 : metric_type;
361 new = STORE_OBJ(sdb_object_create(obj->name, t, obj->type));
362 }
364 if (new) {
365 status = sdb_avltree_insert(obj->parent_tree, SDB_OBJ(new));
367 /* pass control to the tree or destroy in case of an error */
368 sdb_object_deref(SDB_OBJ(new));
369 }
370 else {
371 char errbuf[1024];
372 sdb_log(SDB_LOG_ERR, "memstore: Failed to create %s '%s': %s",
373 SDB_STORE_TYPE_TO_NAME(obj->type), obj->name,
374 sdb_strerror(errno, errbuf, sizeof(errbuf)));
375 status = -1;
376 }
377 }
379 if (status < 0)
380 return status;
381 assert(new);
383 new->last_update = obj->last_update;
384 new->interval = obj->interval;
386 if (new->parent != obj->parent) {
387 // Avoid circular self-references which are not handled
388 // correctly by the ref-count based management layer.
389 //sdb_object_deref(SDB_OBJ(new->parent));
390 //sdb_object_ref(SDB_OBJ(obj->parent));
391 new->parent = obj->parent;
392 }
394 if (updated_obj)
395 *updated_obj = new;
397 if (record_backends(new, obj->backends, obj->backends_num))
398 return -1;
399 return status;
400 } /* store_obj */
402 static int
403 store_metric_store(metric_t *metric, sdb_store_metric_t *m)
404 {
405 char *type = metric->store.type;
406 char *id = metric->store.id;
408 if ((! metric->store.type) || strcasecmp(metric->store.type, m->store.type)) {
409 if (! (type = strdup(m->store.type)))
410 return -1;
411 }
412 if ((! metric->store.id) || strcasecmp(metric->store.id, m->store.id)) {
413 if (! (id = strdup(m->store.id))) {
414 if (type != metric->store.type)
415 free(type);
416 return -1;
417 }
418 }
420 if (type != metric->store.type) {
421 if (metric->store.type)
422 free(metric->store.type);
423 metric->store.type = type;
424 }
425 if (id != metric->store.id) {
426 if (metric->store.id)
427 free(metric->store.id);
428 metric->store.id = id;
429 }
430 return 0;
431 } /* store_metric_store */
433 /* The store's host_lock has to be acquired before calling this function. */
434 static sdb_avltree_t *
435 get_host_children(host_t *host, int type)
436 {
437 if ((type != SDB_SERVICE) && (type != SDB_METRIC)
438 && (type != SDB_ATTRIBUTE))
439 return NULL;
441 if (! host)
442 return NULL;
444 if (type == SDB_ATTRIBUTE)
445 return host->attributes;
446 else if (type == SDB_METRIC)
447 return host->metrics;
448 else
449 return host->services;
450 } /* get_host_children */
452 static sdb_avltree_t *
453 get_obj_attrs(sdb_memstore_obj_t *obj)
454 {
455 if (obj->type == SDB_HOST)
456 return HOST(obj)->attributes;
457 else if (obj->type == SDB_SERVICE)
458 return SVC(obj)->attributes;
459 else if (obj->type == SDB_METRIC)
460 return METRIC(obj)->attributes;
461 return NULL;
462 } /* get_obj_attrs */
464 /*
465 * store writer API
466 */
468 static int
469 store_attribute(sdb_store_attribute_t *attr, sdb_object_t *user_data)
470 {
471 sdb_memstore_t *st = SDB_MEMSTORE(user_data);
472 store_obj_t obj = STORE_OBJ_INIT;
473 sdb_memstore_obj_t *new = NULL;
474 const char *hostname;
475 host_t *host;
477 sdb_avltree_t *children = NULL;
478 int status = 0;
480 if ((! attr) || (! attr->parent) || (! attr->key))
481 return -1;
483 hostname = attr->hostname;
484 if (attr->parent_type == SDB_HOST)
485 hostname = attr->parent;
486 if (! hostname)
487 return -1;
489 pthread_rwlock_wrlock(&st->host_lock);
490 host = HOST(sdb_avltree_lookup(st->hosts, hostname));
491 if (! host) {
492 sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - "
493 "host '%s' not found", attr->key, hostname);
494 status = -1;
495 }
497 switch (attr->parent_type) {
498 case SDB_HOST:
499 obj.parent = STORE_OBJ(host);
500 obj.parent_tree = get_host_children(host, SDB_ATTRIBUTE);
501 break;
502 case SDB_SERVICE:
503 case SDB_METRIC:
504 children = get_host_children(host, attr->parent_type);
505 break;
506 default:
507 status = -1;
508 break;
509 }
511 if (children) {
512 obj.parent = STORE_OBJ(sdb_avltree_lookup(children, attr->parent));
513 if (! obj.parent) {
514 sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - "
515 "%s '%s/%s' not found", attr->key,
516 SDB_STORE_TYPE_TO_NAME(attr->parent_type),
517 attr->hostname, attr->parent);
518 status = -1;
519 }
520 else
521 obj.parent_tree = attr->parent_type == SDB_SERVICE
522 ? SVC(obj.parent)->attributes
523 : METRIC(obj.parent)->attributes;
524 }
526 obj.type = SDB_ATTRIBUTE;
527 obj.name = attr->key;
528 obj.last_update = attr->last_update;
529 obj.interval = attr->interval;
530 obj.backends = attr->backends;
531 obj.backends_num = attr->backends_num;
532 if (! status)
533 status = store_obj(&obj, &new);
535 if (! status) {
536 assert(new);
537 /* update the value if it changed */
538 if (sdb_data_cmp(&ATTR(new)->value, &attr->value))
539 if (sdb_data_copy(&ATTR(new)->value, &attr->value))
540 status = -1;
541 }
543 if (obj.parent != STORE_OBJ(host))
544 sdb_object_deref(SDB_OBJ(obj.parent));
545 sdb_object_deref(SDB_OBJ(host));
546 pthread_rwlock_unlock(&st->host_lock);
548 return status;
549 } /* store_attribute */
551 static int
552 store_host(sdb_store_host_t *host, sdb_object_t *user_data)
553 {
554 sdb_memstore_t *st = SDB_MEMSTORE(user_data);
555 store_obj_t obj = { NULL, st->hosts, SDB_HOST, NULL, 0, 0, NULL, 0 };
556 int status = 0;
558 if ((! host) || (! host->name))
559 return -1;
561 obj.name = host->name;
562 obj.last_update = host->last_update;
563 obj.interval = host->interval;
564 obj.backends = host->backends;
565 obj.backends_num = host->backends_num;
566 pthread_rwlock_wrlock(&st->host_lock);
567 status = store_obj(&obj, NULL);
568 pthread_rwlock_unlock(&st->host_lock);
570 return status;
571 } /* store_host */
573 static int
574 store_service(sdb_store_service_t *service, sdb_object_t *user_data)
575 {
576 sdb_memstore_t *st = SDB_MEMSTORE(user_data);
577 store_obj_t obj = STORE_OBJ_INIT;
578 host_t *host;
580 int status = 0;
582 if ((! service) || (! service->hostname) || (! service->name))
583 return -1;
585 pthread_rwlock_wrlock(&st->host_lock);
586 host = HOST(sdb_avltree_lookup(st->hosts, service->hostname));
587 obj.parent = STORE_OBJ(host);
588 obj.parent_tree = get_host_children(host, SDB_SERVICE);
589 obj.type = SDB_SERVICE;
590 if (! obj.parent_tree) {
591 sdb_log(SDB_LOG_ERR, "memstore: Failed to store service '%s' - "
592 "host '%s' not found", service->name, service->hostname);
593 status = -1;
594 }
596 obj.name = service->name;
597 obj.last_update = service->last_update;
598 obj.interval = service->interval;
599 obj.backends = service->backends;
600 obj.backends_num = service->backends_num;
601 if (! status)
602 status = store_obj(&obj, NULL);
604 sdb_object_deref(SDB_OBJ(host));
605 pthread_rwlock_unlock(&st->host_lock);
606 return status;
607 } /* store_service */
609 static int
610 store_metric(sdb_store_metric_t *metric, sdb_object_t *user_data)
611 {
612 sdb_memstore_t *st = SDB_MEMSTORE(user_data);
613 store_obj_t obj = STORE_OBJ_INIT;
614 sdb_memstore_obj_t *new = NULL;
615 host_t *host;
617 int status = 0;
619 if ((! metric) || (! metric->hostname) || (! metric->name))
620 return -1;
622 if ((metric->store.type != NULL) != (metric->store.id != NULL))
623 return -1;
625 pthread_rwlock_wrlock(&st->host_lock);
626 host = HOST(sdb_avltree_lookup(st->hosts, metric->hostname));
627 obj.parent = STORE_OBJ(host);
628 obj.parent_tree = get_host_children(host, SDB_METRIC);
629 obj.type = SDB_METRIC;
630 if (! obj.parent_tree) {
631 sdb_log(SDB_LOG_ERR, "memstore: Failed to store metric '%s' - "
632 "host '%s' not found", metric->name, metric->hostname);
633 status = -1;
634 }
636 obj.name = metric->name;
637 obj.last_update = metric->last_update;
638 obj.interval = metric->interval;
639 obj.backends = metric->backends;
640 obj.backends_num = metric->backends_num;
641 if (! status)
642 status = store_obj(&obj, &new);
643 sdb_object_deref(SDB_OBJ(host));
645 if (status) {
646 pthread_rwlock_unlock(&st->host_lock);
647 return status;
648 }
650 assert(new);
651 if (metric->store.type && metric->store.id)
652 if (store_metric_store(METRIC(new), metric))
653 status = -1;
654 pthread_rwlock_unlock(&st->host_lock);
655 return status;
656 } /* store_metric */
658 sdb_store_writer_t sdb_memstore_writer = {
659 store_host, store_service, store_metric, store_attribute,
660 };
662 /*
663 * store query API
664 */
666 static sdb_object_t *
667 prepare_query(sdb_ast_node_t *ast,
668 sdb_strbuf_t __attribute__((unused)) *errbuf,
669 sdb_object_t __attribute__((unused)) *user_data)
670 {
671 return SDB_OBJ(sdb_memstore_query_prepare(ast));
672 } /* prepare_query */
674 static int
675 execute_query(sdb_object_t *q,
676 sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
677 sdb_object_t *user_data)
678 {
679 return sdb_memstore_query_execute(SDB_MEMSTORE(user_data),
680 QUERY(q), w, wd, errbuf);
681 } /* execute_query */
683 sdb_store_reader_t sdb_memstore_reader = {
684 prepare_query, execute_query,
685 };
687 /*
688 * public API
689 */
691 sdb_memstore_t *
692 sdb_memstore_create(void)
693 {
694 return SDB_MEMSTORE(sdb_object_create("memstore", store_type));
695 } /* sdb_memstore_create */
697 int
698 sdb_memstore_host(sdb_memstore_t *store, const char *name,
699 sdb_time_t last_update, sdb_time_t interval)
700 {
701 sdb_store_host_t host = {
702 name, last_update, interval, NULL, 0,
703 };
704 return store_host(&host, SDB_OBJ(store));
705 } /* sdb_memstore_host */
707 int
708 sdb_memstore_service(sdb_memstore_t *store, const char *hostname, const char *name,
709 sdb_time_t last_update, sdb_time_t interval)
710 {
711 sdb_store_service_t service = {
712 hostname, name, last_update, interval, NULL, 0,
713 };
714 return store_service(&service, SDB_OBJ(store));
715 } /* sdb_memstore_service */
717 int
718 sdb_memstore_metric(sdb_memstore_t *store, const char *hostname, const char *name,
719 sdb_metric_store_t *metric_store,
720 sdb_time_t last_update, sdb_time_t interval)
721 {
722 sdb_store_metric_t metric = {
723 hostname, name, { NULL, NULL }, last_update, interval, NULL, 0,
724 };
725 if (metric_store) {
726 metric.store.type = metric_store->type;
727 metric.store.id = metric_store->id;
728 }
729 return store_metric(&metric, SDB_OBJ(store));
730 } /* sdb_memstore_metric */
732 int
733 sdb_memstore_attribute(sdb_memstore_t *store, const char *hostname,
734 const char *key, const sdb_data_t *value,
735 sdb_time_t last_update, sdb_time_t interval)
736 {
737 sdb_store_attribute_t attr = {
738 NULL, SDB_HOST, hostname, key, SDB_DATA_INIT,
739 last_update, interval, NULL, 0,
740 };
741 if (value) {
742 attr.value = *value;
743 }
744 return store_attribute(&attr, SDB_OBJ(store));
745 } /* sdb_memstore_attribute */
747 int
748 sdb_memstore_service_attr(sdb_memstore_t *store, const char *hostname,
749 const char *service, const char *key, const sdb_data_t *value,
750 sdb_time_t last_update, sdb_time_t interval)
751 {
752 sdb_store_attribute_t attr = {
753 hostname, SDB_SERVICE, service, key, SDB_DATA_INIT,
754 last_update, interval, NULL, 0,
755 };
756 if (value) {
757 attr.value = *value;
758 }
759 return store_attribute(&attr, SDB_OBJ(store));
760 } /* sdb_memstore_service_attr */
762 int
763 sdb_memstore_metric_attr(sdb_memstore_t *store, const char *hostname,
764 const char *metric, const char *key, const sdb_data_t *value,
765 sdb_time_t last_update, sdb_time_t interval)
766 {
767 sdb_store_attribute_t attr = {
768 hostname, SDB_METRIC, metric, key, SDB_DATA_INIT,
769 last_update, interval, NULL, 0,
770 };
771 if (value) {
772 attr.value = *value;
773 }
774 return store_attribute(&attr, SDB_OBJ(store));
775 } /* sdb_memstore_metric_attr */
777 sdb_memstore_obj_t *
778 sdb_memstore_get_host(sdb_memstore_t *store, const char *name)
779 {
780 host_t *host;
782 if ((! store) || (! name))
783 return NULL;
785 host = HOST(sdb_avltree_lookup(store->hosts, name));
786 if (! host)
787 return NULL;
789 return STORE_OBJ(host);
790 } /* sdb_memstore_get_host */
792 sdb_memstore_obj_t *
793 sdb_memstore_get_child(sdb_memstore_obj_t *obj, int type, const char *name)
794 {
795 sdb_avltree_t *children = NULL;
797 if ((! obj) || (! name))
798 return NULL;
800 if (type & SDB_ATTRIBUTE)
801 children = get_obj_attrs(obj);
802 else if (obj->type == SDB_HOST)
803 children = get_host_children(HOST(obj), type);
804 if (! children)
805 return NULL;
806 return STORE_OBJ(sdb_avltree_lookup(children, name));
807 } /* sdb_memstore_get_child */
809 int
810 sdb_memstore_get_field(sdb_memstore_obj_t *obj, int field, sdb_data_t *res)
811 {
812 sdb_data_t tmp;
814 if (! obj)
815 return -1;
817 switch (field) {
818 case SDB_FIELD_NAME:
819 tmp.type = SDB_TYPE_STRING;
820 tmp.data.string = strdup(SDB_OBJ(obj)->name);
821 if (! tmp.data.string)
822 return -1;
823 break;
824 case SDB_FIELD_LAST_UPDATE:
825 tmp.type = SDB_TYPE_DATETIME;
826 tmp.data.datetime = obj->last_update;
827 break;
828 case SDB_FIELD_AGE:
829 tmp.type = SDB_TYPE_DATETIME;
830 tmp.data.datetime = sdb_gettime() - obj->last_update;
831 break;
832 case SDB_FIELD_INTERVAL:
833 tmp.type = SDB_TYPE_DATETIME;
834 tmp.data.datetime = obj->interval;
835 break;
836 case SDB_FIELD_BACKEND:
837 if (! res)
838 return 0;
839 tmp.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING;
840 tmp.data.array.length = obj->backends_num;
841 tmp.data.array.values = obj->backends;
842 return sdb_data_copy(res, &tmp);
843 case SDB_FIELD_VALUE:
844 if (obj->type != SDB_ATTRIBUTE)
845 return -1;
846 if (! res)
847 return 0;
848 return sdb_data_copy(res, &ATTR(obj)->value);
849 case SDB_FIELD_TIMESERIES:
850 if (obj->type != SDB_METRIC)
851 return -1;
852 tmp.type = SDB_TYPE_BOOLEAN;
853 tmp.data.boolean = METRIC(obj)->store.type != NULL;
854 default:
855 return -1;
856 }
857 if (res)
858 *res = tmp;
859 else
860 sdb_data_free_datum(&tmp);
861 return 0;
862 } /* sdb_memstore_get_field */
864 int
865 sdb_memstore_get_attr(sdb_memstore_obj_t *obj, const char *name, sdb_data_t *res,
866 sdb_memstore_matcher_t *filter)
867 {
868 sdb_memstore_obj_t *attr;
870 if ((! obj) || (! name))
871 return -1;
873 attr = STORE_OBJ(sdb_avltree_lookup(get_obj_attrs(obj), name));
874 if (! attr)
875 return -1;
876 if (filter && (! sdb_memstore_matcher_matches(filter, attr, NULL))) {
877 sdb_object_deref(SDB_OBJ(attr));
878 return -1;
879 }
881 assert(STORE_OBJ(attr)->type == SDB_ATTRIBUTE);
882 if (res)
883 sdb_data_copy(res, &ATTR(attr)->value);
884 sdb_object_deref(SDB_OBJ(attr));
885 return 0;
886 } /* sdb_memstore_get_attr */
888 int
889 sdb_memstore_scan(sdb_memstore_t *store, int type,
890 sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter,
891 sdb_memstore_lookup_cb cb, void *user_data)
892 {
893 sdb_avltree_iter_t *host_iter = NULL;
894 int status = 0;
896 if ((! store) || (! cb))
897 return -1;
899 if ((type != SDB_HOST) && (type != SDB_SERVICE) && (type != SDB_METRIC)) {
900 sdb_log(SDB_LOG_ERR, "memstore: Cannot scan objects of type %d", type);
901 return -1;
902 }
904 pthread_rwlock_rdlock(&store->host_lock);
905 host_iter = sdb_avltree_get_iter(store->hosts);
906 if (! host_iter)
907 status = -1;
909 /* has_next returns false if the iterator is NULL */
910 while (sdb_avltree_iter_has_next(host_iter)) {
911 sdb_memstore_obj_t *host;
912 sdb_avltree_iter_t *iter = NULL;
914 host = STORE_OBJ(sdb_avltree_iter_get_next(host_iter));
915 assert(host);
917 if (! sdb_memstore_matcher_matches(filter, host, NULL))
918 continue;
920 if (type == SDB_SERVICE)
921 iter = sdb_avltree_get_iter(HOST(host)->services);
922 else if (type == SDB_METRIC)
923 iter = sdb_avltree_get_iter(HOST(host)->metrics);
925 if (iter) {
926 while (sdb_avltree_iter_has_next(iter)) {
927 sdb_memstore_obj_t *obj;
928 obj = STORE_OBJ(sdb_avltree_iter_get_next(iter));
929 assert(obj);
931 if (sdb_memstore_matcher_matches(m, obj, filter)) {
932 if (cb(obj, filter, user_data)) {
933 sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
934 "an error while scanning");
935 status = -1;
936 break;
937 }
938 }
939 }
940 }
941 else if (sdb_memstore_matcher_matches(m, host, filter)) {
942 if (cb(host, filter, user_data)) {
943 sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
944 "an error while scanning");
945 status = -1;
946 }
947 }
949 sdb_avltree_iter_destroy(iter);
950 if (status)
951 break;
952 }
954 sdb_avltree_iter_destroy(host_iter);
955 pthread_rwlock_unlock(&store->host_lock);
956 return status;
957 } /* sdb_memstore_scan */
959 int
960 sdb_memstore_emit(sdb_memstore_obj_t *obj, sdb_store_writer_t *w, sdb_object_t *wd)
961 {
962 if ((! obj) || (! w))
963 return -1;
965 switch (obj->type) {
966 case SDB_HOST:
967 {
968 sdb_store_host_t host = {
969 obj->_name,
970 obj->last_update,
971 obj->interval,
972 (const char * const *)obj->backends,
973 obj->backends_num,
974 };
975 if (! w->store_host)
976 return -1;
977 return w->store_host(&host, wd);
978 }
979 case SDB_SERVICE:
980 {
981 sdb_store_service_t service = {
982 obj->parent ? obj->parent->_name : NULL,
983 obj->_name,
984 obj->last_update,
985 obj->interval,
986 (const char * const *)obj->backends,
987 obj->backends_num,
988 };
989 if (! w->store_service)
990 return -1;
991 return w->store_service(&service, wd);
992 }
993 case SDB_METRIC:
994 {
995 sdb_store_metric_t metric = {
996 obj->parent ? obj->parent->_name : NULL,
997 obj->_name,
998 {
999 METRIC(obj)->store.type,
1000 METRIC(obj)->store.id,
1001 },
1002 obj->last_update,
1003 obj->interval,
1004 (const char * const *)obj->backends,
1005 obj->backends_num,
1006 };
1007 if (! w->store_metric)
1008 return -1;
1009 return w->store_metric(&metric, wd);
1010 }
1011 case SDB_ATTRIBUTE:
1012 {
1013 sdb_store_attribute_t attr = {
1014 NULL,
1015 obj->parent ? obj->parent->type : 0,
1016 obj->parent ? obj->parent->_name : NULL,
1017 obj->_name,
1018 ATTR(obj)->value,
1019 obj->last_update,
1020 obj->interval,
1021 (const char * const *)obj->backends,
1022 obj->backends_num,
1023 };
1024 if (obj->parent && (obj->parent->type != SDB_HOST)
1025 && obj->parent->parent)
1026 attr.hostname = obj->parent->parent->_name;
1027 if (! w->store_attribute)
1028 return -1;
1029 return w->store_attribute(&attr, wd);
1030 }
1031 }
1033 return -1;
1034 } /* sdb_memstore_emit */
1036 int
1037 sdb_memstore_emit_full(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter,
1038 sdb_store_writer_t *w, sdb_object_t *wd)
1039 {
1040 sdb_avltree_t *trees[] = { NULL, NULL, NULL };
1041 size_t i;
1043 if (sdb_memstore_emit(obj, w, wd))
1044 return -1;
1046 if (obj->type == SDB_HOST) {
1047 trees[0] = HOST(obj)->attributes;
1048 trees[1] = HOST(obj)->metrics;
1049 trees[2] = HOST(obj)->services;
1050 }
1051 else if (obj->type == SDB_SERVICE)
1052 trees[0] = SVC(obj)->attributes;
1053 else if (obj->type == SDB_METRIC)
1054 trees[0] = METRIC(obj)->attributes;
1055 else if (obj->type == SDB_ATTRIBUTE)
1056 return 0;
1057 else
1058 return -1;
1060 for (i = 0; i < SDB_STATIC_ARRAY_LEN(trees); ++i) {
1061 sdb_avltree_iter_t *iter;
1063 if (! trees[i])
1064 continue;
1066 iter = sdb_avltree_get_iter(trees[i]);
1067 while (sdb_avltree_iter_has_next(iter)) {
1068 sdb_memstore_obj_t *child;
1069 child = STORE_OBJ(sdb_avltree_iter_get_next(iter));
1071 if (filter && (! sdb_memstore_matcher_matches(filter, child, NULL)))
1072 continue;
1074 if (sdb_memstore_emit_full(child, filter, w, wd)) {
1075 sdb_avltree_iter_destroy(iter);
1076 return -1;
1077 }
1078 }
1079 sdb_avltree_iter_destroy(iter);
1080 }
1081 return 0;
1082 } /* sdb_memstore_emit_full */
1084 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */