Code

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