summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: dfa8850)
raw | patch | inline | side by side (parent: dfa8850)
author | Sebastian Harl <sh@tokkee.org> | |
Sat, 2 Aug 2014 22:39:20 +0000 (00:39 +0200) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Sat, 2 Aug 2014 22:39:20 +0000 (00:39 +0200) |
src/core/store.c | patch | blob | history | |
src/include/core/store.h | patch | blob | history | |
t/unit/core/store_test.c | patch | blob | history |
diff --git a/src/core/store.c b/src/core/store.c
index 7611ec4329e0ff4a03b55795610581edca06db58..44e696cccf6549ec49707022d30c58a4f387da64 100644 (file)
--- a/src/core/store.c
+++ b/src/core/store.c
sdb_host_t *host;
assert(hostname);
- assert((type == SDB_SERVICE) || (type == SDB_ATTRIBUTE));
+ assert((type == SDB_SERVICE) || (type == SDB_METRIC)
+ || (type == SDB_ATTRIBUTE));
if (! hosts)
return NULL;
} /* store_common_tojson */
/*
- * store_obj_tojson serializes attribute / service objects to JSON.
+ * store_obj_tojson serializes attribute / metric / service objects to JSON.
*
* The function never returns an error. Rather, an error message will be part
* of the serialized data.
return status;
} /* sdb_store_service_attr */
+int
+sdb_store_metric(const char *hostname, const char *name,
+ sdb_time_t last_update)
+{
+ sdb_avltree_t *metrics;
+
+ int status = 0;
+
+ if ((! hostname) || (! name))
+ return -1;
+
+ pthread_rwlock_wrlock(&host_lock);
+ metrics = get_host_children(hostname, SDB_METRIC);
+ if (! metrics) {
+ sdb_log(SDB_LOG_ERR, "store: Failed to store metric '%s' - "
+ "host '%s' not found", name, hostname);
+ status = -1;
+ }
+
+ if (! status)
+ status = store_obj(metrics, SDB_METRIC, name, last_update, NULL);
+ pthread_rwlock_unlock(&host_lock);
+ return status;
+} /* sdb_store_metric */
+
+int
+sdb_store_metric_attr(const char *hostname, const char *metric,
+ const char *key, const sdb_data_t *value, sdb_time_t last_update)
+{
+ sdb_avltree_t *metrics;
+ sdb_metric_t *m;
+ int status = 0;
+
+ if ((! hostname) || (! metric) || (! key))
+ return -1;
+
+ pthread_rwlock_wrlock(&host_lock);
+ metrics = get_host_children(hostname, SDB_METRIC);
+ if (! metrics) {
+ sdb_log(SDB_LOG_ERR, "store: Failed to store attribute '%s' "
+ "for metric '%s' - host '%ss' not found",
+ key, metric, hostname);
+ pthread_rwlock_unlock(&host_lock);
+ return -1;
+ }
+
+ m = METRIC(sdb_avltree_lookup(metrics, metric));
+ if (! m) {
+ sdb_log(SDB_LOG_ERR, "store: Failed to store attribute '%s' - "
+ "metric '%s/%s' not found", key, hostname, metric);
+ status = -1;
+ }
+
+ if (! status)
+ status = store_attr(m->attributes, key, value, last_update);
+
+ sdb_object_deref(SDB_OBJ(m));
+ pthread_rwlock_unlock(&host_lock);
+ return status;
+} /* sdb_store_metric_attr */
+
int
sdb_store_get_field(sdb_store_obj_t *obj, int field, sdb_data_t *res)
{
index a7d86f529df54f56c4f9328ac6068731f52a28fa..8eaeecdc3f554998e2a63fee3b15bbce50a6125b 100644 (file)
--- a/src/include/core/store.h
+++ b/src/include/core/store.h
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_metric:
+ * Add/update a metric in the store. If the metric, identified by its name,
+ * already exists for the specified host, it will be updated according to the
+ * specified 'metric' object. If the referenced host does not exist, an error
+ * will be reported. Else, a new entry will be created in the store. Any
+ * memory required for storing the entry will be allocated an managed by the
+ * store itself. The specified metric-object will not be referenced or
+ * further accessed.
+ *
+ * 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_metric(const char *hostname, const char *name,
+ sdb_time_t last_update);
+
+/*
+ * sdb_store_metric_attr:
+ * Add/update a metric's attribute in the store. If the attribute, identified
+ * by its key, already exists for the specified metric, it will be updated to
+ * the specified value. If the references metric (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_metric_attr(const char *hostname, const char *metric,
+ const char *key, const sdb_data_t *value, sdb_time_t last_update);
+
/*
* sdb_store_get_field:
* Get the value of a stored object's queryable field. The caller is
index fb2c24bf20d596450c36f67e5b7791a96c2b5122..c056ac7c6d23e132f4a32d83a82ac2dc61173952 100644 (file)
--- a/t/unit/core/store_test.c
+++ b/t/unit/core/store_test.c
sdb_store_attribute("h1", "k2", &datum, 1);
sdb_store_attribute("h1", "k3", &datum, 2);
+ sdb_store_metric("h1", "m1", 2);
+ sdb_store_metric("h1", "m2", 1);
+
sdb_store_service("h2", "s1", 1);
sdb_store_service("h2", "s2", 2);
datum.type = SDB_TYPE_INTEGER;
+ datum.data.integer = 42;
+ sdb_store_metric_attr("h1", "m1", "k3", &datum, 2);
+
datum.data.integer = 123;
sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
datum.data.integer = 4711;
}
END_TEST
+START_TEST(test_store_metric)
+{
+ struct {
+ const char *host;
+ const char *metric;
+ sdb_time_t last_update;
+ int expected;
+ } golden_data[] = {
+ { "k", "m", 1, -1 },
+ { "k", "m", 1, -1 }, /* retry to ensure the host is not created */
+ { "l", "m1", 1, 0 },
+ { "l", "m1", 2, 0 },
+ { "l", "m1", 2, 1 },
+ { "l", "m2", 1, 0 },
+ { "m", "m", 1, 0 },
+ { "m", "m", 1, 1 },
+ };
+
+ size_t i;
+
+ sdb_store_host("m", 1);
+ sdb_store_host("l", 1);
+ for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
+ int status;
+
+ status = sdb_store_metric(golden_data[i].host,
+ golden_data[i].metric, golden_data[i].last_update);
+ fail_unless(status == golden_data[i].expected,
+ "sdb_store_metric(%s, %s, %d) = %d; expected: %d",
+ golden_data[i].host, golden_data[i].metric,
+ golden_data[i].last_update, status, golden_data[i].expected);
+ }
+}
+END_TEST
+
+START_TEST(test_store_metric_attr)
+{
+ struct {
+ const char *host;
+ const char *metric;
+ const char *attr;
+ const sdb_data_t value;
+ sdb_time_t last_update;
+ int expected;
+ } golden_data[] = {
+ { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
+ /* retry, it should still fail */
+ { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
+ { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
+ /* retry, it should still fail */
+ { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
+ { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
+ { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
+ { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2, 0 },
+ { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
+ { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
+ { "l", "m2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
+ { "m", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
+ };
+
+ size_t i;
+
+ sdb_store_host("m", 1);
+ sdb_store_host("l", 1);
+ sdb_store_metric("m", "m1", 1);
+ sdb_store_metric("l", "m1", 1);
+ sdb_store_metric("l", "m2", 1);
+
+ for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
+ int status;
+
+ status = sdb_store_metric_attr(golden_data[i].host,
+ golden_data[i].metric, golden_data[i].attr,
+ &golden_data[i].value, golden_data[i].last_update);
+ fail_unless(status == golden_data[i].expected,
+ "sdb_store_metric_attr(%s, %s, %s, %d, %d) = %d; "
+ "expected: %d", golden_data[i].host, golden_data[i].metric,
+ golden_data[i].attr, golden_data[i].value.data.integer,
+ golden_data[i].last_update, status, golden_data[i].expected);
+ }
+}
+END_TEST
+
START_TEST(test_store_service)
{
struct {
END_TEST
static void
-verify_json_output(sdb_strbuf_t *buf, const char *expected, int flags)
+verify_json_output(sdb_strbuf_t *buf, const char *expected,
+ const char *filter_str, int flags)
{
int pos;
size_t len1, len2;
}
fail_unless(pos == -1,
- "sdb_store_tojson(%x) returned unexpected result\n"
+ "sdb_store_tojson(<buf>, %s, %x) returned unexpected result\n"
" got: %s\n %*s\n expected: %s",
- flags, sdb_strbuf_string(buf), pos + 1, "^", expected);
+ filter_str, flags, sdb_strbuf_string(buf), pos + 1, "^",
+ expected);
} /* verify_json_output */
START_TEST(test_store_tojson)
"\"last_update\": \"1970-01-01 00:00:00 +0000\", "
"\"update_interval\": \"0s\", \"backends\": []}"
"], "
- "\"metrics\": [], "
+ "\"metrics\": ["
+ "{\"name\": \"m1\", "
+ "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
+ "\"update_interval\": \"0s\", \"backends\": [], "
+ "\"attributes\": ["
+ "{\"name\": \"k3\", \"value\": 42, "
+ "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
+ "\"update_interval\": \"0s\", \"backends\": []}"
+ "]},"
+ "{\"name\": \"m2\", "
+ "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
+ "\"update_interval\": \"0s\", \"backends\": [], "
+ "\"attributes\": []}"
+ "], "
"\"services\": []},"
"{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
"\"update_interval\": \"0s\", \"backends\": [], "
"\"last_update\": \"1970-01-01 00:00:00 +0000\", "
"\"update_interval\": \"0s\", \"backends\": []}"
"], "
- "\"metrics\": []},"
+ "\"metrics\": ["
+ "{\"name\": \"m1\", "
+ "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
+ "\"update_interval\": \"0s\", \"backends\": [], "
+ "\"attributes\": ["
+ "{\"name\": \"k3\", \"value\": 42, "
+ "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
+ "\"update_interval\": \"0s\", \"backends\": []}"
+ "]},"
+ "{\"name\": \"m2\", "
+ "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
+ "\"update_interval\": \"0s\", \"backends\": [], "
+ "\"attributes\": []}"
+ "]},"
"{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
"\"update_interval\": \"0s\", \"backends\": [], "
"\"attributes\": [], "
"{\"hosts\":["
"{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
"\"update_interval\": \"0s\", \"backends\": [], "
- "\"metrics\": [], "
+ "\"metrics\": ["
+ "{\"name\": \"m1\", "
+ "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
+ "\"update_interval\": \"0s\", \"backends\": []},"
+ "{\"name\": \"m2\", "
+ "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
+ "\"update_interval\": \"0s\", \"backends\": []}"
+ "], "
"\"services\": []},"
"{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
"\"update_interval\": \"0s\", \"backends\": [], "
"\"last_update\": \"1970-01-01 00:00:00 +0000\", "
"\"update_interval\": \"0s\", \"backends\": []},"
"], "
- "\"metrics\": [], "
+ "\"metrics\": ["
+ "{\"name\": \"m2\", "
+ "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
+ "\"update_interval\": \"0s\", \"backends\": [], "
+ "\"attributes\": []}"
+ "], "
"\"services\": []}"
"]}" },
{ { sdb_store_ge_matcher, SDB_FIELD_LAST_UPDATE,
for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
sdb_store_matcher_t *filter = NULL;
- char filter_str[1024];
+ char filter_str[1024] = "<none>";
int status;
sdb_strbuf_clear(buf);
sdb_object_deref(SDB_OBJ(c));
fail_unless(filter != NULL,
"INTERNAL ERROR: sdb_store_*_matcher() = NULL");
- }
- if (sdb_store_matcher_tostring(filter, filter_str, sizeof(filter_str)))
- snprintf(filter_str, sizeof(filter_str), "ERR");
+ if (sdb_store_matcher_tostring(filter,
+ filter_str, sizeof(filter_str)))
+ snprintf(filter_str, sizeof(filter_str), "ERR");
+ }
status = sdb_store_tojson(buf, filter, golden_data[i].flags);
fail_unless(status == 0,
"sdb_store_tojson(<buf>, %s, %x) = %d; expected: 0",
filter_str, golden_data[i].flags, status);
- verify_json_output(buf, golden_data[i].expected, golden_data[i].flags);
+ verify_json_output(buf, golden_data[i].expected,
+ filter_str, golden_data[i].flags);
sdb_object_deref(SDB_OBJ(filter));
}
sdb_strbuf_destroy(buf);
tcase_add_test(tc, test_store_host);
tcase_add_test(tc, test_store_get_host);
tcase_add_test(tc, test_store_attr);
+ tcase_add_test(tc, test_store_metric);
+ tcase_add_test(tc, test_store_metric_attr);
tcase_add_test(tc, test_store_service);
tcase_add_test(tc, test_store_service_attr);
tcase_add_test(tc, test_get_field);