From 2ebe67e1b7d71c3e7e9b7ab06944637b143daba9 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Sun, 9 Nov 2014 10:39:13 +0100 Subject: [PATCH] store, frontend: Added support for iterating arrays (using ALL / ANY). Currently, this is limited to the 'backend' field of an object. Also, only simple statements like 'ANY/ALL ' are supported by the store (in contrast to service/metric iterators which support arbitrary matchers to be applied). Given that matchers are object based, this limitation should feel natural, though. --- src/core/store_lookup.c | 67 +++++++++++++++++++++++++++++++++++++++-- src/frontend/analyzer.c | 52 ++++++++++++++++++++++++++++++-- src/frontend/grammar.y | 10 ++++-- 3 files changed, 121 insertions(+), 8 deletions(-) diff --git a/src/core/store_lookup.c b/src/core/store_lookup.c index 3d509b0..e2ec1b1 100644 --- a/src/core/store_lookup.c +++ b/src/core/store_lookup.c @@ -119,6 +119,66 @@ match_unary(sdb_store_matcher_t *m, sdb_store_obj_t *obj, return !sdb_store_matcher_matches(UOP_M(m)->op, obj, filter); } /* match_unary */ +/* iterate arrays: ANY/ALL */ +static int +match_iter_array(sdb_store_matcher_t *m, sdb_store_obj_t *obj, + sdb_store_matcher_t *filter) +{ + sdb_store_expr_t *e1, *e2; + sdb_data_t v1 = SDB_DATA_INIT; + sdb_data_t v2 = SDB_DATA_INIT; + + int status; + + /* TODO: fully support arbitrary operators (?) */ + if ((ITER_M(m)->m->type < MATCHER_LT) || (MATCHER_GT < ITER_M(m)->m->type)) + return 0; + + e1 = CMP_M(ITER_M(m)->m)->left; + e2 = CMP_M(ITER_M(m)->m)->right; + + if (sdb_store_expr_eval(e1, obj, &v1, filter)) + return 0; + if (sdb_store_expr_eval(e2, obj, &v2, filter)) { + sdb_data_free_datum(&v1); + return 0; + } + + if ((! (v1.type & SDB_TYPE_ARRAY)) || (v2.type & SDB_TYPE_ARRAY)) + status = 0; + else if (sdb_data_isnull(&v1) || (sdb_data_isnull(&v2))) + status = 0; + else { + size_t i; + int all = (int)(m->type == MATCHER_ALL); + + status = all; + for (i = 0; i < v1.data.array.length; ++i) { + sdb_data_t v = SDB_DATA_INIT; + if (sdb_data_array_get(&v1, i, &v)) { + status = 0; + break; + } + + if (cmp_value(ITER_M(m)->m->type, &v, &v2, + (e1->data_type) < 0 || (e2->data_type < 0))) { + if (! all) { + status = 1; + break; + } + } + else if (all) { + status = 0; + break; + } + } + } + + sdb_data_free_datum(&v1); + sdb_data_free_datum(&v2); + return status; +} /* match_iter_array */ + static int match_iter(sdb_store_matcher_t *m, sdb_store_obj_t *obj, sdb_store_matcher_t *filter) @@ -129,6 +189,9 @@ match_iter(sdb_store_matcher_t *m, sdb_store_obj_t *obj, assert((m->type == MATCHER_ANY) || (m->type == MATCHER_ALL)); + if (ITER_M(m)->type == SDB_FIELD_BACKEND) + return match_iter_array(m, obj, filter); + if (obj->type == SDB_HOST) { if (ITER_M(m)->type == SDB_SERVICE) iter = sdb_avltree_get_iter(HOST(obj)->services); @@ -475,7 +538,7 @@ sdb_store_matcher_t * sdb_store_any_matcher(int type, sdb_store_matcher_t *m) { if ((type != SDB_SERVICE) && (type != SDB_METRIC) - && (type != SDB_ATTRIBUTE)) + && (type != SDB_ATTRIBUTE) && (type != SDB_FIELD_BACKEND)) return NULL; return M(sdb_object_create("any-matcher", iter_type, MATCHER_ANY, type, m)); @@ -485,7 +548,7 @@ sdb_store_matcher_t * sdb_store_all_matcher(int type, sdb_store_matcher_t *m) { if ((type != SDB_SERVICE) && (type != SDB_METRIC) - && (type != SDB_ATTRIBUTE)) + && (type != SDB_ATTRIBUTE) && (type != SDB_FIELD_BACKEND)) return NULL; return M(sdb_object_create("all-matcher", iter_type, MATCHER_ALL, type, m)); diff --git a/src/frontend/analyzer.c b/src/frontend/analyzer.c index 5cb1f7f..20864ca 100644 --- a/src/frontend/analyzer.c +++ b/src/frontend/analyzer.c @@ -47,13 +47,26 @@ iter_error(sdb_strbuf_t *errbuf, int op, int oper, int context) SDB_STORE_TYPE_TO_NAME(context)); } /* iter_error */ +static void +iter_array_error(sdb_strbuf_t *errbuf, int op, + int array_type, int cmp, int value_type) +{ + sdb_strbuf_sprintf(errbuf, "Invalid array iterator %s %s %s %s", + MATCHER_SYM(op), SDB_TYPE_TO_STRING(array_type), + MATCHER_SYM(cmp), SDB_TYPE_TO_STRING(value_type)); + if ((array_type & 0xff) != value_type) + sdb_strbuf_append(errbuf, " (type mismatch)"); + else + sdb_strbuf_append(errbuf, " (invalid operator)"); +} /* iter_array_error */ + static void cmp_error(sdb_strbuf_t *errbuf, int op, int left, int right) { sdb_strbuf_sprintf(errbuf, "Invalid operator %s for types %s and %s", MATCHER_SYM(op), SDB_TYPE_TO_STRING(left), SDB_TYPE_TO_STRING(right)); -} /* iter_error */ +} /* cmp_error */ static int analyze_matcher(int context, sdb_store_matcher_t *m, sdb_strbuf_t *errbuf) @@ -92,7 +105,8 @@ analyze_matcher(int context, sdb_store_matcher_t *m, sdb_strbuf_t *errbuf) } if ((ITER_M(m)->type != SDB_SERVICE) && (ITER_M(m)->type != SDB_METRIC) - && (ITER_M(m)->type != SDB_ATTRIBUTE)) { + && (ITER_M(m)->type != SDB_ATTRIBUTE) + && (ITER_M(m)->type != SDB_FIELD_BACKEND)) { iter_error(errbuf, m->type, ITER_M(m)->type, context); return -1; } @@ -106,7 +120,39 @@ analyze_matcher(int context, sdb_store_matcher_t *m, sdb_strbuf_t *errbuf) iter_error(errbuf, m->type, ITER_M(m)->type, context); return -1; } - if (analyze_matcher(ITER_M(m)->type, ITER_M(m)->m, errbuf)) + if (ITER_M(m)->type == SDB_FIELD_BACKEND) { + /* array iterators only support simple comparison atm */ + if ((ITER_M(m)->m->type != MATCHER_LT) + && (ITER_M(m)->m->type != MATCHER_LE) + && (ITER_M(m)->m->type != MATCHER_EQ) + && (ITER_M(m)->m->type != MATCHER_NE) + && (ITER_M(m)->m->type != MATCHER_GE) + && (ITER_M(m)->m->type != MATCHER_GT)) { + iter_array_error(errbuf, m->type, + CMP_M(ITER_M(m)->m)->left->data_type, + ITER_M(m)->m->type, + CMP_M(ITER_M(m)->m)->right->data_type); + return -1; + } + if (CMP_M(ITER_M(m)->m)->right->data_type < 0) + return 0; /* skip further type checks */ + if (CMP_M(ITER_M(m)->m)->right->data_type & SDB_TYPE_ARRAY) { + iter_array_error(errbuf, m->type, + CMP_M(ITER_M(m)->m)->left->data_type, + ITER_M(m)->m->type, + CMP_M(ITER_M(m)->m)->right->data_type); + return -1; + } + if ((CMP_M(ITER_M(m)->m)->left->data_type & 0xff) + != CMP_M(ITER_M(m)->m)->right->data_type) { + iter_array_error(errbuf, m->type, + CMP_M(ITER_M(m)->m)->left->data_type, + ITER_M(m)->m->type, + CMP_M(ITER_M(m)->m)->right->data_type); + return -1; + } + } + else if (analyze_matcher(ITER_M(m)->type, ITER_M(m)->m, errbuf)) return -1; break; diff --git a/src/frontend/grammar.y b/src/frontend/grammar.y index 6791806..80fb249 100644 --- a/src/frontend/grammar.y +++ b/src/frontend/grammar.y @@ -555,6 +555,8 @@ iterable: METRIC_T { $$ = SDB_METRIC; } | ATTRIBUTE_T { $$ = SDB_ATTRIBUTE; } + | + BACKEND_T { $$ = SDB_FIELD_BACKEND; } ; field: @@ -670,13 +672,15 @@ name_iter_matcher(int m_type, int type, const char *cmp, sdb_store_matcher_t *m, *tmp = NULL; assert(cb); - /* TODO: this only works as long as queries - * are limited to hosts */ + /* hosts are never iterable */ if (type == SDB_HOST) { return NULL; } - e = sdb_store_expr_fieldvalue(SDB_FIELD_NAME); + if (type == SDB_FIELD_BACKEND) + e = sdb_store_expr_fieldvalue(type); + else + e = sdb_store_expr_fieldvalue(SDB_FIELD_NAME); m = cb(e, expr); if (m_type == MATCHER_ANY) tmp = sdb_store_any_matcher(type, m); -- 2.30.2