Code

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