Code

store: Make matchers more generic and applicable to non-hosts as well.
authorSebastian Harl <sh@tokkee.org>
Mon, 28 Jul 2014 21:36:05 +0000 (23:36 +0200)
committerSebastian Harl <sh@tokkee.org>
Mon, 28 Jul 2014 21:36:05 +0000 (23:36 +0200)
Most of the matchers are actually not specific to hosts and may be re-used for
different purposes (e.g. filters). Make them applicable to arbitrary object
types (again) and only check for the right object type when actually needed.

Added simple unit-tests covering filters applied to all types of objects.

src/core/store-private.h
src/core/store_lookup.c
t/unit/core/store_lookup_test.c

index 703bc55e476c0b3ef2663ec28ac63098a0d2399b..0df3c7ba041c5eae961e116231c87605e46b0a47 100644 (file)
@@ -95,9 +95,9 @@ typedef struct {
  * conditionals
  */
 
-/* compares a host using the specified conditional and taking the specified
+/* compares an object using the specified conditional and taking the specified
  * filter into account */
-typedef int (*cmp_cb)(sdb_host_t *, sdb_store_cond_t *,
+typedef int (*cmp_cb)(sdb_store_obj_t *, sdb_store_cond_t *,
                sdb_store_matcher_t *);
 
 struct sdb_store_cond {
index ac0f2e8c794c61c36a9d0aa34cff47deb2a9c939..ed585914cd38bee517d0dddfd84e47bfcbb6b980 100644 (file)
@@ -104,17 +104,20 @@ attr_get(sdb_host_t *host, const char *name, sdb_store_matcher_t *filter)
  */
 
 static int
-attr_cmp(sdb_host_t *host, sdb_store_cond_t *cond,
+attr_cmp(sdb_store_obj_t *obj, sdb_store_cond_t *cond,
                sdb_store_matcher_t *filter)
 {
        sdb_attribute_t *attr;
        sdb_data_t value = SDB_DATA_INIT;
        int status;
 
+       if (obj->type != SDB_HOST)
+               return INT_MAX;
+
        if (sdb_store_expr_eval(ATTR_C(cond)->expr, &value))
                return INT_MAX;
 
-       attr = attr_get(host, ATTR_C(cond)->name, filter);
+       attr = attr_get(HOST(obj), ATTR_C(cond)->name, filter);
        if (! attr)
                status = INT_MAX;
        else if (attr->value.type != value.type)
@@ -147,7 +150,7 @@ match_string(string_matcher_t *m, const char *name)
 } /* match_string */
 
 static int
-match_logical(sdb_store_matcher_t *m, sdb_host_t *host,
+match_logical(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
                sdb_store_matcher_t *filter)
 {
        int status;
@@ -155,8 +158,7 @@ match_logical(sdb_store_matcher_t *m, sdb_host_t *host,
        assert((m->type == MATCHER_AND) || (m->type == MATCHER_OR));
        assert(OP_M(m)->left && OP_M(m)->right);
 
-       status = sdb_store_matcher_matches(OP_M(m)->left, STORE_OBJ(host),
-                       filter);
+       status = sdb_store_matcher_matches(OP_M(m)->left, obj, filter);
 
        /* lazy evaluation */
        if ((! status) && (m->type == MATCHER_AND))
@@ -164,21 +166,21 @@ match_logical(sdb_store_matcher_t *m, sdb_host_t *host,
        else if (status && (m->type == MATCHER_OR))
                return status;
 
-       return sdb_store_matcher_matches(OP_M(m)->right, STORE_OBJ(host), filter);
+       return sdb_store_matcher_matches(OP_M(m)->right, obj, filter);
 } /* match_logical */
 
 static int
-match_unary(sdb_store_matcher_t *m, sdb_host_t *host,
+match_unary(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
                sdb_store_matcher_t *filter)
 {
        assert(m->type == MATCHER_NOT);
        assert(UOP_M(m)->op);
 
-       return !sdb_store_matcher_matches(UOP_M(m)->op, STORE_OBJ(host), filter);
+       return !sdb_store_matcher_matches(UOP_M(m)->op, obj, filter);
 } /* match_unary */
 
 static int
-match_name(sdb_store_matcher_t *m, sdb_host_t *host,
+match_name(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
                sdb_store_matcher_t *filter)
 {
        sdb_avltree_iter_t *iter = NULL;
@@ -186,15 +188,17 @@ match_name(sdb_store_matcher_t *m, sdb_host_t *host,
 
        assert(m->type == MATCHER_NAME);
 
+       if (obj->type == NAME_M(m)->obj_type)
+               return match_string(&NAME_M(m)->name, SDB_OBJ(obj)->name);
+       else if (obj->type != SDB_HOST)
+               return 0;
+
        switch (NAME_M(m)->obj_type) {
-               case SDB_HOST:
-                       return match_string(&NAME_M(m)->name, SDB_OBJ(host)->name);
-                       break;
                case SDB_SERVICE:
-                       iter = sdb_avltree_get_iter(host->services);
+                       iter = sdb_avltree_get_iter(HOST(obj)->services);
                        break;
                case SDB_ATTRIBUTE:
-                       iter = sdb_avltree_get_iter(host->attributes);
+                       iter = sdb_avltree_get_iter(HOST(obj)->attributes);
                        break;
        }
 
@@ -213,7 +217,7 @@ match_name(sdb_store_matcher_t *m, sdb_host_t *host,
 } /* match_name */
 
 static int
-match_attr(sdb_store_matcher_t *m, sdb_host_t *host,
+match_attr(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
                sdb_store_matcher_t *filter)
 {
        sdb_attribute_t *attr;
@@ -221,7 +225,10 @@ match_attr(sdb_store_matcher_t *m, sdb_host_t *host,
        assert(m->type == MATCHER_ATTR);
        assert(ATTR_M(m)->name);
 
-       attr = attr_get(host, ATTR_M(m)->name, filter);
+       if (obj->type != SDB_HOST)
+               return 0;
+
+       attr = attr_get(HOST(obj), ATTR_M(m)->name, filter);
        if (attr) {
                char buf[sdb_data_strlen(&attr->value) + 1];
                if (sdb_data_format(&attr->value, buf, sizeof(buf), SDB_UNQUOTED) <= 0)
@@ -233,64 +240,66 @@ match_attr(sdb_store_matcher_t *m, sdb_host_t *host,
 } /* match_attr */
 
 static int
-match_lt(sdb_store_matcher_t *m, sdb_host_t *host,
+match_lt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
                sdb_store_matcher_t *filter)
 {
        int status;
        assert(m->type == MATCHER_LT);
-       status = COND_M(m)->cond->cmp(host, COND_M(m)->cond, filter);
+       status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
        return (status != INT_MAX) && (status < 0);
 } /* match_lt */
 
 static int
-match_le(sdb_store_matcher_t *m, sdb_host_t *host,
+match_le(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
                sdb_store_matcher_t *filter)
 {
        int status;
        assert(m->type == MATCHER_LE);
-       status = COND_M(m)->cond->cmp(host, COND_M(m)->cond, filter);
+       status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
        return (status != INT_MAX) && (status <= 0);
 } /* match_le */
 
 static int
-match_eq(sdb_store_matcher_t *m, sdb_host_t *host,
+match_eq(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
                sdb_store_matcher_t *filter)
 {
        int status;
        assert(m->type == MATCHER_EQ);
-       status = COND_M(m)->cond->cmp(host, COND_M(m)->cond, filter);
+       status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
        return (status != INT_MAX) && (! status);
 } /* match_eq */
 
 static int
-match_ge(sdb_store_matcher_t *m, sdb_host_t *host,
+match_ge(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
                sdb_store_matcher_t *filter)
 {
        int status;
        assert(m->type == MATCHER_GE);
-       status = COND_M(m)->cond->cmp(host, COND_M(m)->cond, filter);
+       status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
        return (status != INT_MAX) && (status >= 0);
 } /* match_ge */
 
 static int
-match_gt(sdb_store_matcher_t *m, sdb_host_t *host,
+match_gt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
                sdb_store_matcher_t *filter)
 {
        int status;
        assert(m->type == MATCHER_GT);
-       status = COND_M(m)->cond->cmp(host, COND_M(m)->cond, filter);
+       status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
        return (status != INT_MAX) && (status > 0);
 } /* match_gt */
 
 static int
-match_isnull(sdb_store_matcher_t *m, sdb_host_t *host,
+match_isnull(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
                sdb_store_matcher_t *filter)
 {
        assert(m->type == MATCHER_ISNULL);
-       return attr_get(host, ISNULL_M(m)->attr_name, filter) == NULL;
+       if (obj->type != SDB_HOST)
+               return 0;
+       return attr_get(HOST(obj), ISNULL_M(m)->attr_name, filter) == NULL;
 } /* match_isnull */
 
-typedef int (*matcher_cb)(sdb_store_matcher_t *, sdb_host_t *,
+typedef int (*matcher_cb)(sdb_store_matcher_t *, sdb_store_obj_t *,
                sdb_store_matcher_t *);
 
 /* this array needs to be indexable by the matcher types;
@@ -910,9 +919,6 @@ int
 sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
                sdb_store_matcher_t *filter)
 {
-       if (obj->type != SDB_HOST)
-               return 0;
-
        if (filter && (! sdb_store_matcher_matches(filter, obj, NULL)))
                return 0;
 
@@ -923,7 +929,7 @@ sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
        if ((m->type < 0) || ((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers)))
                return 0;
 
-       return matchers[m->type](m, HOST(obj), filter);
+       return matchers[m->type](m, obj, filter);
 } /* sdb_store_matcher_matches */
 
 char *
index c6eeb6bc3ae4d83b2cc6c323063795c5fe04083d..1adece554b031c6f94712b2a4977aa6ed2715e63 100644 (file)
@@ -539,10 +539,10 @@ START_TEST(test_scan)
        } golden_data[] = {
                { "host = 'a'", NULL,               1,
                        "OBJ\\[host\\]\\{ NAME\\{ 'a', \\(nil\\) \\} \\}" },
-               { "host = 'a'", "host = 'b'",       0,
+               { "host = 'a'", "host = 'x'",       0, /* filter never matches */
                        "OBJ\\[host\\]\\{ NAME\\{ 'a', \\(nil\\) \\} \\}" },
                { "host = 'a'",
-                       "attribute.x IS NULL",          1,
+                       "NOT attribute.x = ''",         1, /* filter always matches */
                        "OBJ\\[host\\]\\{ NAME\\{ 'a', \\(nil\\) \\} \\}" },
                { "host =~ 'a|b'", NULL,            2,
                        "OBJ\\[host\\]\\{ NAME\\{ NULL, "PTR_RE" \\} \\}" },
@@ -552,12 +552,22 @@ START_TEST(test_scan)
                        "OBJ\\[host\\]\\{ NAME\\{ NULL, "PTR_RE" \\} \\}" },
                { "service = 's1'", NULL,           2,
                        "OBJ\\[service\\]\\{ NAME\\{ 's1', \\(nil\\) } \\}" },
+               { "service = 's1'", "host = 'x'",   0, /* filter never matches */
+                       "OBJ\\[service\\]\\{ NAME\\{ 's1', \\(nil\\) } \\}" },
+               { "service = 's1'",
+                       "NOT attribute.x = ''",         2, /* filter always matches */
+                       "OBJ\\[service\\]\\{ NAME\\{ 's1', \\(nil\\) } \\}" },
                { "service =~ 's'", NULL,           2,
                        "OBJ\\[service\\]\\{ NAME\\{ NULL, "PTR_RE" } \\}" },
                { "service !~ 's'", NULL,           1,
                        "\\(NOT, OBJ\\[service\\]\\{ NAME\\{ NULL, "PTR_RE" } \\}\\)" },
                { "attribute = 'k1'", NULL,         1,
                        "OBJ\\[attribute\\]\\{ NAME\\{ 'k1', \\(nil\\) \\} " },
+               { "attribute = 'k1'", "host = 'x'", 0, /* filter never matches */
+                       "OBJ\\[attribute\\]\\{ NAME\\{ 'k1', \\(nil\\) \\} " },
+               { "attribute = 'k1'",
+                       "NOT attribute.x = ''",         1, /* filter always matches */
+                       "OBJ\\[attribute\\]\\{ NAME\\{ 'k1', \\(nil\\) \\} " },
                { "attribute = 'x'", NULL,          0,
                        "OBJ\\[attribute\\]\\{ NAME\\{ 'x', \\(nil\\) \\}" },
                { "attribute.k1 = 'v1'", NULL,      1,
@@ -630,9 +640,9 @@ START_TEST(test_scan)
                n = 0;
                sdb_store_scan(m, filter, scan_cb, &n);
                fail_unless(n == golden_data[i].expected,
-                               "sdb_store_scan(matcher{%s}, filter{NULL}) found %d hosts; "
-                               "expected: %d", golden_data[i].query, n,
-                               golden_data[i].expected);
+                               "sdb_store_scan(matcher{%s}, filter{%s}) found %d hosts; "
+                               "expected: %d", golden_data[i].query, golden_data[i].filter,
+                               n, golden_data[i].expected);
                sdb_object_deref(SDB_OBJ(filter));
                sdb_object_deref(SDB_OBJ(m));
        }