Code

Store a separate last_update timestamp for metric 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->store.type = sobj->store.id = NULL;
220         return 0;
221 } /* metric_init */
223 static void
224 metric_destroy(sdb_object_t *obj)
226         metric_t *sobj = METRIC(obj);
227         assert(obj);
229         store_obj_destroy(obj);
231         if (sobj->attributes)
232                 sdb_avltree_destroy(sobj->attributes);
234         if (sobj->store.type)
235                 free(sobj->store.type);
236         if (sobj->store.id)
237                 free(sobj->store.id);
238 } /* metric_destroy */
240 static int
241 attr_init(sdb_object_t *obj, va_list ap)
243         const sdb_data_t *value;
244         int ret;
246         /* this will consume the first argument (type) of ap */
247         ret = store_obj_init(obj, ap);
248         if (ret)
249                 return ret;
250         value = va_arg(ap, const sdb_data_t *);
252         if (value)
253                 if (sdb_data_copy(&ATTR(obj)->value, value))
254                         return -1;
255         return 0;
256 } /* attr_init */
258 static void
259 attr_destroy(sdb_object_t *obj)
261         assert(obj);
263         store_obj_destroy(obj);
264         sdb_data_free_datum(&ATTR(obj)->value);
265 } /* attr_destroy */
267 static sdb_type_t store_type = {
268         /* size = */ sizeof(sdb_memstore_t),
269         /* init = */ store_init,
270         /* destroy = */ store_destroy,
271 };
273 static sdb_type_t host_type = {
274         /* size = */ sizeof(host_t),
275         /* init = */ host_init,
276         /* destroy = */ host_destroy
277 };
279 static sdb_type_t service_type = {
280         /* size = */ sizeof(service_t),
281         /* init = */ service_init,
282         /* destroy = */ service_destroy
283 };
285 static sdb_type_t metric_type = {
286         /* size = */ sizeof(metric_t),
287         /* init = */ metric_init,
288         /* destroy = */ metric_destroy
289 };
291 static sdb_type_t attribute_type = {
292         /* size = */ sizeof(attr_t),
293         /* init = */ attr_init,
294         /* destroy = */ attr_destroy
295 };
297 /*
298  * private helper functions
299  */
301 static int
302 record_backends(sdb_memstore_obj_t *obj,
303                 const char * const *backends, size_t backends_num)
305         char **tmp;
306         size_t i;
308         for (i = 0; i < backends_num; i++) {
309                 bool found = 0;
310                 size_t j;
312                 for (j = 0; j < obj->backends_num; ++j) {
313                         if (!strcasecmp(obj->backends[j], backends[i])) {
314                                 found = 1;
315                                 break;
316                         }
317                 }
318                 if (found)
319                         continue;
321                 tmp = realloc(obj->backends,
322                                 (obj->backends_num + 1) * sizeof(*obj->backends));
323                 if (! tmp)
324                         return -1;
326                 obj->backends = tmp;
327                 obj->backends[obj->backends_num] = strdup(backends[i]);
328                 if (! obj->backends[obj->backends_num])
329                         return -1;
331                 ++obj->backends_num;
332         }
333         return 0;
334 } /* record_backends */
336 static int
337 store_obj(store_obj_t *obj, sdb_memstore_obj_t **updated_obj)
339         sdb_memstore_obj_t *old, *new;
340         int status = 0;
342         assert(obj->parent_tree);
344         old = STORE_OBJ(sdb_avltree_lookup(obj->parent_tree, obj->name));
345         if (old) {
346                 new = old;
347                 sdb_object_deref(SDB_OBJ(old));
348         }
349         else {
350                 if (obj->type == SDB_ATTRIBUTE) {
351                         /* the value will be updated by the caller */
352                         new = STORE_OBJ(sdb_object_create(obj->name, attribute_type,
353                                                 obj->type, NULL));
354                 }
355                 else {
356                         sdb_type_t t;
357                         t = obj->type == SDB_HOST
358                                 ? host_type
359                                 : obj->type == SDB_SERVICE
360                                         ? service_type
361                                         : metric_type;
362                         new = STORE_OBJ(sdb_object_create(obj->name, t, obj->type));
363                 }
365                 if (new) {
366                         status = sdb_avltree_insert(obj->parent_tree, SDB_OBJ(new));
368                         /* pass control to the tree or destroy in case of an error */
369                         sdb_object_deref(SDB_OBJ(new));
370                 }
371                 else {
372                         char errbuf[1024];
373                         sdb_log(SDB_LOG_ERR, "memstore: Failed to create %s '%s': %s",
374                                         SDB_STORE_TYPE_TO_NAME(obj->type), obj->name,
375                                         sdb_strerror(errno, errbuf, sizeof(errbuf)));
376                         status = -1;
377                 }
378         }
380         if (status < 0)
381                 return status;
382         assert(new);
384         new->last_update = obj->last_update;
385         new->interval = obj->interval;
387         if (new->parent != obj->parent) {
388                 // Avoid circular self-references which are not handled
389                 // correctly by the ref-count based management layer.
390                 //sdb_object_deref(SDB_OBJ(new->parent));
391                 //sdb_object_ref(SDB_OBJ(obj->parent));
392                 new->parent = obj->parent;
393         }
395         if (updated_obj)
396                 *updated_obj = new;
398         if (record_backends(new, obj->backends, obj->backends_num))
399                 return -1;
400         return status;
401 } /* store_obj */
403 static int
404 store_metric_store(metric_t *metric, sdb_store_metric_t *m)
406         char *type = metric->store.type;
407         char *id = metric->store.id;
409         if (! m->store.last_update)
410                 m->store.last_update = metric->store.last_update;
411         else if (m->store.last_update < metric->store.last_update)
412                 return 0;
414         if ((! metric->store.type) || strcasecmp(metric->store.type, m->store.type)) {
415                 if (! (type = strdup(m->store.type)))
416                         return -1;
417         }
418         if ((! metric->store.id) || strcasecmp(metric->store.id, m->store.id)) {
419                 if (! (id = strdup(m->store.id))) {
420                         if (type != metric->store.type)
421                                 free(type);
422                         return -1;
423                 }
424         }
426         if (type != metric->store.type) {
427                 if (metric->store.type)
428                         free(metric->store.type);
429                 metric->store.type = type;
430         }
431         if (id != metric->store.id) {
432                 if (metric->store.id)
433                         free(metric->store.id);
434                 metric->store.id = id;
435         }
436         metric->store.last_update = m->store.last_update;
437         return 0;
438 } /* store_metric_store */
440 /* The store's host_lock has to be acquired before calling this function. */
441 static sdb_avltree_t *
442 get_host_children(host_t *host, int type)
444         if ((type != SDB_SERVICE) && (type != SDB_METRIC)
445                         && (type != SDB_ATTRIBUTE))
446                 return NULL;
448         if (! host)
449                 return NULL;
451         if (type == SDB_ATTRIBUTE)
452                 return host->attributes;
453         else if (type == SDB_METRIC)
454                 return host->metrics;
455         else
456                 return host->services;
457 } /* get_host_children */
459 static sdb_avltree_t *
460 get_obj_attrs(sdb_memstore_obj_t *obj)
462         if (obj->type == SDB_HOST)
463                 return HOST(obj)->attributes;
464         else if (obj->type == SDB_SERVICE)
465                 return SVC(obj)->attributes;
466         else if (obj->type == SDB_METRIC)
467                 return METRIC(obj)->attributes;
468         return NULL;
469 } /* get_obj_attrs */
471 /*
472  * store writer API
473  */
475 static int
476 store_attribute(sdb_store_attribute_t *attr, sdb_object_t *user_data)
478         sdb_memstore_t *st = SDB_MEMSTORE(user_data);
479         store_obj_t obj = STORE_OBJ_INIT;
480         sdb_memstore_obj_t *new = NULL;
481         const char *hostname;
482         host_t *host;
484         sdb_avltree_t *children = NULL;
485         int status = 0;
487         if ((! attr) || (! attr->parent) || (! attr->key))
488                 return -1;
490         hostname = attr->hostname;
491         if (attr->parent_type == SDB_HOST)
492                 hostname = attr->parent;
493         if (! hostname)
494                 return -1;
496         pthread_rwlock_wrlock(&st->host_lock);
497         host = HOST(sdb_avltree_lookup(st->hosts, hostname));
498         if (! host) {
499                 sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - "
500                                 "host '%s' not found", attr->key, hostname);
501                 status = -1;
502         }
504         switch (attr->parent_type) {
505         case SDB_HOST:
506                 obj.parent = STORE_OBJ(host);
507                 obj.parent_tree = get_host_children(host, SDB_ATTRIBUTE);
508                 break;
509         case SDB_SERVICE:
510         case SDB_METRIC:
511                 children = get_host_children(host, attr->parent_type);
512                 break;
513         default:
514                 status = -1;
515                 break;
516         }
518         if (children) {
519                 obj.parent = STORE_OBJ(sdb_avltree_lookup(children, attr->parent));
520                 if (! obj.parent) {
521                         sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - "
522                                         "%s '%s/%s' not found", attr->key,
523                                         SDB_STORE_TYPE_TO_NAME(attr->parent_type),
524                                         attr->hostname, attr->parent);
525                         status = -1;
526                 }
527                 else
528                         obj.parent_tree = attr->parent_type == SDB_SERVICE
529                                 ? SVC(obj.parent)->attributes
530                                 : METRIC(obj.parent)->attributes;
531         }
533         obj.type = SDB_ATTRIBUTE;
534         obj.name = attr->key;
535         obj.last_update = attr->last_update;
536         obj.interval = attr->interval;
537         obj.backends = attr->backends;
538         obj.backends_num = attr->backends_num;
539         if (! status)
540                 status = store_obj(&obj, &new);
542         if (! status) {
543                 assert(new);
544                 /* update the value if it changed */
545                 if (sdb_data_cmp(&ATTR(new)->value, &attr->value))
546                         if (sdb_data_copy(&ATTR(new)->value, &attr->value))
547                                 status = -1;
548         }
550         if (obj.parent != STORE_OBJ(host))
551                 sdb_object_deref(SDB_OBJ(obj.parent));
552         sdb_object_deref(SDB_OBJ(host));
553         pthread_rwlock_unlock(&st->host_lock);
555         return status;
556 } /* store_attribute */
558 static int
559 store_host(sdb_store_host_t *host, sdb_object_t *user_data)
561         sdb_memstore_t *st = SDB_MEMSTORE(user_data);
562         store_obj_t obj = { NULL, st->hosts, SDB_HOST, NULL, 0, 0, NULL, 0 };
563         int status = 0;
565         if ((! host) || (! host->name))
566                 return -1;
568         obj.name = host->name;
569         obj.last_update = host->last_update;
570         obj.interval = host->interval;
571         obj.backends = host->backends;
572         obj.backends_num = host->backends_num;
573         pthread_rwlock_wrlock(&st->host_lock);
574         status = store_obj(&obj, NULL);
575         pthread_rwlock_unlock(&st->host_lock);
577         return status;
578 } /* store_host */
580 static int
581 store_service(sdb_store_service_t *service, sdb_object_t *user_data)
583         sdb_memstore_t *st = SDB_MEMSTORE(user_data);
584         store_obj_t obj = STORE_OBJ_INIT;
585         host_t *host;
587         int status = 0;
589         if ((! service) || (! service->hostname) || (! service->name))
590                 return -1;
592         pthread_rwlock_wrlock(&st->host_lock);
593         host = HOST(sdb_avltree_lookup(st->hosts, service->hostname));
594         obj.parent = STORE_OBJ(host);
595         obj.parent_tree = get_host_children(host, SDB_SERVICE);
596         obj.type = SDB_SERVICE;
597         if (! obj.parent_tree) {
598                 sdb_log(SDB_LOG_ERR, "memstore: Failed to store service '%s' - "
599                                 "host '%s' not found", service->name, service->hostname);
600                 status = -1;
601         }
603         obj.name = service->name;
604         obj.last_update = service->last_update;
605         obj.interval = service->interval;
606         obj.backends = service->backends;
607         obj.backends_num = service->backends_num;
608         if (! status)
609                 status = store_obj(&obj, NULL);
611         sdb_object_deref(SDB_OBJ(host));
612         pthread_rwlock_unlock(&st->host_lock);
613         return status;
614 } /* store_service */
616 static int
617 store_metric(sdb_store_metric_t *metric, sdb_object_t *user_data)
619         sdb_memstore_t *st = SDB_MEMSTORE(user_data);
620         store_obj_t obj = STORE_OBJ_INIT;
621         sdb_memstore_obj_t *new = NULL;
622         host_t *host;
624         int status = 0;
626         if ((! metric) || (! metric->hostname) || (! metric->name))
627                 return -1;
629         if ((metric->store.type != NULL) != (metric->store.id != NULL))
630                 return -1;
632         pthread_rwlock_wrlock(&st->host_lock);
633         host = HOST(sdb_avltree_lookup(st->hosts, metric->hostname));
634         obj.parent = STORE_OBJ(host);
635         obj.parent_tree = get_host_children(host, SDB_METRIC);
636         obj.type = SDB_METRIC;
637         if (! obj.parent_tree) {
638                 sdb_log(SDB_LOG_ERR, "memstore: Failed to store metric '%s' - "
639                                 "host '%s' not found", metric->name, metric->hostname);
640                 status = -1;
641         }
643         obj.name = metric->name;
644         obj.last_update = metric->last_update;
645         obj.interval = metric->interval;
646         obj.backends = metric->backends;
647         obj.backends_num = metric->backends_num;
648         if (! status)
649                 status = store_obj(&obj, &new);
650         sdb_object_deref(SDB_OBJ(host));
652         if (status) {
653                 pthread_rwlock_unlock(&st->host_lock);
654                 return status;
655         }
657         assert(new);
658         if (metric->store.type && metric->store.id)
659                 if (store_metric_store(METRIC(new), metric))
660                         status = -1;
661         pthread_rwlock_unlock(&st->host_lock);
662         return status;
663 } /* store_metric */
665 sdb_store_writer_t sdb_memstore_writer = {
666         store_host, store_service, store_metric, store_attribute,
667 };
669 /*
670  * store query API
671  */
673 static sdb_object_t *
674 prepare_query(sdb_ast_node_t *ast,
675                 sdb_strbuf_t __attribute__((unused)) *errbuf,
676                 sdb_object_t __attribute__((unused)) *user_data)
678         return SDB_OBJ(sdb_memstore_query_prepare(ast));
679 } /* prepare_query */
681 static int
682 execute_query(sdb_object_t *q,
683                 sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
684                 sdb_object_t *user_data)
686         return sdb_memstore_query_execute(SDB_MEMSTORE(user_data),
687                         QUERY(q), w, wd, errbuf);
688 } /* execute_query */
690 sdb_store_reader_t sdb_memstore_reader = {
691         prepare_query, execute_query,
692 };
694 /*
695  * public API
696  */
698 sdb_memstore_t *
699 sdb_memstore_create(void)
701         return SDB_MEMSTORE(sdb_object_create("memstore", store_type));
702 } /* sdb_memstore_create */
704 int
705 sdb_memstore_host(sdb_memstore_t *store, const char *name,
706                 sdb_time_t last_update, sdb_time_t interval)
708         sdb_store_host_t host = {
709                 name, last_update, interval, NULL, 0,
710         };
711         return store_host(&host, SDB_OBJ(store));
712 } /* sdb_memstore_host */
714 int
715 sdb_memstore_service(sdb_memstore_t *store, const char *hostname, const char *name,
716                 sdb_time_t last_update, sdb_time_t interval)
718         sdb_store_service_t service = {
719                 hostname, name, last_update, interval, NULL, 0,
720         };
721         return store_service(&service, SDB_OBJ(store));
722 } /* sdb_memstore_service */
724 int
725 sdb_memstore_metric(sdb_memstore_t *store, const char *hostname, const char *name,
726                 sdb_metric_store_t *metric_store,
727                 sdb_time_t last_update, sdb_time_t interval)
729         sdb_store_metric_t metric = {
730                 hostname, name,
731                 { NULL, NULL, 0 },
732                 last_update, interval, NULL, 0,
733         };
734         if (metric_store) {
735                 metric.store.type = metric_store->type;
736                 metric.store.id = metric_store->id;
737                 metric.store.last_update = metric_store->last_update;
738         }
739         return store_metric(&metric, SDB_OBJ(store));
740 } /* sdb_memstore_metric */
742 int
743 sdb_memstore_attribute(sdb_memstore_t *store, const char *hostname,
744                 const char *key, const sdb_data_t *value,
745                 sdb_time_t last_update, sdb_time_t interval)
747         sdb_store_attribute_t attr = {
748                 NULL, SDB_HOST, hostname, key, SDB_DATA_INIT,
749                 last_update, interval, NULL, 0,
750         };
751         if (value) {
752                 attr.value = *value;
753         }
754         return store_attribute(&attr, SDB_OBJ(store));
755 } /* sdb_memstore_attribute */
757 int
758 sdb_memstore_service_attr(sdb_memstore_t *store, const char *hostname,
759                 const char *service, const char *key, const sdb_data_t *value,
760                 sdb_time_t last_update, sdb_time_t interval)
762         sdb_store_attribute_t attr = {
763                 hostname, SDB_SERVICE, service, key, SDB_DATA_INIT,
764                 last_update, interval, NULL, 0,
765         };
766         if (value) {
767                 attr.value = *value;
768         }
769         return store_attribute(&attr, SDB_OBJ(store));
770 } /* sdb_memstore_service_attr */
772 int
773 sdb_memstore_metric_attr(sdb_memstore_t *store, const char *hostname,
774                 const char *metric, const char *key, const sdb_data_t *value,
775                 sdb_time_t last_update, sdb_time_t interval)
777         sdb_store_attribute_t attr = {
778                 hostname, SDB_METRIC, metric, key, SDB_DATA_INIT,
779                 last_update, interval, NULL, 0,
780         };
781         if (value) {
782                 attr.value = *value;
783         }
784         return store_attribute(&attr, SDB_OBJ(store));
785 } /* sdb_memstore_metric_attr */
787 sdb_memstore_obj_t *
788 sdb_memstore_get_host(sdb_memstore_t *store, const char *name)
790         host_t *host;
792         if ((! store) || (! name))
793                 return NULL;
795         host = HOST(sdb_avltree_lookup(store->hosts, name));
796         if (! host)
797                 return NULL;
799         return STORE_OBJ(host);
800 } /* sdb_memstore_get_host */
802 sdb_memstore_obj_t *
803 sdb_memstore_get_child(sdb_memstore_obj_t *obj, int type, const char *name)
805         sdb_avltree_t *children = NULL;
807         if ((! obj) || (! name))
808                 return NULL;
810         if (type & SDB_ATTRIBUTE)
811                 children = get_obj_attrs(obj);
812         else if (obj->type == SDB_HOST)
813                 children = get_host_children(HOST(obj), type);
814         if (! children)
815                 return NULL;
816         return STORE_OBJ(sdb_avltree_lookup(children, name));
817 } /* sdb_memstore_get_child */
819 int
820 sdb_memstore_get_field(sdb_memstore_obj_t *obj, int field, sdb_data_t *res)
822         sdb_data_t tmp;
824         if (! obj)
825                 return -1;
827         switch (field) {
828                 case SDB_FIELD_NAME:
829                         tmp.type = SDB_TYPE_STRING;
830                         tmp.data.string = strdup(SDB_OBJ(obj)->name);
831                         if (! tmp.data.string)
832                                 return -1;
833                         break;
834                 case SDB_FIELD_LAST_UPDATE:
835                         tmp.type = SDB_TYPE_DATETIME;
836                         tmp.data.datetime = obj->last_update;
837                         break;
838                 case SDB_FIELD_AGE:
839                         tmp.type = SDB_TYPE_DATETIME;
840                         tmp.data.datetime = sdb_gettime() - obj->last_update;
841                         break;
842                 case SDB_FIELD_INTERVAL:
843                         tmp.type = SDB_TYPE_DATETIME;
844                         tmp.data.datetime = obj->interval;
845                         break;
846                 case SDB_FIELD_BACKEND:
847                         if (! res)
848                                 return 0;
849                         tmp.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING;
850                         tmp.data.array.length = obj->backends_num;
851                         tmp.data.array.values = obj->backends;
852                         return sdb_data_copy(res, &tmp);
853                 case SDB_FIELD_VALUE:
854                         if (obj->type != SDB_ATTRIBUTE)
855                                 return -1;
856                         if (! res)
857                                 return 0;
858                         return sdb_data_copy(res, &ATTR(obj)->value);
859                 case SDB_FIELD_TIMESERIES:
860                         if (obj->type != SDB_METRIC)
861                                 return -1;
862                         tmp.type = SDB_TYPE_BOOLEAN;
863                         tmp.data.boolean = METRIC(obj)->store.type != NULL;
864                 default:
865                         return -1;
866         }
867         if (res)
868                 *res = tmp;
869         else
870                 sdb_data_free_datum(&tmp);
871         return 0;
872 } /* sdb_memstore_get_field */
874 int
875 sdb_memstore_get_attr(sdb_memstore_obj_t *obj, const char *name, sdb_data_t *res,
876                 sdb_memstore_matcher_t *filter)
878         sdb_memstore_obj_t *attr;
880         if ((! obj) || (! name))
881                 return -1;
883         attr = STORE_OBJ(sdb_avltree_lookup(get_obj_attrs(obj), name));
884         if (! attr)
885                 return -1;
886         if (filter && (! sdb_memstore_matcher_matches(filter, attr, NULL))) {
887                 sdb_object_deref(SDB_OBJ(attr));
888                 return -1;
889         }
891         assert(STORE_OBJ(attr)->type == SDB_ATTRIBUTE);
892         if (res)
893                 sdb_data_copy(res, &ATTR(attr)->value);
894         sdb_object_deref(SDB_OBJ(attr));
895         return 0;
896 } /* sdb_memstore_get_attr */
898 int
899 sdb_memstore_scan(sdb_memstore_t *store, int type,
900                 sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter,
901                 sdb_memstore_lookup_cb cb, void *user_data)
903         sdb_avltree_iter_t *host_iter = NULL;
904         int status = 0;
906         if ((! store) || (! cb))
907                 return -1;
909         if ((type != SDB_HOST) && (type != SDB_SERVICE) && (type != SDB_METRIC)) {
910                 sdb_log(SDB_LOG_ERR, "memstore: Cannot scan objects of type %d", type);
911                 return -1;
912         }
914         pthread_rwlock_rdlock(&store->host_lock);
915         host_iter = sdb_avltree_get_iter(store->hosts);
916         if (! host_iter)
917                 status = -1;
919         /* has_next returns false if the iterator is NULL */
920         while (sdb_avltree_iter_has_next(host_iter)) {
921                 sdb_memstore_obj_t *host;
922                 sdb_avltree_iter_t *iter = NULL;
924                 host = STORE_OBJ(sdb_avltree_iter_get_next(host_iter));
925                 assert(host);
927                 if (! sdb_memstore_matcher_matches(filter, host, NULL))
928                         continue;
930                 if (type == SDB_SERVICE)
931                         iter = sdb_avltree_get_iter(HOST(host)->services);
932                 else if (type == SDB_METRIC)
933                         iter = sdb_avltree_get_iter(HOST(host)->metrics);
935                 if (iter) {
936                         while (sdb_avltree_iter_has_next(iter)) {
937                                 sdb_memstore_obj_t *obj;
938                                 obj = STORE_OBJ(sdb_avltree_iter_get_next(iter));
939                                 assert(obj);
941                                 if (sdb_memstore_matcher_matches(m, obj, filter)) {
942                                         if (cb(obj, filter, user_data)) {
943                                                 sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
944                                                                 "an error while scanning");
945                                                 status = -1;
946                                                 break;
947                                         }
948                                 }
949                         }
950                 }
951                 else if (sdb_memstore_matcher_matches(m, host, filter)) {
952                         if (cb(host, filter, user_data)) {
953                                 sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
954                                                 "an error while scanning");
955                                 status = -1;
956                         }
957                 }
959                 sdb_avltree_iter_destroy(iter);
960                 if (status)
961                         break;
962         }
964         sdb_avltree_iter_destroy(host_iter);
965         pthread_rwlock_unlock(&store->host_lock);
966         return status;
967 } /* sdb_memstore_scan */
969 int
970 sdb_memstore_emit(sdb_memstore_obj_t *obj, sdb_store_writer_t *w, sdb_object_t *wd)
972         if ((! obj) || (! w))
973                 return -1;
975         switch (obj->type) {
976         case SDB_HOST:
977                 {
978                         sdb_store_host_t host = {
979                                 obj->_name,
980                                 obj->last_update,
981                                 obj->interval,
982                                 (const char * const *)obj->backends,
983                                 obj->backends_num,
984                         };
985                         if (! w->store_host)
986                                 return -1;
987                         return w->store_host(&host, wd);
988                 }
989         case SDB_SERVICE:
990                 {
991                         sdb_store_service_t service = {
992                                 obj->parent ? obj->parent->_name : NULL,
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_service)
1000                                 return -1;
1001                         return w->store_service(&service, wd);
1002                 }
1003         case SDB_METRIC:
1004                 {
1005                         sdb_store_metric_t metric = {
1006                                 obj->parent ? obj->parent->_name : NULL,
1007                                 obj->_name,
1008                                 {
1009                                         METRIC(obj)->store.type,
1010                                         METRIC(obj)->store.id,
1011                                         METRIC(obj)->store.last_update,
1012                                 },
1013                                 obj->last_update,
1014                                 obj->interval,
1015                                 (const char * const *)obj->backends,
1016                                 obj->backends_num,
1017                         };
1018                         if (! w->store_metric)
1019                                 return -1;
1020                         return w->store_metric(&metric, wd);
1021                 }
1022         case SDB_ATTRIBUTE:
1023                 {
1024                         sdb_store_attribute_t attr = {
1025                                 NULL,
1026                                 obj->parent ? obj->parent->type : 0,
1027                                 obj->parent ? obj->parent->_name : NULL,
1028                                 obj->_name,
1029                                 ATTR(obj)->value,
1030                                 obj->last_update,
1031                                 obj->interval,
1032                                 (const char * const *)obj->backends,
1033                                 obj->backends_num,
1034                         };
1035                         if (obj->parent && (obj->parent->type != SDB_HOST)
1036                                         && obj->parent->parent)
1037                                 attr.hostname = obj->parent->parent->_name;
1038                         if (! w->store_attribute)
1039                                 return -1;
1040                         return w->store_attribute(&attr, wd);
1041                 }
1042         }
1044         return -1;
1045 } /* sdb_memstore_emit */
1047 int
1048 sdb_memstore_emit_full(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter,
1049                 sdb_store_writer_t *w, sdb_object_t *wd)
1051         sdb_avltree_t *trees[] = { NULL, NULL, NULL };
1052         size_t i;
1054         if (sdb_memstore_emit(obj, w, wd))
1055                 return -1;
1057         if (obj->type == SDB_HOST) {
1058                 trees[0] = HOST(obj)->attributes;
1059                 trees[1] = HOST(obj)->metrics;
1060                 trees[2] = HOST(obj)->services;
1061         }
1062         else if (obj->type == SDB_SERVICE)
1063                 trees[0] = SVC(obj)->attributes;
1064         else if (obj->type == SDB_METRIC)
1065                 trees[0] = METRIC(obj)->attributes;
1066         else if (obj->type == SDB_ATTRIBUTE)
1067                 return 0;
1068         else
1069                 return -1;
1071         for (i = 0; i < SDB_STATIC_ARRAY_LEN(trees); ++i) {
1072                 sdb_avltree_iter_t *iter;
1074                 if (! trees[i])
1075                         continue;
1077                 iter = sdb_avltree_get_iter(trees[i]);
1078                 while (sdb_avltree_iter_has_next(iter)) {
1079                         sdb_memstore_obj_t *child;
1080                         child = STORE_OBJ(sdb_avltree_iter_get_next(iter));
1082                         if (filter && (! sdb_memstore_matcher_matches(filter, child, NULL)))
1083                                 continue;
1085                         if (sdb_memstore_emit_full(child, filter, w, wd)) {
1086                                 sdb_avltree_iter_destroy(iter);
1087                                 return -1;
1088                         }
1089                 }
1090                 sdb_avltree_iter_destroy(iter);
1091         }
1092         return 0;
1093 } /* sdb_memstore_emit_full */
1095 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */