Code

244982777cfb38fc82b5b99e8e8cf1c645e56b91
[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         sdb_time_t interval;
69         const char * const *backends;
70         size_t backends_num;
71 } store_obj_t;
72 #define STORE_OBJ_INIT { NULL, NULL, 0, NULL, 0, 0, NULL, 0 }
74 static sdb_type_t host_type;
75 static sdb_type_t service_type;
76 static sdb_type_t metric_type;
77 static sdb_type_t attribute_type;
79 static int
80 store_init(sdb_object_t *obj, va_list __attribute__((unused)) ap)
81 {
82         int err;
83         if (! (SDB_MEMSTORE(obj)->hosts = sdb_avltree_create()))
84                 return -1;
85         if ((err = pthread_rwlock_init(&SDB_MEMSTORE(obj)->host_lock,
86                                         /* attr = */ NULL))) {
87                 char errbuf[128];
88                 sdb_log(SDB_LOG_ERR, "memstore: Failed to initialize lock: %s",
89                                 sdb_strerror(err, errbuf, sizeof(errbuf)));
90                 return -1;
91         }
92         return 0;
93 } /* store_init */
95 static void
96 store_destroy(sdb_object_t *obj)
97 {
98         int err;
99         if ((err = pthread_rwlock_destroy(&SDB_MEMSTORE(obj)->host_lock))) {
100                 char errbuf[128];
101                 sdb_log(SDB_LOG_ERR, "memstore: Failed to destroy lock: %s",
102                                 sdb_strerror(err, errbuf, sizeof(errbuf)));
103                 return;
104         }
105         sdb_avltree_destroy(SDB_MEMSTORE(obj)->hosts);
106         SDB_MEMSTORE(obj)->hosts = NULL;
107 } /* store_destroy */
109 static int
110 store_obj_init(sdb_object_t *obj, va_list ap)
112         sdb_memstore_obj_t *sobj = STORE_OBJ(obj);
113         sobj->type = va_arg(ap, int);
114         return 0;
115 } /* store_obj_init */
117 static void
118 store_obj_destroy(sdb_object_t *obj)
120         sdb_memstore_obj_t *sobj = STORE_OBJ(obj);
121         size_t i;
123         for (i = 0; i < sobj->backends_num; ++i)
124                 free(sobj->backends[i]);
125         free(sobj->backends);
126         sobj->backends = NULL;
127         sobj->backends_num = 0;
129         // We don't currently keep an extra reference for parent objects to
130         // avoid circular self-references which are not handled correctly by
131         // the ref-count base management layer.
132         //sdb_object_deref(SDB_OBJ(sobj->parent));
133 } /* store_obj_destroy */
135 static int
136 host_init(sdb_object_t *obj, va_list ap)
138         host_t *sobj = HOST(obj);
139         int ret;
141         /* this will consume the first argument (type) of ap */
142         ret = store_obj_init(obj, ap);
143         if (ret)
144                 return ret;
146         sobj->services = sdb_avltree_create();
147         if (! sobj->services)
148                 return -1;
149         sobj->metrics = sdb_avltree_create();
150         if (! sobj->metrics)
151                 return -1;
152         sobj->attributes = sdb_avltree_create();
153         if (! sobj->attributes)
154                 return -1;
155         return 0;
156 } /* host_init */
158 static void
159 host_destroy(sdb_object_t *obj)
161         host_t *sobj = HOST(obj);
162         assert(obj);
164         store_obj_destroy(obj);
166         if (sobj->services)
167                 sdb_avltree_destroy(sobj->services);
168         if (sobj->metrics)
169                 sdb_avltree_destroy(sobj->metrics);
170         if (sobj->attributes)
171                 sdb_avltree_destroy(sobj->attributes);
172 } /* host_destroy */
174 static int
175 service_init(sdb_object_t *obj, va_list ap)
177         service_t *sobj = SVC(obj);
178         int ret;
180         /* this will consume the first argument (type) of ap */
181         ret = store_obj_init(obj, ap);
182         if (ret)
183                 return ret;
185         sobj->attributes = sdb_avltree_create();
186         if (! sobj->attributes)
187                 return -1;
188         return 0;
189 } /* service_init */
191 static void
192 service_destroy(sdb_object_t *obj)
194         service_t *sobj = SVC(obj);
195         assert(obj);
197         store_obj_destroy(obj);
199         if (sobj->attributes)
200                 sdb_avltree_destroy(sobj->attributes);
201 } /* service_destroy */
203 static int
204 metric_init(sdb_object_t *obj, va_list ap)
206         metric_t *sobj = METRIC(obj);
207         int ret;
209         /* this will consume the first argument (type) of ap */
210         ret = store_obj_init(obj, ap);
211         if (ret)
212                 return ret;
214         sobj->attributes = sdb_avltree_create();
215         if (! sobj->attributes)
216                 return -1;
218         sobj->store.type = sobj->store.id = NULL;
219         return 0;
220 } /* metric_init */
222 static void
223 metric_destroy(sdb_object_t *obj)
225         metric_t *sobj = METRIC(obj);
226         assert(obj);
228         store_obj_destroy(obj);
230         if (sobj->attributes)
231                 sdb_avltree_destroy(sobj->attributes);
233         if (sobj->store.type)
234                 free(sobj->store.type);
235         if (sobj->store.id)
236                 free(sobj->store.id);
237 } /* metric_destroy */
239 static int
240 attr_init(sdb_object_t *obj, va_list ap)
242         const sdb_data_t *value;
243         int ret;
245         /* this will consume the first argument (type) of ap */
246         ret = store_obj_init(obj, ap);
247         if (ret)
248                 return ret;
249         value = va_arg(ap, const sdb_data_t *);
251         if (value)
252                 if (sdb_data_copy(&ATTR(obj)->value, value))
253                         return -1;
254         return 0;
255 } /* attr_init */
257 static void
258 attr_destroy(sdb_object_t *obj)
260         assert(obj);
262         store_obj_destroy(obj);
263         sdb_data_free_datum(&ATTR(obj)->value);
264 } /* attr_destroy */
266 static sdb_type_t store_type = {
267         /* size = */ sizeof(sdb_memstore_t),
268         /* init = */ store_init,
269         /* destroy = */ store_destroy,
270 };
272 static sdb_type_t host_type = {
273         /* size = */ sizeof(host_t),
274         /* init = */ host_init,
275         /* destroy = */ host_destroy
276 };
278 static sdb_type_t service_type = {
279         /* size = */ sizeof(service_t),
280         /* init = */ service_init,
281         /* destroy = */ service_destroy
282 };
284 static sdb_type_t metric_type = {
285         /* size = */ sizeof(metric_t),
286         /* init = */ metric_init,
287         /* destroy = */ metric_destroy
288 };
290 static sdb_type_t attribute_type = {
291         /* size = */ sizeof(attr_t),
292         /* init = */ attr_init,
293         /* destroy = */ attr_destroy
294 };
296 /*
297  * private helper functions
298  */
300 static int
301 record_backends(sdb_memstore_obj_t *obj,
302                 const char * const *backends, size_t backends_num)
304         char **tmp;
305         size_t i;
307         for (i = 0; i < backends_num; i++) {
308                 bool found = 0;
309                 size_t j;
311                 for (j = 0; j < obj->backends_num; ++j) {
312                         if (!strcasecmp(obj->backends[j], backends[i])) {
313                                 found = 1;
314                                 break;
315                         }
316                 }
317                 if (found)
318                         continue;
320                 tmp = realloc(obj->backends,
321                                 (obj->backends_num + 1) * sizeof(*obj->backends));
322                 if (! tmp)
323                         return -1;
325                 obj->backends = tmp;
326                 obj->backends[obj->backends_num] = strdup(backends[i]);
327                 if (! obj->backends[obj->backends_num])
328                         return -1;
330                 ++obj->backends_num;
331         }
332         return 0;
333 } /* record_backends */
335 static int
336 store_obj(store_obj_t *obj, sdb_memstore_obj_t **updated_obj)
338         sdb_memstore_obj_t *old, *new;
339         int status = 0;
341         assert(obj->parent_tree);
343         old = STORE_OBJ(sdb_avltree_lookup(obj->parent_tree, obj->name));
344         if (old) {
345                 new = old;
346                 sdb_object_deref(SDB_OBJ(old));
347         }
348         else {
349                 if (obj->type == SDB_ATTRIBUTE) {
350                         /* the value will be updated by the caller */
351                         new = STORE_OBJ(sdb_object_create(obj->name, attribute_type,
352                                                 obj->type, NULL));
353                 }
354                 else {
355                         sdb_type_t t;
356                         t = obj->type == SDB_HOST
357                                 ? host_type
358                                 : obj->type == SDB_SERVICE
359                                         ? service_type
360                                         : metric_type;
361                         new = STORE_OBJ(sdb_object_create(obj->name, t, obj->type));
362                 }
364                 if (new) {
365                         status = sdb_avltree_insert(obj->parent_tree, SDB_OBJ(new));
367                         /* pass control to the tree or destroy in case of an error */
368                         sdb_object_deref(SDB_OBJ(new));
369                 }
370                 else {
371                         char errbuf[1024];
372                         sdb_log(SDB_LOG_ERR, "memstore: Failed to create %s '%s': %s",
373                                         SDB_STORE_TYPE_TO_NAME(obj->type), obj->name,
374                                         sdb_strerror(errno, errbuf, sizeof(errbuf)));
375                         status = -1;
376                 }
377         }
379         if (status < 0)
380                 return status;
381         assert(new);
383         new->last_update = obj->last_update;
384         new->interval = obj->interval;
386         if (new->parent != obj->parent) {
387                 // Avoid circular self-references which are not handled
388                 // correctly by the ref-count based management layer.
389                 //sdb_object_deref(SDB_OBJ(new->parent));
390                 //sdb_object_ref(SDB_OBJ(obj->parent));
391                 new->parent = obj->parent;
392         }
394         if (updated_obj)
395                 *updated_obj = new;
397         if (record_backends(new, obj->backends, obj->backends_num))
398                 return -1;
399         return status;
400 } /* store_obj */
402 static int
403 store_metric_store(metric_t *metric, sdb_store_metric_t *m)
405         char *type = metric->store.type;
406         char *id = metric->store.id;
408         if ((! metric->store.type) || strcasecmp(metric->store.type, m->store.type)) {
409                 if (! (type = strdup(m->store.type)))
410                         return -1;
411         }
412         if ((! metric->store.id) || strcasecmp(metric->store.id, m->store.id)) {
413                 if (! (id = strdup(m->store.id))) {
414                         if (type != metric->store.type)
415                                 free(type);
416                         return -1;
417                 }
418         }
420         if (type != metric->store.type) {
421                 if (metric->store.type)
422                         free(metric->store.type);
423                 metric->store.type = type;
424         }
425         if (id != metric->store.id) {
426                 if (metric->store.id)
427                         free(metric->store.id);
428                 metric->store.id = id;
429         }
430         return 0;
431 } /* store_metric_store */
433 /* The store's host_lock has to be acquired before calling this function. */
434 static sdb_avltree_t *
435 get_host_children(host_t *host, int type)
437         if ((type != SDB_SERVICE) && (type != SDB_METRIC)
438                         && (type != SDB_ATTRIBUTE))
439                 return NULL;
441         if (! host)
442                 return NULL;
444         if (type == SDB_ATTRIBUTE)
445                 return host->attributes;
446         else if (type == SDB_METRIC)
447                 return host->metrics;
448         else
449                 return host->services;
450 } /* get_host_children */
452 static sdb_avltree_t *
453 get_obj_attrs(sdb_memstore_obj_t *obj)
455         if (obj->type == SDB_HOST)
456                 return HOST(obj)->attributes;
457         else if (obj->type == SDB_SERVICE)
458                 return SVC(obj)->attributes;
459         else if (obj->type == SDB_METRIC)
460                 return METRIC(obj)->attributes;
461         return NULL;
462 } /* get_obj_attrs */
464 /*
465  * store writer API
466  */
468 static int
469 store_attribute(sdb_store_attribute_t *attr, sdb_object_t *user_data)
471         sdb_memstore_t *st = SDB_MEMSTORE(user_data);
472         store_obj_t obj = STORE_OBJ_INIT;
473         sdb_memstore_obj_t *new = NULL;
474         const char *hostname;
475         host_t *host;
477         sdb_avltree_t *children = NULL;
478         int status = 0;
480         if ((! attr) || (! attr->parent) || (! attr->key))
481                 return -1;
483         hostname = attr->hostname;
484         if (attr->parent_type == SDB_HOST)
485                 hostname = attr->parent;
486         if (! hostname)
487                 return -1;
489         pthread_rwlock_wrlock(&st->host_lock);
490         host = HOST(sdb_avltree_lookup(st->hosts, hostname));
491         if (! host) {
492                 sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - "
493                                 "host '%s' not found", attr->key, hostname);
494                 status = -1;
495         }
497         switch (attr->parent_type) {
498         case SDB_HOST:
499                 obj.parent = STORE_OBJ(host);
500                 obj.parent_tree = get_host_children(host, SDB_ATTRIBUTE);
501                 break;
502         case SDB_SERVICE:
503         case SDB_METRIC:
504                 children = get_host_children(host, attr->parent_type);
505                 break;
506         default:
507                 status = -1;
508                 break;
509         }
511         if (children) {
512                 obj.parent = STORE_OBJ(sdb_avltree_lookup(children, attr->parent));
513                 if (! obj.parent) {
514                         sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - "
515                                         "%s '%s/%s' not found", attr->key,
516                                         SDB_STORE_TYPE_TO_NAME(attr->parent_type),
517                                         attr->hostname, attr->parent);
518                         status = -1;
519                 }
520                 else
521                         obj.parent_tree = attr->parent_type == SDB_SERVICE
522                                 ? SVC(obj.parent)->attributes
523                                 : METRIC(obj.parent)->attributes;
524         }
526         obj.type = SDB_ATTRIBUTE;
527         obj.name = attr->key;
528         obj.last_update = attr->last_update;
529         obj.interval = attr->interval;
530         obj.backends = attr->backends;
531         obj.backends_num = attr->backends_num;
532         if (! status)
533                 status = store_obj(&obj, &new);
535         if (! status) {
536                 assert(new);
537                 /* update the value if it changed */
538                 if (sdb_data_cmp(&ATTR(new)->value, &attr->value))
539                         if (sdb_data_copy(&ATTR(new)->value, &attr->value))
540                                 status = -1;
541         }
543         if (obj.parent != STORE_OBJ(host))
544                 sdb_object_deref(SDB_OBJ(obj.parent));
545         sdb_object_deref(SDB_OBJ(host));
546         pthread_rwlock_unlock(&st->host_lock);
548         return status;
549 } /* store_attribute */
551 static int
552 store_host(sdb_store_host_t *host, sdb_object_t *user_data)
554         sdb_memstore_t *st = SDB_MEMSTORE(user_data);
555         store_obj_t obj = { NULL, st->hosts, SDB_HOST, NULL, 0, 0, NULL, 0 };
556         int status = 0;
558         if ((! host) || (! host->name))
559                 return -1;
561         obj.name = host->name;
562         obj.last_update = host->last_update;
563         obj.interval = host->interval;
564         obj.backends = host->backends;
565         obj.backends_num = host->backends_num;
566         pthread_rwlock_wrlock(&st->host_lock);
567         status = store_obj(&obj, NULL);
568         pthread_rwlock_unlock(&st->host_lock);
570         return status;
571 } /* store_host */
573 static int
574 store_service(sdb_store_service_t *service, sdb_object_t *user_data)
576         sdb_memstore_t *st = SDB_MEMSTORE(user_data);
577         store_obj_t obj = STORE_OBJ_INIT;
578         host_t *host;
580         int status = 0;
582         if ((! service) || (! service->hostname) || (! service->name))
583                 return -1;
585         pthread_rwlock_wrlock(&st->host_lock);
586         host = HOST(sdb_avltree_lookup(st->hosts, service->hostname));
587         obj.parent = STORE_OBJ(host);
588         obj.parent_tree = get_host_children(host, SDB_SERVICE);
589         obj.type = SDB_SERVICE;
590         if (! obj.parent_tree) {
591                 sdb_log(SDB_LOG_ERR, "memstore: Failed to store service '%s' - "
592                                 "host '%s' not found", service->name, service->hostname);
593                 status = -1;
594         }
596         obj.name = service->name;
597         obj.last_update = service->last_update;
598         obj.interval = service->interval;
599         obj.backends = service->backends;
600         obj.backends_num = service->backends_num;
601         if (! status)
602                 status = store_obj(&obj, NULL);
604         sdb_object_deref(SDB_OBJ(host));
605         pthread_rwlock_unlock(&st->host_lock);
606         return status;
607 } /* store_service */
609 static int
610 store_metric(sdb_store_metric_t *metric, sdb_object_t *user_data)
612         sdb_memstore_t *st = SDB_MEMSTORE(user_data);
613         store_obj_t obj = STORE_OBJ_INIT;
614         sdb_memstore_obj_t *new = NULL;
615         host_t *host;
617         int status = 0;
619         if ((! metric) || (! metric->hostname) || (! metric->name))
620                 return -1;
622         if ((metric->store.type != NULL) != (metric->store.id != NULL))
623                 return -1;
625         pthread_rwlock_wrlock(&st->host_lock);
626         host = HOST(sdb_avltree_lookup(st->hosts, metric->hostname));
627         obj.parent = STORE_OBJ(host);
628         obj.parent_tree = get_host_children(host, SDB_METRIC);
629         obj.type = SDB_METRIC;
630         if (! obj.parent_tree) {
631                 sdb_log(SDB_LOG_ERR, "memstore: Failed to store metric '%s' - "
632                                 "host '%s' not found", metric->name, metric->hostname);
633                 status = -1;
634         }
636         obj.name = metric->name;
637         obj.last_update = metric->last_update;
638         obj.interval = metric->interval;
639         obj.backends = metric->backends;
640         obj.backends_num = metric->backends_num;
641         if (! status)
642                 status = store_obj(&obj, &new);
643         sdb_object_deref(SDB_OBJ(host));
645         if (status) {
646                 pthread_rwlock_unlock(&st->host_lock);
647                 return status;
648         }
650         assert(new);
651         if (metric->store.type && metric->store.id)
652                 if (store_metric_store(METRIC(new), metric))
653                         status = -1;
654         pthread_rwlock_unlock(&st->host_lock);
655         return status;
656 } /* store_metric */
658 sdb_store_writer_t sdb_memstore_writer = {
659         store_host, store_service, store_metric, store_attribute,
660 };
662 /*
663  * store query API
664  */
666 static sdb_object_t *
667 prepare_query(sdb_ast_node_t *ast,
668                 sdb_strbuf_t __attribute__((unused)) *errbuf,
669                 sdb_object_t __attribute__((unused)) *user_data)
671         return SDB_OBJ(sdb_memstore_query_prepare(ast));
672 } /* prepare_query */
674 static int
675 execute_query(sdb_object_t *q,
676                 sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
677                 sdb_object_t *user_data)
679         return sdb_memstore_query_execute(SDB_MEMSTORE(user_data),
680                         QUERY(q), w, wd, errbuf);
681 } /* execute_query */
683 sdb_store_reader_t sdb_memstore_reader = {
684         prepare_query, execute_query,
685 };
687 /*
688  * public API
689  */
691 sdb_memstore_t *
692 sdb_memstore_create(void)
694         return SDB_MEMSTORE(sdb_object_create("memstore", store_type));
695 } /* sdb_memstore_create */
697 int
698 sdb_memstore_host(sdb_memstore_t *store, const char *name,
699                 sdb_time_t last_update, sdb_time_t interval)
701         sdb_store_host_t host = {
702                 name, last_update, interval, NULL, 0,
703         };
704         return store_host(&host, SDB_OBJ(store));
705 } /* sdb_memstore_host */
707 int
708 sdb_memstore_service(sdb_memstore_t *store, const char *hostname, const char *name,
709                 sdb_time_t last_update, sdb_time_t interval)
711         sdb_store_service_t service = {
712                 hostname, name, last_update, interval, NULL, 0,
713         };
714         return store_service(&service, SDB_OBJ(store));
715 } /* sdb_memstore_service */
717 int
718 sdb_memstore_metric(sdb_memstore_t *store, const char *hostname, const char *name,
719                 sdb_metric_store_t *metric_store,
720                 sdb_time_t last_update, sdb_time_t interval)
722         sdb_store_metric_t metric = {
723                 hostname, name, { NULL, NULL }, last_update, interval, NULL, 0,
724         };
725         if (metric_store) {
726                 metric.store.type = metric_store->type;
727                 metric.store.id = metric_store->id;
728         }
729         return store_metric(&metric, SDB_OBJ(store));
730 } /* sdb_memstore_metric */
732 int
733 sdb_memstore_attribute(sdb_memstore_t *store, const char *hostname,
734                 const char *key, const sdb_data_t *value,
735                 sdb_time_t last_update, sdb_time_t interval)
737         sdb_store_attribute_t attr = {
738                 NULL, SDB_HOST, hostname, key, SDB_DATA_INIT,
739                 last_update, interval, NULL, 0,
740         };
741         if (value) {
742                 attr.value = *value;
743         }
744         return store_attribute(&attr, SDB_OBJ(store));
745 } /* sdb_memstore_attribute */
747 int
748 sdb_memstore_service_attr(sdb_memstore_t *store, const char *hostname,
749                 const char *service, const char *key, const sdb_data_t *value,
750                 sdb_time_t last_update, sdb_time_t interval)
752         sdb_store_attribute_t attr = {
753                 hostname, SDB_SERVICE, service, key, SDB_DATA_INIT,
754                 last_update, interval, NULL, 0,
755         };
756         if (value) {
757                 attr.value = *value;
758         }
759         return store_attribute(&attr, SDB_OBJ(store));
760 } /* sdb_memstore_service_attr */
762 int
763 sdb_memstore_metric_attr(sdb_memstore_t *store, const char *hostname,
764                 const char *metric, const char *key, const sdb_data_t *value,
765                 sdb_time_t last_update, sdb_time_t interval)
767         sdb_store_attribute_t attr = {
768                 hostname, SDB_METRIC, metric, key, SDB_DATA_INIT,
769                 last_update, interval, NULL, 0,
770         };
771         if (value) {
772                 attr.value = *value;
773         }
774         return store_attribute(&attr, SDB_OBJ(store));
775 } /* sdb_memstore_metric_attr */
777 sdb_memstore_obj_t *
778 sdb_memstore_get_host(sdb_memstore_t *store, const char *name)
780         host_t *host;
782         if ((! store) || (! name))
783                 return NULL;
785         host = HOST(sdb_avltree_lookup(store->hosts, name));
786         if (! host)
787                 return NULL;
789         return STORE_OBJ(host);
790 } /* sdb_memstore_get_host */
792 sdb_memstore_obj_t *
793 sdb_memstore_get_child(sdb_memstore_obj_t *obj, int type, const char *name)
795         sdb_avltree_t *children = NULL;
797         if ((! obj) || (! name))
798                 return NULL;
800         if (type & SDB_ATTRIBUTE)
801                 children = get_obj_attrs(obj);
802         else if (obj->type == SDB_HOST)
803                 children = get_host_children(HOST(obj), type);
804         if (! children)
805                 return NULL;
806         return STORE_OBJ(sdb_avltree_lookup(children, name));
807 } /* sdb_memstore_get_child */
809 int
810 sdb_memstore_get_field(sdb_memstore_obj_t *obj, int field, sdb_data_t *res)
812         sdb_data_t tmp;
814         if (! obj)
815                 return -1;
817         switch (field) {
818                 case SDB_FIELD_NAME:
819                         tmp.type = SDB_TYPE_STRING;
820                         tmp.data.string = strdup(SDB_OBJ(obj)->name);
821                         if (! tmp.data.string)
822                                 return -1;
823                         break;
824                 case SDB_FIELD_LAST_UPDATE:
825                         tmp.type = SDB_TYPE_DATETIME;
826                         tmp.data.datetime = obj->last_update;
827                         break;
828                 case SDB_FIELD_AGE:
829                         tmp.type = SDB_TYPE_DATETIME;
830                         tmp.data.datetime = sdb_gettime() - obj->last_update;
831                         break;
832                 case SDB_FIELD_INTERVAL:
833                         tmp.type = SDB_TYPE_DATETIME;
834                         tmp.data.datetime = obj->interval;
835                         break;
836                 case SDB_FIELD_BACKEND:
837                         if (! res)
838                                 return 0;
839                         tmp.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING;
840                         tmp.data.array.length = obj->backends_num;
841                         tmp.data.array.values = obj->backends;
842                         return sdb_data_copy(res, &tmp);
843                 case SDB_FIELD_VALUE:
844                         if (obj->type != SDB_ATTRIBUTE)
845                                 return -1;
846                         if (! res)
847                                 return 0;
848                         return sdb_data_copy(res, &ATTR(obj)->value);
849                 case SDB_FIELD_TIMESERIES:
850                         if (obj->type != SDB_METRIC)
851                                 return -1;
852                         tmp.type = SDB_TYPE_BOOLEAN;
853                         tmp.data.boolean = METRIC(obj)->store.type != NULL;
854                 default:
855                         return -1;
856         }
857         if (res)
858                 *res = tmp;
859         else
860                 sdb_data_free_datum(&tmp);
861         return 0;
862 } /* sdb_memstore_get_field */
864 int
865 sdb_memstore_get_attr(sdb_memstore_obj_t *obj, const char *name, sdb_data_t *res,
866                 sdb_memstore_matcher_t *filter)
868         sdb_memstore_obj_t *attr;
870         if ((! obj) || (! name))
871                 return -1;
873         attr = STORE_OBJ(sdb_avltree_lookup(get_obj_attrs(obj), name));
874         if (! attr)
875                 return -1;
876         if (filter && (! sdb_memstore_matcher_matches(filter, attr, NULL))) {
877                 sdb_object_deref(SDB_OBJ(attr));
878                 return -1;
879         }
881         assert(STORE_OBJ(attr)->type == SDB_ATTRIBUTE);
882         if (res)
883                 sdb_data_copy(res, &ATTR(attr)->value);
884         sdb_object_deref(SDB_OBJ(attr));
885         return 0;
886 } /* sdb_memstore_get_attr */
888 int
889 sdb_memstore_scan(sdb_memstore_t *store, int type,
890                 sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter,
891                 sdb_memstore_lookup_cb cb, void *user_data)
893         sdb_avltree_iter_t *host_iter = NULL;
894         int status = 0;
896         if ((! store) || (! cb))
897                 return -1;
899         if ((type != SDB_HOST) && (type != SDB_SERVICE) && (type != SDB_METRIC)) {
900                 sdb_log(SDB_LOG_ERR, "memstore: Cannot scan objects of type %d", type);
901                 return -1;
902         }
904         pthread_rwlock_rdlock(&store->host_lock);
905         host_iter = sdb_avltree_get_iter(store->hosts);
906         if (! host_iter)
907                 status = -1;
909         /* has_next returns false if the iterator is NULL */
910         while (sdb_avltree_iter_has_next(host_iter)) {
911                 sdb_memstore_obj_t *host;
912                 sdb_avltree_iter_t *iter = NULL;
914                 host = STORE_OBJ(sdb_avltree_iter_get_next(host_iter));
915                 assert(host);
917                 if (! sdb_memstore_matcher_matches(filter, host, NULL))
918                         continue;
920                 if (type == SDB_SERVICE)
921                         iter = sdb_avltree_get_iter(HOST(host)->services);
922                 else if (type == SDB_METRIC)
923                         iter = sdb_avltree_get_iter(HOST(host)->metrics);
925                 if (iter) {
926                         while (sdb_avltree_iter_has_next(iter)) {
927                                 sdb_memstore_obj_t *obj;
928                                 obj = STORE_OBJ(sdb_avltree_iter_get_next(iter));
929                                 assert(obj);
931                                 if (sdb_memstore_matcher_matches(m, obj, filter)) {
932                                         if (cb(obj, filter, user_data)) {
933                                                 sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
934                                                                 "an error while scanning");
935                                                 status = -1;
936                                                 break;
937                                         }
938                                 }
939                         }
940                 }
941                 else if (sdb_memstore_matcher_matches(m, host, filter)) {
942                         if (cb(host, filter, user_data)) {
943                                 sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
944                                                 "an error while scanning");
945                                 status = -1;
946                         }
947                 }
949                 sdb_avltree_iter_destroy(iter);
950                 if (status)
951                         break;
952         }
954         sdb_avltree_iter_destroy(host_iter);
955         pthread_rwlock_unlock(&store->host_lock);
956         return status;
957 } /* sdb_memstore_scan */
959 int
960 sdb_memstore_emit(sdb_memstore_obj_t *obj, sdb_store_writer_t *w, sdb_object_t *wd)
962         if ((! obj) || (! w))
963                 return -1;
965         switch (obj->type) {
966         case SDB_HOST:
967                 {
968                         sdb_store_host_t host = {
969                                 obj->_name,
970                                 obj->last_update,
971                                 obj->interval,
972                                 (const char * const *)obj->backends,
973                                 obj->backends_num,
974                         };
975                         if (! w->store_host)
976                                 return -1;
977                         return w->store_host(&host, wd);
978                 }
979         case SDB_SERVICE:
980                 {
981                         sdb_store_service_t service = {
982                                 obj->parent ? obj->parent->_name : NULL,
983                                 obj->_name,
984                                 obj->last_update,
985                                 obj->interval,
986                                 (const char * const *)obj->backends,
987                                 obj->backends_num,
988                         };
989                         if (! w->store_service)
990                                 return -1;
991                         return w->store_service(&service, wd);
992                 }
993         case SDB_METRIC:
994                 {
995                         sdb_store_metric_t metric = {
996                                 obj->parent ? obj->parent->_name : NULL,
997                                 obj->_name,
998                                 {
999                                         METRIC(obj)->store.type,
1000                                         METRIC(obj)->store.id,
1001                                 },
1002                                 obj->last_update,
1003                                 obj->interval,
1004                                 (const char * const *)obj->backends,
1005                                 obj->backends_num,
1006                         };
1007                         if (! w->store_metric)
1008                                 return -1;
1009                         return w->store_metric(&metric, wd);
1010                 }
1011         case SDB_ATTRIBUTE:
1012                 {
1013                         sdb_store_attribute_t attr = {
1014                                 NULL,
1015                                 obj->parent ? obj->parent->type : 0,
1016                                 obj->parent ? obj->parent->_name : NULL,
1017                                 obj->_name,
1018                                 ATTR(obj)->value,
1019                                 obj->last_update,
1020                                 obj->interval,
1021                                 (const char * const *)obj->backends,
1022                                 obj->backends_num,
1023                         };
1024                         if (obj->parent && (obj->parent->type != SDB_HOST)
1025                                         && obj->parent->parent)
1026                                 attr.hostname = obj->parent->parent->_name;
1027                         if (! w->store_attribute)
1028                                 return -1;
1029                         return w->store_attribute(&attr, wd);
1030                 }
1031         }
1033         return -1;
1034 } /* sdb_memstore_emit */
1036 int
1037 sdb_memstore_emit_full(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter,
1038                 sdb_store_writer_t *w, sdb_object_t *wd)
1040         sdb_avltree_t *trees[] = { NULL, NULL, NULL };
1041         size_t i;
1043         if (sdb_memstore_emit(obj, w, wd))
1044                 return -1;
1046         if (obj->type == SDB_HOST) {
1047                 trees[0] = HOST(obj)->attributes;
1048                 trees[1] = HOST(obj)->metrics;
1049                 trees[2] = HOST(obj)->services;
1050         }
1051         else if (obj->type == SDB_SERVICE)
1052                 trees[0] = SVC(obj)->attributes;
1053         else if (obj->type == SDB_METRIC)
1054                 trees[0] = METRIC(obj)->attributes;
1055         else if (obj->type == SDB_ATTRIBUTE)
1056                 return 0;
1057         else
1058                 return -1;
1060         for (i = 0; i < SDB_STATIC_ARRAY_LEN(trees); ++i) {
1061                 sdb_avltree_iter_t *iter;
1063                 if (! trees[i])
1064                         continue;
1066                 iter = sdb_avltree_get_iter(trees[i]);
1067                 while (sdb_avltree_iter_has_next(iter)) {
1068                         sdb_memstore_obj_t *child;
1069                         child = STORE_OBJ(sdb_avltree_iter_get_next(iter));
1071                         if (filter && (! sdb_memstore_matcher_matches(filter, child, NULL)))
1072                                 continue;
1074                         if (sdb_memstore_emit_full(child, filter, w, wd)) {
1075                                 sdb_avltree_iter_destroy(iter);
1076                                 return -1;
1077                         }
1078                 }
1079                 sdb_avltree_iter_destroy(iter);
1080         }
1081         return 0;
1082 } /* sdb_memstore_emit_full */
1084 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */