Code

15c4202829159eee3665b74f7d1654b010d8b602
[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 static sdb_avltree_t *
487 get_obj_attrs(sdb_memstore_obj_t *obj)
489         if (obj->type == SDB_HOST)
490                 return HOST(obj)->attributes;
491         else if (obj->type == SDB_SERVICE)
492                 return SVC(obj)->attributes;
493         else if (obj->type == SDB_METRIC)
494                 return METRIC(obj)->attributes;
495         return NULL;
496 } /* get_obj_attrs */
498 /*
499  * store writer API
500  */
502 static int
503 store_attribute(sdb_store_attribute_t *attr, sdb_object_t *user_data)
505         sdb_memstore_t *st = SDB_MEMSTORE(user_data);
506         store_obj_t obj = STORE_OBJ_INIT;
507         sdb_memstore_obj_t *new = NULL;
508         const char *hostname;
509         host_t *host;
511         sdb_avltree_t *children = NULL;
512         int status = 0;
514         if ((! attr) || (! attr->parent) || (! attr->key))
515                 return -1;
517         hostname = attr->hostname;
518         if (attr->parent_type == SDB_HOST)
519                 hostname = attr->parent;
520         if (! hostname)
521                 return -1;
523         pthread_rwlock_wrlock(&st->host_lock);
524         host = HOST(sdb_avltree_lookup(st->hosts, hostname));
525         if (! host) {
526                 sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - "
527                                 "host '%s' not found", attr->key, hostname);
528                 status = -1;
529         }
531         switch (attr->parent_type) {
532         case SDB_HOST:
533                 obj.parent = STORE_OBJ(host);
534                 obj.parent_tree = get_host_children(host, SDB_ATTRIBUTE);
535                 break;
536         case SDB_SERVICE:
537         case SDB_METRIC:
538                 children = get_host_children(host, attr->parent_type);
539                 break;
540         default:
541                 status = -1;
542                 break;
543         }
545         if (children) {
546                 obj.parent = STORE_OBJ(sdb_avltree_lookup(children, attr->parent));
547                 if (! obj.parent) {
548                         sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - "
549                                         "%s '%s/%s' not found", attr->key,
550                                         SDB_STORE_TYPE_TO_NAME(attr->parent_type),
551                                         attr->hostname, attr->parent);
552                         status = -1;
553                 }
554                 else
555                         obj.parent_tree = attr->parent_type == SDB_SERVICE
556                                 ? SVC(obj.parent)->attributes
557                                 : METRIC(obj.parent)->attributes;
558         }
560         obj.type = SDB_ATTRIBUTE;
561         obj.name = attr->key;
562         obj.last_update = attr->last_update;
563         obj.backends = attr->backends;
564         obj.backends_num = attr->backends_num;
565         if (! status)
566                 status = store_obj(&obj, &new);
568         if (! status) {
569                 assert(new);
570                 /* update the value if it changed */
571                 if (sdb_data_cmp(&ATTR(new)->value, &attr->value))
572                         if (sdb_data_copy(&ATTR(new)->value, &attr->value))
573                                 status = -1;
574         }
576         if (obj.parent != STORE_OBJ(host))
577                 sdb_object_deref(SDB_OBJ(obj.parent));
578         sdb_object_deref(SDB_OBJ(host));
579         pthread_rwlock_unlock(&st->host_lock);
581         return status;
582 } /* store_attribute */
584 static int
585 store_host(sdb_store_host_t *host, sdb_object_t *user_data)
587         sdb_memstore_t *st = SDB_MEMSTORE(user_data);
588         store_obj_t obj = { NULL, st->hosts, SDB_HOST, NULL, 0, NULL, 0 };
589         int status = 0;
591         if ((! host) || (! host->name))
592                 return -1;
594         obj.name = host->name;
595         obj.last_update = host->last_update;
596         obj.backends = host->backends;
597         obj.backends_num = host->backends_num;
598         pthread_rwlock_wrlock(&st->host_lock);
599         status = store_obj(&obj, NULL);
600         pthread_rwlock_unlock(&st->host_lock);
602         return status;
603 } /* store_host */
605 static int
606 store_service(sdb_store_service_t *service, sdb_object_t *user_data)
608         sdb_memstore_t *st = SDB_MEMSTORE(user_data);
609         store_obj_t obj = STORE_OBJ_INIT;
610         host_t *host;
612         int status = 0;
614         if ((! service) || (! service->hostname) || (! service->name))
615                 return -1;
617         pthread_rwlock_wrlock(&st->host_lock);
618         host = HOST(sdb_avltree_lookup(st->hosts, service->hostname));
619         obj.parent = STORE_OBJ(host);
620         obj.parent_tree = get_host_children(host, SDB_SERVICE);
621         obj.type = SDB_SERVICE;
622         if (! obj.parent_tree) {
623                 sdb_log(SDB_LOG_ERR, "memstore: Failed to store service '%s' - "
624                                 "host '%s' not found", service->name, service->hostname);
625                 status = -1;
626         }
628         obj.name = service->name;
629         obj.last_update = service->last_update;
630         obj.backends = service->backends;
631         obj.backends_num = service->backends_num;
632         if (! status)
633                 status = store_obj(&obj, NULL);
635         sdb_object_deref(SDB_OBJ(host));
636         pthread_rwlock_unlock(&st->host_lock);
637         return status;
638 } /* store_service */
640 static int
641 store_metric(sdb_store_metric_t *metric, sdb_object_t *user_data)
643         sdb_memstore_t *st = SDB_MEMSTORE(user_data);
644         store_obj_t obj = STORE_OBJ_INIT;
645         sdb_memstore_obj_t *new = NULL;
646         host_t *host;
648         int status = 0;
650         if ((! metric) || (! metric->hostname) || (! metric->name))
651                 return -1;
653         if ((metric->store.type != NULL) != (metric->store.id != NULL))
654                 return -1;
656         pthread_rwlock_wrlock(&st->host_lock);
657         host = HOST(sdb_avltree_lookup(st->hosts, metric->hostname));
658         obj.parent = STORE_OBJ(host);
659         obj.parent_tree = get_host_children(host, SDB_METRIC);
660         obj.type = SDB_METRIC;
661         if (! obj.parent_tree) {
662                 sdb_log(SDB_LOG_ERR, "memstore: Failed to store metric '%s' - "
663                                 "host '%s' not found", metric->name, metric->hostname);
664                 status = -1;
665         }
667         obj.name = metric->name;
668         obj.last_update = metric->last_update;
669         obj.backends = metric->backends;
670         obj.backends_num = metric->backends_num;
671         if (! status)
672                 status = store_obj(&obj, &new);
673         sdb_object_deref(SDB_OBJ(host));
675         if (status) {
676                 pthread_rwlock_unlock(&st->host_lock);
677                 return status;
678         }
680         assert(new);
681         if (metric->store.type && metric->store.id)
682                 if (store_metric_store(METRIC(new), metric))
683                         status = -1;
684         pthread_rwlock_unlock(&st->host_lock);
685         return status;
686 } /* store_metric */
688 sdb_store_writer_t sdb_memstore_writer = {
689         store_host, store_service, store_metric, store_attribute,
690 };
692 /*
693  * store query API
694  */
696 static sdb_object_t *
697 prepare_query(sdb_ast_node_t *ast,
698                 sdb_strbuf_t __attribute__((unused)) *errbuf,
699                 sdb_object_t __attribute__((unused)) *user_data)
701         return SDB_OBJ(sdb_memstore_query_prepare(ast));
702 } /* prepare_query */
704 static int
705 execute_query(sdb_object_t *q,
706                 sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
707                 sdb_object_t *user_data)
709         return sdb_memstore_query_execute(SDB_MEMSTORE(user_data),
710                         QUERY(q), w, wd, errbuf);
711 } /* execute_query */
713 sdb_store_reader_t sdb_memstore_reader = {
714         prepare_query, execute_query,
715 };
717 /*
718  * public API
719  */
721 sdb_memstore_t *
722 sdb_memstore_create(void)
724         return SDB_MEMSTORE(sdb_object_create("memstore", store_type));
725 } /* sdb_memstore_create */
727 int
728 sdb_memstore_host(sdb_memstore_t *store, const char *name, sdb_time_t last_update)
730         sdb_store_host_t host = {
731                 name, last_update, 0, NULL, 0,
732         };
733         return store_host(&host, SDB_OBJ(store));
734 } /* sdb_memstore_host */
736 int
737 sdb_memstore_service(sdb_memstore_t *store, const char *hostname, const char *name,
738                 sdb_time_t last_update)
740         sdb_store_service_t service = {
741                 hostname, name, last_update, 0, NULL, 0,
742         };
743         return store_service(&service, SDB_OBJ(store));
744 } /* sdb_memstore_service */
746 int
747 sdb_memstore_metric(sdb_memstore_t *store, const char *hostname, const char *name,
748                 sdb_metric_store_t *metric_store, sdb_time_t last_update)
750         sdb_store_metric_t metric = {
751                 hostname, name, { NULL, NULL }, last_update, 0, NULL, 0,
752         };
753         if (metric_store) {
754                 metric.store.type = metric_store->type;
755                 metric.store.id = metric_store->id;
756         }
757         return store_metric(&metric, SDB_OBJ(store));
758 } /* sdb_memstore_metric */
760 int
761 sdb_memstore_attribute(sdb_memstore_t *store, const char *hostname,
762                 const char *key, const sdb_data_t *value, sdb_time_t last_update)
764         sdb_store_attribute_t attr = {
765                 NULL, SDB_HOST, hostname, key, SDB_DATA_INIT, last_update, 0, NULL, 0,
766         };
767         if (value) {
768                 attr.value = *value;
769         }
770         return store_attribute(&attr, SDB_OBJ(store));
771 } /* sdb_memstore_attribute */
773 int
774 sdb_memstore_service_attr(sdb_memstore_t *store, const char *hostname,
775                 const char *service, const char *key, const sdb_data_t *value,
776                 sdb_time_t last_update)
778         sdb_store_attribute_t attr = {
779                 hostname, SDB_SERVICE, service, key, SDB_DATA_INIT, last_update, 0, NULL, 0,
780         };
781         if (value) {
782                 attr.value = *value;
783         }
784         return store_attribute(&attr, SDB_OBJ(store));
785 } /* sdb_memstore_service_attr */
787 int
788 sdb_memstore_metric_attr(sdb_memstore_t *store, const char *hostname,
789                 const char *metric, const char *key, const sdb_data_t *value,
790                 sdb_time_t last_update)
792         sdb_store_attribute_t attr = {
793                 hostname, SDB_METRIC, metric, key, SDB_DATA_INIT, last_update, 0, NULL, 0,
794         };
795         if (value) {
796                 attr.value = *value;
797         }
798         return store_attribute(&attr, SDB_OBJ(store));
799 } /* sdb_memstore_metric_attr */
801 sdb_memstore_obj_t *
802 sdb_memstore_get_host(sdb_memstore_t *store, const char *name)
804         host_t *host;
806         if ((! store) || (! name))
807                 return NULL;
809         host = HOST(sdb_avltree_lookup(store->hosts, name));
810         if (! host)
811                 return NULL;
813         return STORE_OBJ(host);
814 } /* sdb_memstore_get_host */
816 sdb_memstore_obj_t *
817 sdb_memstore_get_child(sdb_memstore_obj_t *obj, int type, const char *name)
819         sdb_avltree_t *children = NULL;
821         if ((! obj) || (! name))
822                 return NULL;
824         if (type & SDB_ATTRIBUTE)
825                 children = get_obj_attrs(obj);
826         else if (obj->type == SDB_HOST)
827                 children = get_host_children(HOST(obj), type);
828         if (! children)
829                 return NULL;
830         return STORE_OBJ(sdb_avltree_lookup(children, name));
831 } /* sdb_memstore_get_child */
833 int
834 sdb_memstore_get_field(sdb_memstore_obj_t *obj, int field, sdb_data_t *res)
836         sdb_data_t tmp;
838         if (! obj)
839                 return -1;
841         switch (field) {
842                 case SDB_FIELD_NAME:
843                         tmp.type = SDB_TYPE_STRING;
844                         tmp.data.string = strdup(SDB_OBJ(obj)->name);
845                         if (! tmp.data.string)
846                                 return -1;
847                         break;
848                 case SDB_FIELD_LAST_UPDATE:
849                         tmp.type = SDB_TYPE_DATETIME;
850                         tmp.data.datetime = obj->last_update;
851                         break;
852                 case SDB_FIELD_AGE:
853                         tmp.type = SDB_TYPE_DATETIME;
854                         tmp.data.datetime = sdb_gettime() - obj->last_update;
855                         break;
856                 case SDB_FIELD_INTERVAL:
857                         tmp.type = SDB_TYPE_DATETIME;
858                         tmp.data.datetime = obj->interval;
859                         break;
860                 case SDB_FIELD_BACKEND:
861                         if (! res)
862                                 return 0;
863                         tmp.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING;
864                         tmp.data.array.length = obj->backends_num;
865                         tmp.data.array.values = obj->backends;
866                         return sdb_data_copy(res, &tmp);
867                 case SDB_FIELD_VALUE:
868                         if (obj->type != SDB_ATTRIBUTE)
869                                 return -1;
870                         if (! res)
871                                 return 0;
872                         return sdb_data_copy(res, &ATTR(obj)->value);
873                 case SDB_FIELD_TIMESERIES:
874                         if (obj->type != SDB_METRIC)
875                                 return -1;
876                         tmp.type = SDB_TYPE_BOOLEAN;
877                         tmp.data.boolean = METRIC(obj)->store.type != NULL;
878                 default:
879                         return -1;
880         }
881         if (res)
882                 *res = tmp;
883         else
884                 sdb_data_free_datum(&tmp);
885         return 0;
886 } /* sdb_memstore_get_field */
888 int
889 sdb_memstore_get_attr(sdb_memstore_obj_t *obj, const char *name, sdb_data_t *res,
890                 sdb_memstore_matcher_t *filter)
892         sdb_memstore_obj_t *attr;
894         if ((! obj) || (! name))
895                 return -1;
897         attr = STORE_OBJ(sdb_avltree_lookup(get_obj_attrs(obj), name));
898         if (! attr)
899                 return -1;
900         if (filter && (! sdb_memstore_matcher_matches(filter, attr, NULL))) {
901                 sdb_object_deref(SDB_OBJ(attr));
902                 return -1;
903         }
905         assert(STORE_OBJ(attr)->type == SDB_ATTRIBUTE);
906         if (res)
907                 sdb_data_copy(res, &ATTR(attr)->value);
908         sdb_object_deref(SDB_OBJ(attr));
909         return 0;
910 } /* sdb_memstore_get_attr */
912 int
913 sdb_memstore_scan(sdb_memstore_t *store, int type,
914                 sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter,
915                 sdb_memstore_lookup_cb cb, void *user_data)
917         sdb_avltree_iter_t *host_iter = NULL;
918         int status = 0;
920         if ((! store) || (! cb))
921                 return -1;
923         if ((type != SDB_HOST) && (type != SDB_SERVICE) && (type != SDB_METRIC)) {
924                 sdb_log(SDB_LOG_ERR, "memstore: Cannot scan objects of type %d", type);
925                 return -1;
926         }
928         pthread_rwlock_rdlock(&store->host_lock);
929         host_iter = sdb_avltree_get_iter(store->hosts);
930         if (! host_iter)
931                 status = -1;
933         /* has_next returns false if the iterator is NULL */
934         while (sdb_avltree_iter_has_next(host_iter)) {
935                 sdb_memstore_obj_t *host;
936                 sdb_avltree_iter_t *iter = NULL;
938                 host = STORE_OBJ(sdb_avltree_iter_get_next(host_iter));
939                 assert(host);
941                 if (! sdb_memstore_matcher_matches(filter, host, NULL))
942                         continue;
944                 if (type == SDB_SERVICE)
945                         iter = sdb_avltree_get_iter(HOST(host)->services);
946                 else if (type == SDB_METRIC)
947                         iter = sdb_avltree_get_iter(HOST(host)->metrics);
949                 if (iter) {
950                         while (sdb_avltree_iter_has_next(iter)) {
951                                 sdb_memstore_obj_t *obj;
952                                 obj = STORE_OBJ(sdb_avltree_iter_get_next(iter));
953                                 assert(obj);
955                                 if (sdb_memstore_matcher_matches(m, obj, filter)) {
956                                         if (cb(obj, filter, user_data)) {
957                                                 sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
958                                                                 "an error while scanning");
959                                                 status = -1;
960                                                 break;
961                                         }
962                                 }
963                         }
964                 }
965                 else if (sdb_memstore_matcher_matches(m, host, filter)) {
966                         if (cb(host, filter, user_data)) {
967                                 sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
968                                                 "an error while scanning");
969                                 status = -1;
970                         }
971                 }
973                 sdb_avltree_iter_destroy(iter);
974                 if (status)
975                         break;
976         }
978         sdb_avltree_iter_destroy(host_iter);
979         pthread_rwlock_unlock(&store->host_lock);
980         return status;
981 } /* sdb_memstore_scan */
983 int
984 sdb_memstore_emit(sdb_memstore_obj_t *obj, sdb_store_writer_t *w, sdb_object_t *wd)
986         if ((! obj) || (! w))
987                 return -1;
989         switch (obj->type) {
990         case SDB_HOST:
991                 {
992                         sdb_store_host_t host = {
993                                 obj->_name,
994                                 obj->last_update,
995                                 obj->interval,
996                                 (const char * const *)obj->backends,
997                                 obj->backends_num,
998                         };
999                         if (! w->store_host)
1000                                 return -1;
1001                         return w->store_host(&host, wd);
1002                 }
1003         case SDB_SERVICE:
1004                 {
1005                         sdb_store_service_t service = {
1006                                 obj->parent ? obj->parent->_name : NULL,
1007                                 obj->_name,
1008                                 obj->last_update,
1009                                 obj->interval,
1010                                 (const char * const *)obj->backends,
1011                                 obj->backends_num,
1012                         };
1013                         if (! w->store_service)
1014                                 return -1;
1015                         return w->store_service(&service, wd);
1016                 }
1017         case SDB_METRIC:
1018                 {
1019                         sdb_store_metric_t metric = {
1020                                 obj->parent ? obj->parent->_name : NULL,
1021                                 obj->_name,
1022                                 {
1023                                         METRIC(obj)->store.type,
1024                                         METRIC(obj)->store.id,
1025                                 },
1026                                 obj->last_update,
1027                                 obj->interval,
1028                                 (const char * const *)obj->backends,
1029                                 obj->backends_num,
1030                         };
1031                         if (! w->store_metric)
1032                                 return -1;
1033                         return w->store_metric(&metric, wd);
1034                 }
1035         case SDB_ATTRIBUTE:
1036                 {
1037                         sdb_store_attribute_t attr = {
1038                                 NULL,
1039                                 obj->parent ? obj->parent->type : 0,
1040                                 obj->parent ? obj->parent->_name : NULL,
1041                                 obj->_name,
1042                                 ATTR(obj)->value,
1043                                 obj->last_update,
1044                                 obj->interval,
1045                                 (const char * const *)obj->backends,
1046                                 obj->backends_num,
1047                         };
1048                         if (obj->parent && (obj->parent->type != SDB_HOST)
1049                                         && obj->parent->parent)
1050                                 attr.hostname = obj->parent->parent->_name;
1051                         if (! w->store_attribute)
1052                                 return -1;
1053                         return w->store_attribute(&attr, wd);
1054                 }
1055         }
1057         return -1;
1058 } /* sdb_memstore_emit */
1060 int
1061 sdb_memstore_emit_full(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter,
1062                 sdb_store_writer_t *w, sdb_object_t *wd)
1064         sdb_avltree_t *trees[] = { NULL, NULL, NULL };
1065         size_t i;
1067         if (sdb_memstore_emit(obj, w, wd))
1068                 return -1;
1070         if (obj->type == SDB_HOST) {
1071                 trees[0] = HOST(obj)->attributes;
1072                 trees[1] = HOST(obj)->metrics;
1073                 trees[2] = HOST(obj)->services;
1074         }
1075         else if (obj->type == SDB_SERVICE)
1076                 trees[0] = SVC(obj)->attributes;
1077         else if (obj->type == SDB_METRIC)
1078                 trees[0] = METRIC(obj)->attributes;
1079         else if (obj->type == SDB_ATTRIBUTE)
1080                 return 0;
1081         else
1082                 return -1;
1084         for (i = 0; i < SDB_STATIC_ARRAY_LEN(trees); ++i) {
1085                 sdb_avltree_iter_t *iter;
1087                 if (! trees[i])
1088                         continue;
1090                 iter = sdb_avltree_get_iter(trees[i]);
1091                 while (sdb_avltree_iter_has_next(iter)) {
1092                         sdb_memstore_obj_t *child;
1093                         child = STORE_OBJ(sdb_avltree_iter_get_next(iter));
1095                         if (filter && (! sdb_memstore_matcher_matches(filter, child, NULL)))
1096                                 continue;
1098                         if (sdb_memstore_emit_full(child, filter, w, wd)) {
1099                                 sdb_avltree_iter_destroy(iter);
1100                                 return -1;
1101                         }
1102                 }
1103                 sdb_avltree_iter_destroy(iter);
1104         }
1105         return 0;
1106 } /* sdb_memstore_emit_full */
1108 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */