Code

When querying services/metrics skip hosts without such children.
authorSebastian Harl <sh@tokkee.org>
Tue, 30 Sep 2014 14:40:52 +0000 (07:40 -0700)
committerSebastian Harl <sh@tokkee.org>
Tue, 30 Sep 2014 17:29:41 +0000 (19:29 +0200)
This takes into account any filters and, thus, might mean that filters have to
be evaluated multiple times: once for determining if there are any children
and then again while serializing the data. This is because filtering happens
during serialization at which point it's too late to skip a host.

src/core/store.c
src/frontend/query.c
src/include/core/store.h
t/integration/simple_query.sh

index e14f27c0e4141482c4edea27f59eca97bc4abdcb..8cb30efaea88a250284cb569db2ae07b05d7fa12 100644 (file)
@@ -928,6 +928,10 @@ sdb_store_host_tojson(sdb_store_obj_t *h, sdb_strbuf_t *buf,
        if ((! h) || (h->type != SDB_HOST) || (! buf))
                return -1;
 
+       /* This function ignores SKIP_EMPTY flags given that the current
+        * implementation sucks and it's nut currently used when calling this
+        * function directly. */
+
        sdb_strbuf_append(buf, "{\"name\": \"%s\", ", SDB_OBJ(host)->name);
        store_common_tojson(h, buf);
 
@@ -950,6 +954,26 @@ sdb_store_host_tojson(sdb_store_obj_t *h, sdb_strbuf_t *buf,
        return 0;
 } /* sdb_store_host_tojson */
 
+static _Bool
+has_children(sdb_avltree_t *tree, sdb_store_matcher_t *filter)
+{
+       sdb_avltree_iter_t *iter;
+
+       if (! filter)
+               return sdb_avltree_size(tree) > 0;
+
+       iter = sdb_avltree_get_iter(tree);
+       while (sdb_avltree_iter_has_next(iter)) {
+               sdb_store_obj_t *sobj = STORE_OBJ(sdb_avltree_iter_get_next(iter));
+               if (sdb_store_matcher_matches(filter, sobj, NULL)) {
+                       sdb_avltree_iter_destroy(iter);
+                       return 1;
+               }
+       }
+       sdb_avltree_iter_destroy(iter);
+       return 0;
+} /* has_children */
+
 int
 sdb_store_tojson(sdb_strbuf_t *buf, sdb_store_matcher_t *filter, int flags)
 {
@@ -979,6 +1003,19 @@ sdb_store_tojson(sdb_strbuf_t *buf, sdb_store_matcher_t *filter, int flags)
                if (filter && (! sdb_store_matcher_matches(filter, host, NULL)))
                        continue;
 
+               /*
+                * XXX: This approach sucks but it's the best we can do at the moment.
+                * In the future, all store lookups should be split into multiple
+                * steps instead: first, retrieve all relevant objects and apply all
+                * pre-processing operations and then format it for the wire.
+                */
+               if ((flags & SDB_SKIP_EMPTY_SERVICES)
+                               && (! has_children(HOST(host)->services, filter)))
+                       continue;
+               if ((flags & SDB_SKIP_EMPTY_METRICS)
+                               && (! has_children(HOST(host)->metrics, filter)))
+                       continue;
+
                if (sdb_strbuf_len(buf) > len)
                        sdb_strbuf_append(buf, ",");
                len = sdb_strbuf_len(buf);
index 0ee734c4ee24428d98efa324b4a1237054fad62d..1751ba57e7a9a241b148cbc4f4dc391787cf0c44 100644 (file)
@@ -271,9 +271,11 @@ sdb_fe_exec_list(sdb_conn_t *conn, int type, sdb_store_matcher_t *filter)
        if (type == SDB_HOST)
                flags = SDB_SKIP_ALL;
        else if (type == SDB_SERVICE)
-               flags = SDB_SKIP_ALL & (~SDB_SKIP_SERVICES);
+               flags = (SDB_SKIP_ALL & (~SDB_SKIP_SERVICES))
+                       | SDB_SKIP_EMPTY_SERVICES;
        else if (type == SDB_METRIC)
-               flags = SDB_SKIP_ALL & (~SDB_SKIP_METRICS);
+               flags = (SDB_SKIP_ALL & (~SDB_SKIP_METRICS))
+                       | SDB_SKIP_EMPTY_METRICS;
        else {
                sdb_log(SDB_LOG_ERR, "frontend: Invalid object type %d "
                                "for LIST command", type);
index fa974bbd1f7f93656992423ad3891f3b66d6b645..d5a76941c06255085215a77215c2cd17b0b89f3c 100644 (file)
@@ -518,8 +518,9 @@ sdb_store_scan(sdb_store_matcher_t *m, sdb_store_matcher_t *filter,
 /*
  * Flags for serialization functions.
  *
- * By default, the full object will be included in the serialized output. When
- * specifying any of the flags, the respective information will be left out.
+ * By default, the full host object will be included in the serialized output.
+ * When specifying any of the flags, the respective information will be left
+ * out. The SKIP_EMPTY flags may be used to skip host objects entirely.
  */
 enum {
        SDB_SKIP_ATTRIBUTES         = 1 << 0,
@@ -527,7 +528,11 @@ enum {
        SDB_SKIP_METRICS            = 1 << 2,
        SDB_SKIP_SERVICE_ATTRIBUTES = 1 << 3,
 
-       SDB_SKIP_ALL                = 0xffff,
+       SDB_SKIP_ALL                = (1 << 8) - 1,
+
+       /* skip hosts if they do not reference any services/metrics */
+       SDB_SKIP_EMPTY_SERVICES     = 1 << 8,
+       SDB_SKIP_EMPTY_METRICS      = 1 << 9,
 };
 
 /*
index 900db90c01519c00c93095fd5eae902c0a906a93..b6394432d1111cd9e9aa58ee7f58a9329dcaee83 100755 (executable)
@@ -75,7 +75,6 @@ echo "$output" \
        | grep -F '"host1.example.com"' \
        | grep -F '"host2.example.com"' \
        | grep -F '"localhost"' \
-       | grep -F '"other.host.name"' \
        | grep -F '"some.host.name"' \
        | grep -F '"mock service"' \
        | grep -F '"other service"' \