15c4202829159eee3665b74f7d1654b010d8b602
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 const char * const *backends;
69 size_t backends_num;
70 } store_obj_t;
71 #define STORE_OBJ_INIT { NULL, NULL, 0, NULL, 0, NULL, 0 }
73 static sdb_type_t host_type;
74 static sdb_type_t service_type;
75 static sdb_type_t metric_type;
76 static sdb_type_t attribute_type;
78 static int
79 store_init(sdb_object_t *obj, va_list __attribute__((unused)) ap)
80 {
81 int err;
82 if (! (SDB_MEMSTORE(obj)->hosts = sdb_avltree_create()))
83 return -1;
84 if ((err = pthread_rwlock_init(&SDB_MEMSTORE(obj)->host_lock,
85 /* attr = */ NULL))) {
86 char errbuf[128];
87 sdb_log(SDB_LOG_ERR, "memstore: Failed to initialize lock: %s",
88 sdb_strerror(err, errbuf, sizeof(errbuf)));
89 return -1;
90 }
91 return 0;
92 } /* store_init */
94 static void
95 store_destroy(sdb_object_t *obj)
96 {
97 int err;
98 if ((err = pthread_rwlock_destroy(&SDB_MEMSTORE(obj)->host_lock))) {
99 char errbuf[128];
100 sdb_log(SDB_LOG_ERR, "memstore: Failed to destroy lock: %s",
101 sdb_strerror(err, errbuf, sizeof(errbuf)));
102 return;
103 }
104 sdb_avltree_destroy(SDB_MEMSTORE(obj)->hosts);
105 SDB_MEMSTORE(obj)->hosts = NULL;
106 } /* store_destroy */
108 static int
109 store_obj_init(sdb_object_t *obj, va_list ap)
110 {
111 sdb_memstore_obj_t *sobj = STORE_OBJ(obj);
113 sobj->type = va_arg(ap, int);
115 sobj->last_update = va_arg(ap, sdb_time_t);
116 sobj->interval = 0;
117 sobj->backends = NULL;
118 sobj->backends_num = 0;
119 sobj->parent = NULL;
120 return 0;
121 } /* store_obj_init */
123 static void
124 store_obj_destroy(sdb_object_t *obj)
125 {
126 sdb_memstore_obj_t *sobj = STORE_OBJ(obj);
127 size_t i;
129 for (i = 0; i < sobj->backends_num; ++i)
130 free(sobj->backends[i]);
131 free(sobj->backends);
132 sobj->backends = NULL;
133 sobj->backends_num = 0;
135 // We don't currently keep an extra reference for parent objects to
136 // avoid circular self-references which are not handled correctly by
137 // the ref-count base management layer.
138 //sdb_object_deref(SDB_OBJ(sobj->parent));
139 } /* store_obj_destroy */
141 static int
142 host_init(sdb_object_t *obj, va_list ap)
143 {
144 host_t *sobj = HOST(obj);
145 int ret;
147 /* this will consume the first argument (type) of ap */
148 ret = store_obj_init(obj, ap);
149 if (ret)
150 return ret;
152 sobj->services = sdb_avltree_create();
153 if (! sobj->services)
154 return -1;
155 sobj->metrics = sdb_avltree_create();
156 if (! sobj->metrics)
157 return -1;
158 sobj->attributes = sdb_avltree_create();
159 if (! sobj->attributes)
160 return -1;
161 return 0;
162 } /* host_init */
164 static void
165 host_destroy(sdb_object_t *obj)
166 {
167 host_t *sobj = HOST(obj);
168 assert(obj);
170 store_obj_destroy(obj);
172 if (sobj->services)
173 sdb_avltree_destroy(sobj->services);
174 if (sobj->metrics)
175 sdb_avltree_destroy(sobj->metrics);
176 if (sobj->attributes)
177 sdb_avltree_destroy(sobj->attributes);
178 } /* host_destroy */
180 static int
181 service_init(sdb_object_t *obj, va_list ap)
182 {
183 service_t *sobj = SVC(obj);
184 int ret;
186 /* this will consume the first argument (type) of ap */
187 ret = store_obj_init(obj, ap);
188 if (ret)
189 return ret;
191 sobj->attributes = sdb_avltree_create();
192 if (! sobj->attributes)
193 return -1;
194 return 0;
195 } /* service_init */
197 static void
198 service_destroy(sdb_object_t *obj)
199 {
200 service_t *sobj = SVC(obj);
201 assert(obj);
203 store_obj_destroy(obj);
205 if (sobj->attributes)
206 sdb_avltree_destroy(sobj->attributes);
207 } /* service_destroy */
209 static int
210 metric_init(sdb_object_t *obj, va_list ap)
211 {
212 metric_t *sobj = METRIC(obj);
213 int ret;
215 /* this will consume the first argument (type) of ap */
216 ret = store_obj_init(obj, ap);
217 if (ret)
218 return ret;
220 sobj->attributes = sdb_avltree_create();
221 if (! sobj->attributes)
222 return -1;
224 sobj->store.type = sobj->store.id = NULL;
225 return 0;
226 } /* metric_init */
228 static void
229 metric_destroy(sdb_object_t *obj)
230 {
231 metric_t *sobj = METRIC(obj);
232 assert(obj);
234 store_obj_destroy(obj);
236 if (sobj->attributes)
237 sdb_avltree_destroy(sobj->attributes);
239 if (sobj->store.type)
240 free(sobj->store.type);
241 if (sobj->store.id)
242 free(sobj->store.id);
243 } /* metric_destroy */
245 static int
246 attr_init(sdb_object_t *obj, va_list ap)
247 {
248 const sdb_data_t *value;
249 int ret;
251 /* this will consume the first two arguments
252 * (type and last_update) of ap */
253 ret = store_obj_init(obj, ap);
254 if (ret)
255 return ret;
256 value = va_arg(ap, const sdb_data_t *);
258 if (value)
259 if (sdb_data_copy(&ATTR(obj)->value, value))
260 return -1;
261 return 0;
262 } /* attr_init */
264 static void
265 attr_destroy(sdb_object_t *obj)
266 {
267 assert(obj);
269 store_obj_destroy(obj);
270 sdb_data_free_datum(&ATTR(obj)->value);
271 } /* attr_destroy */
273 static sdb_type_t store_type = {
274 /* size = */ sizeof(sdb_memstore_t),
275 /* init = */ store_init,
276 /* destroy = */ store_destroy,
277 };
279 static sdb_type_t host_type = {
280 /* size = */ sizeof(host_t),
281 /* init = */ host_init,
282 /* destroy = */ host_destroy
283 };
285 static sdb_type_t service_type = {
286 /* size = */ sizeof(service_t),
287 /* init = */ service_init,
288 /* destroy = */ service_destroy
289 };
291 static sdb_type_t metric_type = {
292 /* size = */ sizeof(metric_t),
293 /* init = */ metric_init,
294 /* destroy = */ metric_destroy
295 };
297 static sdb_type_t attribute_type = {
298 /* size = */ sizeof(attr_t),
299 /* init = */ attr_init,
300 /* destroy = */ attr_destroy
301 };
303 /*
304 * private helper functions
305 */
307 static int
308 record_backends(sdb_memstore_obj_t *obj,
309 const char * const *backends, size_t backends_num)
310 {
311 char **tmp;
312 size_t i;
314 for (i = 0; i < backends_num; i++) {
315 bool found = 0;
316 size_t j;
318 for (j = 0; j < obj->backends_num; ++j) {
319 if (!strcasecmp(obj->backends[j], backends[i])) {
320 found = 1;
321 break;
322 }
323 }
324 if (found)
325 continue;
327 tmp = realloc(obj->backends,
328 (obj->backends_num + 1) * sizeof(*obj->backends));
329 if (! tmp)
330 return -1;
332 obj->backends = tmp;
333 obj->backends[obj->backends_num] = strdup(backends[i]);
334 if (! obj->backends[obj->backends_num])
335 return -1;
337 ++obj->backends_num;
338 }
339 return 0;
340 } /* record_backends */
342 static int
343 store_obj(store_obj_t *obj, sdb_memstore_obj_t **updated_obj)
344 {
345 sdb_memstore_obj_t *old, *new;
346 int status = 0;
348 assert(obj->parent_tree);
350 if (obj->last_update <= 0)
351 obj->last_update = sdb_gettime();
353 old = STORE_OBJ(sdb_avltree_lookup(obj->parent_tree, obj->name));
354 if (old) {
355 if (old->last_update > obj->last_update) {
356 sdb_log(SDB_LOG_DEBUG, "memstore: Cannot update %s '%s' - "
357 "value too old (%"PRIsdbTIME" < %"PRIsdbTIME")",
358 SDB_STORE_TYPE_TO_NAME(obj->type), obj->name,
359 obj->last_update, old->last_update);
360 /* don't report an error; the object may be updated by multiple
361 * backends */
362 status = 1;
363 }
364 else if (old->last_update == obj->last_update) {
365 /* don't report an error and also don't even log this to avoid
366 * excessive noise on high sampling frequencies */
367 status = 1;
368 }
369 else {
370 sdb_time_t interval = obj->last_update - old->last_update;
371 old->last_update = obj->last_update;
372 if (interval) {
373 if (old->interval)
374 old->interval = (sdb_time_t)((0.9 * (double)old->interval)
375 + (0.1 * (double)interval));
376 else
377 old->interval = interval;
378 }
379 }
381 new = old;
382 sdb_object_deref(SDB_OBJ(old));
383 }
384 else {
385 if (obj->type == SDB_ATTRIBUTE) {
386 /* the value will be updated by the caller */
387 new = STORE_OBJ(sdb_object_create(obj->name, attribute_type,
388 obj->type, obj->last_update, NULL));
389 }
390 else {
391 sdb_type_t t;
392 t = obj->type == SDB_HOST
393 ? host_type
394 : obj->type == SDB_SERVICE
395 ? service_type
396 : metric_type;
397 new = STORE_OBJ(sdb_object_create(obj->name, t,
398 obj->type, obj->last_update));
399 }
401 if (new) {
402 status = sdb_avltree_insert(obj->parent_tree, SDB_OBJ(new));
404 /* pass control to the tree or destroy in case of an error */
405 sdb_object_deref(SDB_OBJ(new));
406 }
407 else {
408 char errbuf[1024];
409 sdb_log(SDB_LOG_ERR, "memstore: Failed to create %s '%s': %s",
410 SDB_STORE_TYPE_TO_NAME(obj->type), obj->name,
411 sdb_strerror(errno, errbuf, sizeof(errbuf)));
412 status = -1;
413 }
414 }
416 if (status < 0)
417 return status;
418 assert(new);
420 if (new->parent != obj->parent) {
421 // Avoid circular self-references which are not handled
422 // correctly by the ref-count based management layer.
423 //sdb_object_deref(SDB_OBJ(new->parent));
424 //sdb_object_ref(SDB_OBJ(obj->parent));
425 new->parent = obj->parent;
426 }
428 if (updated_obj)
429 *updated_obj = new;
431 if (record_backends(new, obj->backends, obj->backends_num))
432 return -1;
433 return status;
434 } /* store_obj */
436 static int
437 store_metric_store(metric_t *metric, sdb_store_metric_t *m)
438 {
439 char *type = metric->store.type;
440 char *id = metric->store.id;
442 if ((! metric->store.type) || strcasecmp(metric->store.type, m->store.type)) {
443 if (! (type = strdup(m->store.type)))
444 return -1;
445 }
446 if ((! metric->store.id) || strcasecmp(metric->store.id, m->store.id)) {
447 if (! (id = strdup(m->store.id))) {
448 if (type != metric->store.type)
449 free(type);
450 return -1;
451 }
452 }
454 if (type != metric->store.type) {
455 if (metric->store.type)
456 free(metric->store.type);
457 metric->store.type = type;
458 }
459 if (id != metric->store.id) {
460 if (metric->store.id)
461 free(metric->store.id);
462 metric->store.id = id;
463 }
464 return 0;
465 } /* store_metric_store */
467 /* The store's host_lock has to be acquired before calling this function. */
468 static sdb_avltree_t *
469 get_host_children(host_t *host, int type)
470 {
471 if ((type != SDB_SERVICE) && (type != SDB_METRIC)
472 && (type != SDB_ATTRIBUTE))
473 return NULL;
475 if (! host)
476 return NULL;
478 if (type == SDB_ATTRIBUTE)
479 return host->attributes;
480 else if (type == SDB_METRIC)
481 return host->metrics;
482 else
483 return host->services;
484 } /* get_host_children */
486 static sdb_avltree_t *
487 get_obj_attrs(sdb_memstore_obj_t *obj)
488 {
489 if (obj->type == SDB_HOST)
490 return HOST(obj)->attributes;
491 else if (obj->type == SDB_SERVICE)
492 return SVC(obj)->attributes;
493 else if (obj->type == SDB_METRIC)
494 return METRIC(obj)->attributes;
495 return NULL;
496 } /* get_obj_attrs */
498 /*
499 * store writer API
500 */
502 static int
503 store_attribute(sdb_store_attribute_t *attr, sdb_object_t *user_data)
504 {
505 sdb_memstore_t *st = SDB_MEMSTORE(user_data);
506 store_obj_t obj = STORE_OBJ_INIT;
507 sdb_memstore_obj_t *new = NULL;
508 const char *hostname;
509 host_t *host;
511 sdb_avltree_t *children = NULL;
512 int status = 0;
514 if ((! attr) || (! attr->parent) || (! attr->key))
515 return -1;
517 hostname = attr->hostname;
518 if (attr->parent_type == SDB_HOST)
519 hostname = attr->parent;
520 if (! hostname)
521 return -1;
523 pthread_rwlock_wrlock(&st->host_lock);
524 host = HOST(sdb_avltree_lookup(st->hosts, hostname));
525 if (! host) {
526 sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - "
527 "host '%s' not found", attr->key, hostname);
528 status = -1;
529 }
531 switch (attr->parent_type) {
532 case SDB_HOST:
533 obj.parent = STORE_OBJ(host);
534 obj.parent_tree = get_host_children(host, SDB_ATTRIBUTE);
535 break;
536 case SDB_SERVICE:
537 case SDB_METRIC:
538 children = get_host_children(host, attr->parent_type);
539 break;
540 default:
541 status = -1;
542 break;
543 }
545 if (children) {
546 obj.parent = STORE_OBJ(sdb_avltree_lookup(children, attr->parent));
547 if (! obj.parent) {
548 sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - "
549 "%s '%s/%s' not found", attr->key,
550 SDB_STORE_TYPE_TO_NAME(attr->parent_type),
551 attr->hostname, attr->parent);
552 status = -1;
553 }
554 else
555 obj.parent_tree = attr->parent_type == SDB_SERVICE
556 ? SVC(obj.parent)->attributes
557 : METRIC(obj.parent)->attributes;
558 }
560 obj.type = SDB_ATTRIBUTE;
561 obj.name = attr->key;
562 obj.last_update = attr->last_update;
563 obj.backends = attr->backends;
564 obj.backends_num = attr->backends_num;
565 if (! status)
566 status = store_obj(&obj, &new);
568 if (! status) {
569 assert(new);
570 /* update the value if it changed */
571 if (sdb_data_cmp(&ATTR(new)->value, &attr->value))
572 if (sdb_data_copy(&ATTR(new)->value, &attr->value))
573 status = -1;
574 }
576 if (obj.parent != STORE_OBJ(host))
577 sdb_object_deref(SDB_OBJ(obj.parent));
578 sdb_object_deref(SDB_OBJ(host));
579 pthread_rwlock_unlock(&st->host_lock);
581 return status;
582 } /* store_attribute */
584 static int
585 store_host(sdb_store_host_t *host, sdb_object_t *user_data)
586 {
587 sdb_memstore_t *st = SDB_MEMSTORE(user_data);
588 store_obj_t obj = { NULL, st->hosts, SDB_HOST, NULL, 0, NULL, 0 };
589 int status = 0;
591 if ((! host) || (! host->name))
592 return -1;
594 obj.name = host->name;
595 obj.last_update = host->last_update;
596 obj.backends = host->backends;
597 obj.backends_num = host->backends_num;
598 pthread_rwlock_wrlock(&st->host_lock);
599 status = store_obj(&obj, NULL);
600 pthread_rwlock_unlock(&st->host_lock);
602 return status;
603 } /* store_host */
605 static int
606 store_service(sdb_store_service_t *service, sdb_object_t *user_data)
607 {
608 sdb_memstore_t *st = SDB_MEMSTORE(user_data);
609 store_obj_t obj = STORE_OBJ_INIT;
610 host_t *host;
612 int status = 0;
614 if ((! service) || (! service->hostname) || (! service->name))
615 return -1;
617 pthread_rwlock_wrlock(&st->host_lock);
618 host = HOST(sdb_avltree_lookup(st->hosts, service->hostname));
619 obj.parent = STORE_OBJ(host);
620 obj.parent_tree = get_host_children(host, SDB_SERVICE);
621 obj.type = SDB_SERVICE;
622 if (! obj.parent_tree) {
623 sdb_log(SDB_LOG_ERR, "memstore: Failed to store service '%s' - "
624 "host '%s' not found", service->name, service->hostname);
625 status = -1;
626 }
628 obj.name = service->name;
629 obj.last_update = service->last_update;
630 obj.backends = service->backends;
631 obj.backends_num = service->backends_num;
632 if (! status)
633 status = store_obj(&obj, NULL);
635 sdb_object_deref(SDB_OBJ(host));
636 pthread_rwlock_unlock(&st->host_lock);
637 return status;
638 } /* store_service */
640 static int
641 store_metric(sdb_store_metric_t *metric, sdb_object_t *user_data)
642 {
643 sdb_memstore_t *st = SDB_MEMSTORE(user_data);
644 store_obj_t obj = STORE_OBJ_INIT;
645 sdb_memstore_obj_t *new = NULL;
646 host_t *host;
648 int status = 0;
650 if ((! metric) || (! metric->hostname) || (! metric->name))
651 return -1;
653 if ((metric->store.type != NULL) != (metric->store.id != NULL))
654 return -1;
656 pthread_rwlock_wrlock(&st->host_lock);
657 host = HOST(sdb_avltree_lookup(st->hosts, metric->hostname));
658 obj.parent = STORE_OBJ(host);
659 obj.parent_tree = get_host_children(host, SDB_METRIC);
660 obj.type = SDB_METRIC;
661 if (! obj.parent_tree) {
662 sdb_log(SDB_LOG_ERR, "memstore: Failed to store metric '%s' - "
663 "host '%s' not found", metric->name, metric->hostname);
664 status = -1;
665 }
667 obj.name = metric->name;
668 obj.last_update = metric->last_update;
669 obj.backends = metric->backends;
670 obj.backends_num = metric->backends_num;
671 if (! status)
672 status = store_obj(&obj, &new);
673 sdb_object_deref(SDB_OBJ(host));
675 if (status) {
676 pthread_rwlock_unlock(&st->host_lock);
677 return status;
678 }
680 assert(new);
681 if (metric->store.type && metric->store.id)
682 if (store_metric_store(METRIC(new), metric))
683 status = -1;
684 pthread_rwlock_unlock(&st->host_lock);
685 return status;
686 } /* store_metric */
688 sdb_store_writer_t sdb_memstore_writer = {
689 store_host, store_service, store_metric, store_attribute,
690 };
692 /*
693 * store query API
694 */
696 static sdb_object_t *
697 prepare_query(sdb_ast_node_t *ast,
698 sdb_strbuf_t __attribute__((unused)) *errbuf,
699 sdb_object_t __attribute__((unused)) *user_data)
700 {
701 return SDB_OBJ(sdb_memstore_query_prepare(ast));
702 } /* prepare_query */
704 static int
705 execute_query(sdb_object_t *q,
706 sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
707 sdb_object_t *user_data)
708 {
709 return sdb_memstore_query_execute(SDB_MEMSTORE(user_data),
710 QUERY(q), w, wd, errbuf);
711 } /* execute_query */
713 sdb_store_reader_t sdb_memstore_reader = {
714 prepare_query, execute_query,
715 };
717 /*
718 * public API
719 */
721 sdb_memstore_t *
722 sdb_memstore_create(void)
723 {
724 return SDB_MEMSTORE(sdb_object_create("memstore", store_type));
725 } /* sdb_memstore_create */
727 int
728 sdb_memstore_host(sdb_memstore_t *store, const char *name, sdb_time_t last_update)
729 {
730 sdb_store_host_t host = {
731 name, last_update, 0, NULL, 0,
732 };
733 return store_host(&host, SDB_OBJ(store));
734 } /* sdb_memstore_host */
736 int
737 sdb_memstore_service(sdb_memstore_t *store, const char *hostname, const char *name,
738 sdb_time_t last_update)
739 {
740 sdb_store_service_t service = {
741 hostname, name, last_update, 0, NULL, 0,
742 };
743 return store_service(&service, SDB_OBJ(store));
744 } /* sdb_memstore_service */
746 int
747 sdb_memstore_metric(sdb_memstore_t *store, const char *hostname, const char *name,
748 sdb_metric_store_t *metric_store, sdb_time_t last_update)
749 {
750 sdb_store_metric_t metric = {
751 hostname, name, { NULL, NULL }, last_update, 0, NULL, 0,
752 };
753 if (metric_store) {
754 metric.store.type = metric_store->type;
755 metric.store.id = metric_store->id;
756 }
757 return store_metric(&metric, SDB_OBJ(store));
758 } /* sdb_memstore_metric */
760 int
761 sdb_memstore_attribute(sdb_memstore_t *store, const char *hostname,
762 const char *key, const sdb_data_t *value, sdb_time_t last_update)
763 {
764 sdb_store_attribute_t attr = {
765 NULL, SDB_HOST, hostname, key, SDB_DATA_INIT, last_update, 0, NULL, 0,
766 };
767 if (value) {
768 attr.value = *value;
769 }
770 return store_attribute(&attr, SDB_OBJ(store));
771 } /* sdb_memstore_attribute */
773 int
774 sdb_memstore_service_attr(sdb_memstore_t *store, const char *hostname,
775 const char *service, const char *key, const sdb_data_t *value,
776 sdb_time_t last_update)
777 {
778 sdb_store_attribute_t attr = {
779 hostname, SDB_SERVICE, service, key, SDB_DATA_INIT, last_update, 0, NULL, 0,
780 };
781 if (value) {
782 attr.value = *value;
783 }
784 return store_attribute(&attr, SDB_OBJ(store));
785 } /* sdb_memstore_service_attr */
787 int
788 sdb_memstore_metric_attr(sdb_memstore_t *store, const char *hostname,
789 const char *metric, const char *key, const sdb_data_t *value,
790 sdb_time_t last_update)
791 {
792 sdb_store_attribute_t attr = {
793 hostname, SDB_METRIC, metric, key, SDB_DATA_INIT, last_update, 0, NULL, 0,
794 };
795 if (value) {
796 attr.value = *value;
797 }
798 return store_attribute(&attr, SDB_OBJ(store));
799 } /* sdb_memstore_metric_attr */
801 sdb_memstore_obj_t *
802 sdb_memstore_get_host(sdb_memstore_t *store, const char *name)
803 {
804 host_t *host;
806 if ((! store) || (! name))
807 return NULL;
809 host = HOST(sdb_avltree_lookup(store->hosts, name));
810 if (! host)
811 return NULL;
813 return STORE_OBJ(host);
814 } /* sdb_memstore_get_host */
816 sdb_memstore_obj_t *
817 sdb_memstore_get_child(sdb_memstore_obj_t *obj, int type, const char *name)
818 {
819 sdb_avltree_t *children = NULL;
821 if ((! obj) || (! name))
822 return NULL;
824 if (type & SDB_ATTRIBUTE)
825 children = get_obj_attrs(obj);
826 else if (obj->type == SDB_HOST)
827 children = get_host_children(HOST(obj), type);
828 if (! children)
829 return NULL;
830 return STORE_OBJ(sdb_avltree_lookup(children, name));
831 } /* sdb_memstore_get_child */
833 int
834 sdb_memstore_get_field(sdb_memstore_obj_t *obj, int field, sdb_data_t *res)
835 {
836 sdb_data_t tmp;
838 if (! obj)
839 return -1;
841 switch (field) {
842 case SDB_FIELD_NAME:
843 tmp.type = SDB_TYPE_STRING;
844 tmp.data.string = strdup(SDB_OBJ(obj)->name);
845 if (! tmp.data.string)
846 return -1;
847 break;
848 case SDB_FIELD_LAST_UPDATE:
849 tmp.type = SDB_TYPE_DATETIME;
850 tmp.data.datetime = obj->last_update;
851 break;
852 case SDB_FIELD_AGE:
853 tmp.type = SDB_TYPE_DATETIME;
854 tmp.data.datetime = sdb_gettime() - obj->last_update;
855 break;
856 case SDB_FIELD_INTERVAL:
857 tmp.type = SDB_TYPE_DATETIME;
858 tmp.data.datetime = obj->interval;
859 break;
860 case SDB_FIELD_BACKEND:
861 if (! res)
862 return 0;
863 tmp.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING;
864 tmp.data.array.length = obj->backends_num;
865 tmp.data.array.values = obj->backends;
866 return sdb_data_copy(res, &tmp);
867 case SDB_FIELD_VALUE:
868 if (obj->type != SDB_ATTRIBUTE)
869 return -1;
870 if (! res)
871 return 0;
872 return sdb_data_copy(res, &ATTR(obj)->value);
873 case SDB_FIELD_TIMESERIES:
874 if (obj->type != SDB_METRIC)
875 return -1;
876 tmp.type = SDB_TYPE_BOOLEAN;
877 tmp.data.boolean = METRIC(obj)->store.type != NULL;
878 default:
879 return -1;
880 }
881 if (res)
882 *res = tmp;
883 else
884 sdb_data_free_datum(&tmp);
885 return 0;
886 } /* sdb_memstore_get_field */
888 int
889 sdb_memstore_get_attr(sdb_memstore_obj_t *obj, const char *name, sdb_data_t *res,
890 sdb_memstore_matcher_t *filter)
891 {
892 sdb_memstore_obj_t *attr;
894 if ((! obj) || (! name))
895 return -1;
897 attr = STORE_OBJ(sdb_avltree_lookup(get_obj_attrs(obj), name));
898 if (! attr)
899 return -1;
900 if (filter && (! sdb_memstore_matcher_matches(filter, attr, NULL))) {
901 sdb_object_deref(SDB_OBJ(attr));
902 return -1;
903 }
905 assert(STORE_OBJ(attr)->type == SDB_ATTRIBUTE);
906 if (res)
907 sdb_data_copy(res, &ATTR(attr)->value);
908 sdb_object_deref(SDB_OBJ(attr));
909 return 0;
910 } /* sdb_memstore_get_attr */
912 int
913 sdb_memstore_scan(sdb_memstore_t *store, int type,
914 sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter,
915 sdb_memstore_lookup_cb cb, void *user_data)
916 {
917 sdb_avltree_iter_t *host_iter = NULL;
918 int status = 0;
920 if ((! store) || (! cb))
921 return -1;
923 if ((type != SDB_HOST) && (type != SDB_SERVICE) && (type != SDB_METRIC)) {
924 sdb_log(SDB_LOG_ERR, "memstore: Cannot scan objects of type %d", type);
925 return -1;
926 }
928 pthread_rwlock_rdlock(&store->host_lock);
929 host_iter = sdb_avltree_get_iter(store->hosts);
930 if (! host_iter)
931 status = -1;
933 /* has_next returns false if the iterator is NULL */
934 while (sdb_avltree_iter_has_next(host_iter)) {
935 sdb_memstore_obj_t *host;
936 sdb_avltree_iter_t *iter = NULL;
938 host = STORE_OBJ(sdb_avltree_iter_get_next(host_iter));
939 assert(host);
941 if (! sdb_memstore_matcher_matches(filter, host, NULL))
942 continue;
944 if (type == SDB_SERVICE)
945 iter = sdb_avltree_get_iter(HOST(host)->services);
946 else if (type == SDB_METRIC)
947 iter = sdb_avltree_get_iter(HOST(host)->metrics);
949 if (iter) {
950 while (sdb_avltree_iter_has_next(iter)) {
951 sdb_memstore_obj_t *obj;
952 obj = STORE_OBJ(sdb_avltree_iter_get_next(iter));
953 assert(obj);
955 if (sdb_memstore_matcher_matches(m, obj, filter)) {
956 if (cb(obj, filter, user_data)) {
957 sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
958 "an error while scanning");
959 status = -1;
960 break;
961 }
962 }
963 }
964 }
965 else if (sdb_memstore_matcher_matches(m, host, filter)) {
966 if (cb(host, filter, user_data)) {
967 sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
968 "an error while scanning");
969 status = -1;
970 }
971 }
973 sdb_avltree_iter_destroy(iter);
974 if (status)
975 break;
976 }
978 sdb_avltree_iter_destroy(host_iter);
979 pthread_rwlock_unlock(&store->host_lock);
980 return status;
981 } /* sdb_memstore_scan */
983 int
984 sdb_memstore_emit(sdb_memstore_obj_t *obj, sdb_store_writer_t *w, sdb_object_t *wd)
985 {
986 if ((! obj) || (! w))
987 return -1;
989 switch (obj->type) {
990 case SDB_HOST:
991 {
992 sdb_store_host_t host = {
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_host)
1000 return -1;
1001 return w->store_host(&host, wd);
1002 }
1003 case SDB_SERVICE:
1004 {
1005 sdb_store_service_t service = {
1006 obj->parent ? obj->parent->_name : NULL,
1007 obj->_name,
1008 obj->last_update,
1009 obj->interval,
1010 (const char * const *)obj->backends,
1011 obj->backends_num,
1012 };
1013 if (! w->store_service)
1014 return -1;
1015 return w->store_service(&service, wd);
1016 }
1017 case SDB_METRIC:
1018 {
1019 sdb_store_metric_t metric = {
1020 obj->parent ? obj->parent->_name : NULL,
1021 obj->_name,
1022 {
1023 METRIC(obj)->store.type,
1024 METRIC(obj)->store.id,
1025 },
1026 obj->last_update,
1027 obj->interval,
1028 (const char * const *)obj->backends,
1029 obj->backends_num,
1030 };
1031 if (! w->store_metric)
1032 return -1;
1033 return w->store_metric(&metric, wd);
1034 }
1035 case SDB_ATTRIBUTE:
1036 {
1037 sdb_store_attribute_t attr = {
1038 NULL,
1039 obj->parent ? obj->parent->type : 0,
1040 obj->parent ? obj->parent->_name : NULL,
1041 obj->_name,
1042 ATTR(obj)->value,
1043 obj->last_update,
1044 obj->interval,
1045 (const char * const *)obj->backends,
1046 obj->backends_num,
1047 };
1048 if (obj->parent && (obj->parent->type != SDB_HOST)
1049 && obj->parent->parent)
1050 attr.hostname = obj->parent->parent->_name;
1051 if (! w->store_attribute)
1052 return -1;
1053 return w->store_attribute(&attr, wd);
1054 }
1055 }
1057 return -1;
1058 } /* sdb_memstore_emit */
1060 int
1061 sdb_memstore_emit_full(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter,
1062 sdb_store_writer_t *w, sdb_object_t *wd)
1063 {
1064 sdb_avltree_t *trees[] = { NULL, NULL, NULL };
1065 size_t i;
1067 if (sdb_memstore_emit(obj, w, wd))
1068 return -1;
1070 if (obj->type == SDB_HOST) {
1071 trees[0] = HOST(obj)->attributes;
1072 trees[1] = HOST(obj)->metrics;
1073 trees[2] = HOST(obj)->services;
1074 }
1075 else if (obj->type == SDB_SERVICE)
1076 trees[0] = SVC(obj)->attributes;
1077 else if (obj->type == SDB_METRIC)
1078 trees[0] = METRIC(obj)->attributes;
1079 else if (obj->type == SDB_ATTRIBUTE)
1080 return 0;
1081 else
1082 return -1;
1084 for (i = 0; i < SDB_STATIC_ARRAY_LEN(trees); ++i) {
1085 sdb_avltree_iter_t *iter;
1087 if (! trees[i])
1088 continue;
1090 iter = sdb_avltree_get_iter(trees[i]);
1091 while (sdb_avltree_iter_has_next(iter)) {
1092 sdb_memstore_obj_t *child;
1093 child = STORE_OBJ(sdb_avltree_iter_get_next(iter));
1095 if (filter && (! sdb_memstore_matcher_matches(filter, child, NULL)))
1096 continue;
1098 if (sdb_memstore_emit_full(child, filter, w, wd)) {
1099 sdb_avltree_iter_destroy(iter);
1100 return -1;
1101 }
1102 }
1103 sdb_avltree_iter_destroy(iter);
1104 }
1105 return 0;
1106 } /* sdb_memstore_emit_full */
1108 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */