Code

store: Added support for storing metric objects.
[sysdb.git] / src / core / store.c
1 /*
2  * SysDB - src/core/store.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/store-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 variables
50  */
52 static sdb_avltree_t *hosts = NULL;
53 static pthread_rwlock_t host_lock = PTHREAD_RWLOCK_INITIALIZER;
55 /*
56  * private types
57  */
59 static sdb_type_t sdb_host_type;
60 static sdb_type_t sdb_service_type;
61 static sdb_type_t sdb_metric_type;
62 static sdb_type_t sdb_attribute_type;
64 static int
65 store_obj_init(sdb_object_t *obj, va_list ap)
66 {
67         sdb_store_obj_t *sobj = STORE_OBJ(obj);
69         sobj->type = va_arg(ap, int);
71         sobj->last_update = va_arg(ap, sdb_time_t);
72         sobj->interval = 0;
73         sobj->backends = NULL;
74         sobj->backends_num = 0;
75         sobj->parent = NULL;
76         return 0;
77 } /* store_obj_init */
79 static void
80 store_obj_destroy(sdb_object_t *obj)
81 {
82         sdb_store_obj_t *sobj = STORE_OBJ(obj);
83         size_t i;
85         for (i = 0; i < sobj->backends_num; ++i)
86                 free(sobj->backends[i]);
87         free(sobj->backends);
88         sobj->backends = NULL;
89         sobj->backends_num = 0;
91         if (sobj->parent)
92                 sdb_object_deref(SDB_OBJ(sobj->parent));
93 } /* store_obj_destroy */
95 static int
96 sdb_host_init(sdb_object_t *obj, va_list ap)
97 {
98         sdb_host_t *sobj = HOST(obj);
99         int ret;
101         /* this will consume the first argument (type) of ap */
102         ret = store_obj_init(obj, ap);
103         if (ret)
104                 return ret;
106         sobj->services = sdb_avltree_create();
107         if (! sobj->services)
108                 return -1;
109         sobj->metrics = sdb_avltree_create();
110         if (! sobj->metrics)
111                 return -1;
112         sobj->attributes = sdb_avltree_create();
113         if (! sobj->attributes)
114                 return -1;
115         return 0;
116 } /* sdb_host_init */
118 static void
119 sdb_host_destroy(sdb_object_t *obj)
121         sdb_host_t *sobj = HOST(obj);
122         assert(obj);
124         store_obj_destroy(obj);
126         if (sobj->services)
127                 sdb_avltree_destroy(sobj->services);
128         if (sobj->metrics)
129                 sdb_avltree_destroy(sobj->metrics);
130         if (sobj->attributes)
131                 sdb_avltree_destroy(sobj->attributes);
132 } /* sdb_host_destroy */
134 static int
135 sdb_service_init(sdb_object_t *obj, va_list ap)
137         sdb_service_t *sobj = SVC(obj);
138         int ret;
140         /* this will consume the first argument (type) of ap */
141         ret = store_obj_init(obj, ap);
142         if (ret)
143                 return ret;
145         sobj->attributes = sdb_avltree_create();
146         if (! sobj->attributes)
147                 return -1;
148         return 0;
149 } /* sdb_service_init */
151 static void
152 sdb_service_destroy(sdb_object_t *obj)
154         sdb_service_t *sobj = SVC(obj);
155         assert(obj);
157         store_obj_destroy(obj);
159         if (sobj->attributes)
160                 sdb_avltree_destroy(sobj->attributes);
161 } /* sdb_service_destroy */
163 static int
164 sdb_metric_init(sdb_object_t *obj, va_list ap)
166         sdb_metric_t *sobj = METRIC(obj);
167         int ret;
169         /* this will consume the first argument (type) of ap */
170         ret = store_obj_init(obj, ap);
171         if (ret)
172                 return ret;
174         sobj->attributes = sdb_avltree_create();
175         if (! sobj->attributes)
176                 return -1;
177         return 0;
178 } /* sdb_metric_init */
180 static void
181 sdb_metric_destroy(sdb_object_t *obj)
183         sdb_metric_t *sobj = METRIC(obj);
184         assert(obj);
186         store_obj_destroy(obj);
188         if (sobj->attributes)
189                 sdb_avltree_destroy(sobj->attributes);
190 } /* sdb_metric_destroy */
192 static int
193 sdb_attr_init(sdb_object_t *obj, va_list ap)
195         const sdb_data_t *value;
196         int ret;
198         /* this will consume the first two arguments
199          * (type and last_update) of ap */
200         ret = store_obj_init(obj, ap);
201         if (ret)
202                 return ret;
203         value = va_arg(ap, const sdb_data_t *);
205         if (value)
206                 if (sdb_data_copy(&ATTR(obj)->value, value))
207                         return -1;
208         return 0;
209 } /* sdb_attr_init */
211 static void
212 sdb_attr_destroy(sdb_object_t *obj)
214         assert(obj);
216         store_obj_destroy(obj);
217         sdb_data_free_datum(&ATTR(obj)->value);
218 } /* sdb_attr_destroy */
220 static sdb_type_t sdb_host_type = {
221         sizeof(sdb_host_t),
222         sdb_host_init,
223         sdb_host_destroy
224 };
226 static sdb_type_t sdb_service_type = {
227         sizeof(sdb_service_t),
228         sdb_service_init,
229         sdb_service_destroy
230 };
232 static sdb_type_t sdb_metric_type = {
233         sizeof(sdb_metric_t),
234         sdb_metric_init,
235         sdb_metric_destroy
236 };
238 static sdb_type_t sdb_attribute_type = {
239         sizeof(sdb_attribute_t),
240         sdb_attr_init,
241         sdb_attr_destroy
242 };
244 /*
245  * private helper functions
246  */
248 static sdb_host_t *
249 lookup_host(const char *name)
251         return HOST(sdb_avltree_lookup(hosts, name));
252 } /* lookup_host */
254 static int
255 record_backend(sdb_store_obj_t *obj)
257         const sdb_plugin_info_t *info;
258         char **tmp;
259         size_t i;
261         info = sdb_plugin_current();
262         if (! info)
263                 return 0;
265         for (i = 0; i < obj->backends_num; ++i)
266                 if (!strcasecmp(obj->backends[i], info->plugin_name))
267                         return 0;
269         tmp = realloc(obj->backends,
270                         (obj->backends_num + 1) * sizeof(*obj->backends));
271         if (! tmp)
272                 return -1;
274         obj->backends = tmp;
275         obj->backends[obj->backends_num] = strdup(info->plugin_name);
276         if (! obj->backends[obj->backends_num])
277                 return -1;
279         ++obj->backends_num;
280         return 0;
281 } /* record_backend */
283 static int
284 store_obj(sdb_avltree_t *parent_tree, int type, const char *name,
285                 sdb_time_t last_update, sdb_store_obj_t **updated_obj)
287         sdb_store_obj_t *old, *new;
288         int status = 0;
290         assert(parent_tree);
292         if (last_update <= 0)
293                 last_update = sdb_gettime();
295         old = STORE_OBJ(sdb_avltree_lookup(parent_tree, name));
296         if (old) {
297                 if (old->last_update > last_update) {
298                         sdb_log(SDB_LOG_DEBUG, "store: Cannot update %s '%s' - "
299                                         "value too old (%"PRIsdbTIME" < %"PRIsdbTIME")",
300                                         SDB_STORE_TYPE_TO_NAME(type), name,
301                                         last_update, old->last_update);
302                         /* don't report an error; the object may be updated by multiple
303                          * backends */
304                         status = 1;
305                 }
306                 else if (old->last_update == last_update) {
307                         /* don't report an error and also don't even log this to avoid
308                          * excessive noise on high sampling frequencies */
309                         status = 1;
310                 }
311                 else {
312                         sdb_time_t interval = last_update - old->last_update;
313                         old->last_update = last_update;
314                         if (interval) {
315                                 if (old->interval)
316                                         old->interval = (sdb_time_t)((0.9 * (double)old->interval)
317                                                         + (0.1 * (double)interval));
318                                 else
319                                         old->interval = interval;
320                         }
321                 }
323                 new = old;
324                 sdb_object_deref(SDB_OBJ(old));
325         }
326         else {
327                 if (type == SDB_ATTRIBUTE) {
328                         /* the value will be updated by the caller */
329                         new = STORE_OBJ(sdb_object_create(name, sdb_attribute_type,
330                                                 type, last_update, NULL));
331                 }
332                 else {
333                         sdb_type_t t;
334                         t = type == SDB_HOST
335                                 ? sdb_host_type
336                                 : type == SDB_SERVICE
337                                         ? sdb_service_type
338                                         : sdb_metric_type;
339                         new = STORE_OBJ(sdb_object_create(name, t, type, last_update));
340                 }
342                 if (new) {
343                         status = sdb_avltree_insert(parent_tree, SDB_OBJ(new));
345                         /* pass control to the tree or destroy in case of an error */
346                         sdb_object_deref(SDB_OBJ(new));
347                 }
348                 else {
349                         char errbuf[1024];
350                         sdb_log(SDB_LOG_ERR, "store: Failed to create %s '%s': %s",
351                                         SDB_STORE_TYPE_TO_NAME(type), name,
352                                         sdb_strerror(errno, errbuf, sizeof(errbuf)));
353                         status = -1;
354                 }
355         }
357         if (status < 0)
358                 return status;
359         assert(new);
361         if (updated_obj)
362                 *updated_obj = new;
364         if (record_backend(new))
365                 return -1;
366         return status;
367 } /* store_obj */
369 static int
370 store_attr(sdb_avltree_t *attributes, const char *key, const sdb_data_t *value,
371                 sdb_time_t last_update)
373         sdb_store_obj_t *attr = NULL;
374         int status;
376         status = store_obj(attributes, SDB_ATTRIBUTE, key, last_update, &attr);
377         if (status)
378                 return status;
380         /* don't update unchanged values */
381         if (! sdb_data_cmp(&ATTR(attr)->value, value))
382                 return status;
384         assert(attr);
385         if (sdb_data_copy(&ATTR(attr)->value, value))
386                 return -1;
387         return status;
388 } /* store_attr */
390 /* The host_lock has to be acquired before calling this function. */
391 static sdb_avltree_t *
392 get_host_children(const char *hostname, int type)
394         char *cname = NULL;
395         sdb_host_t *host;
397         assert(hostname);
398         assert((type == SDB_SERVICE) || (type == SDB_METRIC)
399                         || (type == SDB_ATTRIBUTE));
401         if (! hosts)
402                 return NULL;
404         cname = sdb_plugin_cname(strdup(hostname));
405         if (! cname) {
406                 sdb_log(SDB_LOG_ERR, "store: strdup failed");
407                 return NULL;
408         }
410         host = lookup_host(cname);
411         free(cname);
412         if (! host)
413                 return NULL;
415         sdb_object_deref(SDB_OBJ(host));
416         if (type == SDB_ATTRIBUTE)
417                 return host->attributes;
418         else if (type == SDB_METRIC)
419                 return host->metrics;
420         else
421                 return host->services;
422 } /* get_host_children */
424 /*
425  * store_common_tojson serializes common object attributes to JSON.
426  *
427  * The function never returns an error. Rather, an error message will be part
428  * of the serialized data.
429  */
430 static void
431 store_common_tojson(sdb_store_obj_t *obj, sdb_strbuf_t *buf)
433         char time_str[64];
434         char interval_str[64];
435         size_t i;
437         if (! sdb_strftime(time_str, sizeof(time_str),
438                                 "%F %T %z", obj->last_update))
439                 snprintf(time_str, sizeof(time_str), "<error>");
440         time_str[sizeof(time_str) - 1] = '\0';
442         if (! sdb_strfinterval(interval_str, sizeof(interval_str),
443                                 obj->interval))
444                 snprintf(interval_str, sizeof(interval_str), "<error>");
445         interval_str[sizeof(interval_str) - 1] = '\0';
447         sdb_strbuf_append(buf, "\"last_update\": \"%s\", "
448                         "\"update_interval\": \"%s\", \"backends\": [",
449                         time_str, interval_str);
451         for (i = 0; i < obj->backends_num; ++i) {
452                 sdb_strbuf_append(buf, "\"%s\"", obj->backends[i]);
453                 if (i < obj->backends_num - 1)
454                         sdb_strbuf_append(buf, ",");
455         }
456         sdb_strbuf_append(buf, "]");
457 } /* store_common_tojson */
459 /*
460  * store_obj_tojson serializes attribute / metric / service objects to JSON.
461  *
462  * The function never returns an error. Rather, an error message will be part
463  * of the serialized data.
464  */
465 static void
466 store_obj_tojson(sdb_avltree_t *tree, int type, sdb_strbuf_t *buf,
467                 sdb_store_matcher_t *filter, int flags)
469         sdb_avltree_iter_t *iter;
471         assert((type == SDB_ATTRIBUTE)
472                         || (type == SDB_METRIC)
473                         || (type == SDB_SERVICE));
475         sdb_strbuf_append(buf, "[");
476         iter = sdb_avltree_get_iter(tree);
477         if (! iter) {
478                 char errbuf[1024];
479                 sdb_log(SDB_LOG_ERR, "store: Failed to retrieve %ss: %s\n",
480                                 SDB_STORE_TYPE_TO_NAME(type),
481                                 sdb_strerror(errno, errbuf, sizeof(errbuf)));
482                 sdb_strbuf_append(buf, "{\"error\": \"failed to retrieve %ss: %s\"}",
483                                 SDB_STORE_TYPE_TO_NAME(type), errbuf);
484         }
486         /* has_next returns false if the iterator is NULL */
487         while (sdb_avltree_iter_has_next(iter)) {
488                 sdb_store_obj_t *sobj = STORE_OBJ(sdb_avltree_iter_get_next(iter));
489                 assert(sobj);
490                 assert(sobj->type == type);
492                 if (filter && (! sdb_store_matcher_matches(filter, sobj, NULL)))
493                         continue;
495                 sdb_strbuf_append(buf, "{\"name\": \"%s\", ", SDB_OBJ(sobj)->name);
496                 if (sobj->type == SDB_ATTRIBUTE) {
497                         char tmp[sdb_data_strlen(&ATTR(sobj)->value) + 1];
498                         sdb_data_format(&ATTR(sobj)->value, tmp, sizeof(tmp),
499                                         SDB_DOUBLE_QUOTED);
500                         sdb_strbuf_append(buf, "\"value\": %s, ", tmp);
501                 }
502                 store_common_tojson(sobj, buf);
504                 if ((sobj->type == SDB_SERVICE)
505                                 && (! (flags & SDB_SKIP_ATTRIBUTES))) {
506                         sdb_strbuf_append(buf, ", \"attributes\": ");
507                         store_obj_tojson(SVC(sobj)->attributes, SDB_ATTRIBUTE,
508                                         buf, filter, flags);
509                 }
510                 else if ((sobj->type == SDB_METRIC)
511                                 && (! (flags & SDB_SKIP_ATTRIBUTES))) {
512                         sdb_strbuf_append(buf, ", \"attributes\": ");
513                         store_obj_tojson(METRIC(sobj)->attributes, SDB_ATTRIBUTE,
514                                         buf, filter, flags);
515                 }
516                 sdb_strbuf_append(buf, "}");
518                 if (sdb_avltree_iter_has_next(iter))
519                         sdb_strbuf_append(buf, ",");
520         }
522         sdb_avltree_iter_destroy(iter);
523         sdb_strbuf_append(buf, "]");
524 } /* store_obj_tojson */
526 /*
527  * public API
528  */
530 void
531 sdb_store_clear(void)
533         sdb_avltree_destroy(hosts);
534         hosts = NULL;
535 } /* sdb_store_clear */
537 int
538 sdb_store_host(const char *name, sdb_time_t last_update)
540         char *cname = NULL;
541         int status = 0;
543         if (! name)
544                 return -1;
546         cname = sdb_plugin_cname(strdup(name));
547         if (! cname) {
548                 sdb_log(SDB_LOG_ERR, "store: strdup failed");
549                 return -1;
550         }
552         pthread_rwlock_wrlock(&host_lock);
553         if (! hosts)
554                 if (! (hosts = sdb_avltree_create()))
555                         status = -1;
557         if (! status)
558                 status = store_obj(hosts, SDB_HOST, cname, last_update, NULL);
559         pthread_rwlock_unlock(&host_lock);
561         free(cname);
562         return status;
563 } /* sdb_store_host */
565 _Bool
566 sdb_store_has_host(const char *name)
568         sdb_host_t *host;
570         if (! name)
571                 return NULL;
573         host = lookup_host(name);
574         return host != NULL;
575 } /* sdb_store_has_host */
577 sdb_store_obj_t *
578 sdb_store_get_host(const char *name)
580         sdb_host_t *host;
582         if (! name)
583                 return NULL;
585         host = lookup_host(name);
586         if (! host)
587                 return NULL;
589         return STORE_OBJ(host);
590 } /* sdb_store_get_host */
592 int
593 sdb_store_attribute(const char *hostname,
594                 const char *key, const sdb_data_t *value,
595                 sdb_time_t last_update)
597         sdb_avltree_t *attrs;
598         int status = 0;
600         if ((! hostname) || (! key))
601                 return -1;
603         pthread_rwlock_wrlock(&host_lock);
604         attrs = get_host_children(hostname, SDB_ATTRIBUTE);
605         if (! attrs) {
606                 sdb_log(SDB_LOG_ERR, "store: Failed to store attribute '%s' - "
607                                 "host '%s' not found", key, hostname);
608                 status = -1;
609         }
611         if (! status)
612                 status = store_attr(attrs, key, value, last_update);
614         pthread_rwlock_unlock(&host_lock);
615         return status;
616 } /* sdb_store_attribute */
618 int
619 sdb_store_service(const char *hostname, const char *name,
620                 sdb_time_t last_update)
622         sdb_avltree_t *services;
624         int status = 0;
626         if ((! hostname) || (! name))
627                 return -1;
629         pthread_rwlock_wrlock(&host_lock);
630         services = get_host_children(hostname, SDB_SERVICE);
631         if (! services) {
632                 sdb_log(SDB_LOG_ERR, "store: Failed to store service '%s' - "
633                                 "host '%s' not found", name, hostname);
634                 status = -1;
635         }
637         if (! status)
638                 status = store_obj(services, SDB_SERVICE, name, last_update, NULL);
639         pthread_rwlock_unlock(&host_lock);
640         return status;
641 } /* sdb_store_service */
643 int
644 sdb_store_service_attr(const char *hostname, const char *service,
645                 const char *key, const sdb_data_t *value, sdb_time_t last_update)
647         sdb_avltree_t *services;
648         sdb_service_t *svc;
649         int status = 0;
651         if ((! hostname) || (! service) || (! key))
652                 return -1;
654         pthread_rwlock_wrlock(&host_lock);
655         services = get_host_children(hostname, SDB_SERVICE);
656         if (! services) {
657                 sdb_log(SDB_LOG_ERR, "store: Failed to store attribute '%s' "
658                                 "for service '%s' - host '%ss' not found",
659                                 key, service, hostname);
660                 pthread_rwlock_unlock(&host_lock);
661                 return -1;
662         }
664         svc = SVC(sdb_avltree_lookup(services, service));
665         if (! svc) {
666                 sdb_log(SDB_LOG_ERR, "store: Failed to store attribute '%s' - "
667                                 "service '%s/%s' not found", key, hostname, service);
668                 status = -1;
669         }
671         if (! status)
672                 status = store_attr(svc->attributes, key, value, last_update);
674         sdb_object_deref(SDB_OBJ(svc));
675         pthread_rwlock_unlock(&host_lock);
676         return status;
677 } /* sdb_store_service_attr */
679 int
680 sdb_store_metric(const char *hostname, const char *name,
681                 sdb_time_t last_update)
683         sdb_avltree_t *metrics;
685         int status = 0;
687         if ((! hostname) || (! name))
688                 return -1;
690         pthread_rwlock_wrlock(&host_lock);
691         metrics = get_host_children(hostname, SDB_METRIC);
692         if (! metrics) {
693                 sdb_log(SDB_LOG_ERR, "store: Failed to store metric '%s' - "
694                                 "host '%s' not found", name, hostname);
695                 status = -1;
696         }
698         if (! status)
699                 status = store_obj(metrics, SDB_METRIC, name, last_update, NULL);
700         pthread_rwlock_unlock(&host_lock);
701         return status;
702 } /* sdb_store_metric */
704 int
705 sdb_store_metric_attr(const char *hostname, const char *metric,
706                 const char *key, const sdb_data_t *value, sdb_time_t last_update)
708         sdb_avltree_t *metrics;
709         sdb_metric_t *m;
710         int status = 0;
712         if ((! hostname) || (! metric) || (! key))
713                 return -1;
715         pthread_rwlock_wrlock(&host_lock);
716         metrics = get_host_children(hostname, SDB_METRIC);
717         if (! metrics) {
718                 sdb_log(SDB_LOG_ERR, "store: Failed to store attribute '%s' "
719                                 "for metric '%s' - host '%ss' not found",
720                                 key, metric, hostname);
721                 pthread_rwlock_unlock(&host_lock);
722                 return -1;
723         }
725         m = METRIC(sdb_avltree_lookup(metrics, metric));
726         if (! m) {
727                 sdb_log(SDB_LOG_ERR, "store: Failed to store attribute '%s' - "
728                                 "metric '%s/%s' not found", key, hostname, metric);
729                 status = -1;
730         }
732         if (! status)
733                 status = store_attr(m->attributes, key, value, last_update);
735         sdb_object_deref(SDB_OBJ(m));
736         pthread_rwlock_unlock(&host_lock);
737         return status;
738 } /* sdb_store_metric_attr */
740 int
741 sdb_store_get_field(sdb_store_obj_t *obj, int field, sdb_data_t *res)
743         if ((! obj) || (! res))
744                 return -1;
746         switch (field) {
747                 case SDB_FIELD_LAST_UPDATE:
748                         res->type = SDB_TYPE_DATETIME;
749                         res->data.datetime = obj->last_update;
750                         break;
751                 case SDB_FIELD_AGE:
752                         res->type = SDB_TYPE_DATETIME;
753                         res->data.datetime = sdb_gettime() - obj->last_update;
754                         break;
755                 case SDB_FIELD_INTERVAL:
756                         res->type = SDB_TYPE_DATETIME;
757                         res->data.datetime = obj->interval;
758                         break;
759                 case SDB_FIELD_BACKEND:
760                         /* TODO: add support for storing array values in a data object
761                          * for now, fall thru to the error case */
762                 default:
763                         return -1;
764         }
765         return 0;
766 } /* sdb_store_get_field */
768 int
769 sdb_store_host_tojson(sdb_store_obj_t *h, sdb_strbuf_t *buf,
770                 sdb_store_matcher_t *filter, int flags)
772         sdb_host_t *host = HOST(h);
774         if ((! h) || (h->type != SDB_HOST) || (! buf))
775                 return -1;
777         sdb_strbuf_append(buf, "{\"name\": \"%s\", ", SDB_OBJ(host)->name);
778         store_common_tojson(h, buf);
780         if (! (flags & SDB_SKIP_ATTRIBUTES)) {
781                 sdb_strbuf_append(buf, ", \"attributes\": ");
782                 store_obj_tojson(host->attributes, SDB_ATTRIBUTE, buf, filter, flags);
783         }
785         if (! (flags & SDB_SKIP_METRICS)) {
786                 sdb_strbuf_append(buf, ", \"metrics\": ");
787                 store_obj_tojson(host->metrics, SDB_METRIC, buf, filter, flags);
788         }
790         if (! (flags & SDB_SKIP_SERVICES)) {
791                 sdb_strbuf_append(buf, ", \"services\": ");
792                 store_obj_tojson(host->services, SDB_SERVICE, buf, filter, flags);
793         }
795         sdb_strbuf_append(buf, "}");
796         return 0;
797 } /* sdb_store_host_tojson */
799 int
800 sdb_store_tojson(sdb_strbuf_t *buf, sdb_store_matcher_t *filter, int flags)
802         sdb_avltree_iter_t *host_iter;
803         size_t len;
805         if (! buf)
806                 return -1;
808         pthread_rwlock_rdlock(&host_lock);
810         host_iter = sdb_avltree_get_iter(hosts);
811         if (! host_iter) {
812                 pthread_rwlock_unlock(&host_lock);
813                 return -1;
814         }
816         sdb_strbuf_append(buf, "{\"hosts\":[");
818         len = sdb_strbuf_len(buf);
819         while (sdb_avltree_iter_has_next(host_iter)) {
820                 sdb_store_obj_t *host;
822                 host = STORE_OBJ(sdb_avltree_iter_get_next(host_iter));
823                 assert(host);
825                 if (filter && (! sdb_store_matcher_matches(filter, host, NULL)))
826                         continue;
828                 if (sdb_strbuf_len(buf) > len)
829                         sdb_strbuf_append(buf, ",");
830                 len = sdb_strbuf_len(buf);
832                 if (sdb_store_host_tojson(host, buf, filter, flags))
833                         return -1;
834         }
836         sdb_strbuf_append(buf, "]}");
838         sdb_avltree_iter_destroy(host_iter);
839         pthread_rwlock_unlock(&host_lock);
840         return 0;
841 } /* sdb_store_tojson */
843 /* TODO: actually support hierarchical data */
844 int
845 sdb_store_iterate(sdb_store_iter_cb cb, void *user_data)
847         sdb_avltree_iter_t *host_iter;
848         int status = 0;
850         pthread_rwlock_rdlock(&host_lock);
852         host_iter = sdb_avltree_get_iter(hosts);
853         if (! host_iter)
854                 status = -1;
856         /* has_next returns false if the iterator is NULL */
857         while (sdb_avltree_iter_has_next(host_iter)) {
858                 sdb_store_obj_t *host;
860                 host = STORE_OBJ(sdb_avltree_iter_get_next(host_iter));
861                 assert(host);
863                 if (cb(host, user_data)) {
864                         status = -1;
865                         break;
866                 }
867         }
869         sdb_avltree_iter_destroy(host_iter);
870         pthread_rwlock_unlock(&host_lock);
871         return status;
872 } /* sdb_store_iterate */
874 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */