From 0a17f3d9f23b988420acbf5669bda4f2a0936c6b Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Fri, 4 Jul 2014 20:38:52 +0200 Subject: [PATCH] store: Introduced service attributes. --- src/core/store.c | 129 ++++++++++++++++++++++++++------------- src/include/core/store.h | 18 ++++++ t/unit/core/store_test.c | 49 +++++++++++++++ 3 files changed, 154 insertions(+), 42 deletions(-) diff --git a/src/core/store.c b/src/core/store.c index fc2a7f4..323ed77 100644 --- a/src/core/store.c +++ b/src/core/store.c @@ -248,6 +248,9 @@ store_obj(sdb_llist_t *parent_list, int type, const char *name, assert(parent_list); + if (last_update <= 0) + last_update = sdb_gettime(); + old = STORE_OBJ(sdb_llist_search_by_name(parent_list, name)); if (old) { if (old->last_update >= last_update) { @@ -313,52 +316,52 @@ store_obj(sdb_llist_t *parent_list, int type, const char *name, return status; } /* store_obj */ -/* The host_lock has to be acquired before calling this function. */ static int -store_host_obj(const char *hostname, int type, const char *name, - sdb_time_t last_update, sdb_store_obj_t **updated_obj) +store_attr(sdb_llist_t *attributes, const char *key, const sdb_data_t *value, + sdb_time_t last_update) { - char *cname = NULL; - sdb_host_t *host; - sdb_llist_t *parent_list; + sdb_store_obj_t *attr = NULL; + int status; - int status = 0; + status = store_obj(attributes, SDB_ATTRIBUTE, key, last_update, &attr); + if (status < 0) + return status; - if (last_update <= 0) - last_update = sdb_gettime(); + assert(attr); + if (sdb_data_copy(&ATTR(attr)->value, value)) + return -1; + return status; +} /* store_attr */ + +/* The host_lock has to be acquired before calling this function. */ +static sdb_llist_t * +get_host_children(const char *hostname, int type) +{ + char *cname = NULL; + sdb_host_t *host; assert(hostname); assert((type == SDB_SERVICE) || (type == SDB_ATTRIBUTE)); if (! host_list) - return -1; + return NULL; cname = sdb_plugin_cname(strdup(hostname)); if (! cname) { sdb_log(SDB_LOG_ERR, "store: strdup failed"); - return -1; + return NULL; } host = lookup_host(cname); - if (! host) { - sdb_log(SDB_LOG_ERR, "store: Failed to store %s '%s' - " - "host '%s' not found", SDB_STORE_TYPE_TO_NAME(type), - name, hostname); - free(cname); - return -1; - } + free(cname); + if (! host) + return NULL; if (type == SDB_ATTRIBUTE) - parent_list = host->attributes; + return host->attributes; else - parent_list = host->services; - - status = store_obj(parent_list, type, name, - last_update, updated_obj); - - free(cname); - return status; -} /* store_host_obj */ + return host->services; +} /* get_host_children */ /* * store_common_tojson serializes common object attributes to JSON. @@ -464,9 +467,6 @@ sdb_store_host(const char *name, sdb_time_t last_update) if (! name) return -1; - if (last_update <= 0) - last_update = sdb_gettime(); - cname = sdb_plugin_cname(strdup(name)); if (! cname) { sdb_log(SDB_LOG_ERR, "store: strdup failed"); @@ -519,23 +519,23 @@ sdb_store_attribute(const char *hostname, const char *key, const sdb_data_t *value, sdb_time_t last_update) { - int status; - - sdb_store_obj_t *updated_attr = NULL; + sdb_llist_t *attrs; + int status = 0; if ((! hostname) || (! key)) return -1; pthread_rwlock_wrlock(&host_lock); - status = store_host_obj(hostname, SDB_ATTRIBUTE, key, last_update, - &updated_attr); - - if (status >= 0) { - assert(updated_attr); - if (sdb_data_copy(&ATTR(updated_attr)->value, value)) - status = -1; + attrs = get_host_children(hostname, SDB_ATTRIBUTE); + if (! attrs) { + sdb_log(SDB_LOG_ERR, "store: Failed to store attribute '%s' - " + "host '%s' not found", key, hostname); + status = -1; } + if (! status) + status = store_attr(attrs, key, value, last_update); + pthread_rwlock_unlock(&host_lock); return status; } /* sdb_store_attribute */ @@ -544,17 +544,62 @@ int sdb_store_service(const char *hostname, const char *name, sdb_time_t last_update) { - int status; + sdb_llist_t *services; + + int status = 0; if ((! hostname) || (! name)) return -1; pthread_rwlock_wrlock(&host_lock); - status = store_host_obj(hostname, SDB_SERVICE, name, last_update, NULL); + services = get_host_children(hostname, SDB_SERVICE); + if (! services) { + sdb_log(SDB_LOG_ERR, "store: Failed to store service '%s' - " + "host '%s' not found", name, hostname); + status = -1; + } + + if (! status) + status = store_obj(services, SDB_SERVICE, name, last_update, NULL); pthread_rwlock_unlock(&host_lock); return status; } /* sdb_store_service */ +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_llist_t *services; + sdb_service_t *svc; + int status = 0; + + if ((! hostname) || (! service) || (! key)) + return -1; + + pthread_rwlock_wrlock(&host_lock); + services = get_host_children(hostname, SDB_SERVICE); + if (! services) { + sdb_log(SDB_LOG_ERR, "store: Failed to store attribute '%s' " + "for service '%s' - host '%ss' not found", + key, service, hostname); + pthread_rwlock_unlock(&host_lock); + return -1; + } + + svc = SVC(sdb_llist_search_by_name(services, service)); + if (! svc) { + sdb_log(SDB_LOG_ERR, "store: Failed to store attribute '%s' - " + "service '%s/%s' not found", key, hostname, service); + status = -1; + } + + if (! status) + status = store_attr(svc->attributes, key, value, last_update); + + pthread_rwlock_unlock(&host_lock); + return status; +} /* sdb_store_service_attr */ + int sdb_store_host_tojson(sdb_store_obj_t *h, sdb_strbuf_t *buf, int flags) { diff --git a/src/include/core/store.h b/src/include/core/store.h index e273e7c..1d64c4b 100644 --- a/src/include/core/store.h +++ b/src/include/core/store.h @@ -141,6 +141,24 @@ int sdb_store_service(const char *hostname, const char *name, sdb_time_t last_update); +/* + * sdb_store_service_attr: + * Add/update a service's attribute in the store. If the attribute, identified + * by its key, already exists for the specified service, it will be updated to + * the specified value. If the references service (for the specified host) + * does not exist, an error will be reported. Any memory required for storing + * the entry will be allocated and managed by the store itself. + * + * Returns: + * - 0 on success + * - a positive value if the new entry is older than the currently stored + * entry (in this case, no update will happen) + * - a negative value on error + */ +int +sdb_store_service_attr(const char *hostname, const char *service, + const char *key, const sdb_data_t *value, sdb_time_t last_update); + /* * Conditionals may be used to lookup hosts from the store based on a * conditional expression. diff --git a/t/unit/core/store_test.c b/t/unit/core/store_test.c index 0a022e4..6715a5b 100644 --- a/t/unit/core/store_test.c +++ b/t/unit/core/store_test.c @@ -240,6 +240,54 @@ START_TEST(test_store_service) } END_TEST +START_TEST(test_store_service_attr) +{ + struct { + const char *host; + const char *svc; + const char *attr; + const sdb_data_t value; + sdb_time_t last_update; + int expected; + } golden_data[] = { + { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 }, + /* retry, it should still fail */ + { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 }, + { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 }, + /* retry, it should still fail */ + { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 }, + { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 }, + { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 }, + { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2, 0 }, + { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 }, + { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 }, + { "l", "s2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 }, + { "m", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 }, + }; + + size_t i; + + sdb_store_host("m", 1); + sdb_store_host("l", 1); + sdb_store_service("m", "s1", 1); + sdb_store_service("l", "s1", 1); + sdb_store_service("l", "s2", 1); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + int status; + + status = sdb_store_service_attr(golden_data[i].host, + golden_data[i].svc, golden_data[i].attr, + &golden_data[i].value, golden_data[i].last_update); + fail_unless(status == golden_data[i].expected, + "sdb_store_service_attr(%s, %s, %s, %d, %d) = %d; " + "expected: %d", golden_data[i].host, golden_data[i].svc, + golden_data[i].attr, golden_data[i].value.data.integer, + golden_data[i].last_update, status, golden_data[i].expected); + } +} +END_TEST + static void verify_json_output(sdb_strbuf_t *buf, const char *expected, int flags) { @@ -497,6 +545,7 @@ core_store_suite(void) tcase_add_test(tc, test_store_get_host); tcase_add_test(tc, test_store_attr); tcase_add_test(tc, test_store_service); + tcase_add_test(tc, test_store_service_attr); tcase_add_test(tc, test_interval); tcase_add_test(tc, test_iterate); tcase_add_unchecked_fixture(tc, NULL, sdb_store_clear); -- 2.30.2