From 50b3529c9042236758a4e184860d8e26e7528844 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 28 Aug 2017 12:48:15 +0200 Subject: [PATCH] improved mapping module to support node name prefixes --- include/villas/mapping.h | 11 ++-- lib/hooks/map.c | 2 +- lib/mapping.c | 112 +++++++++++++++++++++++---------------- tests/unit/mapping.c | 93 +++++++++++++++++++++++++------- 4 files changed, 147 insertions(+), 71 deletions(-) diff --git a/include/villas/mapping.h b/include/villas/mapping.h index a814f0b93..340124581 100644 --- a/include/villas/mapping.h +++ b/include/villas/mapping.h @@ -36,7 +36,7 @@ struct sample; struct list; struct mapping_entry { - struct node *source; /**< Unused for now. */ + struct node *node; int length; enum { @@ -71,7 +71,8 @@ struct mapping_entry { struct { enum timestamp_type { MAPPING_TIMESTAMP_ORIGIN, - MAPPING_TIMESTAMP_RECEIVED + MAPPING_TIMESTAMP_RECEIVED, + MAPPING_TIMESTAMP_SENT } id; } timestamp; }; @@ -87,7 +88,7 @@ struct mapping { int mapping_init(struct mapping *m); -int mapping_parse(struct mapping *m, json_t *cfg); +int mapping_parse(struct mapping *m, json_t *cfg, struct list *nodes); int mapping_check(struct mapping *m); @@ -95,6 +96,6 @@ int mapping_destroy(struct mapping *m); int mapping_remap(struct mapping *m, struct sample *orig, struct sample *remapped, struct stats *s); -int mapping_entry_parse(struct mapping_entry *e, json_t *cfg); +int mapping_entry_parse(struct mapping_entry *e, json_t *cfg, struct list *nodes); -int mapping_entry_parse_str(struct mapping_entry *e, const char *str); +int mapping_entry_parse_str(struct mapping_entry *e, const char *str, struct list *nodes); diff --git a/lib/hooks/map.c b/lib/hooks/map.c index 7b75f02d7..5f6c18076 100644 --- a/lib/hooks/map.c +++ b/lib/hooks/map.c @@ -64,7 +64,7 @@ static int map_parse(struct hook *h, json_t *cfg) if (ret) jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt)); - ret = mapping_parse(&p->mapping, cfg_mapping); + ret = mapping_parse(&p->mapping, cfg_mapping, NULL); if (ret) return ret; diff --git a/lib/mapping.c b/lib/mapping.c index cc5d8f295..9b8ea3827 100644 --- a/lib/mapping.c +++ b/lib/mapping.c @@ -28,18 +28,35 @@ #include "list.h" #include "utils.h" -int mapping_entry_parse_str(struct mapping_entry *e, const char *str) +int mapping_entry_parse_str(struct mapping_entry *e, const char *str, struct list *nodes) { int id; - char *cpy, *type, *field, *subfield, *end; + char *cpy, *node, *type, *field, *subfield, *end; cpy = strdup(str); if (!cpy) return -1; - - type = strtok(cpy, ".["); - if (!type) - goto invalid_format; + + if (nodes) { + node = strtok(cpy, "."); + if (!node) + goto invalid_format; + + e->node = list_lookup(nodes, node); + if (!e->node) + goto invalid_format; + + type = strtok(NULL, ".["); + if (!type) + type = "data"; + } + else { + e->node = NULL; + + type = strtok(cpy, ".["); + if (!type) + goto invalid_format; + } if (!strcmp(type, "stats")) { e->type = MAPPING_TYPE_STATS; @@ -53,10 +70,6 @@ int mapping_entry_parse_str(struct mapping_entry *e, const char *str) if (!subfield) goto invalid_format; - end = strtok(NULL, "."); - if (end) - goto invalid_format; - id = stats_lookup_id(field); if (id < 0) goto invalid_format; @@ -88,10 +101,6 @@ int mapping_entry_parse_str(struct mapping_entry *e, const char *str) if (!field) goto invalid_format; - end = strtok(NULL, "."); - if (end) - goto invalid_format; - if (!strcmp(field, "sequence")) e->header.id = MAPPING_HEADER_SEQUENCE; else if (!strcmp(field, "length")) @@ -107,70 +116,75 @@ int mapping_entry_parse_str(struct mapping_entry *e, const char *str) if (!field) goto invalid_format; - end = strtok(NULL, "."); - if (end) - goto invalid_format; - if (!strcmp(field, "origin")) e->timestamp.id = MAPPING_TIMESTAMP_ORIGIN; else if (!strcmp(field, "received")) e->timestamp.id = MAPPING_TIMESTAMP_RECEIVED; + else if (!strcmp(field, "sent")) + e->timestamp.id = MAPPING_TIMESTAMP_SENT; else goto invalid_format; } else if (!strcmp(type, "data")) { char *first_str, *last_str, *endptr; - int first, last; e->type = MAPPING_TYPE_DATA; first_str = strtok(NULL, "-]"); - if (!first_str) - goto invalid_format; + if (first_str) { + int first, last; - last_str = strtok(NULL, "]"); - if (!last_str) - last_str = first_str; /* single element: data[5] => data[5-5] */ + last_str = strtok(NULL, "]"); + if (!last_str) + last_str = first_str; /* single element: data[5] => data[5-5] */ - end = strtok(NULL, "."); - if (end) - goto invalid_format; + first = strtoul(first_str, &endptr, 10); + if (endptr != first_str + strlen(first_str)) + goto invalid_format; - first = strtoul(first_str, &endptr, 10); - if (endptr != first_str + strlen(first_str)) - goto invalid_format; + last = strtoul(last_str, &endptr, 10); + if (endptr != last_str + strlen(last_str)) + goto invalid_format; - last = strtoul(last_str, &endptr, 10); - if (endptr != last_str + strlen(last_str)) - goto invalid_format; + if (last < first) + goto invalid_format; - if (last < first) - goto invalid_format; - - e->data.offset = first; - e->length = last - first + 1; + e->data.offset = first; + e->length = last - first + 1; + } + else { + e->data.offset = 0; + e->length = 0; /* Length in unkown.. we will take all values */ + } } else goto invalid_format; + /* Check that there is no garbage at the end */ + end = strtok(NULL, ""); + if (end) + goto invalid_format; + free(cpy); + return 0; invalid_format: free(cpy); + return -1; } -int mapping_entry_parse(struct mapping_entry *e, json_t *cfg) +int mapping_entry_parse(struct mapping_entry *e, json_t *j, struct list *nodes) { const char *str; - str = json_string_value(cfg); + str = json_string_value(j); if (!str) return -1; - return mapping_entry_parse_str(e, str); + return mapping_entry_parse_str(e, str, nodes); } int mapping_init(struct mapping *m) @@ -195,23 +209,29 @@ int mapping_destroy(struct mapping *m) return 0; } -int mapping_parse(struct mapping *m, json_t *cfg) +int mapping_parse(struct mapping *m, json_t *j, struct list *nodes) { int ret; assert(m->state == STATE_INITIALIZED); - if (!json_is_array(cfg)) + json_t *json_entry; + json_t *json_mapping; + + if (json_is_string(j)) { + json_mapping = json_array(); + json_array_append(json_mapping, j); + } + else if (!json_is_array(j)) return -1; m->real_length = 0; size_t index; - json_t *cfg_entry; - json_array_foreach(cfg, index, cfg_entry) { + json_array_foreach(j, index, json_entry) { struct mapping_entry *e = alloc(sizeof(struct mapping_entry)); - ret = mapping_entry_parse(e, cfg_entry); + ret = mapping_entry_parse(e, json_entry, nodes); if (ret) return ret; diff --git a/tests/unit/mapping.c b/tests/unit/mapping.c index 42b96f4eb..899de8c55 100644 --- a/tests/unit/mapping.c +++ b/tests/unit/mapping.c @@ -23,74 +23,129 @@ #include #include "mapping.h" +#include "node.h" +#include "list.h" + +Test(mapping, parse_nodes) +{ + int ret; + struct mapping_entry m; + struct list n; + + struct node n1 = { .name = "apple" }; + struct node n2 = { .name = "cherry" }; + struct node n3 = { .name = "carrot" }; + + list_init(&n); + + list_push(&n, &n1); + list_push(&n, &n2); + list_push(&n, &n3); + + ret = mapping_entry_parse_str(&m, "apple.ts.origin", &n); + cr_assert_eq(ret, 0); + cr_assert_eq(m.node, &n1); + cr_assert_eq(m.type, MAPPING_TYPE_TIMESTAMP); + cr_assert_eq(m.timestamp.id, MAPPING_TIMESTAMP_ORIGIN); + + ret = mapping_entry_parse_str(&m, "cherry.stats.owd.mean", &n); + cr_assert_eq(ret, 0); + cr_assert_eq(m.node, &n2); + cr_assert_eq(m.type, MAPPING_TYPE_STATS); + cr_assert_eq(m.stats.id, STATS_OWD); + cr_assert_eq(m.stats.type, MAPPING_STATS_TYPE_MEAN); + + ret = mapping_entry_parse_str(&m, "carrot.data[1-2]", &n); + cr_assert_eq(ret, 0); + cr_assert_eq(m.node, &n3); + cr_assert_eq(m.type, MAPPING_TYPE_DATA); + cr_assert_eq(m.data.offset, 1); + cr_assert_eq(m.length, 2); + + ret = mapping_entry_parse_str(&m, "carrot", &n); + cr_assert_eq(ret, 0); + cr_assert_eq(m.node, &n3); + cr_assert_eq(m.type, MAPPING_TYPE_DATA); + cr_assert_eq(m.data.offset, 0); + cr_assert_eq(m.length, 0); + + ret = list_destroy(&n, NULL, false); + cr_assert_eq(ret, 0); +} Test(mapping, parse) { int ret; struct mapping_entry m; - ret = mapping_entry_parse_str(&m, "ts.origin"); + ret = mapping_entry_parse_str(&m, "ts.origin", NULL); cr_assert_eq(ret, 0); cr_assert_eq(m.type, MAPPING_TYPE_TIMESTAMP); cr_assert_eq(m.timestamp.id, MAPPING_TIMESTAMP_ORIGIN); - ret = mapping_entry_parse_str(&m, "hdr.sequence"); + ret = mapping_entry_parse_str(&m, "hdr.sequence", NULL); cr_assert_eq(ret, 0); cr_assert_eq(m.type, MAPPING_TYPE_HEADER); cr_assert_eq(m.header.id, MAPPING_HEADER_SEQUENCE); - ret = mapping_entry_parse_str(&m, "stats.owd.mean"); + ret = mapping_entry_parse_str(&m, "stats.owd.mean", NULL); cr_assert_eq(ret, 0); cr_assert_eq(m.type, MAPPING_TYPE_STATS); cr_assert_eq(m.stats.id, STATS_OWD); cr_assert_eq(m.stats.type, MAPPING_STATS_TYPE_MEAN); - ret = mapping_entry_parse_str(&m, "data[1-2]"); + ret = mapping_entry_parse_str(&m, "data[1-2]", NULL); cr_assert_eq(ret, 0); cr_assert_eq(m.type, MAPPING_TYPE_DATA); cr_assert_eq(m.data.offset, 1); cr_assert_eq(m.length, 2); - ret = mapping_entry_parse_str(&m, "data[5-5]"); + ret = mapping_entry_parse_str(&m, "data[5-5]", NULL); cr_assert_eq(ret, 0); cr_assert_eq(m.type, MAPPING_TYPE_DATA); cr_assert_eq(m.data.offset, 5); cr_assert_eq(m.length, 1); - ret = mapping_entry_parse_str(&m, "data[22]"); + ret = mapping_entry_parse_str(&m, "data[22]", NULL); cr_assert_eq(ret, 0); cr_assert_eq(m.type, MAPPING_TYPE_DATA); cr_assert_eq(m.data.offset, 22); cr_assert_eq(m.length, 1); + + ret = mapping_entry_parse_str(&m, "data", NULL); + cr_assert_eq(ret, 0); + cr_assert_eq(m.type, MAPPING_TYPE_DATA); + cr_assert_eq(m.data.offset, 0); + cr_assert_eq(m.length, 0); + + ret = mapping_entry_parse_str(&m, "data[]", NULL); + cr_assert_eq(ret, 0); + cr_assert_eq(m.type, MAPPING_TYPE_DATA); + cr_assert_eq(m.data.offset, 0); + cr_assert_eq(m.length, 0); - ret = mapping_entry_parse_str(&m, "data[]"); - cr_assert_neq(ret, 0); - - ret = mapping_entry_parse_str(&m, "data[1.1-2f]"); + ret = mapping_entry_parse_str(&m, "data[1.1-2f]", NULL); cr_assert_neq(ret, 0); /* Missing parts */ - ret = mapping_entry_parse_str(&m, "stats.owd"); - cr_assert_neq(ret, 0); - - ret = mapping_entry_parse_str(&m, "data"); + ret = mapping_entry_parse_str(&m, "stats.owd", NULL); cr_assert_neq(ret, 0); /* This a type */ - ret = mapping_entry_parse_str(&m, "hdr.sequences"); + ret = mapping_entry_parse_str(&m, "hdr.sequences", NULL); cr_assert_neq(ret, 0); /* Check for superfluous chars at the end */ - ret = mapping_entry_parse_str(&m, "stats.ts.origin.bla"); + ret = mapping_entry_parse_str(&m, "stats.ts.origin.bla", NULL); cr_assert_neq(ret, 0); - ret = mapping_entry_parse_str(&m, "stats.ts.origin."); + ret = mapping_entry_parse_str(&m, "stats.ts.origin.", NULL); cr_assert_neq(ret, 0); - ret = mapping_entry_parse_str(&m, "data[1-2]bla"); + ret = mapping_entry_parse_str(&m, "data[1-2]bla", NULL); cr_assert_neq(ret, 0); /* Negative length of chunk */ - ret = mapping_entry_parse_str(&m, "data[5-3]"); + ret = mapping_entry_parse_str(&m, "data[5-3]", NULL); cr_assert_eq(ret, -1); } \ No newline at end of file