Code

Let the JSON formatter include a metric's data_names.
[sysdb.git] / src / core / memstore.c
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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 : */