From a0a73b582d908694116271b75cd82c1a49b6466c Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Tue, 1 Apr 2014 21:34:23 +0200 Subject: [PATCH] store: Added sdb_store_iterate(). This function iterates over all (host, for now) objects in the store and calls a user-specified callback for each. --- src/core/store.c | 30 +++++++++++- src/include/core/store.h | 18 +++++++ t/core/store_test.c | 100 +++++++++++++++++++++++++++++++++------ 3 files changed, 132 insertions(+), 16 deletions(-) diff --git a/src/core/store.c b/src/core/store.c index 47ba035..b2fb0f6 100644 --- a/src/core/store.c +++ b/src/core/store.c @@ -525,7 +525,6 @@ sdb_store_host_tojson(sdb_store_base_t *h, sdb_strbuf_t *buf, int flags) return 0; } /* sdb_store_host_tojson */ -/* TODO: actually support hierarchical data */ int sdb_store_tojson(sdb_strbuf_t *buf, int flags) { @@ -562,5 +561,34 @@ sdb_store_tojson(sdb_strbuf_t *buf, int flags) return 0; } /* sdb_store_tojson */ +/* TODO: actually support hierarchical data */ +int +sdb_store_iterate(sdb_store_iter_cb cb, void *user_data) +{ + sdb_llist_iter_t *host_iter; + int status = 0; + + pthread_rwlock_rdlock(&obj_lock); + + host_iter = sdb_llist_get_iter(obj_list); + if (! host_iter) + status = -1; + + /* has_next returns false if the iterator is NULL */ + while (sdb_llist_iter_has_next(host_iter)) { + sdb_store_base_t *host = STORE_BASE(sdb_llist_iter_get_next(host_iter)); + assert(host); + + if (cb(host, user_data)) { + status = -1; + break; + } + } + + sdb_llist_iter_destroy(host_iter); + pthread_rwlock_unlock(&obj_lock); + return status; +} /* sdb_store_iterate */ + /* vim: set tw=78 sw=4 ts=4 noexpandtab : */ diff --git a/src/include/core/store.h b/src/include/core/store.h index 8097508..a149b1d 100644 --- a/src/include/core/store.h +++ b/src/include/core/store.h @@ -230,6 +230,24 @@ sdb_store_tojson(sdb_strbuf_t *buf, int flags); int sdb_store_host_tojson(sdb_store_base_t *host, sdb_strbuf_t *buf, int flags); +/* + * sdb_store_iter_cb: + * Store iterator callback. Iteration stops if the callback returns non-zero. + */ +typedef int (*sdb_store_iter_cb)(sdb_store_base_t *obj, void *user_data); + +/* + * sdb_store_iterate: + * Iterate the entire store, calling the specified callback for each object. + * The user_data pointer is passed on to each call of the callback. + * + * Returns: + * - 0 on success + * - a negative value else + */ +int +sdb_store_iterate(sdb_store_iter_cb cb, void *user_data); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/t/core/store_test.c b/t/core/store_test.c index 8d484b6..d0ef5a9 100644 --- a/t/core/store_test.c +++ b/t/core/store_test.c @@ -31,6 +31,26 @@ #include #include +static void +populate(void) +{ + sdb_data_t datum; + + sdb_store_host("h1", 1); + sdb_store_host("h2", 1); + + datum.type = SDB_TYPE_STRING; + datum.data.string = "v1"; + sdb_store_attribute("h1", "k1", &datum, 1); + datum.data.string = "v2"; + sdb_store_attribute("h1", "k2", &datum, 1); + datum.data.string = "v3"; + sdb_store_attribute("h1", "k3", &datum, 1); + + sdb_store_service("h2", "s1", 1); + sdb_store_service("h2", "s2", 1); +} /* populate */ + START_TEST(test_store_host) { struct { @@ -249,7 +269,6 @@ verify_json_output(sdb_strbuf_t *buf, const char *expected, int flags) START_TEST(test_store_tojson) { sdb_strbuf_t *buf; - sdb_data_t datum; size_t i; struct { @@ -299,21 +318,9 @@ START_TEST(test_store_tojson) "]}" }, }; - sdb_store_host("h1", 1); - sdb_store_host("h2", 1); - - datum.type = SDB_TYPE_STRING; - datum.data.string = "v1"; - sdb_store_attribute("h1", "k1", &datum, 1); - datum.data.string = "v2"; - sdb_store_attribute("h1", "k2", &datum, 1); - datum.data.string = "v3"; - sdb_store_attribute("h1", "k3", &datum, 1); - - sdb_store_service("h2", "s1", 1); - sdb_store_service("h2", "s2", 1); - buf = sdb_strbuf_create(0); + fail_unless(buf != NULL, "INTERNAL ERROR: failed to create string buffer"); + populate(); for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { int status; @@ -331,6 +338,68 @@ START_TEST(test_store_tojson) } END_TEST +static int +iter_incr(sdb_store_base_t *obj, void *user_data) +{ + intptr_t *i = user_data; + + fail_unless(obj != NULL, + "sdb_store_iterate callback received NULL obj; expected: " + ""); + fail_unless(i != NULL, + "sdb_store_iterate callback received NULL user_data; " + "expected: "); + + ++(*i); + return 0; +} /* iter_incr */ + +static int +iter_error(sdb_store_base_t *obj, void *user_data) +{ + intptr_t *i = user_data; + + fail_unless(obj != NULL, + "sdb_store_iterate callback received NULL obj; expected: " + ""); + fail_unless(i != NULL, + "sdb_store_iterate callback received NULL user_data; " + "expected: "); + + ++(*i); + return -1; +} /* iter_error */ + +START_TEST(test_iterate) +{ + intptr_t i = 0; + int check; + + /* empty store */ + check = sdb_store_iterate(iter_incr, &i); + fail_unless(check == -1, + "sdb_store_iterate(), empty store = %d; expected: -1", check); + fail_unless(i == 0, + "sdb_store_iterate called callback %d times; expected: 0", (int)i); + + populate(); + + check = sdb_store_iterate(iter_incr, &i); + fail_unless(check == 0, + "sdb_store_iterate() = %d; expected: 0", check); + fail_unless(i == 2, + "sdb_store_iterate called callback %d times; expected: 1", (int)i); + + i = 0; + check = sdb_store_iterate(iter_error, &i); + fail_unless(check == -1, + "sdb_store_iterate(), error callback = %d; expected: -1", check); + fail_unless(i == 1, + "sdb_store_iterate called callback %d times " + "(callback returned error); expected: 1", (int)i); +} +END_TEST + Suite * core_store_suite(void) { @@ -343,6 +412,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_iterate); tcase_add_unchecked_fixture(tc, NULL, sdb_store_clear); suite_add_tcase(s, tc); -- 2.30.2