Code

store, frontend: Added support for iterating arrays (using ALL / ANY).
authorSebastian Harl <sh@tokkee.org>
Sun, 9 Nov 2014 09:39:13 +0000 (10:39 +0100)
committerSebastian Harl <sh@tokkee.org>
Sun, 9 Nov 2014 10:38:02 +0000 (11:38 +0100)
Currently, this is limited to the 'backend' field of an object. Also, only
simple statements like 'ANY/ALL <array> <cmp> <value>' 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
src/frontend/analyzer.c
src/frontend/grammar.y

index 3d509b0511f026276cfa55194aafad34435164e2..e2ec1b14936b3c6586bdd698bdd0c792519c61aa 100644 (file)
@@ -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 <array> <cmp> <value> */
+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));
index 5cb1f7f7538564398fbf731c2aaecd9e1315e90d..20864cae4d348ca2e3072e1e48945fd157cb6c66 100644 (file)
@@ -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;
 
index 6791806b0bf473593330a7c057b75644268d7d0e..80fb249684e0120be85cd421905fec666d277bc4 100644 (file)
@@ -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);