From eb1b9560958c3458eab599e4e1577771ab4aa05c Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Mon, 3 Nov 2014 19:35:34 +0100 Subject: [PATCH] store: Added sdb_store_get_child(). This function may be used to retrieve a host's child object (service, metric, attribute) by it's name. --- src/core/store.c | 19 ++++++++- src/include/core/store.h | 14 +++++++ t/unit/core/store_test.c | 91 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 2 deletions(-) diff --git a/src/core/store.c b/src/core/store.c index b206283..d6ad01f 100644 --- a/src/core/store.c +++ b/src/core/store.c @@ -426,8 +426,9 @@ store_attr(sdb_store_obj_t *parent, sdb_avltree_t *attributes, static sdb_avltree_t * get_host_children(sdb_host_t *host, int type) { - assert((type == SDB_SERVICE) || (type == SDB_METRIC) - || (type == SDB_ATTRIBUTE)); + if ((type != SDB_SERVICE) && (type != SDB_METRIC) + && (type != SDB_ATTRIBUTE)) + return NULL; if (! host) return NULL; @@ -762,6 +763,20 @@ sdb_store_metric_attr(const char *hostname, const char *metric, return status; } /* sdb_store_metric_attr */ +sdb_store_obj_t * +sdb_store_get_child(sdb_store_obj_t *host, int type, const char *name) +{ + sdb_avltree_t *children; + + if ((! host) || (host->type != SDB_HOST) || (! name)) + return NULL; + + children = get_host_children(HOST(host), type); + if (! children) + return NULL; + return STORE_OBJ(sdb_avltree_lookup(children, name)); +} /* sdb_store_get_child */ + int sdb_store_fetch_timeseries(const char *hostname, const char *metric, sdb_timeseries_opts_t *opts, sdb_strbuf_t *buf) diff --git a/src/include/core/store.h b/src/include/core/store.h index 9bb7594..b84fc72 100644 --- a/src/include/core/store.h +++ b/src/include/core/store.h @@ -216,6 +216,20 @@ int sdb_store_service_attr(const char *hostname, const char *service, const char *key, const sdb_data_t *value, sdb_time_t last_update); +/* + * sdb_store_get_child: + * Retrieve a host's child object of the specified type and name. The + * reference count of the child object will be incremented before returning + * it. The caller is responsible for releasing the object once it's no longer + * used. + * + * Returns: + * - the child object on success + * - NULL else + */ +sdb_store_obj_t * +sdb_store_get_child(sdb_store_obj_t *host, int type, const char *name); + /* * A metric store describes how to access a metric's data. */ diff --git a/t/unit/core/store_test.c b/t/unit/core/store_test.c index ab3087a..262f681 100644 --- a/t/unit/core/store_test.c +++ b/t/unit/core/store_test.c @@ -31,6 +31,7 @@ #include #include +#include static void populate(void) @@ -501,6 +502,95 @@ START_TEST(test_get_field) } END_TEST +START_TEST(test_get_child) +{ + struct { + const char *host; + const char *name; + int type; + int expected; + } golden_data[] = { + { "h1", NULL, SDB_HOST, 0 }, + { "h1", NULL, SDB_SERVICE, -1 }, + { "h1", NULL, SDB_METRIC, -1 }, + { "h1", NULL, SDB_ATTRIBUTE, -1 }, + { "h2", NULL, SDB_HOST, 0 }, + { "h2", NULL, SDB_SERVICE, -1 }, + { "h2", NULL, SDB_METRIC, -1 }, + { "h2", NULL, SDB_ATTRIBUTE, -1 }, + { "h3", NULL, SDB_HOST, -1 }, + { "h1", "k1", SDB_ATTRIBUTE, 0 }, + { "h1", "x1", SDB_ATTRIBUTE, -1 }, + { "h2", "k1", SDB_ATTRIBUTE, -1 }, + { "h1", "k1", SDB_SERVICE, -1 }, + { "h1", "k1", SDB_METRIC, -1 }, + { "h1", "s1", SDB_SERVICE, -1 }, + { "h2", "s1", SDB_SERVICE, 0 }, + { "h1", "m2", SDB_METRIC, 0 }, + { "h2", "m2", SDB_METRIC, -1 }, + }; + + size_t i; + + populate(); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + sdb_store_obj_t *obj; + const char *expected_name = golden_data[i].host; + + obj = sdb_store_get_host(golden_data[i].host); + if (golden_data[i].expected && (golden_data[i].type == SDB_HOST)) + fail_unless(obj == NULL, + "sdb_store_get_host(%s) = %p; expected: NULL", + golden_data[i].host, obj); + else + fail_unless(obj != NULL, + "sdb_store_get_host(%s) = NULL; expected: ", + golden_data[i].host); + + if (golden_data[i].type != SDB_HOST) { + sdb_store_obj_t *tmp; + + expected_name = golden_data[i].name; + + tmp = sdb_store_get_child(obj, + golden_data[i].type, golden_data[i].name); + if (golden_data[i].expected) + fail_unless(tmp == NULL, + "sdb_store_get_child(<%s>, %s, %s) = %p; " + "expected: NULL", golden_data[i].host, + SDB_STORE_TYPE_TO_NAME(golden_data[i].type), + golden_data[i].name, tmp); + else + fail_unless(tmp != NULL, + "sdb_store_get_child(<%s>, %s, %s) = NULL; " + "expected: ", golden_data[i].host, + SDB_STORE_TYPE_TO_NAME(golden_data[i].type), + golden_data[i].name); + + sdb_object_deref(SDB_OBJ(obj)); + obj = tmp; + } + + if (golden_data[i].expected) + continue; + + fail_unless(obj->type == golden_data[i].type, + "sdb_store_get_<%s>(%s, %s) returned object of type %d; " + "expected: %d", SDB_STORE_TYPE_TO_NAME(golden_data[i].type), + golden_data[i].host, golden_data[i].name, obj->type, + golden_data[i].type); + fail_unless(! strcasecmp(SDB_OBJ(obj)->name, expected_name), + "sdb_store_get_<%s>(%s, %s) returned object named '%s'; " + "expected: '%s'", SDB_STORE_TYPE_TO_NAME(golden_data[i].type), + golden_data[i].host, golden_data[i].name, SDB_OBJ(obj)->name, + expected_name); + + sdb_object_deref(SDB_OBJ(obj)); + } +} +END_TEST + START_TEST(test_interval) { sdb_store_obj_t *host; @@ -663,6 +753,7 @@ core_store_suite(void) tcase_add_test(tc, test_store_service); tcase_add_test(tc, test_store_service_attr); tcase_add_test(tc, test_get_field); + tcase_add_test(tc, test_get_child); tcase_add_test(tc, test_interval); tcase_add_test(tc, test_scan); tcase_add_unchecked_fixture(tc, NULL, sdb_store_clear); -- 2.30.2