X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fcore%2Fstore.c;h=74cbea2703bdd727aca9011de1861a29b587d58f;hb=ebfd78eb79806777c3de889d75a62665ff78eaca;hp=c778c52d7dd4a234890b381bea8fb5434a4bab0a;hpb=eac4c0869db1f50e86910e082d72ed2731b8269a;p=sysdb.git diff --git a/src/core/store.c b/src/core/store.c index c778c52..74cbea2 100644 --- a/src/core/store.c +++ b/src/core/store.c @@ -551,11 +551,11 @@ ts_tojson(sdb_timeseries_t *ts, sdb_strbuf_t *buf) snprintf(start_str, sizeof(start_str), ""); start_str[sizeof(start_str) - 1] = '\0'; if (! sdb_strftime(end_str, sizeof(end_str), - "%F %T %z", ts->start)) + "%F %T %z", ts->end)) snprintf(end_str, sizeof(end_str), ""); end_str[sizeof(end_str) - 1] = '\0'; - sdb_strbuf_append(buf, "{\"start\": \"%s\", \"end\": \"%s\", {", + sdb_strbuf_append(buf, "{\"start\": \"%s\", \"end\": \"%s\", \"data\": {", start_str, end_str); for (i = 0; i < ts->data_names_len; ++i) { @@ -571,7 +571,7 @@ ts_tojson(sdb_timeseries_t *ts, sdb_strbuf_t *buf) time_str[sizeof(time_str) - 1] = '\0'; sdb_strbuf_append(buf, "{\"timestamp\": \"%s\", " - "\"value\": \"%s\"}", time_str, ts->data[i][j].value); + "\"value\": \"%f\"}", time_str, ts->data[i][j].value); if (j < ts->data_len - 1) sdb_strbuf_append(buf, ","); @@ -894,31 +894,91 @@ sdb_store_fetch_timeseries(const char *hostname, const char *metric, int sdb_store_get_field(sdb_store_obj_t *obj, int field, sdb_data_t *res) { - if ((! obj) || (! res)) + sdb_data_t tmp; + + if (! obj) return -1; switch (field) { + case SDB_FIELD_NAME: + tmp.type = SDB_TYPE_STRING; + tmp.data.string = strdup(SDB_OBJ(obj)->name); + if (! tmp.data.string) + return -1; + break; case SDB_FIELD_LAST_UPDATE: - res->type = SDB_TYPE_DATETIME; - res->data.datetime = obj->last_update; + tmp.type = SDB_TYPE_DATETIME; + tmp.data.datetime = obj->last_update; break; case SDB_FIELD_AGE: - res->type = SDB_TYPE_DATETIME; - res->data.datetime = sdb_gettime() - obj->last_update; + tmp.type = SDB_TYPE_DATETIME; + tmp.data.datetime = sdb_gettime() - obj->last_update; break; case SDB_FIELD_INTERVAL: - res->type = SDB_TYPE_DATETIME; - res->data.datetime = obj->interval; + tmp.type = SDB_TYPE_DATETIME; + tmp.data.datetime = obj->interval; break; case SDB_FIELD_BACKEND: - /* TODO: add support for storing array values in a data object - * for now, fall thru to the error case */ + { + tmp.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING; + tmp.data.array.length = obj->backends_num; + tmp.data.array.values = obj->backends; + return sdb_data_copy(res, &tmp); + break; + } default: return -1; } + if (res) + *res = tmp; + else + sdb_data_free_datum(&tmp); return 0; } /* sdb_store_get_field */ +int +sdb_store_get_attr(sdb_store_obj_t *obj, const char *name, sdb_data_t *res, + sdb_store_matcher_t *filter) +{ + sdb_avltree_t *tree = NULL; + sdb_avltree_iter_t *iter = NULL; + + if ((! obj) || (! name)) + return -1; + + if (obj->type == SDB_HOST) + tree = HOST(obj)->attributes; + else if (obj->type == SDB_SERVICE) + tree = SVC(obj)->attributes; + else if (obj->type == SDB_METRIC) + tree = METRIC(obj)->attributes; + + if (! tree) + return -1; + + iter = sdb_avltree_get_iter(tree); + while (sdb_avltree_iter_has_next(iter)) { + sdb_object_t *attr = sdb_avltree_iter_get_next(iter); + + if (strcasecmp(SDB_OBJ(attr)->name, name)) + continue; + + if (filter&& (! sdb_store_matcher_matches(filter, + STORE_OBJ(attr), NULL))) + break; /* found it but it's filtered */ + + assert(STORE_OBJ(attr)->type == SDB_ATTRIBUTE); + if (res) + sdb_data_copy(res, &ATTR(attr)->value); + sdb_avltree_iter_destroy(iter); + return 0; + } + sdb_avltree_iter_destroy(iter); + + /* not found */ + return -1; +} /* sdb_store_get_attr */ + int sdb_store_host_tojson(sdb_store_obj_t *h, sdb_strbuf_t *buf, sdb_store_matcher_t *filter, int flags) @@ -928,6 +988,10 @@ sdb_store_host_tojson(sdb_store_obj_t *h, sdb_strbuf_t *buf, if ((! h) || (h->type != SDB_HOST) || (! buf)) return -1; + /* This function ignores SKIP_EMPTY flags given that the current + * implementation sucks and it's nut currently used when calling this + * function directly. */ + sdb_strbuf_append(buf, "{\"name\": \"%s\", ", SDB_OBJ(host)->name); store_common_tojson(h, buf); @@ -950,6 +1014,26 @@ sdb_store_host_tojson(sdb_store_obj_t *h, sdb_strbuf_t *buf, return 0; } /* sdb_store_host_tojson */ +static _Bool +has_children(sdb_avltree_t *tree, sdb_store_matcher_t *filter) +{ + sdb_avltree_iter_t *iter; + + if (! filter) + return sdb_avltree_size(tree) > 0; + + iter = sdb_avltree_get_iter(tree); + while (sdb_avltree_iter_has_next(iter)) { + sdb_store_obj_t *sobj = STORE_OBJ(sdb_avltree_iter_get_next(iter)); + if (sdb_store_matcher_matches(filter, sobj, NULL)) { + sdb_avltree_iter_destroy(iter); + return 1; + } + } + sdb_avltree_iter_destroy(iter); + return 0; +} /* has_children */ + int sdb_store_tojson(sdb_strbuf_t *buf, sdb_store_matcher_t *filter, int flags) { @@ -967,7 +1051,7 @@ sdb_store_tojson(sdb_strbuf_t *buf, sdb_store_matcher_t *filter, int flags) return -1; } - sdb_strbuf_append(buf, "{\"hosts\":["); + sdb_strbuf_append(buf, "["); len = sdb_strbuf_len(buf); while (sdb_avltree_iter_has_next(host_iter)) { @@ -979,6 +1063,19 @@ sdb_store_tojson(sdb_strbuf_t *buf, sdb_store_matcher_t *filter, int flags) if (filter && (! sdb_store_matcher_matches(filter, host, NULL))) continue; + /* + * XXX: This approach sucks but it's the best we can do at the moment. + * In the future, all store lookups should be split into multiple + * steps instead: first, retrieve all relevant objects and apply all + * pre-processing operations and then format it for the wire. + */ + if ((flags & SDB_SKIP_EMPTY_SERVICES) + && (! has_children(HOST(host)->services, filter))) + continue; + if ((flags & SDB_SKIP_EMPTY_METRICS) + && (! has_children(HOST(host)->metrics, filter))) + continue; + if (sdb_strbuf_len(buf) > len) sdb_strbuf_append(buf, ","); len = sdb_strbuf_len(buf); @@ -987,20 +1084,26 @@ sdb_store_tojson(sdb_strbuf_t *buf, sdb_store_matcher_t *filter, int flags) return -1; } - sdb_strbuf_append(buf, "]}"); + sdb_strbuf_append(buf, "]"); sdb_avltree_iter_destroy(host_iter); pthread_rwlock_unlock(&host_lock); return 0; } /* sdb_store_tojson */ -/* TODO: actually support hierarchical data */ int -sdb_store_iterate(sdb_store_iter_cb cb, void *user_data) +sdb_store_scan(int type, sdb_store_matcher_t *m, sdb_store_matcher_t *filter, + sdb_store_lookup_cb cb, void *user_data) { sdb_avltree_iter_t *host_iter; int status = 0; + if (! cb) + return -1; + + if ((type != SDB_HOST) && (type != SDB_SERVICE) && (type != SDB_METRIC)) + return -1; + pthread_rwlock_rdlock(&host_lock); host_iter = sdb_avltree_get_iter(hosts); @@ -1010,20 +1113,47 @@ sdb_store_iterate(sdb_store_iter_cb cb, void *user_data) /* has_next returns false if the iterator is NULL */ while (sdb_avltree_iter_has_next(host_iter)) { sdb_store_obj_t *host; + sdb_avltree_iter_t *iter = NULL; host = STORE_OBJ(sdb_avltree_iter_get_next(host_iter)); assert(host); - if (cb(host, user_data)) { - status = -1; - break; + if (! sdb_store_matcher_matches(filter, host, NULL)) + continue; + + if (type == SDB_SERVICE) + iter = sdb_avltree_get_iter(HOST(host)->services); + else if (type == SDB_METRIC) + iter = sdb_avltree_get_iter(HOST(host)->metrics); + + if (iter) { + while (sdb_avltree_iter_has_next(iter)) { + sdb_store_obj_t *obj; + obj = STORE_OBJ(sdb_avltree_iter_get_next(iter)); + assert(obj); + + if (sdb_store_matcher_matches(m, obj, filter)) { + if (cb(obj, user_data)) { + status = -1; + break; + } + } + } } + else if (sdb_store_matcher_matches(m, host, filter)) { + if (cb(host, user_data)) + status = -1; + } + + sdb_avltree_iter_destroy(iter); + if (status) + break; } sdb_avltree_iter_destroy(host_iter); pthread_rwlock_unlock(&host_lock); return status; -} /* sdb_store_iterate */ +} /* sdb_store_scan */ /* vim: set tw=78 sw=4 ts=4 noexpandtab : */