diff --git a/include/villas/mapping.h b/include/villas/mapping.h index 4512c3681..2d3d9076c 100644 --- a/include/villas/mapping.h +++ b/include/villas/mapping.h @@ -85,7 +85,9 @@ struct mapping_entry { }; }; -int mapping_remap(struct list *m, struct sample *orig, struct sample *remapped, struct stats *s); +int mapping_remap(struct list *m, struct sample *remapped, struct sample *original, struct stats *s); + +int mapping_update(struct mapping_entry *e, struct sample *remapped, struct sample *new, struct stats *s); int mapping_parse(struct mapping_entry *e, json_t *cfg, struct list *nodes); diff --git a/lib/hooks/map.c b/lib/hooks/map.c index bc274ecd6..7e7460a48 100644 --- a/lib/hooks/map.c +++ b/lib/hooks/map.c @@ -86,7 +86,10 @@ static int map_read(struct hook *h, struct sample *smps[], unsigned *cnt) return ret; for (int i = 0; i < *cnt; i++) { - mapping_remap(&p->mapping, smps[i], tmp[i], NULL); + tmp[i]->format = 0; + tmp[i]->length = 0; + + mapping_remap(&p->mapping, tmp[i], smps[i], NULL); SWAP(smps[i], tmp[i]); } diff --git a/lib/mapping.c b/lib/mapping.c index c92c1966f..d11fad758 100644 --- a/lib/mapping.c +++ b/lib/mapping.c @@ -191,119 +191,132 @@ int mapping_parse(struct mapping_entry *e, json_t *j, struct list *nodes) return mapping_parse_str(e, str, nodes); } -int mapping_remap(struct list *m, struct sample *original, struct sample *remapped, struct stats *s) +int mapping_update(struct mapping_entry *me, struct sample *remapped, struct sample *original, struct stats *s) { - int k = 0, length; + int len = me->length; + int off = me->offset; + + /* me->length == 0 means that we want to take all values */ + if (!len) + len = original->length; + + if (len + off > remapped->capacity) + return -1; + + if (len + off > remapped->length) + remapped->length = len + off; + + switch (me->type) { + case MAPPING_TYPE_STATS: { + struct hist *h = &s->histograms[me->stats.id]; + + switch (me->stats.type) { + case MAPPING_STATS_TYPE_TOTAL: + sample_set_data_format(remapped, off, SAMPLE_DATA_FORMAT_INT); + remapped->data[off++].f = h->total; + break; + case MAPPING_STATS_TYPE_LAST: + remapped->data[off++].f = h->last; + break; + case MAPPING_STATS_TYPE_HIGHEST: + remapped->data[off++].f = h->highest; + break; + case MAPPING_STATS_TYPE_LOWEST: + remapped->data[off++].f = h->lowest; + break; + case MAPPING_STATS_TYPE_MEAN: + remapped->data[off++].f = hist_mean(h); + break; + case MAPPING_STATS_TYPE_STDDEV: + remapped->data[off++].f = hist_stddev(h); + break; + case MAPPING_STATS_TYPE_VAR: + remapped->data[off++].f = hist_var(h); + break; + default: + return -1; + } + } + + case MAPPING_TYPE_TS: { + struct timespec *ts; + + switch (me->ts.id) { + case MAPPING_TS_RECEIVED: + ts = &original->ts.received; + break; + case MAPPING_TS_ORIGIN: + ts = &original->ts.origin; + break; + default: + return -1; + } + + sample_set_data_format(remapped, off, SAMPLE_DATA_FORMAT_INT); + sample_set_data_format(remapped, off+1, SAMPLE_DATA_FORMAT_INT); + + remapped->data[off++].i = ts->tv_sec; + remapped->data[off++].i = ts->tv_nsec; + + break; + } + + case MAPPING_TYPE_HDR: + sample_set_data_format(remapped, off, SAMPLE_DATA_FORMAT_INT); + + switch (me->hdr.id) { + case MAPPING_HDR_LENGTH: + remapped->data[off++].i = original->length; + break; + case MAPPING_HDR_SEQUENCE: + remapped->data[off++].i = original->sequence; + break; + case MAPPING_HDR_ID: + remapped->data[off++].i = original->id; + break; + case MAPPING_HDR_FORMAT: + remapped->data[off++].i = original->format; + break; + default: + return -1; + } + + break; + + case MAPPING_TYPE_DATA: + for (int j = me->data.offset; j < len + me->data.offset; j++) { + if (j >= original->length) { + sample_set_data_format(remapped, off, SAMPLE_DATA_FORMAT_FLOAT); + remapped->data[off++].f = 0; + } + else { + sample_set_data_format(remapped, off, sample_get_data_format(original, j)); + remapped->data[off++] = original->data[j]; + } + } + + break; + } + + return 0; +} + +int mapping_remap(struct list *m, struct sample *remapped, struct sample *original, struct stats *s) +{ + int ret; /* We copy all the header fields */ remapped->sequence = original->sequence; - remapped->pool_off = (char *) original + original->pool_off - (char *) remapped; + remapped->pool_off = (char *) sample_pool(original) - (char *) remapped; remapped->source = original->source; remapped->ts = original->ts; - remapped->format = 0; - remapped->length = 0; for (size_t i = 0; i < list_length(m); i++) { - struct mapping_entry *mapping = list_at(m, i); + struct mapping_entry *me = list_at(m, i); - length = mapping->length; - if (length + k > remapped->capacity) - break; - - switch (mapping->type) { - case MAPPING_TYPE_STATS: { - struct hist *h = &s->histograms[mapping->stats.id]; - - switch (mapping->stats.type) { - case MAPPING_STATS_TYPE_TOTAL: - sample_set_data_format(remapped, k, SAMPLE_DATA_FORMAT_INT); - remapped->data[k++].f = h->total; - break; - case MAPPING_STATS_TYPE_LAST: - remapped->data[k++].f = h->last; - break; - case MAPPING_STATS_TYPE_HIGHEST: - remapped->data[k++].f = h->highest; - break; - case MAPPING_STATS_TYPE_LOWEST: - remapped->data[k++].f = h->lowest; - break; - case MAPPING_STATS_TYPE_MEAN: - remapped->data[k++].f = hist_mean(h); - break; - case MAPPING_STATS_TYPE_STDDEV: - remapped->data[k++].f = hist_stddev(h); - break; - case MAPPING_STATS_TYPE_VAR: - remapped->data[k++].f = hist_var(h); - break; - default: - return -1; - } - } - - case MAPPING_TYPE_TS: { - struct timespec *ts; - - switch (mapping->ts.id) { - case MAPPING_TS_RECEIVED: - ts = &original->ts.received; - break; - case MAPPING_TS_ORIGIN: - ts = &original->ts.origin; - break; - default: - return -1; - } - - sample_set_data_format(remapped, k, SAMPLE_DATA_FORMAT_INT); - sample_set_data_format(remapped, k+1, SAMPLE_DATA_FORMAT_INT); - - remapped->data[k++].i = ts->tv_sec; - remapped->data[k++].i = ts->tv_nsec; - - break; - } - - case MAPPING_TYPE_HDR: - sample_set_data_format(remapped, k, SAMPLE_DATA_FORMAT_INT); - - switch (mapping->hdr.id) { - case MAPPING_HDR_LENGTH: - remapped->data[k++].i = original->length; - break; - case MAPPING_HDR_SEQUENCE: - remapped->data[k++].i = original->sequence; - break; - default: - return -1; - } - - break; - - case MAPPING_TYPE_DATA: - /* mapping->length == 0 means that we want to take all values */ - if (!length) - length = original->length; - - if (length + k > remapped->capacity) - length = remapped->capacity - k; - - for (int j = mapping->data.offset; j < length + mapping->data.offset; j++) { - if (j >= original->length) { - sample_set_data_format(remapped, k, SAMPLE_DATA_FORMAT_FLOAT); - remapped->data[k++].f = 0; - } - else { - sample_set_data_format(remapped, k, sample_get_data_format(original, j)); - remapped->data[k++] = original->data[j]; - } - } - - break; - } - - remapped->length += length; + ret = mapping_update(me, remapped, original, s); + if (ret) + return ret; } return 0; diff --git a/lib/node.c b/lib/node.c index a2be6ab0f..9a4dba0fe 100644 --- a/lib/node.c +++ b/lib/node.c @@ -350,8 +350,9 @@ invalid2: int node_parse_mapping_list(struct list *l, json_t *cfg, struct list *all) { - int ret; + int ret, off, len; + size_t i; json_t *json_entry; json_t *json_mapping; @@ -364,13 +365,21 @@ int node_parse_mapping_list(struct list *l, json_t *cfg, struct list *all) else return -1; - size_t i; + off = 0; + len = json_array_size(json_mapping); json_array_foreach(json_mapping, i, json_entry) { struct mapping_entry *e = alloc(sizeof(struct mapping_entry)); ret = mapping_parse(e, json_entry, all); if (ret) return ret; + + /* Variable length mapping entries are currently only supported as the last element in a mapping */ + if (e->length == 0 && i != len - 1) + return -1; + + e->offset = off; + off += e->length; list_push(l, e); }