From 4b1c3e70c727641934d697339cad02cda0a3c565 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Thu, 25 Dec 2014 18:21:02 +0100 Subject: [PATCH] proto: Added support for marshaling attribute objects. --- src/include/frontend/proto.h | 5 +-- src/include/utils/proto.h | 16 +++++++-- src/utils/proto.c | 42 ++++++++++++++++++++++- t/unit/utils/proto_test.c | 66 ++++++++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 5 deletions(-) diff --git a/src/include/frontend/proto.h b/src/include/frontend/proto.h index 57c721f..99e2a8d 100644 --- a/src/include/frontend/proto.h +++ b/src/include/frontend/proto.h @@ -251,7 +251,8 @@ typedef enum { * include the type of the object to be stored, the timestamp of the last * update, and a list of fields describing the object depending on the * object type. Object types are encoded as 32bit integers in network - * byte-order. Timestamps are encoded as 64bit integers in network + * byte-order where attribute types are bitwise ORed with the appropriate + * parent object type. Timestamps are encoded as 64bit integers in network * byte-order. Fields are null-terminated strings. * * 0 32 64 @@ -269,7 +270,7 @@ typedef enum { * HOST: name * SERVICE: hostname, name * METRIC: hostname, name, [store type, store id] - * ATTRIBUTE: parent object type, hostname, [object name], key, + * ATTRIBUTE: [hostname], parent object name, key, * * Values are encoded as their type (32bit integer in network byte-order), * and their content as implemented by sdb_proto_marshal_data. diff --git a/src/include/utils/proto.h b/src/include/utils/proto.h index eb0d528..fd842c1 100644 --- a/src/include/utils/proto.h +++ b/src/include/utils/proto.h @@ -61,6 +61,15 @@ typedef struct { const char *store_id; /* optional */ } sdb_proto_metric_t; +typedef struct { + sdb_time_t last_update; + int parent_type; + const char *hostname; /* optional */ + const char *parent; + const char *key; + const sdb_data_t *value; +} sdb_proto_attribute_t; + /* * sdb_proto_marshal: * Encode the message into the wire format by adding an appropriate header. @@ -90,11 +99,11 @@ sdb_proto_marshal(char *buf, size_t buf_len, uint32_t code, * - a negative value else */ ssize_t -sdb_proto_marshal_data(char *buf, size_t buf_len, sdb_data_t *datum); +sdb_proto_marshal_data(char *buf, size_t buf_len, const sdb_data_t *datum); /* * sdb_proto_marshal_host, sdb_proto_marshal_service, - * sdb_proto_marshal_metric: + * sdb_proto_marshal_metric, sdb_proto_marshal_attribute: * Encode the basic information of a stored object into the wire format and * write it to buf. These functions are similar to the sdb_store_ * functions. See their documentation for details about the arguments. @@ -115,6 +124,9 @@ sdb_proto_marshal_service(char *buf, size_t buf_len, ssize_t sdb_proto_marshal_metric(char *buf, size_t buf_len, const sdb_proto_metric_t *metric); +ssize_t +sdb_proto_marshal_attribute(char *buf, size_t buf_len, + const sdb_proto_attribute_t *attr); /* * sdb_proto_unmarshal_header: diff --git a/src/utils/proto.c b/src/utils/proto.c index 5a7a2e3..cd4e050 100644 --- a/src/utils/proto.c +++ b/src/utils/proto.c @@ -162,7 +162,7 @@ sdb_proto_marshal(char *buf, size_t buf_len, uint32_t code, } /* sdb_proto_marshal */ ssize_t -sdb_proto_marshal_data(char *buf, size_t buf_len, sdb_data_t *datum) +sdb_proto_marshal_data(char *buf, size_t buf_len, const sdb_data_t *datum) { ssize_t len = 0, n = 0; uint32_t tmp; @@ -339,6 +339,46 @@ sdb_proto_marshal_metric(char *buf, size_t buf_len, return len; } /* sdb_proto_marshal_metric */ +ssize_t +sdb_proto_marshal_attribute(char *buf, size_t buf_len, + const sdb_proto_attribute_t *attr) +{ + size_t len; + ssize_t n; + + if ((! attr) || (! attr->parent) || (! attr->key) || (! attr->value) + || ((attr->parent_type != SDB_HOST) && (! attr->hostname)) + || ((attr->parent_type != SDB_HOST) + && (attr->parent_type != SDB_SERVICE) + && (attr->parent_type != SDB_METRIC))) + return -1; + + n = sdb_proto_marshal_data(NULL, 0, attr->value); + if (n < 0) + return -1; + + len = OBJ_HEADER_LEN + + strlen(attr->parent) + strlen(attr->key) + 2 + (size_t)n; + if (attr->parent_type != SDB_HOST) + len += strlen(attr->hostname) + 1; + if (buf_len < len) + return len; + + n = marshal_obj_header(buf, buf_len, + attr->parent_type | SDB_ATTRIBUTE, attr->last_update); + buf += n; buf_len -= n; + if (attr->parent_type != SDB_HOST) { + n = marshal_string(buf, buf_len, attr->hostname); + buf += n; buf_len -= n; + } + n = marshal_string(buf, buf_len, attr->parent); + buf += n; buf_len -= n; + n = marshal_string(buf, buf_len, attr->key); + buf += n; buf_len -= n; + sdb_proto_marshal_data(buf, buf_len, attr->value); + return len; +} /* sdb_proto_marshal_attribute */ + int sdb_proto_unmarshal_header(const char *buf, size_t buf_len, uint32_t *code, uint32_t *msg_len) diff --git a/t/unit/utils/proto_test.c b/t/unit/utils/proto_test.c index 6bf8a7b..442234e 100644 --- a/t/unit/utils/proto_test.c +++ b/t/unit/utils/proto_test.c @@ -25,6 +25,7 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "core/store.h" #include "utils/proto.h" #include "libsysdb_test.h" @@ -176,6 +177,9 @@ END_TEST #define HOST_TYPE "\0\0\0\1" #define SVC_TYPE "\0\0\0\2" #define METRIC_TYPE "\0\0\0\3" +#define HOST_ATTR_TYPE "\0\0\0\x11" +#define SVC_ATTR_TYPE "\0\0\0\x12" +#define METRIC_ATTR_TYPE "\0\0\0\x13" START_TEST(test_marshal_host) { @@ -343,6 +347,67 @@ START_TEST(test_marshal_metric) } END_TEST +START_TEST(test_marshal_attribute) +{ + sdb_data_t v = { SDB_TYPE_NULL, { .integer = 0 } }; +#define VAL "\0\0\0\0" + struct { + sdb_proto_attribute_t attr; + ssize_t expected_len; + char *expected; + } golden_data[] = { + { + { 4711, SDB_HOST, NULL, "hostA", "k1", &v }, + 25, HOST_ATTR_TYPE "\0\0\0\0\0\0\x12\x67" "hostA\0" "k1\0" VAL + }, + { + { 4711, SDB_SERVICE, "hostA", "svc1", "k1", &v }, + 30, SVC_ATTR_TYPE "\0\0\0\0\0\0\x12\x67" "hostA\0" "svc1\0" "k1\0" VAL + }, + { + { 4711, SDB_METRIC, "hostA", "m1", "k1", &v }, + 28, METRIC_ATTR_TYPE "\0\0\0\0\0\0\x12\x67" "hostA\0" "m1\0" "k1\0" VAL + }, + { { 4711, SDB_HOST, NULL, NULL, "k1", &v }, -1, NULL }, + { { 4711, SDB_HOST, NULL, "hostA", NULL, &v }, -1, NULL }, + { { 4711, SDB_HOST, NULL, "hostA", "k1", NULL }, -1, NULL }, + { { 4711, SDB_SERVICE, NULL, "svc1", "k1", &v }, -1, NULL }, + { { 4711, SDB_METRIC, NULL, "m1", "k1", &v }, -1, NULL }, + { { 4711, 0, "hostA", "svc1", "k1", &v }, -1, NULL }, + }; + + size_t i; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + ssize_t len = sdb_proto_marshal_attribute(NULL, 0, &golden_data[i].attr); + char buf[len > 0 ? len : 1]; + + fail_unless(len == golden_data[i].expected_len, + "<%zu> sdb_proto_marshal_attribute(NULL, 0, %s) = %zi; expected: %zi", + i, golden_data[i].attr.key, len, golden_data[i].expected_len); + + if (len < 0) + continue; + + len = sdb_proto_marshal_attribute(buf, sizeof(buf), &golden_data[i].attr); + fail_unless(len == golden_data[i].expected_len, + "<%zu> sdb_proto_marshal_attribute(, %zu, %s) = %zi; expected: %zi", + i, sizeof(buf), golden_data[i].attr.key, + len, golden_data[i].expected_len); + if (memcmp(buf, golden_data[i].expected, len) != 0) { + size_t pos; + for (pos = 0; pos < (size_t)len; ++pos) + if (buf[pos] != golden_data[i].expected[pos]) + break; + fail("<%zu> sdb_proto_marshal_attribute(%s) -> \"%s\"; expected: \"%s\" " + "(bytes %zu differ: '%x' != '%x')", + i, golden_data[i].attr.key, buf, golden_data[i].expected, + pos, (int)buf[pos], (int)golden_data[i].expected[pos]); + } + } +} +END_TEST + Suite * util_proto_suite(void) { @@ -354,6 +419,7 @@ util_proto_suite(void) tcase_add_test(tc, test_marshal_host); tcase_add_test(tc, test_marshal_service); tcase_add_test(tc, test_marshal_metric); + tcase_add_test(tc, test_marshal_attribute); suite_add_tcase(s, tc); return s; -- 2.30.2