Code

Merged branch 'master' of git://git.tokkee.org/sysdb.
authorSebastian Harl <sh@tokkee.org>
Tue, 13 Oct 2015 19:30:13 +0000 (21:30 +0200)
committerSebastian Harl <sh@tokkee.org>
Tue, 13 Oct 2015 19:30:13 +0000 (21:30 +0200)
30 files changed:
src/Makefile.am
src/core/memstore-private.h [new file with mode: 0644]
src/core/memstore.c [new file with mode: 0644]
src/core/memstore_exec.c [new file with mode: 0644]
src/core/memstore_expr.c [new file with mode: 0644]
src/core/memstore_lookup.c [new file with mode: 0644]
src/core/memstore_query.c [new file with mode: 0644]
src/core/plugin.c
src/core/store-private.h [deleted file]
src/core/store.c [deleted file]
src/core/store_exec.c [deleted file]
src/core/store_expr.c [deleted file]
src/core/store_json.c
src/core/store_lookup.c [deleted file]
src/core/store_query.c [deleted file]
src/frontend/connection-private.h
src/frontend/query.c
src/include/core/memstore.h [new file with mode: 0644]
src/include/core/store.h
src/include/parser/ast.h
src/parser/analyzer.c
src/parser/ast.c
src/parser/grammar.y
src/plugins/store/memory.c
t/unit/core/store_expr_test.c
t/unit/core/store_json_test.c
t/unit/core/store_lookup_test.c
t/unit/core/store_test.c
t/unit/frontend/query_test.c
t/unit/parser/parser_test.c

index f3bcae192846276a26dfbd868ba946868d5cbc19..886cc1ad2d80d562db0bba0fe71d141bb9518c9a 100644 (file)
@@ -72,16 +72,16 @@ libsysdb_fe_parser_la_CFLAGS = @COVERAGE_CFLAGS@ @PROFILING_CFLAGS@ \
                -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\""
 libsysdb_la_SOURCES = \
                sysdb.c include/sysdb.h \
+               core/data.c include/core/data.h \
+               core/memstore.c include/core/memstore.h \
+               core/memstore-private.h \
+               core/memstore_exec.c \
+               core/memstore_expr.c \
+               core/memstore_lookup.c \
+               core/memstore_query.c \
                core/object.c include/core/object.h \
                core/plugin.c include/core/plugin.h \
-               core/store.c include/core/store.h \
-               core/store-private.h \
-               core/store_exec.c \
-               core/store_expr.c \
-               core/store_json.c \
-               core/store_lookup.c \
-               core/store_query.c \
-               core/data.c include/core/data.h \
+               core/store_json.c include/core/store.h \
                core/time.c include/core/time.h \
                core/timeseries.c include/core/timeseries.h \
                frontend/connection.c include/frontend/connection.h \
diff --git a/src/core/memstore-private.h b/src/core/memstore-private.h
new file mode 100644 (file)
index 0000000..cd0152d
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * SysDB - src/core/memstore-private.h
+ * Copyright (C) 2012-2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * private data structures used by the memstore module
+ */
+
+#ifndef SDB_CORE_MEMSTORE_PRIVATE_H
+#define SDB_CORE_MEMSTORE_PRIVATE_H 1
+
+#include "core/memstore.h"
+#include "core/store.h"
+#include "utils/avltree.h"
+
+#include <sys/types.h>
+#include <regex.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * core types
+ */
+
+struct sdb_memstore_obj {
+       sdb_object_t super;
+#define _name super.name
+
+       /* object type */
+       int type;
+
+       /* common meta information */
+       sdb_time_t last_update;
+       sdb_time_t interval; /* moving average */
+       char **backends;
+       size_t backends_num;
+       sdb_memstore_obj_t *parent;
+};
+#define STORE_OBJ(obj) ((sdb_memstore_obj_t *)(obj))
+#define STORE_CONST_OBJ(obj) ((const sdb_memstore_obj_t *)(obj))
+
+typedef struct {
+       sdb_memstore_obj_t super;
+
+       sdb_data_t value;
+} attr_t;
+#define ATTR(obj) ((attr_t *)(obj))
+#define CONST_ATTR(obj) ((const attr_t *)(obj))
+
+typedef struct {
+       sdb_memstore_obj_t super;
+
+       sdb_avltree_t *attributes;
+} service_t;
+#define SVC(obj) ((service_t *)(obj))
+#define CONST_SVC(obj) ((const service_t *)(obj))
+
+typedef struct {
+       sdb_memstore_obj_t super;
+
+       sdb_avltree_t *attributes;
+       struct {
+               char *type;
+               char *id;
+       } store;
+} metric_t;
+#define METRIC(obj) ((metric_t *)(obj))
+
+typedef struct {
+       sdb_memstore_obj_t super;
+
+       sdb_avltree_t *services;
+       sdb_avltree_t *metrics;
+       sdb_avltree_t *attributes;
+} host_t;
+#define HOST(obj) ((host_t *)(obj))
+#define CONST_HOST(obj) ((const host_t *)(obj))
+
+/* shortcuts for accessing service/host attributes */
+#define _last_update super.last_update
+#define _interval super.interval
+
+/*
+ * querying
+ */
+
+struct sdb_memstore_query {
+       sdb_object_t super;
+       sdb_ast_node_t *ast;
+       sdb_memstore_matcher_t *matcher;
+       sdb_memstore_matcher_t *filter;
+};
+#define QUERY(m) ((sdb_memstore_query_t *)(m))
+
+/*
+ * expressions
+ */
+
+enum {
+       TYPED_EXPR  = -3, /* obj type stored in data.data.integer */
+       ATTR_VALUE  = -2, /* attr name stored in data.data.string */
+       FIELD_VALUE = -1, /* field type stored in data.data.integer */
+       /*  0: const value (stored in data) */
+       /* >0: operator id */
+};
+
+struct sdb_memstore_expr {
+       sdb_object_t super;
+
+       int type; /* see above */
+       int data_type;
+
+       sdb_memstore_expr_t *left;
+       sdb_memstore_expr_t *right;
+
+       sdb_data_t data;
+};
+#define CONST_EXPR(v) { SDB_OBJECT_INIT, 0, (v).type, NULL, NULL, (v) }
+#define EXPR_TO_STRING(e) \
+       (((e)->type == TYPED_EXPR) ? "<typed>" \
+               : ((e)->type == ATTR_VALUE) ? "attribute" \
+               : ((e)->type == FIELD_VALUE) ? SDB_FIELD_TO_NAME((e)->data.data.integer) \
+               : ((e)->type == 0) ? "<constant>" \
+               : ((e)->type > 0) ? SDB_DATA_OP_TO_STRING((e)->type) \
+               : "<unknown>")
+
+/*
+ * matchers
+ */
+
+/* when adding to this, also update 'MATCHER_SYM' below and 'matchers' in
+ * memstore_lookup.c */
+enum {
+       MATCHER_OR,
+       MATCHER_AND,
+       MATCHER_NOT,
+       MATCHER_ANY,
+       MATCHER_ALL,
+       MATCHER_IN,
+
+       /* unary operators */
+       MATCHER_ISNULL,
+       MATCHER_ISTRUE,
+       MATCHER_ISFALSE,
+
+       /* ary operators */
+       MATCHER_LT,
+       MATCHER_LE,
+       MATCHER_EQ,
+       MATCHER_NE,
+       MATCHER_GE,
+       MATCHER_GT,
+       MATCHER_REGEX,
+       MATCHER_NREGEX,
+
+       /* a generic query */
+       MATCHER_QUERY,
+};
+
+#define MATCHER_SYM(t) \
+       (((t) == MATCHER_OR) ? "OR" \
+               : ((t) == MATCHER_AND) ? "AND" \
+               : ((t) == MATCHER_NOT) ? "NOT" \
+               : ((t) == MATCHER_ANY) ? "ANY" \
+               : ((t) == MATCHER_ALL) ? "ALL" \
+               : ((t) == MATCHER_IN) ? "IN" \
+               : ((t) == MATCHER_ISNULL) ? "IS NULL" \
+               : ((t) == MATCHER_ISTRUE) ? "IS TRUE" \
+               : ((t) == MATCHER_ISFALSE) ? "IS FALSE" \
+               : ((t) == MATCHER_LT) ? "<" \
+               : ((t) == MATCHER_LE) ? "<=" \
+               : ((t) == MATCHER_EQ) ? "=" \
+               : ((t) == MATCHER_NE) ? "!=" \
+               : ((t) == MATCHER_GE) ? ">=" \
+               : ((t) == MATCHER_GT) ? ">" \
+               : ((t) == MATCHER_REGEX) ? "=~" \
+               : ((t) == MATCHER_NREGEX) ? "!~" \
+               : ((t) == MATCHER_QUERY) ? "QUERY" \
+               : "UNKNOWN")
+
+/* matcher base type */
+struct sdb_memstore_matcher {
+       sdb_object_t super;
+       /* type of the matcher */
+       int type;
+};
+#define M(m) ((sdb_memstore_matcher_t *)(m))
+
+/* infix operator matcher */
+typedef struct {
+       sdb_memstore_matcher_t super;
+
+       /* left and right hand operands */
+       sdb_memstore_matcher_t *left;
+       sdb_memstore_matcher_t *right;
+} op_matcher_t;
+#define OP_M(m) ((op_matcher_t *)(m))
+
+/* unary operator matcher */
+typedef struct {
+       sdb_memstore_matcher_t super;
+
+       /* operand */
+       sdb_memstore_matcher_t *op;
+} uop_matcher_t;
+#define UOP_M(m) ((uop_matcher_t *)(m))
+
+/* iter matcher */
+typedef struct {
+       sdb_memstore_matcher_t super;
+       sdb_memstore_expr_t *iter;
+       sdb_memstore_matcher_t *m;
+} iter_matcher_t;
+#define ITER_M(m) ((iter_matcher_t *)(m))
+
+/* compare operator matcher */
+typedef struct {
+       sdb_memstore_matcher_t super;
+
+       /* left and right hand expressions */
+       sdb_memstore_expr_t *left;
+       sdb_memstore_expr_t *right;
+} cmp_matcher_t;
+#define CMP_M(m) ((cmp_matcher_t *)(m))
+
+typedef struct {
+       sdb_memstore_matcher_t super;
+       sdb_memstore_expr_t *expr;
+} unary_matcher_t;
+#define UNARY_M(m) ((unary_matcher_t *)(m))
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ! SDB_CORE_MEMSTORE_H */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
diff --git a/src/core/memstore.c b/src/core/memstore.c
new file mode 100644 (file)
index 0000000..2449827
--- /dev/null
@@ -0,0 +1,1085 @@
+/*
+ * SysDB - src/core/memstore.c
+ * Copyright (C) 2012-2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#      include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "sysdb.h"
+#include "core/memstore-private.h"
+#include "core/plugin.h"
+#include "utils/avltree.h"
+#include "utils/error.h"
+
+#include <assert.h>
+
+#include <errno.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <pthread.h>
+
+/*
+ * private types
+ */
+
+struct sdb_memstore {
+       sdb_object_t super;
+
+       /* hosts are the top-level entries and
+        * reference everything else */
+       sdb_avltree_t *hosts;
+       pthread_rwlock_t host_lock;
+};
+
+/* internal representation of a to-be-stored object */
+typedef struct {
+       sdb_memstore_obj_t *parent;
+       sdb_avltree_t *parent_tree;
+       int type;
+       const char *name;
+       sdb_time_t last_update;
+       sdb_time_t interval;
+       const char * const *backends;
+       size_t backends_num;
+} store_obj_t;
+#define STORE_OBJ_INIT { NULL, NULL, 0, NULL, 0, 0, NULL, 0 }
+
+static sdb_type_t host_type;
+static sdb_type_t service_type;
+static sdb_type_t metric_type;
+static sdb_type_t attribute_type;
+
+static int
+store_init(sdb_object_t *obj, va_list __attribute__((unused)) ap)
+{
+       int err;
+       if (! (SDB_MEMSTORE(obj)->hosts = sdb_avltree_create()))
+               return -1;
+       if ((err = pthread_rwlock_init(&SDB_MEMSTORE(obj)->host_lock,
+                                       /* attr = */ NULL))) {
+               char errbuf[128];
+               sdb_log(SDB_LOG_ERR, "memstore: Failed to initialize lock: %s",
+                               sdb_strerror(err, errbuf, sizeof(errbuf)));
+               return -1;
+       }
+       return 0;
+} /* store_init */
+
+static void
+store_destroy(sdb_object_t *obj)
+{
+       int err;
+       if ((err = pthread_rwlock_destroy(&SDB_MEMSTORE(obj)->host_lock))) {
+               char errbuf[128];
+               sdb_log(SDB_LOG_ERR, "memstore: Failed to destroy lock: %s",
+                               sdb_strerror(err, errbuf, sizeof(errbuf)));
+               return;
+       }
+       sdb_avltree_destroy(SDB_MEMSTORE(obj)->hosts);
+       SDB_MEMSTORE(obj)->hosts = NULL;
+} /* store_destroy */
+
+static int
+store_obj_init(sdb_object_t *obj, va_list ap)
+{
+       sdb_memstore_obj_t *sobj = STORE_OBJ(obj);
+       sobj->type = va_arg(ap, int);
+       return 0;
+} /* store_obj_init */
+
+static void
+store_obj_destroy(sdb_object_t *obj)
+{
+       sdb_memstore_obj_t *sobj = STORE_OBJ(obj);
+       size_t i;
+
+       for (i = 0; i < sobj->backends_num; ++i)
+               free(sobj->backends[i]);
+       free(sobj->backends);
+       sobj->backends = NULL;
+       sobj->backends_num = 0;
+
+       // We don't currently keep an extra reference for parent objects to
+       // avoid circular self-references which are not handled correctly by
+       // the ref-count base management layer.
+       //sdb_object_deref(SDB_OBJ(sobj->parent));
+} /* store_obj_destroy */
+
+static int
+host_init(sdb_object_t *obj, va_list ap)
+{
+       host_t *sobj = HOST(obj);
+       int ret;
+
+       /* this will consume the first argument (type) of ap */
+       ret = store_obj_init(obj, ap);
+       if (ret)
+               return ret;
+
+       sobj->services = sdb_avltree_create();
+       if (! sobj->services)
+               return -1;
+       sobj->metrics = sdb_avltree_create();
+       if (! sobj->metrics)
+               return -1;
+       sobj->attributes = sdb_avltree_create();
+       if (! sobj->attributes)
+               return -1;
+       return 0;
+} /* host_init */
+
+static void
+host_destroy(sdb_object_t *obj)
+{
+       host_t *sobj = HOST(obj);
+       assert(obj);
+
+       store_obj_destroy(obj);
+
+       if (sobj->services)
+               sdb_avltree_destroy(sobj->services);
+       if (sobj->metrics)
+               sdb_avltree_destroy(sobj->metrics);
+       if (sobj->attributes)
+               sdb_avltree_destroy(sobj->attributes);
+} /* host_destroy */
+
+static int
+service_init(sdb_object_t *obj, va_list ap)
+{
+       service_t *sobj = SVC(obj);
+       int ret;
+
+       /* this will consume the first argument (type) of ap */
+       ret = store_obj_init(obj, ap);
+       if (ret)
+               return ret;
+
+       sobj->attributes = sdb_avltree_create();
+       if (! sobj->attributes)
+               return -1;
+       return 0;
+} /* service_init */
+
+static void
+service_destroy(sdb_object_t *obj)
+{
+       service_t *sobj = SVC(obj);
+       assert(obj);
+
+       store_obj_destroy(obj);
+
+       if (sobj->attributes)
+               sdb_avltree_destroy(sobj->attributes);
+} /* service_destroy */
+
+static int
+metric_init(sdb_object_t *obj, va_list ap)
+{
+       metric_t *sobj = METRIC(obj);
+       int ret;
+
+       /* this will consume the first argument (type) of ap */
+       ret = store_obj_init(obj, ap);
+       if (ret)
+               return ret;
+
+       sobj->attributes = sdb_avltree_create();
+       if (! sobj->attributes)
+               return -1;
+
+       sobj->store.type = sobj->store.id = NULL;
+       return 0;
+} /* metric_init */
+
+static void
+metric_destroy(sdb_object_t *obj)
+{
+       metric_t *sobj = METRIC(obj);
+       assert(obj);
+
+       store_obj_destroy(obj);
+
+       if (sobj->attributes)
+               sdb_avltree_destroy(sobj->attributes);
+
+       if (sobj->store.type)
+               free(sobj->store.type);
+       if (sobj->store.id)
+               free(sobj->store.id);
+} /* metric_destroy */
+
+static int
+attr_init(sdb_object_t *obj, va_list ap)
+{
+       const sdb_data_t *value;
+       int ret;
+
+       /* this will consume the first argument (type) of ap */
+       ret = store_obj_init(obj, ap);
+       if (ret)
+               return ret;
+       value = va_arg(ap, const sdb_data_t *);
+
+       if (value)
+               if (sdb_data_copy(&ATTR(obj)->value, value))
+                       return -1;
+       return 0;
+} /* attr_init */
+
+static void
+attr_destroy(sdb_object_t *obj)
+{
+       assert(obj);
+
+       store_obj_destroy(obj);
+       sdb_data_free_datum(&ATTR(obj)->value);
+} /* attr_destroy */
+
+static sdb_type_t store_type = {
+       /* size = */ sizeof(sdb_memstore_t),
+       /* init = */ store_init,
+       /* destroy = */ store_destroy,
+};
+
+static sdb_type_t host_type = {
+       /* size = */ sizeof(host_t),
+       /* init = */ host_init,
+       /* destroy = */ host_destroy
+};
+
+static sdb_type_t service_type = {
+       /* size = */ sizeof(service_t),
+       /* init = */ service_init,
+       /* destroy = */ service_destroy
+};
+
+static sdb_type_t metric_type = {
+       /* size = */ sizeof(metric_t),
+       /* init = */ metric_init,
+       /* destroy = */ metric_destroy
+};
+
+static sdb_type_t attribute_type = {
+       /* size = */ sizeof(attr_t),
+       /* init = */ attr_init,
+       /* destroy = */ attr_destroy
+};
+
+/*
+ * private helper functions
+ */
+
+static int
+record_backends(sdb_memstore_obj_t *obj,
+               const char * const *backends, size_t backends_num)
+{
+       char **tmp;
+       size_t i;
+
+       for (i = 0; i < backends_num; i++) {
+               bool found = 0;
+               size_t j;
+
+               for (j = 0; j < obj->backends_num; ++j) {
+                       if (!strcasecmp(obj->backends[j], backends[i])) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (found)
+                       continue;
+
+               tmp = realloc(obj->backends,
+                               (obj->backends_num + 1) * sizeof(*obj->backends));
+               if (! tmp)
+                       return -1;
+
+               obj->backends = tmp;
+               obj->backends[obj->backends_num] = strdup(backends[i]);
+               if (! obj->backends[obj->backends_num])
+                       return -1;
+
+               ++obj->backends_num;
+       }
+       return 0;
+} /* record_backends */
+
+static int
+store_obj(store_obj_t *obj, sdb_memstore_obj_t **updated_obj)
+{
+       sdb_memstore_obj_t *old, *new;
+       int status = 0;
+
+       assert(obj->parent_tree);
+
+       old = STORE_OBJ(sdb_avltree_lookup(obj->parent_tree, obj->name));
+       if (old) {
+               new = old;
+               sdb_object_deref(SDB_OBJ(old));
+       }
+       else {
+               if (obj->type == SDB_ATTRIBUTE) {
+                       /* the value will be updated by the caller */
+                       new = STORE_OBJ(sdb_object_create(obj->name, attribute_type,
+                                               obj->type, NULL));
+               }
+               else {
+                       sdb_type_t t;
+                       t = obj->type == SDB_HOST
+                               ? host_type
+                               : obj->type == SDB_SERVICE
+                                       ? service_type
+                                       : metric_type;
+                       new = STORE_OBJ(sdb_object_create(obj->name, t, obj->type));
+               }
+
+               if (new) {
+                       status = sdb_avltree_insert(obj->parent_tree, SDB_OBJ(new));
+
+                       /* pass control to the tree or destroy in case of an error */
+                       sdb_object_deref(SDB_OBJ(new));
+               }
+               else {
+                       char errbuf[1024];
+                       sdb_log(SDB_LOG_ERR, "memstore: Failed to create %s '%s': %s",
+                                       SDB_STORE_TYPE_TO_NAME(obj->type), obj->name,
+                                       sdb_strerror(errno, errbuf, sizeof(errbuf)));
+                       status = -1;
+               }
+       }
+
+       if (status < 0)
+               return status;
+       assert(new);
+
+       new->last_update = obj->last_update;
+       new->interval = obj->interval;
+
+       if (new->parent != obj->parent) {
+               // Avoid circular self-references which are not handled
+               // correctly by the ref-count based management layer.
+               //sdb_object_deref(SDB_OBJ(new->parent));
+               //sdb_object_ref(SDB_OBJ(obj->parent));
+               new->parent = obj->parent;
+       }
+
+       if (updated_obj)
+               *updated_obj = new;
+
+       if (record_backends(new, obj->backends, obj->backends_num))
+               return -1;
+       return status;
+} /* store_obj */
+
+static int
+store_metric_store(metric_t *metric, sdb_store_metric_t *m)
+{
+       char *type = metric->store.type;
+       char *id = metric->store.id;
+
+       if ((! metric->store.type) || strcasecmp(metric->store.type, m->store.type)) {
+               if (! (type = strdup(m->store.type)))
+                       return -1;
+       }
+       if ((! metric->store.id) || strcasecmp(metric->store.id, m->store.id)) {
+               if (! (id = strdup(m->store.id))) {
+                       if (type != metric->store.type)
+                               free(type);
+                       return -1;
+               }
+       }
+
+       if (type != metric->store.type) {
+               if (metric->store.type)
+                       free(metric->store.type);
+               metric->store.type = type;
+       }
+       if (id != metric->store.id) {
+               if (metric->store.id)
+                       free(metric->store.id);
+               metric->store.id = id;
+       }
+       return 0;
+} /* store_metric_store */
+
+/* The store's host_lock has to be acquired before calling this function. */
+static sdb_avltree_t *
+get_host_children(host_t *host, int type)
+{
+       if ((type != SDB_SERVICE) && (type != SDB_METRIC)
+                       && (type != SDB_ATTRIBUTE))
+               return NULL;
+
+       if (! host)
+               return NULL;
+
+       if (type == SDB_ATTRIBUTE)
+               return host->attributes;
+       else if (type == SDB_METRIC)
+               return host->metrics;
+       else
+               return host->services;
+} /* get_host_children */
+
+static sdb_avltree_t *
+get_obj_attrs(sdb_memstore_obj_t *obj)
+{
+       if (obj->type == SDB_HOST)
+               return HOST(obj)->attributes;
+       else if (obj->type == SDB_SERVICE)
+               return SVC(obj)->attributes;
+       else if (obj->type == SDB_METRIC)
+               return METRIC(obj)->attributes;
+       return NULL;
+} /* get_obj_attrs */
+
+/*
+ * store writer API
+ */
+
+static int
+store_attribute(sdb_store_attribute_t *attr, sdb_object_t *user_data)
+{
+       sdb_memstore_t *st = SDB_MEMSTORE(user_data);
+       store_obj_t obj = STORE_OBJ_INIT;
+       sdb_memstore_obj_t *new = NULL;
+       const char *hostname;
+       host_t *host;
+
+       sdb_avltree_t *children = NULL;
+       int status = 0;
+
+       if ((! attr) || (! attr->parent) || (! attr->key))
+               return -1;
+
+       hostname = attr->hostname;
+       if (attr->parent_type == SDB_HOST)
+               hostname = attr->parent;
+       if (! hostname)
+               return -1;
+
+       pthread_rwlock_wrlock(&st->host_lock);
+       host = HOST(sdb_avltree_lookup(st->hosts, hostname));
+       if (! host) {
+               sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - "
+                               "host '%s' not found", attr->key, hostname);
+               status = -1;
+       }
+
+       switch (attr->parent_type) {
+       case SDB_HOST:
+               obj.parent = STORE_OBJ(host);
+               obj.parent_tree = get_host_children(host, SDB_ATTRIBUTE);
+               break;
+       case SDB_SERVICE:
+       case SDB_METRIC:
+               children = get_host_children(host, attr->parent_type);
+               break;
+       default:
+               status = -1;
+               break;
+       }
+
+       if (children) {
+               obj.parent = STORE_OBJ(sdb_avltree_lookup(children, attr->parent));
+               if (! obj.parent) {
+                       sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - "
+                                       "%s '%s/%s' not found", attr->key,
+                                       SDB_STORE_TYPE_TO_NAME(attr->parent_type),
+                                       attr->hostname, attr->parent);
+                       status = -1;
+               }
+               else
+                       obj.parent_tree = attr->parent_type == SDB_SERVICE
+                               ? SVC(obj.parent)->attributes
+                               : METRIC(obj.parent)->attributes;
+       }
+
+       obj.type = SDB_ATTRIBUTE;
+       obj.name = attr->key;
+       obj.last_update = attr->last_update;
+       obj.interval = attr->interval;
+       obj.backends = attr->backends;
+       obj.backends_num = attr->backends_num;
+       if (! status)
+               status = store_obj(&obj, &new);
+
+       if (! status) {
+               assert(new);
+               /* update the value if it changed */
+               if (sdb_data_cmp(&ATTR(new)->value, &attr->value))
+                       if (sdb_data_copy(&ATTR(new)->value, &attr->value))
+                               status = -1;
+       }
+
+       if (obj.parent != STORE_OBJ(host))
+               sdb_object_deref(SDB_OBJ(obj.parent));
+       sdb_object_deref(SDB_OBJ(host));
+       pthread_rwlock_unlock(&st->host_lock);
+
+       return status;
+} /* store_attribute */
+
+static int
+store_host(sdb_store_host_t *host, sdb_object_t *user_data)
+{
+       sdb_memstore_t *st = SDB_MEMSTORE(user_data);
+       store_obj_t obj = { NULL, st->hosts, SDB_HOST, NULL, 0, 0, NULL, 0 };
+       int status = 0;
+
+       if ((! host) || (! host->name))
+               return -1;
+
+       obj.name = host->name;
+       obj.last_update = host->last_update;
+       obj.interval = host->interval;
+       obj.backends = host->backends;
+       obj.backends_num = host->backends_num;
+       pthread_rwlock_wrlock(&st->host_lock);
+       status = store_obj(&obj, NULL);
+       pthread_rwlock_unlock(&st->host_lock);
+
+       return status;
+} /* store_host */
+
+static int
+store_service(sdb_store_service_t *service, sdb_object_t *user_data)
+{
+       sdb_memstore_t *st = SDB_MEMSTORE(user_data);
+       store_obj_t obj = STORE_OBJ_INIT;
+       host_t *host;
+
+       int status = 0;
+
+       if ((! service) || (! service->hostname) || (! service->name))
+               return -1;
+
+       pthread_rwlock_wrlock(&st->host_lock);
+       host = HOST(sdb_avltree_lookup(st->hosts, service->hostname));
+       obj.parent = STORE_OBJ(host);
+       obj.parent_tree = get_host_children(host, SDB_SERVICE);
+       obj.type = SDB_SERVICE;
+       if (! obj.parent_tree) {
+               sdb_log(SDB_LOG_ERR, "memstore: Failed to store service '%s' - "
+                               "host '%s' not found", service->name, service->hostname);
+               status = -1;
+       }
+
+       obj.name = service->name;
+       obj.last_update = service->last_update;
+       obj.interval = service->interval;
+       obj.backends = service->backends;
+       obj.backends_num = service->backends_num;
+       if (! status)
+               status = store_obj(&obj, NULL);
+
+       sdb_object_deref(SDB_OBJ(host));
+       pthread_rwlock_unlock(&st->host_lock);
+       return status;
+} /* store_service */
+
+static int
+store_metric(sdb_store_metric_t *metric, sdb_object_t *user_data)
+{
+       sdb_memstore_t *st = SDB_MEMSTORE(user_data);
+       store_obj_t obj = STORE_OBJ_INIT;
+       sdb_memstore_obj_t *new = NULL;
+       host_t *host;
+
+       int status = 0;
+
+       if ((! metric) || (! metric->hostname) || (! metric->name))
+               return -1;
+
+       if ((metric->store.type != NULL) != (metric->store.id != NULL))
+               return -1;
+
+       pthread_rwlock_wrlock(&st->host_lock);
+       host = HOST(sdb_avltree_lookup(st->hosts, metric->hostname));
+       obj.parent = STORE_OBJ(host);
+       obj.parent_tree = get_host_children(host, SDB_METRIC);
+       obj.type = SDB_METRIC;
+       if (! obj.parent_tree) {
+               sdb_log(SDB_LOG_ERR, "memstore: Failed to store metric '%s' - "
+                               "host '%s' not found", metric->name, metric->hostname);
+               status = -1;
+       }
+
+       obj.name = metric->name;
+       obj.last_update = metric->last_update;
+       obj.interval = metric->interval;
+       obj.backends = metric->backends;
+       obj.backends_num = metric->backends_num;
+       if (! status)
+               status = store_obj(&obj, &new);
+       sdb_object_deref(SDB_OBJ(host));
+
+       if (status) {
+               pthread_rwlock_unlock(&st->host_lock);
+               return status;
+       }
+
+       assert(new);
+       if (metric->store.type && metric->store.id)
+               if (store_metric_store(METRIC(new), metric))
+                       status = -1;
+       pthread_rwlock_unlock(&st->host_lock);
+       return status;
+} /* store_metric */
+
+sdb_store_writer_t sdb_memstore_writer = {
+       store_host, store_service, store_metric, store_attribute,
+};
+
+/*
+ * store query API
+ */
+
+static sdb_object_t *
+prepare_query(sdb_ast_node_t *ast,
+               sdb_strbuf_t __attribute__((unused)) *errbuf,
+               sdb_object_t __attribute__((unused)) *user_data)
+{
+       return SDB_OBJ(sdb_memstore_query_prepare(ast));
+} /* prepare_query */
+
+static int
+execute_query(sdb_object_t *q,
+               sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
+               sdb_object_t *user_data)
+{
+       return sdb_memstore_query_execute(SDB_MEMSTORE(user_data),
+                       QUERY(q), w, wd, errbuf);
+} /* execute_query */
+
+sdb_store_reader_t sdb_memstore_reader = {
+       prepare_query, execute_query,
+};
+
+/*
+ * public API
+ */
+
+sdb_memstore_t *
+sdb_memstore_create(void)
+{
+       return SDB_MEMSTORE(sdb_object_create("memstore", store_type));
+} /* sdb_memstore_create */
+
+int
+sdb_memstore_host(sdb_memstore_t *store, const char *name,
+               sdb_time_t last_update, sdb_time_t interval)
+{
+       sdb_store_host_t host = {
+               name, last_update, interval, NULL, 0,
+       };
+       return store_host(&host, SDB_OBJ(store));
+} /* sdb_memstore_host */
+
+int
+sdb_memstore_service(sdb_memstore_t *store, const char *hostname, const char *name,
+               sdb_time_t last_update, sdb_time_t interval)
+{
+       sdb_store_service_t service = {
+               hostname, name, last_update, interval, NULL, 0,
+       };
+       return store_service(&service, SDB_OBJ(store));
+} /* sdb_memstore_service */
+
+int
+sdb_memstore_metric(sdb_memstore_t *store, const char *hostname, const char *name,
+               sdb_metric_store_t *metric_store,
+               sdb_time_t last_update, sdb_time_t interval)
+{
+       sdb_store_metric_t metric = {
+               hostname, name, { NULL, NULL }, last_update, interval, NULL, 0,
+       };
+       if (metric_store) {
+               metric.store.type = metric_store->type;
+               metric.store.id = metric_store->id;
+       }
+       return store_metric(&metric, SDB_OBJ(store));
+} /* sdb_memstore_metric */
+
+int
+sdb_memstore_attribute(sdb_memstore_t *store, const char *hostname,
+               const char *key, const sdb_data_t *value,
+               sdb_time_t last_update, sdb_time_t interval)
+{
+       sdb_store_attribute_t attr = {
+               NULL, SDB_HOST, hostname, key, SDB_DATA_INIT,
+               last_update, interval, NULL, 0,
+       };
+       if (value) {
+               attr.value = *value;
+       }
+       return store_attribute(&attr, SDB_OBJ(store));
+} /* sdb_memstore_attribute */
+
+int
+sdb_memstore_service_attr(sdb_memstore_t *store, const char *hostname,
+               const char *service, const char *key, const sdb_data_t *value,
+               sdb_time_t last_update, sdb_time_t interval)
+{
+       sdb_store_attribute_t attr = {
+               hostname, SDB_SERVICE, service, key, SDB_DATA_INIT,
+               last_update, interval, NULL, 0,
+       };
+       if (value) {
+               attr.value = *value;
+       }
+       return store_attribute(&attr, SDB_OBJ(store));
+} /* sdb_memstore_service_attr */
+
+int
+sdb_memstore_metric_attr(sdb_memstore_t *store, const char *hostname,
+               const char *metric, const char *key, const sdb_data_t *value,
+               sdb_time_t last_update, sdb_time_t interval)
+{
+       sdb_store_attribute_t attr = {
+               hostname, SDB_METRIC, metric, key, SDB_DATA_INIT,
+               last_update, interval, NULL, 0,
+       };
+       if (value) {
+               attr.value = *value;
+       }
+       return store_attribute(&attr, SDB_OBJ(store));
+} /* sdb_memstore_metric_attr */
+
+sdb_memstore_obj_t *
+sdb_memstore_get_host(sdb_memstore_t *store, const char *name)
+{
+       host_t *host;
+
+       if ((! store) || (! name))
+               return NULL;
+
+       host = HOST(sdb_avltree_lookup(store->hosts, name));
+       if (! host)
+               return NULL;
+
+       return STORE_OBJ(host);
+} /* sdb_memstore_get_host */
+
+sdb_memstore_obj_t *
+sdb_memstore_get_child(sdb_memstore_obj_t *obj, int type, const char *name)
+{
+       sdb_avltree_t *children = NULL;
+
+       if ((! obj) || (! name))
+               return NULL;
+
+       if (type & SDB_ATTRIBUTE)
+               children = get_obj_attrs(obj);
+       else if (obj->type == SDB_HOST)
+               children = get_host_children(HOST(obj), type);
+       if (! children)
+               return NULL;
+       return STORE_OBJ(sdb_avltree_lookup(children, name));
+} /* sdb_memstore_get_child */
+
+int
+sdb_memstore_get_field(sdb_memstore_obj_t *obj, int field, sdb_data_t *res)
+{
+       sdb_data_t tmp;
+
+       if (! obj)
+               return -1;
+
+       switch (field) {
+               case SDB_FIELD_NAME:
+                       tmp.type = SDB_TYPE_STRING;
+                       tmp.data.string = strdup(SDB_OBJ(obj)->name);
+                       if (! tmp.data.string)
+                               return -1;
+                       break;
+               case SDB_FIELD_LAST_UPDATE:
+                       tmp.type = SDB_TYPE_DATETIME;
+                       tmp.data.datetime = obj->last_update;
+                       break;
+               case SDB_FIELD_AGE:
+                       tmp.type = SDB_TYPE_DATETIME;
+                       tmp.data.datetime = sdb_gettime() - obj->last_update;
+                       break;
+               case SDB_FIELD_INTERVAL:
+                       tmp.type = SDB_TYPE_DATETIME;
+                       tmp.data.datetime = obj->interval;
+                       break;
+               case SDB_FIELD_BACKEND:
+                       if (! res)
+                               return 0;
+                       tmp.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING;
+                       tmp.data.array.length = obj->backends_num;
+                       tmp.data.array.values = obj->backends;
+                       return sdb_data_copy(res, &tmp);
+               case SDB_FIELD_VALUE:
+                       if (obj->type != SDB_ATTRIBUTE)
+                               return -1;
+                       if (! res)
+                               return 0;
+                       return sdb_data_copy(res, &ATTR(obj)->value);
+               case SDB_FIELD_TIMESERIES:
+                       if (obj->type != SDB_METRIC)
+                               return -1;
+                       tmp.type = SDB_TYPE_BOOLEAN;
+                       tmp.data.boolean = METRIC(obj)->store.type != NULL;
+               default:
+                       return -1;
+       }
+       if (res)
+               *res = tmp;
+       else
+               sdb_data_free_datum(&tmp);
+       return 0;
+} /* sdb_memstore_get_field */
+
+int
+sdb_memstore_get_attr(sdb_memstore_obj_t *obj, const char *name, sdb_data_t *res,
+               sdb_memstore_matcher_t *filter)
+{
+       sdb_memstore_obj_t *attr;
+
+       if ((! obj) || (! name))
+               return -1;
+
+       attr = STORE_OBJ(sdb_avltree_lookup(get_obj_attrs(obj), name));
+       if (! attr)
+               return -1;
+       if (filter && (! sdb_memstore_matcher_matches(filter, attr, NULL))) {
+               sdb_object_deref(SDB_OBJ(attr));
+               return -1;
+       }
+
+       assert(STORE_OBJ(attr)->type == SDB_ATTRIBUTE);
+       if (res)
+               sdb_data_copy(res, &ATTR(attr)->value);
+       sdb_object_deref(SDB_OBJ(attr));
+       return 0;
+} /* sdb_memstore_get_attr */
+
+int
+sdb_memstore_scan(sdb_memstore_t *store, int type,
+               sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter,
+               sdb_memstore_lookup_cb cb, void *user_data)
+{
+       sdb_avltree_iter_t *host_iter = NULL;
+       int status = 0;
+
+       if ((! store) || (! cb))
+               return -1;
+
+       if ((type != SDB_HOST) && (type != SDB_SERVICE) && (type != SDB_METRIC)) {
+               sdb_log(SDB_LOG_ERR, "memstore: Cannot scan objects of type %d", type);
+               return -1;
+       }
+
+       pthread_rwlock_rdlock(&store->host_lock);
+       host_iter = sdb_avltree_get_iter(store->hosts);
+       if (! host_iter)
+               status = -1;
+
+       /* has_next returns false if the iterator is NULL */
+       while (sdb_avltree_iter_has_next(host_iter)) {
+               sdb_memstore_obj_t *host;
+               sdb_avltree_iter_t *iter = NULL;
+
+               host = STORE_OBJ(sdb_avltree_iter_get_next(host_iter));
+               assert(host);
+
+               if (! sdb_memstore_matcher_matches(filter, host, NULL))
+                       continue;
+
+               if (type == SDB_SERVICE)
+                       iter = sdb_avltree_get_iter(HOST(host)->services);
+               else if (type == SDB_METRIC)
+                       iter = sdb_avltree_get_iter(HOST(host)->metrics);
+
+               if (iter) {
+                       while (sdb_avltree_iter_has_next(iter)) {
+                               sdb_memstore_obj_t *obj;
+                               obj = STORE_OBJ(sdb_avltree_iter_get_next(iter));
+                               assert(obj);
+
+                               if (sdb_memstore_matcher_matches(m, obj, filter)) {
+                                       if (cb(obj, filter, user_data)) {
+                                               sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
+                                                               "an error while scanning");
+                                               status = -1;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               else if (sdb_memstore_matcher_matches(m, host, filter)) {
+                       if (cb(host, filter, user_data)) {
+                               sdb_log(SDB_LOG_ERR, "memstore: Callback returned "
+                                               "an error while scanning");
+                               status = -1;
+                       }
+               }
+
+               sdb_avltree_iter_destroy(iter);
+               if (status)
+                       break;
+       }
+
+       sdb_avltree_iter_destroy(host_iter);
+       pthread_rwlock_unlock(&store->host_lock);
+       return status;
+} /* sdb_memstore_scan */
+
+int
+sdb_memstore_emit(sdb_memstore_obj_t *obj, sdb_store_writer_t *w, sdb_object_t *wd)
+{
+       if ((! obj) || (! w))
+               return -1;
+
+       switch (obj->type) {
+       case SDB_HOST:
+               {
+                       sdb_store_host_t host = {
+                               obj->_name,
+                               obj->last_update,
+                               obj->interval,
+                               (const char * const *)obj->backends,
+                               obj->backends_num,
+                       };
+                       if (! w->store_host)
+                               return -1;
+                       return w->store_host(&host, wd);
+               }
+       case SDB_SERVICE:
+               {
+                       sdb_store_service_t service = {
+                               obj->parent ? obj->parent->_name : NULL,
+                               obj->_name,
+                               obj->last_update,
+                               obj->interval,
+                               (const char * const *)obj->backends,
+                               obj->backends_num,
+                       };
+                       if (! w->store_service)
+                               return -1;
+                       return w->store_service(&service, wd);
+               }
+       case SDB_METRIC:
+               {
+                       sdb_store_metric_t metric = {
+                               obj->parent ? obj->parent->_name : NULL,
+                               obj->_name,
+                               {
+                                       METRIC(obj)->store.type,
+                                       METRIC(obj)->store.id,
+                               },
+                               obj->last_update,
+                               obj->interval,
+                               (const char * const *)obj->backends,
+                               obj->backends_num,
+                       };
+                       if (! w->store_metric)
+                               return -1;
+                       return w->store_metric(&metric, wd);
+               }
+       case SDB_ATTRIBUTE:
+               {
+                       sdb_store_attribute_t attr = {
+                               NULL,
+                               obj->parent ? obj->parent->type : 0,
+                               obj->parent ? obj->parent->_name : NULL,
+                               obj->_name,
+                               ATTR(obj)->value,
+                               obj->last_update,
+                               obj->interval,
+                               (const char * const *)obj->backends,
+                               obj->backends_num,
+                       };
+                       if (obj->parent && (obj->parent->type != SDB_HOST)
+                                       && obj->parent->parent)
+                               attr.hostname = obj->parent->parent->_name;
+                       if (! w->store_attribute)
+                               return -1;
+                       return w->store_attribute(&attr, wd);
+               }
+       }
+
+       return -1;
+} /* sdb_memstore_emit */
+
+int
+sdb_memstore_emit_full(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter,
+               sdb_store_writer_t *w, sdb_object_t *wd)
+{
+       sdb_avltree_t *trees[] = { NULL, NULL, NULL };
+       size_t i;
+
+       if (sdb_memstore_emit(obj, w, wd))
+               return -1;
+
+       if (obj->type == SDB_HOST) {
+               trees[0] = HOST(obj)->attributes;
+               trees[1] = HOST(obj)->metrics;
+               trees[2] = HOST(obj)->services;
+       }
+       else if (obj->type == SDB_SERVICE)
+               trees[0] = SVC(obj)->attributes;
+       else if (obj->type == SDB_METRIC)
+               trees[0] = METRIC(obj)->attributes;
+       else if (obj->type == SDB_ATTRIBUTE)
+               return 0;
+       else
+               return -1;
+
+       for (i = 0; i < SDB_STATIC_ARRAY_LEN(trees); ++i) {
+               sdb_avltree_iter_t *iter;
+
+               if (! trees[i])
+                       continue;
+
+               iter = sdb_avltree_get_iter(trees[i]);
+               while (sdb_avltree_iter_has_next(iter)) {
+                       sdb_memstore_obj_t *child;
+                       child = STORE_OBJ(sdb_avltree_iter_get_next(iter));
+
+                       if (filter && (! sdb_memstore_matcher_matches(filter, child, NULL)))
+                               continue;
+
+                       if (sdb_memstore_emit_full(child, filter, w, wd)) {
+                               sdb_avltree_iter_destroy(iter);
+                               return -1;
+                       }
+               }
+               sdb_avltree_iter_destroy(iter);
+       }
+       return 0;
+} /* sdb_memstore_emit_full */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
diff --git a/src/core/memstore_exec.c b/src/core/memstore_exec.c
new file mode 100644 (file)
index 0000000..a489a66
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * SysDB - src/core/memstore_exec.c
+ * Copyright (C) 2014-2015 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core/object.h"
+#include "core/plugin.h"
+#include "core/memstore-private.h"
+#include "frontend/connection.h"
+#include "parser/ast.h"
+#include "utils/error.h"
+
+#include <errno.h>
+
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * private helper functions
+ */
+
+typedef struct {
+       sdb_memstore_obj_t *current_host;
+
+       sdb_store_writer_t *w;
+       sdb_object_t *wd;
+} iter_t;
+
+static int
+maybe_emit_host(iter_t *iter, sdb_memstore_obj_t *obj)
+{
+       if ((obj->type == SDB_HOST) || (obj->type == SDB_ATTRIBUTE))
+               return 0;
+       if (iter->current_host == obj->parent)
+               return 0;
+       iter->current_host = obj->parent;
+       return sdb_memstore_emit(obj->parent, iter->w, iter->wd);
+} /* maybe_emit_host */
+
+static int
+list_tojson(sdb_memstore_obj_t *obj,
+               sdb_memstore_matcher_t __attribute__((unused)) *filter,
+               void *user_data)
+{
+       iter_t *iter = user_data;
+       maybe_emit_host(iter, obj);
+       return sdb_memstore_emit(obj, iter->w, iter->wd);
+} /* list_tojson */
+
+static int
+lookup_tojson(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter,
+               void *user_data)
+{
+       iter_t *iter = user_data;
+       maybe_emit_host(iter, obj);
+       return sdb_memstore_emit_full(obj, filter, iter->w, iter->wd);
+} /* lookup_tojson */
+
+/*
+ * query implementations
+ */
+
+static int
+exec_fetch(sdb_memstore_t *store,
+               sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
+               int type, const char *hostname, int parent_type, const char *parent,
+               const char *name, bool full, sdb_memstore_matcher_t *filter)
+{
+       sdb_memstore_obj_t *host, *p = NULL, *obj;
+       int status = 0;
+
+       if (type == SDB_HOST)
+               hostname = name;
+
+       host = sdb_memstore_get_host(store, hostname);
+       if ((! host)
+                       || (filter && (! sdb_memstore_matcher_matches(filter, host, NULL)))) {
+               sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s: "
+                               "host %s not found", SDB_STORE_TYPE_TO_NAME(type),
+                               name, hostname);
+               sdb_object_deref(SDB_OBJ(host));
+               return -1;
+       }
+       obj = host;
+       if (type != SDB_HOST) {
+               if (parent) {
+                       p = sdb_memstore_get_child(obj, parent_type, parent);
+                       if ((! p) || (filter
+                                               && (! sdb_memstore_matcher_matches(filter, p, NULL)))) {
+                               sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s.%s.%s: "
+                                               "%s not found", SDB_STORE_TYPE_TO_NAME(type),
+                                               hostname, parent, name, parent);
+                               status = -1;
+                       }
+                       obj = p;
+               }
+               if (! status) {
+                       obj = sdb_memstore_get_child(obj, type, name);
+                       if ((! obj) || (filter
+                                               && (! sdb_memstore_matcher_matches(filter, obj, NULL)))) {
+                               sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s.%s: "
+                                               "%s not found", SDB_STORE_TYPE_TO_NAME(type),
+                                               hostname, name, name);
+                               status = -1;
+                       }
+               }
+       }
+
+       if (! status) {
+               if (type != SDB_HOST)
+                       status = sdb_memstore_emit(host, w, wd);
+               if ((! status) && parent)
+                       status = sdb_memstore_emit(p, w, wd);
+               if (! status) {
+                       if (full)
+                               status = sdb_memstore_emit_full(obj, filter, w, wd);
+                       else
+                               status = sdb_memstore_emit(obj, w, wd);
+               }
+               if (status) {
+                       sdb_log(SDB_LOG_ERR, "memstore: Failed to serialize "
+                                       "%s %s.%s to JSON", SDB_STORE_TYPE_TO_NAME(type),
+                                       hostname, name);
+                       sdb_strbuf_sprintf(errbuf, "Out of memory");
+                       status = -1;
+               }
+       }
+
+       if (host != obj)
+               sdb_object_deref(SDB_OBJ(host));
+       if (p != obj)
+               sdb_object_deref(SDB_OBJ(p));
+       sdb_object_deref(SDB_OBJ(obj));
+
+       if (status)
+               return status;
+       return SDB_CONNECTION_DATA;
+} /* exec_fetch */
+
+static int
+exec_list(sdb_memstore_t *store,
+               sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
+               int type, sdb_memstore_matcher_t *filter)
+{
+       iter_t iter = { NULL, w, wd };
+
+       if (sdb_memstore_scan(store, type, /* m = */ NULL, filter, list_tojson, &iter)) {
+               sdb_log(SDB_LOG_ERR, "memstore: Failed to serialize "
+                               "store to JSON");
+               sdb_strbuf_sprintf(errbuf, "Out of memory");
+               return -1;
+       }
+
+       return SDB_CONNECTION_DATA;
+} /* exec_list */
+
+static int
+exec_lookup(sdb_memstore_t *store,
+               sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
+               int type, sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter)
+{
+       iter_t iter = { NULL, w, wd };
+
+       if (sdb_memstore_scan(store, type, m, filter, lookup_tojson, &iter)) {
+               sdb_log(SDB_LOG_ERR, "memstore: Failed to lookup %ss",
+                               SDB_STORE_TYPE_TO_NAME(type));
+               sdb_strbuf_sprintf(errbuf, "Failed to lookup %ss",
+                               SDB_STORE_TYPE_TO_NAME(type));
+               return -1;
+       }
+
+       return SDB_CONNECTION_DATA;
+} /* exec_lookup */
+
+/*
+ * public API
+ */
+
+int
+sdb_memstore_query_execute(sdb_memstore_t *store, sdb_memstore_query_t *q,
+               sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf)
+{
+       sdb_ast_node_t *ast;
+
+       if (! q)
+               return -1;
+       if (! q->ast) {
+               sdb_log(SDB_LOG_ERR, "memstore: Invalid empty query");
+               return -1;
+       }
+
+       ast = q->ast;
+       switch (ast->type) {
+       case SDB_AST_TYPE_FETCH:
+               return exec_fetch(store, w, wd, errbuf,
+                               SDB_AST_FETCH(ast)->obj_type, SDB_AST_FETCH(ast)->hostname,
+                               SDB_AST_FETCH(ast)->parent_type, SDB_AST_FETCH(ast)->parent,
+                               SDB_AST_FETCH(ast)->name, SDB_AST_FETCH(ast)->full, q->filter);
+
+       case SDB_AST_TYPE_LIST:
+               return exec_list(store, w, wd, errbuf, SDB_AST_LIST(ast)->obj_type,
+                               q->filter);
+
+       case SDB_AST_TYPE_LOOKUP:
+               return exec_lookup(store, w, wd, errbuf, SDB_AST_LOOKUP(ast)->obj_type,
+                               q->matcher, q->filter);
+
+       default:
+               sdb_log(SDB_LOG_ERR, "memstore: Invalid query of type %s",
+                               SDB_AST_TYPE_TO_STRING(ast));
+               return -1;
+       }
+
+       return 0;
+} /* sdb_memstore_query_execute */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
diff --git a/src/core/memstore_expr.c b/src/core/memstore_expr.c
new file mode 100644 (file)
index 0000000..8335584
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * SysDB - src/core/memstore_expr.c
+ * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This module implements arithmetic and logical expressions for in-memory
+ * stores.
+ */
+
+#if HAVE_CONFIG_H
+#      include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "sysdb.h"
+#include "core/memstore-private.h"
+#include "core/data.h"
+#include "core/object.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * private data types
+ */
+
+/* iterate through either a list of child nodes or arrays */
+struct sdb_memstore_expr_iter {
+       sdb_memstore_obj_t *obj;
+       sdb_memstore_expr_t *expr;
+
+       sdb_avltree_iter_t *tree;
+
+       sdb_data_t array;
+       size_t array_idx;
+       bool free_array;
+
+       sdb_memstore_matcher_t *filter;
+};
+
+/*
+ * private types
+ */
+
+static int
+expr_init(sdb_object_t *obj, va_list ap)
+{
+       int type = va_arg(ap, int);
+       sdb_memstore_expr_t *left  = va_arg(ap, sdb_memstore_expr_t *);
+       sdb_memstore_expr_t *right = va_arg(ap, sdb_memstore_expr_t *);
+       const sdb_data_t *value = va_arg(ap, const sdb_data_t *);
+
+       sdb_memstore_expr_t *expr = SDB_MEMSTORE_EXPR(obj);
+
+       if (type <= 0) {
+               if (! value)
+                       return -1;
+               if ((type == TYPED_EXPR) && (! left))
+                       return -1;
+       } else {
+               if (value)
+                       return -1;
+               if ((! left) || (! right))
+                       return -1;
+       }
+
+       if (value)
+               expr->data = *value;
+
+       sdb_object_ref(SDB_OBJ(left));
+       sdb_object_ref(SDB_OBJ(right));
+
+       expr->type  = type;
+       expr->left  = left;
+       expr->right = right;
+
+       /* unknown for now */
+       expr->data_type = -1;
+       return 0;
+} /* expr_init */
+
+static void
+expr_destroy(sdb_object_t *obj)
+{
+       sdb_memstore_expr_t *expr = SDB_MEMSTORE_EXPR(obj);
+       sdb_object_deref(SDB_OBJ(expr->left));
+       sdb_object_deref(SDB_OBJ(expr->right));
+
+       if (expr->data.type)
+               sdb_data_free_datum(&expr->data);
+} /* expr_destroy */
+
+static sdb_type_t expr_type = {
+       /* size = */ sizeof(sdb_memstore_expr_t),
+       /* init = */ expr_init,
+       /* destroy = */ expr_destroy,
+};
+
+/*
+ * public API
+ */
+
+sdb_memstore_expr_t *
+sdb_memstore_expr_create(int op, sdb_memstore_expr_t *left, sdb_memstore_expr_t *right)
+{
+       sdb_data_t value = SDB_DATA_INIT;
+       sdb_memstore_expr_t *e;
+
+       if ((op < 0) || (SDB_DATA_CONCAT < op) || (! left) || (! right))
+               return NULL;
+
+       if (left->type || right->type) {
+               e = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-expr", expr_type,
+                                       op, left, right, NULL));
+               e->data_type = sdb_data_expr_type(op, left->type, right->type);
+               return e;
+       }
+       /* else: both expressions are constant values; evaluate now */
+
+       if (sdb_data_expr_eval(op, &left->data, &right->data, &value))
+               return NULL;
+       e = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-constvalue", expr_type,
+                               0, NULL, NULL, &value));
+       e->data_type = value.type;
+       return e;
+} /* sdb_memstore_expr_create */
+
+sdb_memstore_expr_t *
+sdb_memstore_expr_typed(int typ, sdb_memstore_expr_t *expr)
+{
+       sdb_data_t value = { SDB_TYPE_INTEGER, { .integer = typ } };
+       sdb_memstore_expr_t *e;
+
+       if ((typ < SDB_HOST) || (SDB_ATTRIBUTE < typ))
+               return NULL;
+
+       e = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-typedexpr", expr_type,
+                               TYPED_EXPR, expr, NULL, &value));
+       e->data_type = expr->data_type;
+       return e;
+} /* sdb_memstore_expr_typed */
+
+sdb_memstore_expr_t *
+sdb_memstore_expr_fieldvalue(int field)
+{
+       sdb_data_t value = { SDB_TYPE_INTEGER, { .integer = field } };
+       sdb_memstore_expr_t *e;
+
+       if ((field < SDB_FIELD_NAME) || (SDB_FIELD_TIMESERIES < field))
+               return NULL;
+       e = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-fieldvalue", expr_type,
+                               FIELD_VALUE, NULL, NULL, &value));
+       e->data_type = SDB_FIELD_TYPE(field);
+       return e;
+} /* sdb_memstore_expr_fieldvalue */
+
+sdb_memstore_expr_t *
+sdb_memstore_expr_attrvalue(const char *name)
+{
+       sdb_data_t value = { SDB_TYPE_STRING, { .string = NULL} };
+       sdb_memstore_expr_t *expr;
+
+       value.data.string = strdup(name);
+       if (! value.data.string)
+               return NULL;
+
+       expr = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-attrvalue", expr_type,
+                               ATTR_VALUE, NULL, NULL, &value));
+       if (! expr)
+               free(value.data.string);
+       expr->data_type = -1;
+       return expr;
+} /* sdb_memstore_expr_attrvalue */
+
+sdb_memstore_expr_t *
+sdb_memstore_expr_constvalue(const sdb_data_t *value)
+{
+       sdb_data_t data = SDB_DATA_INIT;
+       sdb_memstore_expr_t *e;
+
+       if (sdb_data_copy(&data, value))
+               return NULL;
+       e = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-constvalue", expr_type,
+                               0, NULL, NULL, &data));
+       e->data_type = data.type;
+       return e;
+} /* sdb_memstore_expr_constvalue */
+
+int
+sdb_memstore_expr_eval(sdb_memstore_expr_t *expr, sdb_memstore_obj_t *obj,
+               sdb_data_t *res, sdb_memstore_matcher_t *filter)
+{
+       sdb_data_t v1 = SDB_DATA_INIT, v2 = SDB_DATA_INIT;
+       int status = 0;
+
+       if ((! expr) || (! res))
+               return -1;
+
+       if (filter && obj && (! sdb_memstore_matcher_matches(filter, obj, NULL)))
+               obj = NULL; /* this object does not exist */
+
+       if (! expr->type)
+               return sdb_data_copy(res, &expr->data);
+       else if (expr->type == FIELD_VALUE)
+               return sdb_memstore_get_field(obj, (int)expr->data.data.integer, res);
+       else if (expr->type == ATTR_VALUE) {
+               status = sdb_memstore_get_attr(obj, expr->data.data.string, res, filter);
+               if ((status < 0) && obj) {
+                       /* attribute does not exist => NULL */
+                       status = 0;
+                       res->type = SDB_TYPE_STRING;
+                       res->data.string = NULL;
+               }
+               return status;
+       }
+       else if (expr->type == TYPED_EXPR) {
+               int typ = (int)expr->data.data.integer;
+               if (typ != obj->type) {
+                       /* we support self-references and { service, metric } -> host */
+                       if ((typ != SDB_HOST)
+                                       || ((obj->type != SDB_SERVICE)
+                                               && (obj->type != SDB_METRIC)))
+                               return -1;
+                       obj = obj->parent;
+               }
+               return sdb_memstore_expr_eval(expr->left, obj, res, filter);
+       }
+
+       if (sdb_memstore_expr_eval(expr->left, obj, &v1, filter))
+               return -1;
+       if (sdb_memstore_expr_eval(expr->right, obj, &v2, filter)) {
+               sdb_data_free_datum(&v1);
+               return -1;
+       }
+
+       if (sdb_data_expr_eval(expr->type, &v1, &v2, res))
+               status = -1;
+       sdb_data_free_datum(&v1);
+       sdb_data_free_datum(&v2);
+       return status;
+} /* sdb_memstore_expr_eval */
+
+sdb_memstore_expr_iter_t *
+sdb_memstore_expr_iter(sdb_memstore_expr_t *expr, sdb_memstore_obj_t *obj,
+               sdb_memstore_matcher_t *filter)
+{
+       sdb_memstore_expr_iter_t *iter;
+       sdb_avltree_iter_t *tree = NULL;
+       sdb_data_t array = SDB_DATA_INIT;
+       bool free_array = 0;
+
+       if (! expr)
+               return NULL;
+
+       while (expr->type == TYPED_EXPR) {
+               int type = (int)expr->data.data.integer;
+
+               if (obj->type == type) {
+                       /* self reference */
+               }
+               else if ((type == SDB_HOST)
+                               && ((obj->type == SDB_SERVICE)
+                                       || (obj->type == SDB_METRIC))) {
+                       /* reference to parent host */
+                       obj = obj->parent;
+               }
+               else
+                       break;
+               expr = expr->left;
+       }
+
+       if (expr->type == TYPED_EXPR) {
+               if (! obj)
+                       return NULL;
+               if (obj->type == SDB_HOST) {
+                       if (expr->data.data.integer == SDB_SERVICE)
+                               tree = sdb_avltree_get_iter(HOST(obj)->services);
+                       else if (expr->data.data.integer == SDB_METRIC)
+                               tree = sdb_avltree_get_iter(HOST(obj)->metrics);
+                       else if (expr->data.data.integer == SDB_ATTRIBUTE)
+                               tree = sdb_avltree_get_iter(HOST(obj)->attributes);
+               }
+               else if (obj->type == SDB_SERVICE) {
+                       if (expr->data.data.integer == SDB_ATTRIBUTE)
+                               tree = sdb_avltree_get_iter(SVC(obj)->attributes);
+               }
+               else if (obj->type == SDB_METRIC) {
+                       if (expr->data.data.integer == SDB_ATTRIBUTE)
+                               tree = sdb_avltree_get_iter(METRIC(obj)->attributes);
+               }
+       }
+       else if (expr->type == FIELD_VALUE) {
+               if (! obj)
+                       return NULL;
+               if (expr->data.data.integer == SDB_FIELD_BACKEND) {
+                       /* while scanning the store, we hold a read lock, so it's safe to
+                        * access the data without copying */
+                       array.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING;
+                       array.data.array.length = obj->backends_num;
+                       array.data.array.values = obj->backends;
+               }
+       }
+       else if (! expr->type) {
+               if (expr->data.type & SDB_TYPE_ARRAY)
+                       array = expr->data;
+       }
+       else {
+               sdb_data_t value = SDB_DATA_INIT;
+               if (sdb_memstore_expr_eval(expr, obj, &value, filter))
+                       return NULL;
+               if (! (value.type & SDB_TYPE_ARRAY)) {
+                       sdb_data_free_datum(&value);
+                       return NULL;
+               }
+               array = value;
+               free_array = 1;
+       }
+
+       if ((! tree) && (array.type == SDB_TYPE_NULL))
+               return NULL;
+
+       iter = calloc(1, sizeof(*iter));
+       if (! iter) {
+               if (free_array)
+                       sdb_data_free_datum(&array);
+               return NULL;
+       }
+
+       sdb_object_ref(SDB_OBJ(obj));
+       sdb_object_ref(SDB_OBJ(expr));
+       sdb_object_ref(SDB_OBJ(filter));
+
+       iter->obj = obj;
+       iter->expr = expr;
+       iter->tree = tree;
+       iter->array = array;
+       iter->free_array = free_array;
+       iter->filter = filter;
+       return iter;
+} /* sdb_memstore_expr_iter */
+
+void
+sdb_memstore_expr_iter_destroy(sdb_memstore_expr_iter_t *iter)
+{
+       sdb_data_t null = SDB_DATA_INIT;
+
+       if (! iter)
+               return;
+
+       if (iter->tree)
+               sdb_avltree_iter_destroy(iter->tree);
+       iter->tree = NULL;
+
+       if (iter->free_array)
+               sdb_data_free_datum(&iter->array);
+       iter->array = null;
+       iter->array_idx = 0;
+
+       sdb_object_deref(SDB_OBJ(iter->obj));
+       sdb_object_deref(SDB_OBJ(iter->expr));
+       sdb_object_deref(SDB_OBJ(iter->filter));
+       free(iter);
+} /* sdb_memstore_expr_iter_destroy */
+
+bool
+sdb_memstore_expr_iter_has_next(sdb_memstore_expr_iter_t *iter)
+{
+       if (! iter)
+               return 0;
+
+       if (iter->tree) {
+               /* this function may be called before get_next,
+                * so we'll have to apply filters here as well */
+               if (iter->filter) {
+                       sdb_memstore_obj_t *child;
+                       while ((child = STORE_OBJ(sdb_avltree_iter_peek_next(iter->tree)))) {
+                               if (sdb_memstore_matcher_matches(iter->filter, child, NULL))
+                                       break;
+                               (void)sdb_avltree_iter_get_next(iter->tree);
+                       }
+               }
+
+               return sdb_avltree_iter_has_next(iter->tree);
+       }
+
+       return iter->array_idx < iter->array.data.array.length;
+} /* sdb_memstore_expr_iter_has_next */
+
+sdb_data_t
+sdb_memstore_expr_iter_get_next(sdb_memstore_expr_iter_t *iter)
+{
+       sdb_data_t null = SDB_DATA_INIT;
+       sdb_data_t ret = SDB_DATA_INIT;
+       sdb_data_t tmp = SDB_DATA_INIT;
+
+       if (! iter)
+               return null;
+
+       if (iter->tree) {
+               sdb_memstore_obj_t *child;
+
+               while (42) {
+                       child = STORE_OBJ(sdb_avltree_iter_get_next(iter->tree));
+                       if (! child)
+                               break;
+                       if (iter->filter
+                                       && (! sdb_memstore_matcher_matches(iter->filter, child, NULL)))
+                               continue;
+
+                       if (sdb_memstore_expr_eval(iter->expr, child, &ret, iter->filter))
+                               return null;
+                       break;
+               }
+
+               /* Skip over any filtered objects */
+               if (iter->filter) {
+                       while ((child = STORE_OBJ(sdb_avltree_iter_peek_next(iter->tree)))) {
+                               if (sdb_memstore_matcher_matches(iter->filter, child, NULL))
+                                       break;
+                               (void)sdb_avltree_iter_get_next(iter->tree);
+                       }
+               }
+
+               return ret;
+       }
+
+       if (iter->array_idx >= iter->array.data.array.length)
+               return null;
+
+       ++iter->array_idx;
+       if (sdb_data_array_get(&iter->array, iter->array_idx - 1, &ret))
+               return null;
+       if (sdb_data_copy(&tmp, &ret))
+               return null;
+       ret = tmp;
+       return ret;
+} /* sdb_memstore_expr_iter_get_next */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
diff --git a/src/core/memstore_lookup.c b/src/core/memstore_lookup.c
new file mode 100644 (file)
index 0000000..2752a66
--- /dev/null
@@ -0,0 +1,694 @@
+/*
+ * SysDB - src/core/memstore_lookup.c
+ * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This module implements operators which may be used to select contents of
+ * the store by matching various attributes of the stored objects. For now, a
+ * simple full table scan is supported only.
+ */
+
+#if HAVE_CONFIG_H
+#      include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "sysdb.h"
+#include "core/memstore-private.h"
+#include "core/object.h"
+#include "utils/error.h"
+
+#include <assert.h>
+
+#include <sys/types.h>
+#include <regex.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <limits.h>
+
+static int
+expr_eval2(sdb_memstore_expr_t *e1, sdb_data_t *v1,
+               sdb_memstore_expr_t *e2, sdb_data_t *v2,
+               sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter)
+{
+       if (e1->type) {
+               if (sdb_memstore_expr_eval(e1, obj, v1, filter))
+                       return -1;
+       }
+       else
+               *v1 = e1->data;
+       if (e2->type) {
+               if (sdb_memstore_expr_eval(e2, obj, v2, filter)) {
+                       if (e1->type)
+                               sdb_data_free_datum(v1);
+                       return -1;
+               }
+       }
+       else
+               *v2 = e2->data;
+       return 0;
+} /* expr_eval2 */
+
+static void
+expr_free_datum2(sdb_memstore_expr_t *e1, sdb_data_t *v1,
+               sdb_memstore_expr_t *e2, sdb_data_t *v2)
+{
+       if (e1->type)
+               sdb_data_free_datum(v1);
+       if (e2->type)
+               sdb_data_free_datum(v2);
+} /* expr_free_datum2 */
+
+/*
+ * matcher implementations
+ */
+
+/*
+ * cmp_expr:
+ * Compare two values using the specified matcher operator. If strcmp_fallback
+ * is enabled, compare the string values in case of a type mismatch.
+ */
+static int
+match_cmp_value(int op, sdb_data_t *v1, sdb_data_t *v2, bool strcmp_fallback)
+{
+       int status;
+
+       if (sdb_data_isnull(v1) || (sdb_data_isnull(v2)))
+               status = INT_MAX;
+       else if (v1->type == v2->type)
+               status = sdb_data_cmp(v1, v2);
+       else if (! strcmp_fallback)
+               status = INT_MAX;
+       else
+               status = sdb_data_strcmp(v1, v2);
+
+       if (status == INT_MAX)
+               return 0;
+       switch (op) {
+               case MATCHER_LT: return status < 0;
+               case MATCHER_LE: return status <= 0;
+               case MATCHER_EQ: return status == 0;
+               case MATCHER_NE: return status != 0;
+               case MATCHER_GE: return status >= 0;
+               case MATCHER_GT: return status > 0;
+       }
+       return 0;
+} /* match_cmp_value */
+
+static int
+match_regex_value(int op, sdb_data_t *v, sdb_data_t *re)
+{
+       char value[sdb_data_strlen(v) + 1];
+       int status = 0;
+
+       assert((op == MATCHER_REGEX)
+                       || (op == MATCHER_NREGEX));
+
+       if (sdb_data_isnull(v) || sdb_data_isnull(re))
+               return 0;
+
+       if (re->type == SDB_TYPE_STRING) {
+               sdb_data_t tmp = SDB_DATA_INIT;
+
+               if (sdb_data_parse(re->data.string, SDB_TYPE_REGEX, &tmp))
+                       return 0;
+
+               sdb_data_free_datum(re);
+               *re = tmp;
+       }
+       else if (re->type != SDB_TYPE_REGEX)
+               return 0;
+
+       if (! sdb_data_format(v, value, sizeof(value), SDB_UNQUOTED))
+               status = 0;
+       else if (! regexec(&re->data.re.regex, value, 0, NULL, 0))
+               status = 1;
+
+       if (op == MATCHER_NREGEX)
+               return !status;
+       return status;
+} /* match_regex_value */
+
+static int
+match_logical(sdb_memstore_matcher_t *m, sdb_memstore_obj_t *obj,
+               sdb_memstore_matcher_t *filter)
+{
+       int status;
+
+       assert((m->type == MATCHER_AND) || (m->type == MATCHER_OR));
+       assert(OP_M(m)->left && OP_M(m)->right);
+
+       status = sdb_memstore_matcher_matches(OP_M(m)->left, obj, filter);
+
+       /* lazy evaluation */
+       if ((! status) && (m->type == MATCHER_AND))
+               return status;
+       else if (status && (m->type == MATCHER_OR))
+               return status;
+
+       return sdb_memstore_matcher_matches(OP_M(m)->right, obj, filter);
+} /* match_logical */
+
+static int
+match_uop(sdb_memstore_matcher_t *m, sdb_memstore_obj_t *obj,
+               sdb_memstore_matcher_t *filter)
+{
+       assert(m->type == MATCHER_NOT);
+       assert(UOP_M(m)->op);
+
+       return !sdb_memstore_matcher_matches(UOP_M(m)->op, obj, filter);
+} /* match_uop */
+
+/* iterate: ANY/ALL <iter> <cmp> <value> */
+static int
+match_iter(sdb_memstore_matcher_t *m, sdb_memstore_obj_t *obj,
+               sdb_memstore_matcher_t *filter)
+{
+       sdb_memstore_expr_iter_t *iter = NULL;
+       int status;
+       int all = (int)(m->type == MATCHER_ALL);
+
+       assert((m->type == MATCHER_ANY) || (m->type == MATCHER_ALL));
+       assert((! CMP_M(ITER_M(m)->m)->left) && CMP_M(ITER_M(m)->m)->right);
+
+       iter = sdb_memstore_expr_iter(ITER_M(m)->iter, obj, filter);
+       if (! iter) {
+               sdb_log(SDB_LOG_WARNING, "memstore: Invalid iterator");
+               return 0;
+       }
+
+       status = all;
+       while (sdb_memstore_expr_iter_has_next(iter)) {
+               sdb_data_t v = sdb_memstore_expr_iter_get_next(iter);
+               sdb_memstore_expr_t expr = CONST_EXPR(v);
+               bool matches;
+
+               CMP_M(ITER_M(m)->m)->left = &expr;
+               matches = sdb_memstore_matcher_matches(ITER_M(m)->m, obj, filter);
+               CMP_M(ITER_M(m)->m)->left = NULL;
+               sdb_data_free_datum(&v);
+
+               if (matches) {
+                       if (! all) {
+                               status = 1;
+                               break;
+                       }
+               } else if (all) {
+                       status = 0;
+                       break;
+               }
+       }
+       sdb_memstore_expr_iter_destroy(iter);
+       return status;
+} /* match_iter */
+
+static int
+match_cmp(sdb_memstore_matcher_t *m, sdb_memstore_obj_t *obj,
+               sdb_memstore_matcher_t *filter)
+{
+       sdb_memstore_expr_t *e1 = CMP_M(m)->left;
+       sdb_memstore_expr_t *e2 = CMP_M(m)->right;
+       sdb_data_t v1 = SDB_DATA_INIT, v2 = SDB_DATA_INIT;
+       int status;
+
+       assert((m->type == MATCHER_LT)
+                       || (m->type == MATCHER_LE)
+                       || (m->type == MATCHER_EQ)
+                       || (m->type == MATCHER_NE)
+                       || (m->type == MATCHER_GE)
+                       || (m->type == MATCHER_GT));
+       assert(e1 && e2);
+
+       if (expr_eval2(e1, &v1, e2, &v2, obj, filter))
+               return 0;
+
+       status = match_cmp_value(m->type, &v1, &v2,
+                       (e1->data_type) < 0 || (e2->data_type < 0));
+
+       expr_free_datum2(e1, &v1, e2, &v2);
+       return status;
+} /* match_cmp */
+
+static int
+match_in(sdb_memstore_matcher_t *m, sdb_memstore_obj_t *obj,
+               sdb_memstore_matcher_t *filter)
+{
+       sdb_data_t value = SDB_DATA_INIT, array = SDB_DATA_INIT;
+       int status = 1;
+
+       assert(m->type == MATCHER_IN);
+       assert(CMP_M(m)->left && CMP_M(m)->right);
+
+       if (expr_eval2(CMP_M(m)->left, &value,
+                               CMP_M(m)->right, &array, obj, filter))
+               status = 0;
+
+       if (status)
+               status = sdb_data_inarray(&value, &array);
+
+       expr_free_datum2(CMP_M(m)->left, &value, CMP_M(m)->right, &array);
+       return status;
+} /* match_in */
+
+static int
+match_regex(sdb_memstore_matcher_t *m, sdb_memstore_obj_t *obj,
+               sdb_memstore_matcher_t *filter)
+{
+       sdb_data_t regex = SDB_DATA_INIT, v = SDB_DATA_INIT;
+       int status = 0;
+
+       assert((m->type == MATCHER_REGEX)
+                       || (m->type == MATCHER_NREGEX));
+       assert(CMP_M(m)->left && CMP_M(m)->right);
+
+       if (expr_eval2(CMP_M(m)->left, &v, CMP_M(m)->right, &regex, obj, filter))
+               return 0;
+
+       status = match_regex_value(m->type, &v, &regex);
+
+       expr_free_datum2(CMP_M(m)->left, &v, CMP_M(m)->right, &regex);
+       return status;
+} /* match_regex */
+
+static int
+match_unary(sdb_memstore_matcher_t *m, sdb_memstore_obj_t *obj,
+               sdb_memstore_matcher_t *filter)
+{
+       sdb_data_t v = SDB_DATA_INIT;
+       int status;
+
+       assert((m->type == MATCHER_ISNULL)
+                       || (m->type == MATCHER_ISTRUE)
+                       || (m->type == MATCHER_ISFALSE));
+
+       if (UNARY_M(m)->expr->type) {
+               /* TODO: this might hide real errors;
+                * improve error reporting and propagation */
+               if (sdb_memstore_expr_eval(UNARY_M(m)->expr, obj, &v, filter))
+                       return 1;
+       }
+       else
+               v = UNARY_M(m)->expr->data;
+
+       if (m->type == MATCHER_ISNULL)
+               status = sdb_data_isnull(&v) ? 1 : 0;
+       else { /* ISTRUE or ISFALSE */
+               if ((v.type == SDB_TYPE_BOOLEAN)
+                               && (v.data.boolean == (m->type == MATCHER_ISTRUE)))
+                       status = 1;
+               else
+                       status = 0;
+       }
+
+       if (UNARY_M(m)->expr->type)
+               sdb_data_free_datum(&v);
+       return status;
+} /* match_unary */
+
+typedef int (*matcher_cb)(sdb_memstore_matcher_t *, sdb_memstore_obj_t *,
+               sdb_memstore_matcher_t *);
+
+/* this array needs to be indexable by the matcher types;
+ * -> update the enum in memstore-private.h when updating this */
+static matcher_cb
+matchers[] = {
+       match_logical,
+       match_logical,
+       match_uop,
+       match_iter,
+       match_iter,
+       match_in,
+
+       /* unary operators */
+       match_unary,
+       match_unary,
+       match_unary,
+
+       /* ary operators */
+       match_cmp,
+       match_cmp,
+       match_cmp,
+       match_cmp,
+       match_cmp,
+       match_cmp,
+       match_regex,
+       match_regex,
+
+       NULL, /* QUERY */
+};
+
+/*
+ * private matcher types
+ */
+
+static int
+op_matcher_init(sdb_object_t *obj, va_list ap)
+{
+       M(obj)->type = va_arg(ap, int);
+       if ((M(obj)->type != MATCHER_OR) && (M(obj)->type != MATCHER_AND))
+               return -1;
+
+       OP_M(obj)->left = va_arg(ap, sdb_memstore_matcher_t *);
+       sdb_object_ref(SDB_OBJ(OP_M(obj)->left));
+       OP_M(obj)->right = va_arg(ap, sdb_memstore_matcher_t *);
+       sdb_object_ref(SDB_OBJ(OP_M(obj)->right));
+
+       if ((! OP_M(obj)->left) || (! OP_M(obj)->right))
+               return -1;
+       return 0;
+} /* op_matcher_init */
+
+static void
+op_matcher_destroy(sdb_object_t *obj)
+{
+       if (OP_M(obj)->left)
+               sdb_object_deref(SDB_OBJ(OP_M(obj)->left));
+       if (OP_M(obj)->right)
+               sdb_object_deref(SDB_OBJ(OP_M(obj)->right));
+} /* op_matcher_destroy */
+
+static int
+iter_matcher_init(sdb_object_t *obj, va_list ap)
+{
+       M(obj)->type = va_arg(ap, int);
+       ITER_M(obj)->iter = va_arg(ap, sdb_memstore_expr_t *);
+       ITER_M(obj)->m = va_arg(ap, sdb_memstore_matcher_t *);
+
+       sdb_object_ref(SDB_OBJ(ITER_M(obj)->iter));
+       sdb_object_ref(SDB_OBJ(ITER_M(obj)->m));
+
+       if ((! ITER_M(obj)->iter) || (! ITER_M(obj)->m))
+               return -1;
+       return 0;
+} /* iter_matcher_init */
+
+static void
+iter_matcher_destroy(sdb_object_t *obj)
+{
+       sdb_object_deref(SDB_OBJ(ITER_M(obj)->iter));
+       sdb_object_deref(SDB_OBJ(ITER_M(obj)->m));
+} /* iter_matcher_destroy */
+
+static int
+cmp_matcher_init(sdb_object_t *obj, va_list ap)
+{
+       M(obj)->type = va_arg(ap, int);
+
+       CMP_M(obj)->left = va_arg(ap, sdb_memstore_expr_t *);
+       sdb_object_ref(SDB_OBJ(CMP_M(obj)->left));
+       CMP_M(obj)->right = va_arg(ap, sdb_memstore_expr_t *);
+       sdb_object_ref(SDB_OBJ(CMP_M(obj)->right));
+
+       if (! CMP_M(obj)->right)
+               return -1;
+       return 0;
+} /* cmp_matcher_init */
+
+static void
+cmp_matcher_destroy(sdb_object_t *obj)
+{
+       sdb_object_deref(SDB_OBJ(CMP_M(obj)->left));
+       sdb_object_deref(SDB_OBJ(CMP_M(obj)->right));
+} /* cmp_matcher_destroy */
+
+static int
+uop_matcher_init(sdb_object_t *obj, va_list ap)
+{
+       M(obj)->type = va_arg(ap, int);
+       if (M(obj)->type != MATCHER_NOT)
+               return -1;
+
+       UOP_M(obj)->op = va_arg(ap, sdb_memstore_matcher_t *);
+       sdb_object_ref(SDB_OBJ(UOP_M(obj)->op));
+
+       if (! UOP_M(obj)->op)
+               return -1;
+       return 0;
+} /* uop_matcher_init */
+
+static void
+uop_matcher_destroy(sdb_object_t *obj)
+{
+       if (UOP_M(obj)->op)
+               sdb_object_deref(SDB_OBJ(UOP_M(obj)->op));
+} /* uop_matcher_destroy */
+
+static int
+unary_matcher_init(sdb_object_t *obj, va_list ap)
+{
+       M(obj)->type = va_arg(ap, int);
+       if ((M(obj)->type != MATCHER_ISNULL)
+                       && (M(obj)->type != MATCHER_ISTRUE)
+                       && (M(obj)->type != MATCHER_ISFALSE))
+               return -1;
+
+       UNARY_M(obj)->expr = va_arg(ap, sdb_memstore_expr_t *);
+       sdb_object_ref(SDB_OBJ(UNARY_M(obj)->expr));
+       return 0;
+} /* unary_matcher_init */
+
+static void
+unary_matcher_destroy(sdb_object_t *obj)
+{
+       sdb_object_deref(SDB_OBJ(UNARY_M(obj)->expr));
+       UNARY_M(obj)->expr = NULL;
+} /* unary_matcher_destroy */
+
+static sdb_type_t op_type = {
+       /* size = */ sizeof(op_matcher_t),
+       /* init = */ op_matcher_init,
+       /* destroy = */ op_matcher_destroy,
+};
+
+static sdb_type_t uop_type = {
+       /* size = */ sizeof(uop_matcher_t),
+       /* init = */ uop_matcher_init,
+       /* destroy = */ uop_matcher_destroy,
+};
+
+static sdb_type_t iter_type = {
+       /* size = */ sizeof(iter_matcher_t),
+       /* init = */ iter_matcher_init,
+       /* destroy = */ iter_matcher_destroy,
+};
+
+static sdb_type_t cmp_type = {
+       /* size = */ sizeof(cmp_matcher_t),
+       /* init = */ cmp_matcher_init,
+       /* destroy = */ cmp_matcher_destroy,
+};
+
+static sdb_type_t unary_type = {
+       /* size = */ sizeof(unary_matcher_t),
+       /* init = */ unary_matcher_init,
+       /* destroy = */ unary_matcher_destroy,
+};
+
+/*
+ * public API
+ */
+
+sdb_memstore_matcher_t *
+sdb_memstore_any_matcher(sdb_memstore_expr_t *iter, sdb_memstore_matcher_t *m)
+{
+       if ((m->type < MATCHER_LT) || (MATCHER_NREGEX < m->type)) {
+               sdb_log(SDB_LOG_ERR, "memstore: Invalid ANY -> %s matcher "
+                               "(invalid operator)", MATCHER_SYM(m->type));
+               return NULL;
+       }
+       if (CMP_M(m)->left) {
+               sdb_log(SDB_LOG_ERR, "memstore: Invalid ANY %s %s %s matcher "
+                               "(invalid left operand)",
+                               SDB_TYPE_TO_STRING(CMP_M(m)->left->data_type),
+                               MATCHER_SYM(m->type),
+                               SDB_TYPE_TO_STRING(CMP_M(m)->right->data_type));
+               return NULL;
+       }
+       return M(sdb_object_create("any-matcher", iter_type,
+                               MATCHER_ANY, iter, m));
+} /* sdb_memstore_any_matcher */
+
+sdb_memstore_matcher_t *
+sdb_memstore_all_matcher(sdb_memstore_expr_t *iter, sdb_memstore_matcher_t *m)
+{
+       if ((m->type < MATCHER_LT) || (MATCHER_NREGEX < m->type)) {
+               sdb_log(SDB_LOG_ERR, "memstore: Invalid ALL -> %s matcher "
+                               "(invalid operator)", MATCHER_SYM(m->type));
+               return NULL;
+       }
+       if (CMP_M(m)->left) {
+               sdb_log(SDB_LOG_ERR, "memstore: Invalid ALL %s %s %s matcher "
+                               "(invalid left operand)",
+                               SDB_TYPE_TO_STRING(CMP_M(m)->left->data_type),
+                               MATCHER_SYM(m->type),
+                               SDB_TYPE_TO_STRING(CMP_M(m)->right->data_type));
+               return NULL;
+       }
+       return M(sdb_object_create("all-matcher", iter_type,
+                               MATCHER_ALL, iter, m));
+} /* sdb_memstore_all_matcher */
+
+sdb_memstore_matcher_t *
+sdb_memstore_lt_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right)
+{
+       return M(sdb_object_create("lt-matcher", cmp_type,
+                               MATCHER_LT, left, right));
+} /* sdb_memstore_lt_matcher */
+
+sdb_memstore_matcher_t *
+sdb_memstore_le_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right)
+{
+       return M(sdb_object_create("le-matcher", cmp_type,
+                               MATCHER_LE, left, right));
+} /* sdb_memstore_le_matcher */
+
+sdb_memstore_matcher_t *
+sdb_memstore_eq_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right)
+{
+       return M(sdb_object_create("eq-matcher", cmp_type,
+                               MATCHER_EQ, left, right));
+} /* sdb_memstore_eq_matcher */
+
+sdb_memstore_matcher_t *
+sdb_memstore_ne_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right)
+{
+       return M(sdb_object_create("ne-matcher", cmp_type,
+                               MATCHER_NE, left, right));
+} /* sdb_memstore_ne_matcher */
+
+sdb_memstore_matcher_t *
+sdb_memstore_ge_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right)
+{
+       return M(sdb_object_create("ge-matcher", cmp_type,
+                               MATCHER_GE, left, right));
+} /* sdb_memstore_ge_matcher */
+
+sdb_memstore_matcher_t *
+sdb_memstore_gt_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right)
+{
+       return M(sdb_object_create("gt-matcher", cmp_type,
+                               MATCHER_GT, left, right));
+} /* sdb_memstore_gt_matcher */
+
+sdb_memstore_matcher_t *
+sdb_memstore_in_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right)
+{
+       return M(sdb_object_create("in-matcher", cmp_type,
+                               MATCHER_IN, left, right));
+} /* sdb_memstore_in_matcher */
+
+sdb_memstore_matcher_t *
+sdb_memstore_regex_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right)
+{
+       if (! right->type) {
+               if ((right->data.type != SDB_TYPE_STRING)
+                               && (right->data.type != SDB_TYPE_REGEX))
+                       return NULL;
+
+               if (right->data.type == SDB_TYPE_STRING) {
+                       char *raw = right->data.data.string;
+                       if (sdb_data_parse(raw, SDB_TYPE_REGEX, &right->data))
+                               return NULL;
+                       free(raw);
+               }
+       }
+       return M(sdb_object_create("regex-matcher", cmp_type,
+                               MATCHER_REGEX, left, right));
+} /* sdb_memstore_regex_matcher */
+
+sdb_memstore_matcher_t *
+sdb_memstore_nregex_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right)
+{
+       sdb_memstore_matcher_t *m = sdb_memstore_regex_matcher(left, right);
+       if (! m)
+               return NULL;
+       m->type = MATCHER_NREGEX;
+       return m;
+} /* sdb_memstore_nregex_matcher */
+
+sdb_memstore_matcher_t *
+sdb_memstore_isnull_matcher(sdb_memstore_expr_t *expr)
+{
+       return M(sdb_object_create("isnull-matcher", unary_type,
+                               MATCHER_ISNULL, expr));
+} /* sdb_memstore_isnull_matcher */
+
+sdb_memstore_matcher_t *
+sdb_memstore_istrue_matcher(sdb_memstore_expr_t *expr)
+{
+       return M(sdb_object_create("istrue-matcher", unary_type,
+                               MATCHER_ISTRUE, expr));
+} /* sdb_memstore_istrue_matcher */
+
+sdb_memstore_matcher_t *
+sdb_memstore_isfalse_matcher(sdb_memstore_expr_t *expr)
+{
+       return M(sdb_object_create("isfalse-matcher", unary_type,
+                               MATCHER_ISFALSE, expr));
+} /* sdb_memstore_isfalse_matcher */
+
+sdb_memstore_matcher_t *
+sdb_memstore_dis_matcher(sdb_memstore_matcher_t *left, sdb_memstore_matcher_t *right)
+{
+       return M(sdb_object_create("dis-matcher", op_type, MATCHER_OR,
+                               left, right));
+} /* sdb_memstore_dis_matcher */
+
+sdb_memstore_matcher_t *
+sdb_memstore_con_matcher(sdb_memstore_matcher_t *left, sdb_memstore_matcher_t *right)
+{
+       return M(sdb_object_create("con-matcher", op_type, MATCHER_AND,
+                               left, right));
+} /* sdb_memstore_con_matcher */
+
+sdb_memstore_matcher_t *
+sdb_memstore_inv_matcher(sdb_memstore_matcher_t *m)
+{
+       return M(sdb_object_create("inv-matcher", uop_type, MATCHER_NOT, m));
+} /* sdb_memstore_inv_matcher */
+
+int
+sdb_memstore_matcher_matches(sdb_memstore_matcher_t *m, sdb_memstore_obj_t *obj,
+               sdb_memstore_matcher_t *filter)
+{
+       if (filter && (! sdb_memstore_matcher_matches(filter, obj, NULL)))
+               return 0;
+
+       /* "NULL" always matches */
+       if ((! m) || (! obj))
+               return 1;
+
+       if ((m->type < 0) || ((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers)))
+               return 0;
+
+       if (! matchers[m->type])
+               return 0;
+       return matchers[m->type](m, obj, filter);
+} /* sdb_memstore_matcher_matches */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
diff --git a/src/core/memstore_query.c b/src/core/memstore_query.c
new file mode 100644 (file)
index 0000000..eb1e82f
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * SysDB - src/core/memstore_query.c
+ * Copyright (C) 2014-2015 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core/object.h"
+#include "core/memstore-private.h"
+#include "parser/ast.h"
+#include "utils/error.h"
+
+#include <assert.h>
+
+static sdb_memstore_matcher_t *
+node_to_matcher(sdb_ast_node_t *n);
+
+static sdb_memstore_expr_t *
+node_to_expr(sdb_ast_node_t *n)
+{
+       sdb_memstore_expr_t *left = NULL, *right = NULL;
+       sdb_memstore_expr_t *e;
+       int op;
+
+       if (! n) {
+               sdb_log(SDB_LOG_ERR, "memstore: Encountered empty AST expression node");
+               return NULL;
+       }
+
+       switch (n->type) {
+       case SDB_AST_TYPE_OPERATOR:
+               if (! SDB_AST_IS_ARITHMETIC(n)) {
+                       sdb_log(SDB_LOG_ERR, "memstore: Invalid arithmetic operator of "
+                                       "type %s (%#x)", SDB_AST_TYPE_TO_STRING(n), n->type);
+                       return NULL;
+               }
+
+               left = node_to_expr(SDB_AST_OP(n)->left);
+               if (! left)
+                       return NULL;
+               right = node_to_expr(SDB_AST_OP(n)->right);
+               if (! right) {
+                       sdb_object_deref(SDB_OBJ(left));
+                       return NULL;
+               }
+               op = SDB_AST_OP_TO_DATA_OP(SDB_AST_OP(n)->kind);
+               e = sdb_memstore_expr_create(op, left, right);
+               break;
+
+       case SDB_AST_TYPE_CONST:
+               return sdb_memstore_expr_constvalue(&SDB_AST_CONST(n)->value);
+
+       case SDB_AST_TYPE_VALUE:
+               if (SDB_AST_VALUE(n)->type == SDB_ATTRIBUTE)
+                       return sdb_memstore_expr_attrvalue(SDB_AST_VALUE(n)->name);
+               return sdb_memstore_expr_fieldvalue(SDB_AST_VALUE(n)->type);
+
+       case SDB_AST_TYPE_TYPED:
+               right = node_to_expr(SDB_AST_TYPED(n)->expr);
+               if (! right)
+                       return NULL;
+               e = sdb_memstore_expr_typed(SDB_AST_TYPED(n)->type, right);
+               break;
+
+       default:
+               sdb_log(SDB_LOG_ERR, "memstore: Invalid matcher node of type %s (%#x)",
+                               SDB_AST_TYPE_TO_STRING(n), n->type);
+               e = NULL;
+       }
+
+       /* expressions take a reference */
+       sdb_object_deref(SDB_OBJ(left));
+       sdb_object_deref(SDB_OBJ(right));
+       return e;
+} /* node_to_expr */
+
+static sdb_memstore_matcher_t *
+logical_to_matcher(sdb_ast_node_t *n)
+{
+       sdb_memstore_matcher_t *left = NULL, *right;
+       sdb_memstore_matcher_t *m;
+
+       if (SDB_AST_OP(n)->left) {
+               left = node_to_matcher(SDB_AST_OP(n)->left);
+               if (! left)
+                       return NULL;
+       }
+       right = node_to_matcher(SDB_AST_OP(n)->right);
+       if (! right) {
+               sdb_object_deref(SDB_OBJ(left));
+               return NULL;
+       }
+
+       switch (SDB_AST_OP(n)->kind) {
+       case SDB_AST_AND:
+               m = sdb_memstore_con_matcher(left, right);
+               break;
+       case SDB_AST_OR:
+               m = sdb_memstore_dis_matcher(left, right);
+               break;
+       case SDB_AST_NOT:
+               m = sdb_memstore_inv_matcher(right);
+               break;
+
+       default:
+               m = NULL;
+       }
+
+       /* matchers take a reference */
+       sdb_object_deref(SDB_OBJ(left));
+       sdb_object_deref(SDB_OBJ(right));
+       return m;
+} /* logical_to_matcher */
+
+static sdb_memstore_matcher_t *
+cmp_to_matcher(sdb_ast_node_t *n)
+{
+       sdb_memstore_expr_t *left = NULL, *right;
+       sdb_memstore_matcher_t *m;
+
+       if (SDB_AST_OP(n)->left) {
+               left = node_to_expr(SDB_AST_OP(n)->left);
+               if (! left)
+                       return NULL;
+       }
+       right = node_to_expr(SDB_AST_OP(n)->right);
+       if (! right) {
+               sdb_object_deref(SDB_OBJ(left));
+               return NULL;
+       }
+
+       switch (SDB_AST_OP(n)->kind) {
+       case SDB_AST_LT:
+               m = sdb_memstore_lt_matcher(left, right);
+               break;
+       case SDB_AST_LE:
+               m = sdb_memstore_le_matcher(left, right);
+               break;
+       case SDB_AST_EQ:
+               m = sdb_memstore_eq_matcher(left, right);
+               break;
+       case SDB_AST_NE:
+               m = sdb_memstore_ne_matcher(left, right);
+               break;
+       case SDB_AST_GE:
+               m = sdb_memstore_ge_matcher(left, right);
+               break;
+       case SDB_AST_GT:
+               m = sdb_memstore_gt_matcher(left, right);
+               break;
+       case SDB_AST_REGEX:
+               m = sdb_memstore_regex_matcher(left, right);
+               break;
+       case SDB_AST_NREGEX:
+               m = sdb_memstore_nregex_matcher(left, right);
+               break;
+       case SDB_AST_ISNULL:
+               m = sdb_memstore_isnull_matcher(right);
+               break;
+       case SDB_AST_ISTRUE:
+               m = sdb_memstore_istrue_matcher(right);
+               break;
+       case SDB_AST_ISFALSE:
+               m = sdb_memstore_isfalse_matcher(right);
+               break;
+       case SDB_AST_IN:
+               m = sdb_memstore_in_matcher(left, right);
+               break;
+
+       default:
+               sdb_log(SDB_LOG_ERR, "memstore: Invalid matcher node of type %s (%#x)",
+                               SDB_AST_TYPE_TO_STRING(n), n->type);
+               m = NULL;
+       }
+
+       /* matchers take a reference */
+       sdb_object_deref(SDB_OBJ(left));
+       sdb_object_deref(SDB_OBJ(right));
+       return m;
+} /* cmp_to_matcher */
+
+static sdb_memstore_matcher_t *
+iter_to_matcher(sdb_ast_node_t *n)
+{
+       sdb_memstore_expr_t *iter;
+       sdb_memstore_matcher_t *expr, *m;
+
+       assert((SDB_AST_ITER(n)->expr->type == SDB_AST_TYPE_OPERATOR)
+                       && (! SDB_AST_OP(SDB_AST_ITER(n)->expr)->left));
+
+       iter = node_to_expr(SDB_AST_ITER(n)->iter);
+       if (! iter)
+               return NULL;
+       expr = cmp_to_matcher(SDB_AST_ITER(n)->expr);
+       if (! expr) {
+               sdb_object_deref(SDB_OBJ(iter));
+               return NULL;
+       }
+
+       switch (SDB_AST_ITER(n)->kind) {
+       case SDB_AST_ALL:
+               m = sdb_memstore_all_matcher(iter, expr);
+               break;
+       case SDB_AST_ANY:
+               m = sdb_memstore_any_matcher(iter, expr);
+               break;
+
+       default:
+               sdb_log(SDB_LOG_ERR, "memstore: Invalid iterator node of type %s (%#x)",
+                               SDB_AST_OP_TO_STRING(SDB_AST_ITER(n)->kind), SDB_AST_ITER(n)->kind);
+               m = NULL;
+       }
+
+       /* matchers take a reference */
+       sdb_object_deref(SDB_OBJ(iter));
+       sdb_object_deref(SDB_OBJ(expr));
+       return m;
+} /* iter_to_matcher */
+
+static sdb_memstore_matcher_t *
+node_to_matcher(sdb_ast_node_t *n)
+{
+       int kind;
+
+       if (! n) {
+               sdb_log(SDB_LOG_ERR, "memstore: Encountered empty AST matcher node");
+               return NULL;
+       }
+
+       switch (n->type) {
+       case SDB_AST_TYPE_OPERATOR:
+               if (! SDB_AST_IS_LOGICAL(n)) {
+                       sdb_log(SDB_LOG_ERR, "memstore: Invalid logical operator of "
+                                       "type %s (%#x)", SDB_AST_TYPE_TO_STRING(n), n->type);
+                       return NULL;
+               }
+
+               kind = SDB_AST_OP(n)->kind;
+               if ((kind == SDB_AST_AND) || (kind == SDB_AST_OR) || (kind == SDB_AST_NOT))
+                       return logical_to_matcher(n);
+               else
+                       return cmp_to_matcher(n);
+
+       case SDB_AST_TYPE_ITERATOR:
+               return iter_to_matcher(n);
+       }
+
+       sdb_log(SDB_LOG_ERR, "memstore: Invalid matcher node of type %s (%#x)",
+                       SDB_AST_TYPE_TO_STRING(n), n->type);
+       return NULL;
+} /* node_to_matcher */
+
+/*
+ * query type
+ */
+
+static int
+query_init(sdb_object_t *obj, va_list ap)
+{
+       sdb_ast_node_t *ast = va_arg(ap, sdb_ast_node_t *);
+       sdb_ast_node_t *matcher = NULL, *filter = NULL;
+
+       QUERY(obj)->ast = ast;
+       sdb_object_ref(SDB_OBJ(ast));
+
+       switch (ast->type) {
+       case SDB_AST_TYPE_FETCH:
+               filter = SDB_AST_FETCH(ast)->filter;
+               break;
+       case SDB_AST_TYPE_LIST:
+               filter = SDB_AST_LIST(ast)->filter;
+               break;
+       case SDB_AST_TYPE_LOOKUP:
+               matcher = SDB_AST_LOOKUP(ast)->matcher;
+               filter = SDB_AST_LOOKUP(ast)->filter;
+               break;
+       case SDB_AST_TYPE_STORE:
+       case SDB_AST_TYPE_TIMESERIES:
+               /* nothing to do */
+               break;
+
+       default:
+               sdb_log(SDB_LOG_ERR, "memstore: Invalid top-level AST node "
+                               "of type %#x", ast->type);
+               return -1;
+       }
+
+       if (matcher) {
+               QUERY(obj)->matcher = node_to_matcher(matcher);
+               if (! QUERY(obj)->matcher)
+                       return -1;
+       }
+       if (filter) {
+               QUERY(obj)->filter = node_to_matcher(filter);
+               if (! QUERY(obj)->filter)
+                       return -1;
+       }
+
+       return 0;
+} /* query_init */
+
+static void
+query_destroy(sdb_object_t *obj)
+{
+       sdb_object_deref(SDB_OBJ(QUERY(obj)->ast));
+       sdb_object_deref(SDB_OBJ(QUERY(obj)->matcher));
+       sdb_object_deref(SDB_OBJ(QUERY(obj)->filter));
+} /* query_destroy */
+
+static sdb_type_t query_type = {
+       /* size = */ sizeof(sdb_memstore_query_t),
+       /* init = */ query_init,
+       /* destroy = */ query_destroy,
+};
+
+/*
+ * public API
+ */
+
+sdb_memstore_query_t *
+sdb_memstore_query_prepare(sdb_ast_node_t *ast)
+{
+       if (! ast)
+               return NULL;
+       return QUERY(sdb_object_create(SDB_AST_TYPE_TO_STRING(ast), query_type, ast));
+} /* sdb_memstore_query_prepare */
+
+sdb_memstore_matcher_t *
+sdb_memstore_query_prepare_matcher(sdb_ast_node_t *ast)
+{
+       return node_to_matcher(ast);
+} /* sdb_memstore_query_prepare_matcher */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
index 728e20c1740815d83b2d1366ac852b20ec19c140..76b0b1e45b656a6416bb8aa526581cd311ac5921 100644 (file)
@@ -661,6 +661,111 @@ plugin_add_callback(sdb_llist_t **list, const char *type,
        return 0;
 } /* plugin_add_callback */
 
+/*
+ * object meta-data
+ */
+
+typedef struct {
+       int obj_type;
+       sdb_time_t last_update;
+       sdb_time_t interval;
+} interval_fetcher_t;
+
+static int
+interval_fetcher_host(sdb_store_host_t *host, sdb_object_t *user_data)
+{
+       interval_fetcher_t *lu = SDB_OBJ_WRAPPER(user_data)->data;
+       lu->obj_type = SDB_HOST;
+       lu->last_update = host->last_update;
+       return 0;
+} /* interval_fetcher_host */
+
+static int
+interval_fetcher_service(sdb_store_service_t *svc, sdb_object_t *user_data)
+{
+       interval_fetcher_t *lu = SDB_OBJ_WRAPPER(user_data)->data;
+       lu->obj_type = SDB_SERVICE;
+       lu->last_update = svc->last_update;
+       return 0;
+} /* interval_fetcher_service */
+
+static int
+interval_fetcher_metric(sdb_store_metric_t *metric, sdb_object_t *user_data)
+{
+       interval_fetcher_t *lu = SDB_OBJ_WRAPPER(user_data)->data;
+       lu->obj_type = SDB_METRIC;
+       lu->last_update = metric->last_update;
+       return 0;
+} /* interval_fetcher_metric */
+
+static int
+interval_fetcher_attr(sdb_store_attribute_t *attr, sdb_object_t *user_data)
+{
+       interval_fetcher_t *lu = SDB_OBJ_WRAPPER(user_data)->data;
+       lu->obj_type = SDB_ATTRIBUTE;
+       lu->last_update = attr->last_update;
+       return 0;
+} /* interval_fetcher_attr */
+
+static sdb_store_writer_t interval_fetcher = {
+       interval_fetcher_host, interval_fetcher_service,
+       interval_fetcher_metric, interval_fetcher_attr,
+};
+
+static int
+get_interval(int obj_type, const char *hostname,
+               int parent_type, const char *parent, const char *name,
+               sdb_time_t last_update, sdb_time_t *interval_out)
+{
+       sdb_ast_fetch_t fetch = SDB_AST_FETCH_INIT;
+       char hn[hostname ? strlen(hostname) + 1 : 1];
+       char pn[parent ? strlen(parent) + 1 : 1];
+       char n[strlen(name) + 1];
+       int status;
+
+       interval_fetcher_t lu = { 0, 0, 0 };
+       sdb_object_wrapper_t obj = SDB_OBJECT_WRAPPER_STATIC(&lu);
+       sdb_time_t interval;
+
+       assert(name);
+
+       if (hostname)
+               strncpy(hn, hostname, sizeof(hn));
+       if (parent)
+               strncpy(pn, parent, sizeof(pn));
+       strncpy(n, name, sizeof(n));
+
+       fetch.obj_type = obj_type;
+       fetch.hostname = hostname ? hn : NULL;
+       fetch.parent_type = parent_type;
+       fetch.parent = parent ? pn : NULL;
+       fetch.name = n;
+
+       status = sdb_plugin_query(SDB_AST_NODE(&fetch),
+                       &interval_fetcher, SDB_OBJ(&obj), NULL);
+       if ((status < 0) || (lu.obj_type != obj_type) || (lu.last_update == 0)) {
+               *interval_out = 0;
+               return 0;
+       }
+
+       if (lu.last_update >= last_update) {
+               if (lu.last_update > last_update)
+                       sdb_log(SDB_LOG_DEBUG, "memstore: Cannot update %s '%s' - "
+                                       "value too old (%"PRIsdbTIME" < %"PRIsdbTIME")",
+                                       SDB_STORE_TYPE_TO_NAME(obj_type), name,
+                                       lu.last_update, last_update);
+               *interval_out = lu.interval;
+               return 1;
+       }
+
+       interval = last_update - lu.last_update;
+       if (lu.interval && interval)
+               interval = (sdb_time_t)((0.9 * (double)lu.interval)
+                               + (0.1 * (double)interval));
+       *interval_out = interval;
+       return 0;
+} /* get_interval */
+
 static void
 get_backend(char **backends, size_t *backends_num)
 {
@@ -1508,7 +1613,12 @@ sdb_plugin_store_host(const char *name, sdb_time_t last_update)
        }
 
        host.name = cname;
-       host.last_update = last_update;
+       host.last_update = last_update ? last_update : sdb_gettime();
+       if (get_interval(SDB_HOST, NULL, -1, NULL, cname,
+                               host.last_update, &host.interval)) {
+               free(cname);
+               return 1;
+       }
        host.backends = (const char * const *)backends;
        get_backend(backends, &host.backends_num);
 
@@ -1556,7 +1666,12 @@ sdb_plugin_store_service(const char *hostname, const char *name,
 
        service.hostname = cname;
        service.name = name;
-       service.last_update = last_update;
+       service.last_update = last_update ? last_update : sdb_gettime();
+       if (get_interval(SDB_SERVICE, cname, -1, NULL, name,
+                               service.last_update, &service.interval)) {
+               free(cname);
+               return 1;
+       }
        service.backends = (const char * const *)backends;
        get_backend(backends, &service.backends_num);
 
@@ -1576,7 +1691,7 @@ sdb_plugin_store_service(const char *hostname, const char *name,
                d.type = SDB_TYPE_STRING;
                d.data.string = cname;
                if (sdb_plugin_store_service_attribute(cname, name,
-                                       "hostname", &d, last_update))
+                                       "hostname", &d, service.last_update))
                        status = -1;
        }
 
@@ -1621,7 +1736,12 @@ sdb_plugin_store_metric(const char *hostname, const char *name,
                metric.store.type = store->type;
                metric.store.id = store->id;
        }
-       metric.last_update = last_update;
+       metric.last_update = last_update ? last_update : sdb_gettime();
+       if (get_interval(SDB_METRIC, cname, -1, NULL, name,
+                               metric.last_update, &metric.interval)) {
+               free(cname);
+               return 1;
+       }
        metric.backends = (const char * const *)backends;
        get_backend(backends, &metric.backends_num);
 
@@ -1641,7 +1761,7 @@ sdb_plugin_store_metric(const char *hostname, const char *name,
                d.type = SDB_TYPE_STRING;
                d.data.string = cname;
                if (sdb_plugin_store_metric_attribute(cname, name,
-                                       "hostname", &d, last_update))
+                                       "hostname", &d, metric.last_update))
                        status = -1;
        }
 
@@ -1679,7 +1799,12 @@ sdb_plugin_store_attribute(const char *hostname, const char *key,
        attr.parent = cname;
        attr.key = key;
        attr.value = *value;
-       attr.last_update = last_update;
+       attr.last_update = last_update ? last_update : sdb_gettime();
+       if (get_interval(SDB_ATTRIBUTE, cname, -1, NULL, key,
+                               attr.last_update, &attr.interval)) {
+               free(cname);
+               return 1;
+       }
        attr.backends = (const char * const *)backends;
        get_backend(backends, &attr.backends_num);
 
@@ -1728,7 +1853,12 @@ sdb_plugin_store_service_attribute(const char *hostname, const char *service,
        attr.parent = service;
        attr.key = key;
        attr.value = *value;
-       attr.last_update = last_update;
+       attr.last_update = last_update ? last_update : sdb_gettime();
+       if (get_interval(SDB_ATTRIBUTE, cname, SDB_SERVICE, service, key,
+                               attr.last_update, &attr.interval)) {
+               free(cname);
+               return 1;
+       }
        attr.backends = (const char * const *)backends;
        get_backend(backends, &attr.backends_num);
 
@@ -1777,7 +1907,12 @@ sdb_plugin_store_metric_attribute(const char *hostname, const char *metric,
        attr.parent = metric;
        attr.key = key;
        attr.value = *value;
-       attr.last_update = last_update;
+       attr.last_update = last_update ? last_update : sdb_gettime();
+       if (get_interval(SDB_ATTRIBUTE, cname, SDB_METRIC, metric, key,
+                               attr.last_update, &attr.interval)) {
+               free(cname);
+               return 1;
+       }
        attr.backends = (const char * const *)backends;
        get_backend(backends, &attr.backends_num);
 
diff --git a/src/core/store-private.h b/src/core/store-private.h
deleted file mode 100644 (file)
index e851487..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * SysDB - src/core/store-private.h
- * Copyright (C) 2012-2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * private data structures used by the store module
- */
-
-#ifndef SDB_CORE_STORE_PRIVATE_H
-#define SDB_CORE_STORE_PRIVATE_H 1
-
-#include "core/store.h"
-#include "utils/avltree.h"
-
-#include <sys/types.h>
-#include <regex.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * core types
- */
-
-struct sdb_store_obj {
-       sdb_object_t super;
-#define _name super.name
-
-       /* object type */
-       int type;
-
-       /* common meta information */
-       sdb_time_t last_update;
-       sdb_time_t interval; /* moving average */
-       char **backends;
-       size_t backends_num;
-       sdb_store_obj_t *parent;
-};
-#define STORE_OBJ(obj) ((sdb_store_obj_t *)(obj))
-#define STORE_CONST_OBJ(obj) ((const sdb_store_obj_t *)(obj))
-
-typedef struct {
-       sdb_store_obj_t super;
-
-       sdb_data_t value;
-} attr_t;
-#define ATTR(obj) ((attr_t *)(obj))
-#define CONST_ATTR(obj) ((const attr_t *)(obj))
-
-typedef struct {
-       sdb_store_obj_t super;
-
-       sdb_avltree_t *attributes;
-} service_t;
-#define SVC(obj) ((service_t *)(obj))
-#define CONST_SVC(obj) ((const service_t *)(obj))
-
-typedef struct {
-       sdb_store_obj_t super;
-
-       sdb_avltree_t *attributes;
-       struct {
-               char *type;
-               char *id;
-       } store;
-} sdb_metric_t;
-#define METRIC(obj) ((sdb_metric_t *)(obj))
-
-typedef struct {
-       sdb_store_obj_t super;
-
-       sdb_avltree_t *services;
-       sdb_avltree_t *metrics;
-       sdb_avltree_t *attributes;
-} host_t;
-#define HOST(obj) ((host_t *)(obj))
-#define CONST_HOST(obj) ((const host_t *)(obj))
-
-/* shortcuts for accessing service/host attributes */
-#define _last_update super.last_update
-#define _interval super.interval
-
-/*
- * querying
- */
-
-struct sdb_store_query {
-       sdb_object_t super;
-       sdb_ast_node_t *ast;
-       sdb_store_matcher_t *matcher;
-       sdb_store_matcher_t *filter;
-};
-#define QUERY(m) ((sdb_store_query_t *)(m))
-
-/*
- * expressions
- */
-
-enum {
-       TYPED_EXPR  = -3, /* obj type stored in data.data.integer */
-       ATTR_VALUE  = -2, /* attr name stored in data.data.string */
-       FIELD_VALUE = -1, /* field type stored in data.data.integer */
-       /*  0: const value (stored in data) */
-       /* >0: operator id */
-};
-
-struct sdb_store_expr {
-       sdb_object_t super;
-
-       int type; /* see above */
-       int data_type;
-
-       sdb_store_expr_t *left;
-       sdb_store_expr_t *right;
-
-       sdb_data_t data;
-};
-#define CONST_EXPR(v) { SDB_OBJECT_INIT, 0, (v).type, NULL, NULL, (v) }
-#define EXPR_TO_STRING(e) \
-       (((e)->type == TYPED_EXPR) ? "<typed>" \
-               : ((e)->type == ATTR_VALUE) ? "attribute" \
-               : ((e)->type == FIELD_VALUE) ? SDB_FIELD_TO_NAME((e)->data.data.integer) \
-               : ((e)->type == 0) ? "<constant>" \
-               : ((e)->type > 0) ? SDB_DATA_OP_TO_STRING((e)->type) \
-               : "<unknown>")
-
-/*
- * matchers
- */
-
-/* when adding to this, also update 'MATCHER_SYM' below and 'matchers' in
- * store_lookup.c */
-enum {
-       MATCHER_OR,
-       MATCHER_AND,
-       MATCHER_NOT,
-       MATCHER_ANY,
-       MATCHER_ALL,
-       MATCHER_IN,
-
-       /* unary operators */
-       MATCHER_ISNULL,
-       MATCHER_ISTRUE,
-       MATCHER_ISFALSE,
-
-       /* ary operators */
-       MATCHER_LT,
-       MATCHER_LE,
-       MATCHER_EQ,
-       MATCHER_NE,
-       MATCHER_GE,
-       MATCHER_GT,
-       MATCHER_REGEX,
-       MATCHER_NREGEX,
-
-       /* a generic query */
-       MATCHER_QUERY,
-};
-
-#define MATCHER_SYM(t) \
-       (((t) == MATCHER_OR) ? "OR" \
-               : ((t) == MATCHER_AND) ? "AND" \
-               : ((t) == MATCHER_NOT) ? "NOT" \
-               : ((t) == MATCHER_ANY) ? "ANY" \
-               : ((t) == MATCHER_ALL) ? "ALL" \
-               : ((t) == MATCHER_IN) ? "IN" \
-               : ((t) == MATCHER_ISNULL) ? "IS NULL" \
-               : ((t) == MATCHER_ISTRUE) ? "IS TRUE" \
-               : ((t) == MATCHER_ISFALSE) ? "IS FALSE" \
-               : ((t) == MATCHER_LT) ? "<" \
-               : ((t) == MATCHER_LE) ? "<=" \
-               : ((t) == MATCHER_EQ) ? "=" \
-               : ((t) == MATCHER_NE) ? "!=" \
-               : ((t) == MATCHER_GE) ? ">=" \
-               : ((t) == MATCHER_GT) ? ">" \
-               : ((t) == MATCHER_REGEX) ? "=~" \
-               : ((t) == MATCHER_NREGEX) ? "!~" \
-               : ((t) == MATCHER_QUERY) ? "QUERY" \
-               : "UNKNOWN")
-
-/* matcher base type */
-struct sdb_store_matcher {
-       sdb_object_t super;
-       /* type of the matcher */
-       int type;
-};
-#define M(m) ((sdb_store_matcher_t *)(m))
-
-/* infix operator matcher */
-typedef struct {
-       sdb_store_matcher_t super;
-
-       /* left and right hand operands */
-       sdb_store_matcher_t *left;
-       sdb_store_matcher_t *right;
-} op_matcher_t;
-#define OP_M(m) ((op_matcher_t *)(m))
-
-/* unary operator matcher */
-typedef struct {
-       sdb_store_matcher_t super;
-
-       /* operand */
-       sdb_store_matcher_t *op;
-} uop_matcher_t;
-#define UOP_M(m) ((uop_matcher_t *)(m))
-
-/* iter matcher */
-typedef struct {
-       sdb_store_matcher_t super;
-       sdb_store_expr_t *iter;
-       sdb_store_matcher_t *m;
-} iter_matcher_t;
-#define ITER_M(m) ((iter_matcher_t *)(m))
-
-/* compare operator matcher */
-typedef struct {
-       sdb_store_matcher_t super;
-
-       /* left and right hand expressions */
-       sdb_store_expr_t *left;
-       sdb_store_expr_t *right;
-} cmp_matcher_t;
-#define CMP_M(m) ((cmp_matcher_t *)(m))
-
-typedef struct {
-       sdb_store_matcher_t super;
-       sdb_store_expr_t *expr;
-} unary_matcher_t;
-#define UNARY_M(m) ((unary_matcher_t *)(m))
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* ! SDB_CORE_STORE_H */
-
-/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
-
diff --git a/src/core/store.c b/src/core/store.c
deleted file mode 100644 (file)
index fa72955..0000000
+++ /dev/null
@@ -1,978 +0,0 @@
-/*
- * SysDB - src/core/store.c
- * Copyright (C) 2012-2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#if HAVE_CONFIG_H
-#      include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#include "sysdb.h"
-#include "core/store-private.h"
-#include "core/plugin.h"
-#include "utils/avltree.h"
-#include "utils/error.h"
-
-#include <assert.h>
-
-#include <errno.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <pthread.h>
-
-/*
- * private types
- */
-
-struct sdb_store {
-       sdb_object_t super;
-
-       /* hosts are the top-level entries and
-        * reference everything else */
-       sdb_avltree_t *hosts;
-       pthread_rwlock_t host_lock;
-};
-
-/* internal representation of a to-be-stored object */
-typedef struct {
-       sdb_store_obj_t *parent;
-       sdb_avltree_t *parent_tree;
-       int type;
-       const char *name;
-       sdb_time_t last_update;
-       const char * const *backends;
-       size_t backends_num;
-} store_obj_t;
-#define STORE_OBJ_INIT { NULL, NULL, 0, NULL, 0, NULL, 0 }
-
-static sdb_type_t host_type;
-static sdb_type_t service_type;
-static sdb_type_t metric_type;
-static sdb_type_t attribute_type;
-
-static int
-store_init(sdb_object_t *obj, va_list __attribute__((unused)) ap)
-{
-       int err;
-       if (! (SDB_STORE(obj)->hosts = sdb_avltree_create()))
-               return -1;
-       if ((err = pthread_rwlock_init(&SDB_STORE(obj)->host_lock,
-                                       /* attr = */ NULL))) {
-               char errbuf[128];
-               sdb_log(SDB_LOG_ERR, "store: Failed to initialize lock: %s",
-                               sdb_strerror(err, errbuf, sizeof(errbuf)));
-               return -1;
-       }
-       return 0;
-} /* store_init */
-
-static void
-store_destroy(sdb_object_t *obj)
-{
-       int err;
-       if ((err = pthread_rwlock_destroy(&SDB_STORE(obj)->host_lock))) {
-               char errbuf[128];
-               sdb_log(SDB_LOG_ERR, "store: Failed to destroy lock: %s",
-                               sdb_strerror(err, errbuf, sizeof(errbuf)));
-               return;
-       }
-       sdb_avltree_destroy(SDB_STORE(obj)->hosts);
-       SDB_STORE(obj)->hosts = NULL;
-} /* store_destroy */
-
-static int
-store_obj_init(sdb_object_t *obj, va_list ap)
-{
-       sdb_store_obj_t *sobj = STORE_OBJ(obj);
-
-       sobj->type = va_arg(ap, int);
-
-       sobj->last_update = va_arg(ap, sdb_time_t);
-       sobj->interval = 0;
-       sobj->backends = NULL;
-       sobj->backends_num = 0;
-       sobj->parent = NULL;
-       return 0;
-} /* store_obj_init */
-
-static void
-store_obj_destroy(sdb_object_t *obj)
-{
-       sdb_store_obj_t *sobj = STORE_OBJ(obj);
-       size_t i;
-
-       for (i = 0; i < sobj->backends_num; ++i)
-               free(sobj->backends[i]);
-       free(sobj->backends);
-       sobj->backends = NULL;
-       sobj->backends_num = 0;
-
-       // We don't currently keep an extra reference for parent objects to
-       // avoid circular self-references which are not handled correctly by
-       // the ref-count base management layer.
-       //sdb_object_deref(SDB_OBJ(sobj->parent));
-} /* store_obj_destroy */
-
-static int
-host_init(sdb_object_t *obj, va_list ap)
-{
-       host_t *sobj = HOST(obj);
-       int ret;
-
-       /* this will consume the first argument (type) of ap */
-       ret = store_obj_init(obj, ap);
-       if (ret)
-               return ret;
-
-       sobj->services = sdb_avltree_create();
-       if (! sobj->services)
-               return -1;
-       sobj->metrics = sdb_avltree_create();
-       if (! sobj->metrics)
-               return -1;
-       sobj->attributes = sdb_avltree_create();
-       if (! sobj->attributes)
-               return -1;
-       return 0;
-} /* host_init */
-
-static void
-host_destroy(sdb_object_t *obj)
-{
-       host_t *sobj = HOST(obj);
-       assert(obj);
-
-       store_obj_destroy(obj);
-
-       if (sobj->services)
-               sdb_avltree_destroy(sobj->services);
-       if (sobj->metrics)
-               sdb_avltree_destroy(sobj->metrics);
-       if (sobj->attributes)
-               sdb_avltree_destroy(sobj->attributes);
-} /* host_destroy */
-
-static int
-service_init(sdb_object_t *obj, va_list ap)
-{
-       service_t *sobj = SVC(obj);
-       int ret;
-
-       /* this will consume the first argument (type) of ap */
-       ret = store_obj_init(obj, ap);
-       if (ret)
-               return ret;
-
-       sobj->attributes = sdb_avltree_create();
-       if (! sobj->attributes)
-               return -1;
-       return 0;
-} /* service_init */
-
-static void
-service_destroy(sdb_object_t *obj)
-{
-       service_t *sobj = SVC(obj);
-       assert(obj);
-
-       store_obj_destroy(obj);
-
-       if (sobj->attributes)
-               sdb_avltree_destroy(sobj->attributes);
-} /* service_destroy */
-
-static int
-metric_init(sdb_object_t *obj, va_list ap)
-{
-       sdb_metric_t *sobj = METRIC(obj);
-       int ret;
-
-       /* this will consume the first argument (type) of ap */
-       ret = store_obj_init(obj, ap);
-       if (ret)
-               return ret;
-
-       sobj->attributes = sdb_avltree_create();
-       if (! sobj->attributes)
-               return -1;
-
-       sobj->store.type = sobj->store.id = NULL;
-       return 0;
-} /* metric_init */
-
-static void
-metric_destroy(sdb_object_t *obj)
-{
-       sdb_metric_t *sobj = METRIC(obj);
-       assert(obj);
-
-       store_obj_destroy(obj);
-
-       if (sobj->attributes)
-               sdb_avltree_destroy(sobj->attributes);
-
-       if (sobj->store.type)
-               free(sobj->store.type);
-       if (sobj->store.id)
-               free(sobj->store.id);
-} /* metric_destroy */
-
-static int
-attr_init(sdb_object_t *obj, va_list ap)
-{
-       const sdb_data_t *value;
-       int ret;
-
-       /* this will consume the first two arguments
-        * (type and last_update) of ap */
-       ret = store_obj_init(obj, ap);
-       if (ret)
-               return ret;
-       value = va_arg(ap, const sdb_data_t *);
-
-       if (value)
-               if (sdb_data_copy(&ATTR(obj)->value, value))
-                       return -1;
-       return 0;
-} /* attr_init */
-
-static void
-attr_destroy(sdb_object_t *obj)
-{
-       assert(obj);
-
-       store_obj_destroy(obj);
-       sdb_data_free_datum(&ATTR(obj)->value);
-} /* attr_destroy */
-
-static sdb_type_t store_type = {
-       /* size = */ sizeof(sdb_store_t),
-       /* init = */ store_init,
-       /* destroy = */ store_destroy,
-};
-
-static sdb_type_t host_type = {
-       /* size = */ sizeof(host_t),
-       /* init = */ host_init,
-       /* destroy = */ host_destroy
-};
-
-static sdb_type_t service_type = {
-       /* size = */ sizeof(service_t),
-       /* init = */ service_init,
-       /* destroy = */ service_destroy
-};
-
-static sdb_type_t metric_type = {
-       /* size = */ sizeof(sdb_metric_t),
-       /* init = */ metric_init,
-       /* destroy = */ metric_destroy
-};
-
-static sdb_type_t attribute_type = {
-       /* size = */ sizeof(attr_t),
-       /* init = */ attr_init,
-       /* destroy = */ attr_destroy
-};
-
-/*
- * private helper functions
- */
-
-static int
-record_backends(sdb_store_obj_t *obj,
-               const char * const *backends, size_t backends_num)
-{
-       char **tmp;
-       size_t i;
-
-       for (i = 0; i < backends_num; i++) {
-               bool found = 0;
-               size_t j;
-
-               for (j = 0; j < obj->backends_num; ++j) {
-                       if (!strcasecmp(obj->backends[j], backends[i])) {
-                               found = 1;
-                               break;
-                       }
-               }
-               if (found)
-                       continue;
-
-               tmp = realloc(obj->backends,
-                               (obj->backends_num + 1) * sizeof(*obj->backends));
-               if (! tmp)
-                       return -1;
-
-               obj->backends = tmp;
-               obj->backends[obj->backends_num] = strdup(backends[i]);
-               if (! obj->backends[obj->backends_num])
-                       return -1;
-
-               ++obj->backends_num;
-       }
-       return 0;
-} /* record_backends */
-
-static int
-store_obj(store_obj_t *obj, sdb_store_obj_t **updated_obj)
-{
-       sdb_store_obj_t *old, *new;
-       int status = 0;
-
-       assert(obj->parent_tree);
-
-       if (obj->last_update <= 0)
-               obj->last_update = sdb_gettime();
-
-       old = STORE_OBJ(sdb_avltree_lookup(obj->parent_tree, obj->name));
-       if (old) {
-               if (old->last_update > obj->last_update) {
-                       sdb_log(SDB_LOG_DEBUG, "store: Cannot update %s '%s' - "
-                                       "value too old (%"PRIsdbTIME" < %"PRIsdbTIME")",
-                                       SDB_STORE_TYPE_TO_NAME(obj->type), obj->name,
-                                       obj->last_update, old->last_update);
-                       /* don't report an error; the object may be updated by multiple
-                        * backends */
-                       status = 1;
-               }
-               else if (old->last_update == obj->last_update) {
-                       /* don't report an error and also don't even log this to avoid
-                        * excessive noise on high sampling frequencies */
-                       status = 1;
-               }
-               else {
-                       sdb_time_t interval = obj->last_update - old->last_update;
-                       old->last_update = obj->last_update;
-                       if (interval) {
-                               if (old->interval)
-                                       old->interval = (sdb_time_t)((0.9 * (double)old->interval)
-                                                       + (0.1 * (double)interval));
-                               else
-                                       old->interval = interval;
-                       }
-               }
-
-               new = old;
-               sdb_object_deref(SDB_OBJ(old));
-       }
-       else {
-               if (obj->type == SDB_ATTRIBUTE) {
-                       /* the value will be updated by the caller */
-                       new = STORE_OBJ(sdb_object_create(obj->name, attribute_type,
-                                               obj->type, obj->last_update, NULL));
-               }
-               else {
-                       sdb_type_t t;
-                       t = obj->type == SDB_HOST
-                               ? host_type
-                               : obj->type == SDB_SERVICE
-                                       ? service_type
-                                       : metric_type;
-                       new = STORE_OBJ(sdb_object_create(obj->name, t,
-                                               obj->type, obj->last_update));
-               }
-
-               if (new) {
-                       status = sdb_avltree_insert(obj->parent_tree, SDB_OBJ(new));
-
-                       /* pass control to the tree or destroy in case of an error */
-                       sdb_object_deref(SDB_OBJ(new));
-               }
-               else {
-                       char errbuf[1024];
-                       sdb_log(SDB_LOG_ERR, "store: Failed to create %s '%s': %s",
-                                       SDB_STORE_TYPE_TO_NAME(obj->type), obj->name,
-                                       sdb_strerror(errno, errbuf, sizeof(errbuf)));
-                       status = -1;
-               }
-       }
-
-       if (status < 0)
-               return status;
-       assert(new);
-
-       if (new->parent != obj->parent) {
-               // Avoid circular self-references which are not handled
-               // correctly by the ref-count based management layer.
-               //sdb_object_deref(SDB_OBJ(new->parent));
-               //sdb_object_ref(SDB_OBJ(obj->parent));
-               new->parent = obj->parent;
-       }
-
-       if (updated_obj)
-               *updated_obj = new;
-
-       if (record_backends(new, obj->backends, obj->backends_num))
-               return -1;
-       return status;
-} /* store_obj */
-
-static int
-store_metric_store(sdb_metric_t *metric, sdb_store_metric_t *m)
-{
-       char *type = metric->store.type;
-       char *id = metric->store.id;
-
-       if ((! metric->store.type) || strcasecmp(metric->store.type, m->store.type)) {
-               if (! (type = strdup(m->store.type)))
-                       return -1;
-       }
-       if ((! metric->store.id) || strcasecmp(metric->store.id, m->store.id)) {
-               if (! (id = strdup(m->store.id))) {
-                       if (type != metric->store.type)
-                               free(type);
-                       return -1;
-               }
-       }
-
-       if (type != metric->store.type) {
-               if (metric->store.type)
-                       free(metric->store.type);
-               metric->store.type = type;
-       }
-       if (id != metric->store.id) {
-               if (metric->store.id)
-                       free(metric->store.id);
-               metric->store.id = id;
-       }
-       return 0;
-} /* store_metric_store */
-
-/* The store's host_lock has to be acquired before calling this function. */
-static sdb_avltree_t *
-get_host_children(host_t *host, int type)
-{
-       if ((type != SDB_SERVICE) && (type != SDB_METRIC)
-                       && (type != SDB_ATTRIBUTE))
-               return NULL;
-
-       if (! host)
-               return NULL;
-
-       if (type == SDB_ATTRIBUTE)
-               return host->attributes;
-       else if (type == SDB_METRIC)
-               return host->metrics;
-       else
-               return host->services;
-} /* get_host_children */
-
-/*
- * store writer API
- */
-
-static int
-store_attribute(sdb_store_attribute_t *attr, sdb_object_t *user_data)
-{
-       sdb_store_t *st = SDB_STORE(user_data);
-       store_obj_t obj = STORE_OBJ_INIT;
-       sdb_store_obj_t *new = NULL;
-       const char *hostname;
-       host_t *host;
-
-       sdb_avltree_t *children = NULL;
-       int status = 0;
-
-       if ((! attr) || (! attr->parent) || (! attr->key))
-               return -1;
-
-       hostname = attr->hostname;
-       if (attr->parent_type == SDB_HOST)
-               hostname = attr->parent;
-       if (! hostname)
-               return -1;
-
-       pthread_rwlock_wrlock(&st->host_lock);
-       host = HOST(sdb_avltree_lookup(st->hosts, hostname));
-       if (! host) {
-               sdb_log(SDB_LOG_ERR, "store: Failed to store attribute '%s' - "
-                               "host '%s' not found", attr->key, hostname);
-               status = -1;
-       }
-
-       switch (attr->parent_type) {
-       case SDB_HOST:
-               obj.parent = STORE_OBJ(host);
-               obj.parent_tree = get_host_children(host, SDB_ATTRIBUTE);
-               break;
-       case SDB_SERVICE:
-               children = get_host_children(host, SDB_SERVICE);
-               break;
-       case SDB_METRIC:
-               children = get_host_children(host, SDB_METRIC);
-               break;
-       default:
-               status = -1;
-               break;
-       }
-
-       if (children) {
-               obj.parent = STORE_OBJ(sdb_avltree_lookup(children, attr->parent));
-               if (! obj.parent) {
-                       sdb_log(SDB_LOG_ERR, "store: Failed to store attribute '%s' - "
-                                       "%s '%s/%s' not found", attr->key,
-                                       SDB_STORE_TYPE_TO_NAME(attr->parent_type),
-                                       attr->hostname, attr->parent);
-                       status = -1;
-               }
-               else
-                       obj.parent_tree = attr->parent_type == SDB_SERVICE
-                               ? SVC(obj.parent)->attributes
-                               : METRIC(obj.parent)->attributes;
-       }
-
-       obj.type = SDB_ATTRIBUTE;
-       obj.name = attr->key;
-       obj.last_update = attr->last_update;
-       obj.backends = attr->backends;
-       obj.backends_num = attr->backends_num;
-       if (! status)
-               status = store_obj(&obj, &new);
-
-       if (! status) {
-               assert(new);
-               /* update the value if it changed */
-               if (sdb_data_cmp(&ATTR(new)->value, &attr->value))
-                       if (sdb_data_copy(&ATTR(new)->value, &attr->value))
-                               status = -1;
-       }
-
-       if (obj.parent != STORE_OBJ(host))
-               sdb_object_deref(SDB_OBJ(obj.parent));
-       sdb_object_deref(SDB_OBJ(host));
-       pthread_rwlock_unlock(&st->host_lock);
-
-       return status;
-} /* store_attribute */
-
-static int
-store_host(sdb_store_host_t *host, sdb_object_t *user_data)
-{
-       sdb_store_t *st = SDB_STORE(user_data);
-       store_obj_t obj = { NULL, st->hosts, SDB_HOST, NULL, 0, NULL, 0 };
-       int status = 0;
-
-       if ((! host) || (! host->name))
-               return -1;
-
-       obj.name = host->name;
-       obj.last_update = host->last_update;
-       obj.backends = host->backends;
-       obj.backends_num = host->backends_num;
-       pthread_rwlock_wrlock(&st->host_lock);
-       status = store_obj(&obj, NULL);
-       pthread_rwlock_unlock(&st->host_lock);
-
-       return status;
-} /* store_host */
-
-static int
-store_service(sdb_store_service_t *service, sdb_object_t *user_data)
-{
-       sdb_store_t *st = SDB_STORE(user_data);
-       store_obj_t obj = STORE_OBJ_INIT;
-       host_t *host;
-
-       int status = 0;
-
-       if ((! service) || (! service->hostname) || (! service->name))
-               return -1;
-
-       pthread_rwlock_wrlock(&st->host_lock);
-       host = HOST(sdb_avltree_lookup(st->hosts, service->hostname));
-       obj.parent = STORE_OBJ(host);
-       obj.parent_tree = get_host_children(host, SDB_SERVICE);
-       obj.type = SDB_SERVICE;
-       if (! obj.parent_tree) {
-               sdb_log(SDB_LOG_ERR, "store: Failed to store service '%s' - "
-                               "host '%s' not found", service->name, service->hostname);
-               status = -1;
-       }
-
-       obj.name = service->name;
-       obj.last_update = service->last_update;
-       obj.backends = service->backends;
-       obj.backends_num = service->backends_num;
-       if (! status)
-               status = store_obj(&obj, NULL);
-
-       sdb_object_deref(SDB_OBJ(host));
-       pthread_rwlock_unlock(&st->host_lock);
-       return status;
-} /* store_service */
-
-static int
-store_metric(sdb_store_metric_t *metric, sdb_object_t *user_data)
-{
-       sdb_store_t *st = SDB_STORE(user_data);
-       store_obj_t obj = STORE_OBJ_INIT;
-       sdb_store_obj_t *new = NULL;
-       host_t *host;
-
-       int status = 0;
-
-       if ((! metric) || (! metric->hostname) || (! metric->name))
-               return -1;
-
-       if ((metric->store.type != NULL) != (metric->store.id != NULL))
-               return -1;
-
-       pthread_rwlock_wrlock(&st->host_lock);
-       host = HOST(sdb_avltree_lookup(st->hosts, metric->hostname));
-       obj.parent = STORE_OBJ(host);
-       obj.parent_tree = get_host_children(host, SDB_METRIC);
-       obj.type = SDB_METRIC;
-       if (! obj.parent_tree) {
-               sdb_log(SDB_LOG_ERR, "store: Failed to store metric '%s' - "
-                               "host '%s' not found", metric->name, metric->hostname);
-               status = -1;
-       }
-
-       obj.name = metric->name;
-       obj.last_update = metric->last_update;
-       obj.backends = metric->backends;
-       obj.backends_num = metric->backends_num;
-       if (! status)
-               status = store_obj(&obj, &new);
-       sdb_object_deref(SDB_OBJ(host));
-
-       if (status) {
-               pthread_rwlock_unlock(&st->host_lock);
-               return status;
-       }
-
-       assert(new);
-       if (metric->store.type && metric->store.id)
-               if (store_metric_store(METRIC(new), metric))
-                       status = -1;
-       pthread_rwlock_unlock(&st->host_lock);
-       return status;
-} /* store_metric */
-
-sdb_store_writer_t sdb_store_writer = {
-       store_host, store_service, store_metric, store_attribute,
-};
-
-static sdb_object_t *
-prepare_query(sdb_ast_node_t *ast,
-               sdb_strbuf_t __attribute__((unused)) *errbuf,
-               sdb_object_t __attribute__((unused)) *user_data)
-{
-       return SDB_OBJ(sdb_store_query_prepare(ast));
-} /* prepare_query */
-
-static int
-execute_query(sdb_object_t *q,
-               sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
-               sdb_object_t *user_data)
-{
-       return sdb_store_query_execute(SDB_STORE(user_data),
-                       QUERY(q), w, wd, errbuf);
-} /* execute_query */
-
-sdb_store_reader_t sdb_store_reader = {
-       prepare_query, execute_query,
-};
-
-/*
- * public API
- */
-
-sdb_store_t *
-sdb_store_create(void)
-{
-       return SDB_STORE(sdb_object_create("store", store_type));
-} /* sdb_store_create */
-
-int
-sdb_store_host(sdb_store_t *store, const char *name, sdb_time_t last_update)
-{
-       sdb_store_host_t host = {
-               name, last_update, 0, NULL, 0,
-       };
-       return store_host(&host, SDB_OBJ(store));
-} /* sdb_store_host */
-
-int
-sdb_store_service(sdb_store_t *store, const char *hostname, const char *name,
-               sdb_time_t last_update)
-{
-       sdb_store_service_t service = {
-               hostname, name, last_update, 0, NULL, 0,
-       };
-       return store_service(&service, SDB_OBJ(store));
-} /* sdb_store_service */
-
-int
-sdb_store_metric(sdb_store_t *store, const char *hostname, const char *name,
-               sdb_metric_store_t *metric_store, sdb_time_t last_update)
-{
-       sdb_store_metric_t metric = {
-               hostname, name, { NULL, NULL }, last_update, 0, NULL, 0,
-       };
-       if (metric_store) {
-               metric.store.type = metric_store->type;
-               metric.store.id = metric_store->id;
-       }
-       return store_metric(&metric, SDB_OBJ(store));
-} /* sdb_store_metric */
-
-int
-sdb_store_attribute(sdb_store_t *store, const char *hostname,
-               const char *key, const sdb_data_t *value, sdb_time_t last_update)
-{
-       sdb_store_attribute_t attr = {
-               NULL, SDB_HOST, hostname, key, SDB_DATA_INIT, last_update, 0, NULL, 0,
-       };
-       if (value) {
-               attr.value = *value;
-       }
-       return store_attribute(&attr, SDB_OBJ(store));
-} /* sdb_store_attribute */
-
-int
-sdb_store_service_attr(sdb_store_t *store, const char *hostname,
-               const char *service, const char *key, const sdb_data_t *value,
-               sdb_time_t last_update)
-{
-       sdb_store_attribute_t attr = {
-               hostname, SDB_SERVICE, service, key, SDB_DATA_INIT, last_update, 0, NULL, 0,
-       };
-       if (value) {
-               attr.value = *value;
-       }
-       return store_attribute(&attr, SDB_OBJ(store));
-} /* sdb_store_service_attr */
-
-int
-sdb_store_metric_attr(sdb_store_t *store, const char *hostname,
-               const char *metric, const char *key, const sdb_data_t *value,
-               sdb_time_t last_update)
-{
-       sdb_store_attribute_t attr = {
-               hostname, SDB_METRIC, metric, key, SDB_DATA_INIT, last_update, 0, NULL, 0,
-       };
-       if (value) {
-               attr.value = *value;
-       }
-       return store_attribute(&attr, SDB_OBJ(store));
-} /* sdb_store_metric_attr */
-
-sdb_store_obj_t *
-sdb_store_get_host(sdb_store_t *store, const char *name)
-{
-       host_t *host;
-
-       if ((! store) || (! name))
-               return NULL;
-
-       host = HOST(sdb_avltree_lookup(store->hosts, name));
-       if (! host)
-               return NULL;
-
-       return STORE_OBJ(host);
-} /* sdb_store_get_host */
-
-sdb_store_obj_t *
-sdb_store_get_child(sdb_store_obj_t *host, int type, const char *name)
-{
-       sdb_avltree_t *children;
-
-       if ((! host) || (host->type != SDB_HOST) || (! name))
-               return NULL;
-
-       children = get_host_children(HOST(host), type);
-       if (! children)
-               return NULL;
-       return STORE_OBJ(sdb_avltree_lookup(children, name));
-} /* sdb_store_get_child */
-
-int
-sdb_store_get_field(sdb_store_obj_t *obj, int field, sdb_data_t *res)
-{
-       sdb_data_t tmp;
-
-       if (! obj)
-               return -1;
-
-       switch (field) {
-               case SDB_FIELD_NAME:
-                       tmp.type = SDB_TYPE_STRING;
-                       tmp.data.string = strdup(SDB_OBJ(obj)->name);
-                       if (! tmp.data.string)
-                               return -1;
-                       break;
-               case SDB_FIELD_LAST_UPDATE:
-                       tmp.type = SDB_TYPE_DATETIME;
-                       tmp.data.datetime = obj->last_update;
-                       break;
-               case SDB_FIELD_AGE:
-                       tmp.type = SDB_TYPE_DATETIME;
-                       tmp.data.datetime = sdb_gettime() - obj->last_update;
-                       break;
-               case SDB_FIELD_INTERVAL:
-                       tmp.type = SDB_TYPE_DATETIME;
-                       tmp.data.datetime = obj->interval;
-                       break;
-               case SDB_FIELD_BACKEND:
-                       if (! res)
-                               return 0;
-                       tmp.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING;
-                       tmp.data.array.length = obj->backends_num;
-                       tmp.data.array.values = obj->backends;
-                       return sdb_data_copy(res, &tmp);
-               case SDB_FIELD_VALUE:
-                       if (obj->type != SDB_ATTRIBUTE)
-                               return -1;
-                       if (! res)
-                               return 0;
-                       return sdb_data_copy(res, &ATTR(obj)->value);
-               case SDB_FIELD_TIMESERIES:
-                       if (obj->type != SDB_METRIC)
-                               return -1;
-                       tmp.type = SDB_TYPE_BOOLEAN;
-                       tmp.data.boolean = METRIC(obj)->store.type != NULL;
-               default:
-                       return -1;
-       }
-       if (res)
-               *res = tmp;
-       else
-               sdb_data_free_datum(&tmp);
-       return 0;
-} /* sdb_store_get_field */
-
-int
-sdb_store_get_attr(sdb_store_obj_t *obj, const char *name, sdb_data_t *res,
-               sdb_store_matcher_t *filter)
-{
-       sdb_avltree_t *tree = NULL;
-       sdb_store_obj_t *attr;
-
-       if ((! obj) || (! name))
-               return -1;
-
-       if (obj->type == SDB_HOST)
-               tree = HOST(obj)->attributes;
-       else if (obj->type == SDB_SERVICE)
-               tree = SVC(obj)->attributes;
-       else if (obj->type == SDB_METRIC)
-               tree = METRIC(obj)->attributes;
-
-       if (! tree)
-               return -1;
-
-       attr = STORE_OBJ(sdb_avltree_lookup(tree, name));
-       if (! attr)
-               return -1;
-       if (filter && (! sdb_store_matcher_matches(filter, attr, NULL))) {
-               sdb_object_deref(SDB_OBJ(attr));
-               return -1;
-       }
-
-       assert(STORE_OBJ(attr)->type == SDB_ATTRIBUTE);
-       if (res)
-               sdb_data_copy(res, &ATTR(attr)->value);
-       sdb_object_deref(SDB_OBJ(attr));
-       return 0;
-} /* sdb_store_get_attr */
-
-int
-sdb_store_scan(sdb_store_t *store, int type,
-               sdb_store_matcher_t *m, sdb_store_matcher_t *filter,
-               sdb_store_lookup_cb cb, void *user_data)
-{
-       sdb_avltree_iter_t *host_iter = NULL;
-       int status = 0;
-
-       if ((! store) || (! cb))
-               return -1;
-
-       if ((type != SDB_HOST) && (type != SDB_SERVICE) && (type != SDB_METRIC)) {
-               sdb_log(SDB_LOG_ERR, "store: Cannot scan objects of type %d", type);
-               return -1;
-       }
-
-       pthread_rwlock_rdlock(&store->host_lock);
-       host_iter = sdb_avltree_get_iter(store->hosts);
-       if (! host_iter)
-               status = -1;
-
-       /* has_next returns false if the iterator is NULL */
-       while (sdb_avltree_iter_has_next(host_iter)) {
-               sdb_store_obj_t *host;
-               sdb_avltree_iter_t *iter = NULL;
-
-               host = STORE_OBJ(sdb_avltree_iter_get_next(host_iter));
-               assert(host);
-
-               if (! sdb_store_matcher_matches(filter, host, NULL))
-                       continue;
-
-               if (type == SDB_SERVICE)
-                       iter = sdb_avltree_get_iter(HOST(host)->services);
-               else if (type == SDB_METRIC)
-                       iter = sdb_avltree_get_iter(HOST(host)->metrics);
-
-               if (iter) {
-                       while (sdb_avltree_iter_has_next(iter)) {
-                               sdb_store_obj_t *obj;
-                               obj = STORE_OBJ(sdb_avltree_iter_get_next(iter));
-                               assert(obj);
-
-                               if (sdb_store_matcher_matches(m, obj, filter)) {
-                                       if (cb(obj, filter, user_data)) {
-                                               sdb_log(SDB_LOG_ERR, "store: Callback returned "
-                                                               "an error while scanning");
-                                               status = -1;
-                                               break;
-                                       }
-                               }
-                       }
-               }
-               else if (sdb_store_matcher_matches(m, host, filter)) {
-                       if (cb(host, filter, user_data)) {
-                               sdb_log(SDB_LOG_ERR, "store: Callback returned "
-                                               "an error while scanning");
-                               status = -1;
-                       }
-               }
-
-               sdb_avltree_iter_destroy(iter);
-               if (status)
-                       break;
-       }
-
-       sdb_avltree_iter_destroy(host_iter);
-       pthread_rwlock_unlock(&store->host_lock);
-       return status;
-} /* sdb_store_scan */
-
-/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
-
diff --git a/src/core/store_exec.c b/src/core/store_exec.c
deleted file mode 100644 (file)
index d4e3088..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * SysDB - src/core/store_exec.c
- * Copyright (C) 2014-2015 Sebastian 'tokkee' Harl <sh@tokkee.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "core/object.h"
-#include "core/plugin.h"
-#include "core/store-private.h"
-#include "frontend/connection.h"
-#include "parser/ast.h"
-#include "utils/error.h"
-
-#include <errno.h>
-
-#include <arpa/inet.h>
-#include <stdlib.h>
-#include <string.h>
-
-/*
- * private helper functions
- */
-
-typedef struct {
-       sdb_store_obj_t *current_host;
-
-       sdb_store_writer_t *w;
-       sdb_object_t *wd;
-} iter_t;
-
-static int
-maybe_emit_host(iter_t *iter, sdb_store_obj_t *obj)
-{
-       if ((obj->type == SDB_HOST) || (obj->type == SDB_ATTRIBUTE))
-               return 0;
-       if (iter->current_host == obj->parent)
-               return 0;
-       iter->current_host = obj->parent;
-       return sdb_store_emit(obj->parent, iter->w, iter->wd);
-} /* maybe_emit_host */
-
-static int
-list_tojson(sdb_store_obj_t *obj,
-               sdb_store_matcher_t __attribute__((unused)) *filter,
-               void *user_data)
-{
-       iter_t *iter = user_data;
-       maybe_emit_host(iter, obj);
-       return sdb_store_emit(obj, iter->w, iter->wd);
-} /* list_tojson */
-
-static int
-lookup_tojson(sdb_store_obj_t *obj, sdb_store_matcher_t *filter,
-               void *user_data)
-{
-       iter_t *iter = user_data;
-       maybe_emit_host(iter, obj);
-       return sdb_store_emit_full(obj, filter, iter->w, iter->wd);
-} /* lookup_tojson */
-
-/*
- * query implementations
- */
-
-static int
-exec_fetch(sdb_store_t *store,
-               sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
-               int type, const char *hostname, const char *name,
-               sdb_store_matcher_t *filter)
-{
-       sdb_store_obj_t *host;
-       sdb_store_obj_t *obj;
-
-       int status = 0;
-
-       if ((! name) || ((type == SDB_HOST) && hostname)
-                       || ((type != SDB_HOST) && (! hostname))) {
-               /* This is a programming error, not something the client did wrong */
-               sdb_strbuf_sprintf(errbuf, "INTERNAL ERROR: invalid "
-                               "arguments to FETCH(%s, %s, %s)",
-                               SDB_STORE_TYPE_TO_NAME(type), hostname, name);
-               return -1;
-       }
-       if (type == SDB_HOST)
-               hostname = name;
-
-       host = sdb_store_get_host(store, hostname);
-       if ((! host)
-                       || (filter && (! sdb_store_matcher_matches(filter, host, NULL)))) {
-               sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s: "
-                               "host %s not found", SDB_STORE_TYPE_TO_NAME(type),
-                               name, hostname);
-               sdb_object_deref(SDB_OBJ(host));
-               return -1;
-       }
-       if (type == SDB_HOST) {
-               obj = host;
-       }
-       else {
-               obj = sdb_store_get_child(host, type, name);
-               if ((! obj)
-                               || (filter && (! sdb_store_matcher_matches(filter, obj, NULL)))) {
-                       sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s.%s: "
-                                       "%s not found", SDB_STORE_TYPE_TO_NAME(type),
-                                       hostname, name, name);
-                       if (obj)
-                               sdb_object_deref(SDB_OBJ(obj));
-                       sdb_object_deref(SDB_OBJ(host));
-                       return -1;
-               }
-               sdb_object_deref(SDB_OBJ(host));
-       }
-       host = NULL;
-
-       if (type != SDB_HOST)
-               status = sdb_store_emit(obj->parent, w, wd);
-       if (status || sdb_store_emit_full(obj, filter, w, wd)) {
-               sdb_log(SDB_LOG_ERR, "frontend: Failed to serialize "
-                               "%s %s.%s to JSON", SDB_STORE_TYPE_TO_NAME(type),
-                               hostname, name);
-               sdb_strbuf_sprintf(errbuf, "Out of memory");
-               sdb_object_deref(SDB_OBJ(obj));
-               return -1;
-       }
-
-       sdb_object_deref(SDB_OBJ(obj));
-       return SDB_CONNECTION_DATA;
-} /* exec_fetch */
-
-static int
-exec_list(sdb_store_t *store,
-               sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
-               int type, sdb_store_matcher_t *filter)
-{
-       iter_t iter = { NULL, w, wd };
-
-       if (sdb_store_scan(store, type, /* m = */ NULL, filter, list_tojson, &iter)) {
-               sdb_log(SDB_LOG_ERR, "frontend: Failed to serialize "
-                               "store to JSON");
-               sdb_strbuf_sprintf(errbuf, "Out of memory");
-               return -1;
-       }
-
-       return SDB_CONNECTION_DATA;
-} /* exec_list */
-
-static int
-exec_lookup(sdb_store_t *store,
-               sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
-               int type, sdb_store_matcher_t *m, sdb_store_matcher_t *filter)
-{
-       iter_t iter = { NULL, w, wd };
-
-       if (sdb_store_scan(store, type, m, filter, lookup_tojson, &iter)) {
-               sdb_log(SDB_LOG_ERR, "frontend: Failed to lookup %ss",
-                               SDB_STORE_TYPE_TO_NAME(type));
-               sdb_strbuf_sprintf(errbuf, "Failed to lookup %ss",
-                               SDB_STORE_TYPE_TO_NAME(type));
-               return -1;
-       }
-
-       return SDB_CONNECTION_DATA;
-} /* exec_lookup */
-
-/*
- * public API
- */
-
-int
-sdb_store_query_execute(sdb_store_t *store, sdb_store_query_t *q,
-               sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf)
-{
-       sdb_ast_node_t *ast;
-
-       if (! q)
-               return -1;
-       if (! q->ast) {
-               sdb_log(SDB_LOG_ERR, "store: Invalid empty query");
-               return -1;
-       }
-
-       ast = q->ast;
-       switch (ast->type) {
-       case SDB_AST_TYPE_FETCH:
-               return exec_fetch(store, w, wd, errbuf, SDB_AST_FETCH(ast)->obj_type,
-                               SDB_AST_FETCH(ast)->hostname, SDB_AST_FETCH(ast)->name,
-                               q->filter);
-
-       case SDB_AST_TYPE_LIST:
-               return exec_list(store, w, wd, errbuf, SDB_AST_LIST(ast)->obj_type,
-                               q->filter);
-
-       case SDB_AST_TYPE_LOOKUP:
-               return exec_lookup(store, w, wd, errbuf, SDB_AST_LOOKUP(ast)->obj_type,
-                               q->matcher, q->filter);
-
-       default:
-               sdb_log(SDB_LOG_ERR, "store: Invalid query of type %s",
-                               SDB_AST_TYPE_TO_STRING(ast));
-               return -1;
-       }
-
-       return 0;
-} /* sdb_store_query_execute */
-
-/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
diff --git a/src/core/store_expr.c b/src/core/store_expr.c
deleted file mode 100644 (file)
index 6405002..0000000
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- * SysDB - src/core/store_expr.c
- * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * This module implements expressions which may be executed in the store.
- */
-
-#if HAVE_CONFIG_H
-#      include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#include "sysdb.h"
-#include "core/store-private.h"
-#include "core/data.h"
-#include "core/object.h"
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-
-/*
- * private data types
- */
-
-/* iterate through either a list of child nodes or arrays */
-struct sdb_store_expr_iter {
-       sdb_store_obj_t *obj;
-       sdb_store_expr_t *expr;
-
-       sdb_avltree_iter_t *tree;
-
-       sdb_data_t array;
-       size_t array_idx;
-       bool free_array;
-
-       sdb_store_matcher_t *filter;
-};
-
-/*
- * private types
- */
-
-static int
-expr_init(sdb_object_t *obj, va_list ap)
-{
-       int type = va_arg(ap, int);
-       sdb_store_expr_t *left  = va_arg(ap, sdb_store_expr_t *);
-       sdb_store_expr_t *right = va_arg(ap, sdb_store_expr_t *);
-       const sdb_data_t *value = va_arg(ap, const sdb_data_t *);
-
-       sdb_store_expr_t *expr = SDB_STORE_EXPR(obj);
-
-       if (type <= 0) {
-               if (! value)
-                       return -1;
-               if ((type == TYPED_EXPR) && (! left))
-                       return -1;
-       } else {
-               if (value)
-                       return -1;
-               if ((! left) || (! right))
-                       return -1;
-       }
-
-       if (value)
-               expr->data = *value;
-
-       sdb_object_ref(SDB_OBJ(left));
-       sdb_object_ref(SDB_OBJ(right));
-
-       expr->type  = type;
-       expr->left  = left;
-       expr->right = right;
-
-       /* unknown for now */
-       expr->data_type = -1;
-       return 0;
-} /* expr_init */
-
-static void
-expr_destroy(sdb_object_t *obj)
-{
-       sdb_store_expr_t *expr = SDB_STORE_EXPR(obj);
-       sdb_object_deref(SDB_OBJ(expr->left));
-       sdb_object_deref(SDB_OBJ(expr->right));
-
-       if (expr->data.type)
-               sdb_data_free_datum(&expr->data);
-} /* expr_destroy */
-
-static sdb_type_t expr_type = {
-       /* size = */ sizeof(sdb_store_expr_t),
-       /* init = */ expr_init,
-       /* destroy = */ expr_destroy,
-};
-
-/*
- * public API
- */
-
-sdb_store_expr_t *
-sdb_store_expr_create(int op, sdb_store_expr_t *left, sdb_store_expr_t *right)
-{
-       sdb_data_t value = SDB_DATA_INIT;
-       sdb_store_expr_t *e;
-
-       if ((op < 0) || (SDB_DATA_CONCAT < op) || (! left) || (! right))
-               return NULL;
-
-       if (left->type || right->type) {
-               e = SDB_STORE_EXPR(sdb_object_create("store-expr", expr_type,
-                                       op, left, right, NULL));
-               e->data_type = sdb_data_expr_type(op, left->type, right->type);
-               return e;
-       }
-       /* else: both expressions are constant values; evaluate now */
-
-       if (sdb_data_expr_eval(op, &left->data, &right->data, &value))
-               return NULL;
-       e = SDB_STORE_EXPR(sdb_object_create("store-constvalue", expr_type,
-                               0, NULL, NULL, &value));
-       e->data_type = value.type;
-       return e;
-} /* sdb_store_expr_create */
-
-sdb_store_expr_t *
-sdb_store_expr_typed(int typ, sdb_store_expr_t *expr)
-{
-       sdb_data_t value = { SDB_TYPE_INTEGER, { .integer = typ } };
-       sdb_store_expr_t *e;
-
-       if ((typ < SDB_HOST) || (SDB_ATTRIBUTE < typ))
-               return NULL;
-
-       e = SDB_STORE_EXPR(sdb_object_create("store-typedexpr", expr_type,
-                               TYPED_EXPR, expr, NULL, &value));
-       e->data_type = expr->data_type;
-       return e;
-} /* sdb_store_expr_typed */
-
-sdb_store_expr_t *
-sdb_store_expr_fieldvalue(int field)
-{
-       sdb_data_t value = { SDB_TYPE_INTEGER, { .integer = field } };
-       sdb_store_expr_t *e;
-
-       if ((field < SDB_FIELD_NAME) || (SDB_FIELD_TIMESERIES < field))
-               return NULL;
-       e = SDB_STORE_EXPR(sdb_object_create("store-fieldvalue", expr_type,
-                               FIELD_VALUE, NULL, NULL, &value));
-       e->data_type = SDB_FIELD_TYPE(field);
-       return e;
-} /* sdb_store_expr_fieldvalue */
-
-sdb_store_expr_t *
-sdb_store_expr_attrvalue(const char *name)
-{
-       sdb_data_t value = { SDB_TYPE_STRING, { .string = NULL} };
-       sdb_store_expr_t *expr;
-
-       value.data.string = strdup(name);
-       if (! value.data.string)
-               return NULL;
-
-       expr = SDB_STORE_EXPR(sdb_object_create("store-attrvalue", expr_type,
-                               ATTR_VALUE, NULL, NULL, &value));
-       if (! expr)
-               free(value.data.string);
-       expr->data_type = -1;
-       return expr;
-} /* sdb_store_expr_attrvalue */
-
-sdb_store_expr_t *
-sdb_store_expr_constvalue(const sdb_data_t *value)
-{
-       sdb_data_t data = SDB_DATA_INIT;
-       sdb_store_expr_t *e;
-
-       if (sdb_data_copy(&data, value))
-               return NULL;
-       e = SDB_STORE_EXPR(sdb_object_create("store-constvalue", expr_type,
-                               0, NULL, NULL, &data));
-       e->data_type = data.type;
-       return e;
-} /* sdb_store_expr_constvalue */
-
-int
-sdb_store_expr_eval(sdb_store_expr_t *expr, sdb_store_obj_t *obj,
-               sdb_data_t *res, sdb_store_matcher_t *filter)
-{
-       sdb_data_t v1 = SDB_DATA_INIT, v2 = SDB_DATA_INIT;
-       int status = 0;
-
-       if ((! expr) || (! res))
-               return -1;
-
-       if (filter && obj && (! sdb_store_matcher_matches(filter, obj, NULL)))
-               obj = NULL; /* this object does not exist */
-
-       if (! expr->type)
-               return sdb_data_copy(res, &expr->data);
-       else if (expr->type == FIELD_VALUE)
-               return sdb_store_get_field(obj, (int)expr->data.data.integer, res);
-       else if (expr->type == ATTR_VALUE) {
-               status = sdb_store_get_attr(obj, expr->data.data.string, res, filter);
-               if ((status < 0) && obj) {
-                       /* attribute does not exist => NULL */
-                       status = 0;
-                       res->type = SDB_TYPE_STRING;
-                       res->data.string = NULL;
-               }
-               return status;
-       }
-       else if (expr->type == TYPED_EXPR) {
-               int typ = (int)expr->data.data.integer;
-               if (typ != obj->type) {
-                       /* we support self-references and { service, metric } -> host */
-                       if ((typ != SDB_HOST)
-                                       || ((obj->type != SDB_SERVICE)
-                                               && (obj->type != SDB_METRIC)))
-                               return -1;
-                       obj = obj->parent;
-               }
-               return sdb_store_expr_eval(expr->left, obj, res, filter);
-       }
-
-       if (sdb_store_expr_eval(expr->left, obj, &v1, filter))
-               return -1;
-       if (sdb_store_expr_eval(expr->right, obj, &v2, filter)) {
-               sdb_data_free_datum(&v1);
-               return -1;
-       }
-
-       if (sdb_data_expr_eval(expr->type, &v1, &v2, res))
-               status = -1;
-       sdb_data_free_datum(&v1);
-       sdb_data_free_datum(&v2);
-       return status;
-} /* sdb_store_expr_eval */
-
-sdb_store_expr_iter_t *
-sdb_store_expr_iter(sdb_store_expr_t *expr, sdb_store_obj_t *obj,
-               sdb_store_matcher_t *filter)
-{
-       sdb_store_expr_iter_t *iter;
-       sdb_avltree_iter_t *tree = NULL;
-       sdb_data_t array = SDB_DATA_INIT;
-       bool free_array = 0;
-
-       if (! expr)
-               return NULL;
-
-       while (expr->type == TYPED_EXPR) {
-               int type = (int)expr->data.data.integer;
-
-               if (obj->type == type) {
-                       /* self reference */
-               }
-               else if ((type == SDB_HOST)
-                               && ((obj->type == SDB_SERVICE)
-                                       || (obj->type == SDB_METRIC))) {
-                       /* reference to parent host */
-                       obj = obj->parent;
-               }
-               else
-                       break;
-               expr = expr->left;
-       }
-
-       if (expr->type == TYPED_EXPR) {
-               if (! obj)
-                       return NULL;
-               if (obj->type == SDB_HOST) {
-                       if (expr->data.data.integer == SDB_SERVICE)
-                               tree = sdb_avltree_get_iter(HOST(obj)->services);
-                       else if (expr->data.data.integer == SDB_METRIC)
-                               tree = sdb_avltree_get_iter(HOST(obj)->metrics);
-                       else if (expr->data.data.integer == SDB_ATTRIBUTE)
-                               tree = sdb_avltree_get_iter(HOST(obj)->attributes);
-               }
-               else if (obj->type == SDB_SERVICE) {
-                       if (expr->data.data.integer == SDB_ATTRIBUTE)
-                               tree = sdb_avltree_get_iter(SVC(obj)->attributes);
-               }
-               else if (obj->type == SDB_METRIC) {
-                       if (expr->data.data.integer == SDB_ATTRIBUTE)
-                               tree = sdb_avltree_get_iter(METRIC(obj)->attributes);
-               }
-       }
-       else if (expr->type == FIELD_VALUE) {
-               if (! obj)
-                       return NULL;
-               if (expr->data.data.integer == SDB_FIELD_BACKEND) {
-                       /* while scanning the store, we hold a read lock, so it's safe to
-                        * access the data without copying */
-                       array.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING;
-                       array.data.array.length = obj->backends_num;
-                       array.data.array.values = obj->backends;
-               }
-       }
-       else if (! expr->type) {
-               if (expr->data.type & SDB_TYPE_ARRAY)
-                       array = expr->data;
-       }
-       else {
-               sdb_data_t value = SDB_DATA_INIT;
-               if (sdb_store_expr_eval(expr, obj, &value, filter))
-                       return NULL;
-               if (! (value.type & SDB_TYPE_ARRAY)) {
-                       sdb_data_free_datum(&value);
-                       return NULL;
-               }
-               array = value;
-               free_array = 1;
-       }
-
-       if ((! tree) && (array.type == SDB_TYPE_NULL))
-               return NULL;
-
-       iter = calloc(1, sizeof(*iter));
-       if (! iter) {
-               if (free_array)
-                       sdb_data_free_datum(&array);
-               return NULL;
-       }
-
-       sdb_object_ref(SDB_OBJ(obj));
-       sdb_object_ref(SDB_OBJ(expr));
-       sdb_object_ref(SDB_OBJ(filter));
-
-       iter->obj = obj;
-       iter->expr = expr;
-       iter->tree = tree;
-       iter->array = array;
-       iter->free_array = free_array;
-       iter->filter = filter;
-       return iter;
-} /* sdb_store_expr_iter */
-
-void
-sdb_store_expr_iter_destroy(sdb_store_expr_iter_t *iter)
-{
-       sdb_data_t null = SDB_DATA_INIT;
-
-       if (! iter)
-               return;
-
-       if (iter->tree)
-               sdb_avltree_iter_destroy(iter->tree);
-       iter->tree = NULL;
-
-       if (iter->free_array)
-               sdb_data_free_datum(&iter->array);
-       iter->array = null;
-       iter->array_idx = 0;
-
-       sdb_object_deref(SDB_OBJ(iter->obj));
-       sdb_object_deref(SDB_OBJ(iter->expr));
-       sdb_object_deref(SDB_OBJ(iter->filter));
-       free(iter);
-} /* sdb_store_expr_iter_destroy */
-
-bool
-sdb_store_expr_iter_has_next(sdb_store_expr_iter_t *iter)
-{
-       if (! iter)
-               return 0;
-
-       if (iter->tree) {
-               /* this function may be called before get_next,
-                * so we'll have to apply filters here as well */
-               if (iter->filter) {
-                       sdb_store_obj_t *child;
-                       while ((child = STORE_OBJ(sdb_avltree_iter_peek_next(iter->tree)))) {
-                               if (sdb_store_matcher_matches(iter->filter, child, NULL))
-                                       break;
-                               (void)sdb_avltree_iter_get_next(iter->tree);
-                       }
-               }
-
-               return sdb_avltree_iter_has_next(iter->tree);
-       }
-
-       return iter->array_idx < iter->array.data.array.length;
-} /* sdb_store_expr_iter_has_next */
-
-sdb_data_t
-sdb_store_expr_iter_get_next(sdb_store_expr_iter_t *iter)
-{
-       sdb_data_t null = SDB_DATA_INIT;
-       sdb_data_t ret = SDB_DATA_INIT;
-       sdb_data_t tmp = SDB_DATA_INIT;
-
-       if (! iter)
-               return null;
-
-       if (iter->tree) {
-               sdb_store_obj_t *child;
-
-               while (42) {
-                       child = STORE_OBJ(sdb_avltree_iter_get_next(iter->tree));
-                       if (! child)
-                               break;
-                       if (iter->filter
-                                       && (! sdb_store_matcher_matches(iter->filter, child, NULL)))
-                               continue;
-
-                       if (sdb_store_expr_eval(iter->expr, child, &ret, iter->filter))
-                               return null;
-                       break;
-               }
-
-               /* Skip over any filtered objects */
-               if (iter->filter) {
-                       while ((child = STORE_OBJ(sdb_avltree_iter_peek_next(iter->tree)))) {
-                               if (sdb_store_matcher_matches(iter->filter, child, NULL))
-                                       break;
-                               (void)sdb_avltree_iter_get_next(iter->tree);
-                       }
-               }
-
-               return ret;
-       }
-
-       if (iter->array_idx >= iter->array.data.array.length)
-               return null;
-
-       ++iter->array_idx;
-       if (sdb_data_array_get(&iter->array, iter->array_idx - 1, &ret))
-               return null;
-       if (sdb_data_copy(&tmp, &ret))
-               return null;
-       ret = tmp;
-       return ret;
-} /* sdb_store_expr_iter_get_next */
-
-/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
-
index 961e54c0606ae84206d1199758506ad4ff212cbf..92666089870016beea0b0307f846d458b258b8fc 100644 (file)
@@ -34,7 +34,7 @@
 #endif /* HAVE_CONFIG_H */
 
 #include "sysdb.h"
-#include "core/store-private.h"
+#include "core/store.h"
 #include "utils/error.h"
 
 #include <assert.h>
@@ -379,133 +379,6 @@ sdb_store_json_formatter(sdb_strbuf_t *buf, int type, int flags)
                                buf, type, flags));
 } /* sdb_store_json_formatter */
 
-/* TODO: Move sdb_store_emit* somewhere else. */
-
-int
-sdb_store_emit(sdb_store_obj_t *obj, sdb_store_writer_t *w, sdb_object_t *wd)
-{
-       if ((! obj) || (! w))
-               return -1;
-
-       switch (obj->type) {
-       case SDB_HOST:
-               {
-                       sdb_store_host_t host = {
-                               obj->_name,
-                               obj->last_update,
-                               obj->interval,
-                               (const char * const *)obj->backends,
-                               obj->backends_num,
-                       };
-                       if (! w->store_host)
-                               return -1;
-                       return w->store_host(&host, wd);
-               }
-       case SDB_SERVICE:
-               {
-                       sdb_store_service_t service = {
-                               obj->parent ? obj->parent->_name : NULL,
-                               obj->_name,
-                               obj->last_update,
-                               obj->interval,
-                               (const char * const *)obj->backends,
-                               obj->backends_num,
-                       };
-                       if (! w->store_service)
-                               return -1;
-                       return w->store_service(&service, wd);
-               }
-       case SDB_METRIC:
-               {
-                       sdb_store_metric_t metric = {
-                               obj->parent ? obj->parent->_name : NULL,
-                               obj->_name,
-                               {
-                                       METRIC(obj)->store.type,
-                                       METRIC(obj)->store.id,
-                               },
-                               obj->last_update,
-                               obj->interval,
-                               (const char * const *)obj->backends,
-                               obj->backends_num,
-                       };
-                       if (! w->store_metric)
-                               return -1;
-                       return w->store_metric(&metric, wd);
-               }
-       case SDB_ATTRIBUTE:
-               {
-                       sdb_store_attribute_t attr = {
-                               NULL,
-                               obj->parent ? obj->parent->type : 0,
-                               obj->parent ? obj->parent->_name : NULL,
-                               obj->_name,
-                               ATTR(obj)->value,
-                               obj->last_update,
-                               obj->interval,
-                               (const char * const *)obj->backends,
-                               obj->backends_num,
-                       };
-                       if (obj->parent && (obj->parent->type != SDB_HOST)
-                                       && obj->parent->parent)
-                               attr.hostname = obj->parent->parent->_name;
-                       if (! w->store_attribute)
-                               return -1;
-                       return w->store_attribute(&attr, wd);
-               }
-       }
-
-       return -1;
-} /* sdb_store_emit */
-
-int
-sdb_store_emit_full(sdb_store_obj_t *obj, sdb_store_matcher_t *filter,
-               sdb_store_writer_t *w, sdb_object_t *wd)
-{
-       sdb_avltree_t *trees[] = { NULL, NULL, NULL };
-       size_t i;
-
-       if (sdb_store_emit(obj, w, wd))
-               return -1;
-
-       if (obj->type == SDB_HOST) {
-               trees[0] = HOST(obj)->attributes;
-               trees[1] = HOST(obj)->metrics;
-               trees[2] = HOST(obj)->services;
-       }
-       else if (obj->type == SDB_SERVICE)
-               trees[0] = SVC(obj)->attributes;
-       else if (obj->type == SDB_METRIC)
-               trees[0] = METRIC(obj)->attributes;
-       else if (obj->type == SDB_ATTRIBUTE)
-               return 0;
-       else
-               return -1;
-
-       for (i = 0; i < SDB_STATIC_ARRAY_LEN(trees); ++i) {
-               sdb_avltree_iter_t *iter;
-
-               if (! trees[i])
-                       continue;
-
-               iter = sdb_avltree_get_iter(trees[i]);
-               while (sdb_avltree_iter_has_next(iter)) {
-                       sdb_store_obj_t *child;
-                       child = STORE_OBJ(sdb_avltree_iter_get_next(iter));
-
-                       if (filter && (! sdb_store_matcher_matches(filter, child, NULL)))
-                               continue;
-
-                       if (sdb_store_emit_full(child, filter, w, wd)) {
-                               sdb_avltree_iter_destroy(iter);
-                               return -1;
-                       }
-               }
-               sdb_avltree_iter_destroy(iter);
-       }
-       return 0;
-} /* sdb_store_emit_full */
-
 int
 sdb_store_json_finish(sdb_store_json_formatter_t *f)
 {
diff --git a/src/core/store_lookup.c b/src/core/store_lookup.c
deleted file mode 100644 (file)
index 06151a8..0000000
+++ /dev/null
@@ -1,694 +0,0 @@
-/*
- * SysDB - src/core/store_lookup.c
- * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * This module implements operators which may be used to select contents of
- * the store by matching various attributes of the stored objects. For now, a
- * simple full table scan is supported only.
- */
-
-#if HAVE_CONFIG_H
-#      include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#include "sysdb.h"
-#include "core/store-private.h"
-#include "core/object.h"
-#include "utils/error.h"
-
-#include <assert.h>
-
-#include <sys/types.h>
-#include <regex.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <limits.h>
-
-static int
-expr_eval2(sdb_store_expr_t *e1, sdb_data_t *v1,
-               sdb_store_expr_t *e2, sdb_data_t *v2,
-               sdb_store_obj_t *obj, sdb_store_matcher_t *filter)
-{
-       if (e1->type) {
-               if (sdb_store_expr_eval(e1, obj, v1, filter))
-                       return -1;
-       }
-       else
-               *v1 = e1->data;
-       if (e2->type) {
-               if (sdb_store_expr_eval(e2, obj, v2, filter)) {
-                       if (e1->type)
-                               sdb_data_free_datum(v1);
-                       return -1;
-               }
-       }
-       else
-               *v2 = e2->data;
-       return 0;
-} /* expr_eval2 */
-
-static void
-expr_free_datum2(sdb_store_expr_t *e1, sdb_data_t *v1,
-               sdb_store_expr_t *e2, sdb_data_t *v2)
-{
-       if (e1->type)
-               sdb_data_free_datum(v1);
-       if (e2->type)
-               sdb_data_free_datum(v2);
-} /* expr_free_datum2 */
-
-/*
- * matcher implementations
- */
-
-/*
- * cmp_expr:
- * Compare two values using the specified matcher operator. If strcmp_fallback
- * is enabled, compare the string values in case of a type mismatch.
- */
-static int
-match_cmp_value(int op, sdb_data_t *v1, sdb_data_t *v2, bool strcmp_fallback)
-{
-       int status;
-
-       if (sdb_data_isnull(v1) || (sdb_data_isnull(v2)))
-               status = INT_MAX;
-       else if (v1->type == v2->type)
-               status = sdb_data_cmp(v1, v2);
-       else if (! strcmp_fallback)
-               status = INT_MAX;
-       else
-               status = sdb_data_strcmp(v1, v2);
-
-       if (status == INT_MAX)
-               return 0;
-       switch (op) {
-               case MATCHER_LT: return status < 0;
-               case MATCHER_LE: return status <= 0;
-               case MATCHER_EQ: return status == 0;
-               case MATCHER_NE: return status != 0;
-               case MATCHER_GE: return status >= 0;
-               case MATCHER_GT: return status > 0;
-       }
-       return 0;
-} /* match_cmp_value */
-
-static int
-match_regex_value(int op, sdb_data_t *v, sdb_data_t *re)
-{
-       char value[sdb_data_strlen(v) + 1];
-       int status = 0;
-
-       assert((op == MATCHER_REGEX)
-                       || (op == MATCHER_NREGEX));
-
-       if (sdb_data_isnull(v) || sdb_data_isnull(re))
-               return 0;
-
-       if (re->type == SDB_TYPE_STRING) {
-               sdb_data_t tmp = SDB_DATA_INIT;
-
-               if (sdb_data_parse(re->data.string, SDB_TYPE_REGEX, &tmp))
-                       return 0;
-
-               sdb_data_free_datum(re);
-               *re = tmp;
-       }
-       else if (re->type != SDB_TYPE_REGEX)
-               return 0;
-
-       if (! sdb_data_format(v, value, sizeof(value), SDB_UNQUOTED))
-               status = 0;
-       else if (! regexec(&re->data.re.regex, value, 0, NULL, 0))
-               status = 1;
-
-       if (op == MATCHER_NREGEX)
-               return !status;
-       return status;
-} /* match_regex_value */
-
-static int
-match_logical(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
-               sdb_store_matcher_t *filter)
-{
-       int status;
-
-       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, obj, filter);
-
-       /* lazy evaluation */
-       if ((! status) && (m->type == MATCHER_AND))
-               return status;
-       else if (status && (m->type == MATCHER_OR))
-               return status;
-
-       return sdb_store_matcher_matches(OP_M(m)->right, obj, filter);
-} /* match_logical */
-
-static int
-match_uop(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, obj, filter);
-} /* match_uop */
-
-/* iterate: ANY/ALL <iter> <cmp> <value> */
-static int
-match_iter(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
-               sdb_store_matcher_t *filter)
-{
-       sdb_store_expr_iter_t *iter = NULL;
-       int status;
-       int all = (int)(m->type == MATCHER_ALL);
-
-       assert((m->type == MATCHER_ANY) || (m->type == MATCHER_ALL));
-       assert((! CMP_M(ITER_M(m)->m)->left) && CMP_M(ITER_M(m)->m)->right);
-
-       iter = sdb_store_expr_iter(ITER_M(m)->iter, obj, filter);
-       if (! iter) {
-               sdb_log(SDB_LOG_WARNING, "store: Invalid iterator");
-               return 0;
-       }
-
-       status = all;
-       while (sdb_store_expr_iter_has_next(iter)) {
-               sdb_data_t v = sdb_store_expr_iter_get_next(iter);
-               sdb_store_expr_t expr = CONST_EXPR(v);
-               bool matches;
-
-               CMP_M(ITER_M(m)->m)->left = &expr;
-               matches = sdb_store_matcher_matches(ITER_M(m)->m, obj, filter);
-               CMP_M(ITER_M(m)->m)->left = NULL;
-               sdb_data_free_datum(&v);
-
-               if (matches) {
-                       if (! all) {
-                               status = 1;
-                               break;
-                       }
-               } else if (all) {
-                       status = 0;
-                       break;
-               }
-       }
-       sdb_store_expr_iter_destroy(iter);
-       return status;
-} /* match_iter */
-
-static int
-match_cmp(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
-               sdb_store_matcher_t *filter)
-{
-       sdb_store_expr_t *e1 = CMP_M(m)->left;
-       sdb_store_expr_t *e2 = CMP_M(m)->right;
-       sdb_data_t v1 = SDB_DATA_INIT, v2 = SDB_DATA_INIT;
-       int status;
-
-       assert((m->type == MATCHER_LT)
-                       || (m->type == MATCHER_LE)
-                       || (m->type == MATCHER_EQ)
-                       || (m->type == MATCHER_NE)
-                       || (m->type == MATCHER_GE)
-                       || (m->type == MATCHER_GT));
-       assert(e1 && e2);
-
-       if (expr_eval2(e1, &v1, e2, &v2, obj, filter))
-               return 0;
-
-       status = match_cmp_value(m->type, &v1, &v2,
-                       (e1->data_type) < 0 || (e2->data_type < 0));
-
-       expr_free_datum2(e1, &v1, e2, &v2);
-       return status;
-} /* match_cmp */
-
-static int
-match_in(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
-               sdb_store_matcher_t *filter)
-{
-       sdb_data_t value = SDB_DATA_INIT, array = SDB_DATA_INIT;
-       int status = 1;
-
-       assert(m->type == MATCHER_IN);
-       assert(CMP_M(m)->left && CMP_M(m)->right);
-
-       if (expr_eval2(CMP_M(m)->left, &value,
-                               CMP_M(m)->right, &array, obj, filter))
-               status = 0;
-
-       if (status)
-               status = sdb_data_inarray(&value, &array);
-
-       expr_free_datum2(CMP_M(m)->left, &value, CMP_M(m)->right, &array);
-       return status;
-} /* match_in */
-
-static int
-match_regex(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
-               sdb_store_matcher_t *filter)
-{
-       sdb_data_t regex = SDB_DATA_INIT, v = SDB_DATA_INIT;
-       int status = 0;
-
-       assert((m->type == MATCHER_REGEX)
-                       || (m->type == MATCHER_NREGEX));
-       assert(CMP_M(m)->left && CMP_M(m)->right);
-
-       if (expr_eval2(CMP_M(m)->left, &v, CMP_M(m)->right, &regex, obj, filter))
-               return 0;
-
-       status = match_regex_value(m->type, &v, &regex);
-
-       expr_free_datum2(CMP_M(m)->left, &v, CMP_M(m)->right, &regex);
-       return status;
-} /* match_regex */
-
-static int
-match_unary(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
-               sdb_store_matcher_t *filter)
-{
-       sdb_data_t v = SDB_DATA_INIT;
-       int status;
-
-       assert((m->type == MATCHER_ISNULL)
-                       || (m->type == MATCHER_ISTRUE)
-                       || (m->type == MATCHER_ISFALSE));
-
-       if (UNARY_M(m)->expr->type) {
-               /* TODO: this might hide real errors;
-                * improve error reporting and propagation */
-               if (sdb_store_expr_eval(UNARY_M(m)->expr, obj, &v, filter))
-                       return 1;
-       }
-       else
-               v = UNARY_M(m)->expr->data;
-
-       if (m->type == MATCHER_ISNULL)
-               status = sdb_data_isnull(&v) ? 1 : 0;
-       else { /* ISTRUE or ISFALSE */
-               if ((v.type == SDB_TYPE_BOOLEAN)
-                               && (v.data.boolean == (m->type == MATCHER_ISTRUE)))
-                       status = 1;
-               else
-                       status = 0;
-       }
-
-       if (UNARY_M(m)->expr->type)
-               sdb_data_free_datum(&v);
-       return status;
-} /* match_unary */
-
-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;
- * -> update the enum in store-private.h when updating this */
-static matcher_cb
-matchers[] = {
-       match_logical,
-       match_logical,
-       match_uop,
-       match_iter,
-       match_iter,
-       match_in,
-
-       /* unary operators */
-       match_unary,
-       match_unary,
-       match_unary,
-
-       /* ary operators */
-       match_cmp,
-       match_cmp,
-       match_cmp,
-       match_cmp,
-       match_cmp,
-       match_cmp,
-       match_regex,
-       match_regex,
-
-       NULL, /* QUERY */
-};
-
-/*
- * private matcher types
- */
-
-static int
-op_matcher_init(sdb_object_t *obj, va_list ap)
-{
-       M(obj)->type = va_arg(ap, int);
-       if ((M(obj)->type != MATCHER_OR) && (M(obj)->type != MATCHER_AND))
-               return -1;
-
-       OP_M(obj)->left = va_arg(ap, sdb_store_matcher_t *);
-       sdb_object_ref(SDB_OBJ(OP_M(obj)->left));
-       OP_M(obj)->right = va_arg(ap, sdb_store_matcher_t *);
-       sdb_object_ref(SDB_OBJ(OP_M(obj)->right));
-
-       if ((! OP_M(obj)->left) || (! OP_M(obj)->right))
-               return -1;
-       return 0;
-} /* op_matcher_init */
-
-static void
-op_matcher_destroy(sdb_object_t *obj)
-{
-       if (OP_M(obj)->left)
-               sdb_object_deref(SDB_OBJ(OP_M(obj)->left));
-       if (OP_M(obj)->right)
-               sdb_object_deref(SDB_OBJ(OP_M(obj)->right));
-} /* op_matcher_destroy */
-
-static int
-iter_matcher_init(sdb_object_t *obj, va_list ap)
-{
-       M(obj)->type = va_arg(ap, int);
-       ITER_M(obj)->iter = va_arg(ap, sdb_store_expr_t *);
-       ITER_M(obj)->m = va_arg(ap, sdb_store_matcher_t *);
-
-       sdb_object_ref(SDB_OBJ(ITER_M(obj)->iter));
-       sdb_object_ref(SDB_OBJ(ITER_M(obj)->m));
-
-       if ((! ITER_M(obj)->iter) || (! ITER_M(obj)->m))
-               return -1;
-       return 0;
-} /* iter_matcher_init */
-
-static void
-iter_matcher_destroy(sdb_object_t *obj)
-{
-       sdb_object_deref(SDB_OBJ(ITER_M(obj)->iter));
-       sdb_object_deref(SDB_OBJ(ITER_M(obj)->m));
-} /* iter_matcher_destroy */
-
-static int
-cmp_matcher_init(sdb_object_t *obj, va_list ap)
-{
-       M(obj)->type = va_arg(ap, int);
-
-       CMP_M(obj)->left = va_arg(ap, sdb_store_expr_t *);
-       sdb_object_ref(SDB_OBJ(CMP_M(obj)->left));
-       CMP_M(obj)->right = va_arg(ap, sdb_store_expr_t *);
-       sdb_object_ref(SDB_OBJ(CMP_M(obj)->right));
-
-       if (! CMP_M(obj)->right)
-               return -1;
-       return 0;
-} /* cmp_matcher_init */
-
-static void
-cmp_matcher_destroy(sdb_object_t *obj)
-{
-       sdb_object_deref(SDB_OBJ(CMP_M(obj)->left));
-       sdb_object_deref(SDB_OBJ(CMP_M(obj)->right));
-} /* cmp_matcher_destroy */
-
-static int
-uop_matcher_init(sdb_object_t *obj, va_list ap)
-{
-       M(obj)->type = va_arg(ap, int);
-       if (M(obj)->type != MATCHER_NOT)
-               return -1;
-
-       UOP_M(obj)->op = va_arg(ap, sdb_store_matcher_t *);
-       sdb_object_ref(SDB_OBJ(UOP_M(obj)->op));
-
-       if (! UOP_M(obj)->op)
-               return -1;
-       return 0;
-} /* uop_matcher_init */
-
-static void
-uop_matcher_destroy(sdb_object_t *obj)
-{
-       if (UOP_M(obj)->op)
-               sdb_object_deref(SDB_OBJ(UOP_M(obj)->op));
-} /* uop_matcher_destroy */
-
-static int
-unary_matcher_init(sdb_object_t *obj, va_list ap)
-{
-       M(obj)->type = va_arg(ap, int);
-       if ((M(obj)->type != MATCHER_ISNULL)
-                       && (M(obj)->type != MATCHER_ISTRUE)
-                       && (M(obj)->type != MATCHER_ISFALSE))
-               return -1;
-
-       UNARY_M(obj)->expr = va_arg(ap, sdb_store_expr_t *);
-       sdb_object_ref(SDB_OBJ(UNARY_M(obj)->expr));
-       return 0;
-} /* unary_matcher_init */
-
-static void
-unary_matcher_destroy(sdb_object_t *obj)
-{
-       sdb_object_deref(SDB_OBJ(UNARY_M(obj)->expr));
-       UNARY_M(obj)->expr = NULL;
-} /* unary_matcher_destroy */
-
-static sdb_type_t op_type = {
-       /* size = */ sizeof(op_matcher_t),
-       /* init = */ op_matcher_init,
-       /* destroy = */ op_matcher_destroy,
-};
-
-static sdb_type_t uop_type = {
-       /* size = */ sizeof(uop_matcher_t),
-       /* init = */ uop_matcher_init,
-       /* destroy = */ uop_matcher_destroy,
-};
-
-static sdb_type_t iter_type = {
-       /* size = */ sizeof(iter_matcher_t),
-       /* init = */ iter_matcher_init,
-       /* destroy = */ iter_matcher_destroy,
-};
-
-static sdb_type_t cmp_type = {
-       /* size = */ sizeof(cmp_matcher_t),
-       /* init = */ cmp_matcher_init,
-       /* destroy = */ cmp_matcher_destroy,
-};
-
-static sdb_type_t unary_type = {
-       /* size = */ sizeof(unary_matcher_t),
-       /* init = */ unary_matcher_init,
-       /* destroy = */ unary_matcher_destroy,
-};
-
-/*
- * public API
- */
-
-sdb_store_matcher_t *
-sdb_store_any_matcher(sdb_store_expr_t *iter, sdb_store_matcher_t *m)
-{
-       if ((m->type < MATCHER_LT) || (MATCHER_NREGEX < m->type)) {
-               sdb_log(SDB_LOG_ERR, "store: Invalid ANY -> %s matcher "
-                               "(invalid operator)", MATCHER_SYM(m->type));
-               return NULL;
-       }
-       if (CMP_M(m)->left) {
-               sdb_log(SDB_LOG_ERR, "store: Invalid ANY %s %s %s matcher "
-                               "(invalid left operand)",
-                               SDB_TYPE_TO_STRING(CMP_M(m)->left->data_type),
-                               MATCHER_SYM(m->type),
-                               SDB_TYPE_TO_STRING(CMP_M(m)->right->data_type));
-               return NULL;
-       }
-       return M(sdb_object_create("any-matcher", iter_type,
-                               MATCHER_ANY, iter, m));
-} /* sdb_store_any_matcher */
-
-sdb_store_matcher_t *
-sdb_store_all_matcher(sdb_store_expr_t *iter, sdb_store_matcher_t *m)
-{
-       if ((m->type < MATCHER_LT) || (MATCHER_NREGEX < m->type)) {
-               sdb_log(SDB_LOG_ERR, "store: Invalid ALL -> %s matcher "
-                               "(invalid operator)", MATCHER_SYM(m->type));
-               return NULL;
-       }
-       if (CMP_M(m)->left) {
-               sdb_log(SDB_LOG_ERR, "store: Invalid ALL %s %s %s matcher "
-                               "(invalid left operand)",
-                               SDB_TYPE_TO_STRING(CMP_M(m)->left->data_type),
-                               MATCHER_SYM(m->type),
-                               SDB_TYPE_TO_STRING(CMP_M(m)->right->data_type));
-               return NULL;
-       }
-       return M(sdb_object_create("all-matcher", iter_type,
-                               MATCHER_ALL, iter, m));
-} /* sdb_store_all_matcher */
-
-sdb_store_matcher_t *
-sdb_store_lt_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
-{
-       return M(sdb_object_create("lt-matcher", cmp_type,
-                               MATCHER_LT, left, right));
-} /* sdb_store_lt_matcher */
-
-sdb_store_matcher_t *
-sdb_store_le_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
-{
-       return M(sdb_object_create("le-matcher", cmp_type,
-                               MATCHER_LE, left, right));
-} /* sdb_store_le_matcher */
-
-sdb_store_matcher_t *
-sdb_store_eq_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
-{
-       return M(sdb_object_create("eq-matcher", cmp_type,
-                               MATCHER_EQ, left, right));
-} /* sdb_store_eq_matcher */
-
-sdb_store_matcher_t *
-sdb_store_ne_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
-{
-       return M(sdb_object_create("ne-matcher", cmp_type,
-                               MATCHER_NE, left, right));
-} /* sdb_store_ne_matcher */
-
-sdb_store_matcher_t *
-sdb_store_ge_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
-{
-       return M(sdb_object_create("ge-matcher", cmp_type,
-                               MATCHER_GE, left, right));
-} /* sdb_store_ge_matcher */
-
-sdb_store_matcher_t *
-sdb_store_gt_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
-{
-       return M(sdb_object_create("gt-matcher", cmp_type,
-                               MATCHER_GT, left, right));
-} /* sdb_store_gt_matcher */
-
-sdb_store_matcher_t *
-sdb_store_in_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
-{
-       return M(sdb_object_create("in-matcher", cmp_type,
-                               MATCHER_IN, left, right));
-} /* sdb_store_in_matcher */
-
-sdb_store_matcher_t *
-sdb_store_regex_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
-{
-       if (! right->type) {
-               if ((right->data.type != SDB_TYPE_STRING)
-                               && (right->data.type != SDB_TYPE_REGEX))
-                       return NULL;
-
-               if (right->data.type == SDB_TYPE_STRING) {
-                       char *raw = right->data.data.string;
-                       if (sdb_data_parse(raw, SDB_TYPE_REGEX, &right->data))
-                               return NULL;
-                       free(raw);
-               }
-       }
-       return M(sdb_object_create("regex-matcher", cmp_type,
-                               MATCHER_REGEX, left, right));
-} /* sdb_store_regex_matcher */
-
-sdb_store_matcher_t *
-sdb_store_nregex_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
-{
-       sdb_store_matcher_t *m = sdb_store_regex_matcher(left, right);
-       if (! m)
-               return NULL;
-       m->type = MATCHER_NREGEX;
-       return m;
-} /* sdb_store_nregex_matcher */
-
-sdb_store_matcher_t *
-sdb_store_isnull_matcher(sdb_store_expr_t *expr)
-{
-       return M(sdb_object_create("isnull-matcher", unary_type,
-                               MATCHER_ISNULL, expr));
-} /* sdb_store_isnull_matcher */
-
-sdb_store_matcher_t *
-sdb_store_istrue_matcher(sdb_store_expr_t *expr)
-{
-       return M(sdb_object_create("istrue-matcher", unary_type,
-                               MATCHER_ISTRUE, expr));
-} /* sdb_store_istrue_matcher */
-
-sdb_store_matcher_t *
-sdb_store_isfalse_matcher(sdb_store_expr_t *expr)
-{
-       return M(sdb_object_create("isfalse-matcher", unary_type,
-                               MATCHER_ISFALSE, expr));
-} /* sdb_store_isfalse_matcher */
-
-sdb_store_matcher_t *
-sdb_store_dis_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
-{
-       return M(sdb_object_create("dis-matcher", op_type, MATCHER_OR,
-                               left, right));
-} /* sdb_store_dis_matcher */
-
-sdb_store_matcher_t *
-sdb_store_con_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
-{
-       return M(sdb_object_create("con-matcher", op_type, MATCHER_AND,
-                               left, right));
-} /* sdb_store_con_matcher */
-
-sdb_store_matcher_t *
-sdb_store_inv_matcher(sdb_store_matcher_t *m)
-{
-       return M(sdb_object_create("inv-matcher", uop_type, MATCHER_NOT, m));
-} /* sdb_store_inv_matcher */
-
-int
-sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
-               sdb_store_matcher_t *filter)
-{
-       if (filter && (! sdb_store_matcher_matches(filter, obj, NULL)))
-               return 0;
-
-       /* "NULL" always matches */
-       if ((! m) || (! obj))
-               return 1;
-
-       if ((m->type < 0) || ((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers)))
-               return 0;
-
-       if (! matchers[m->type])
-               return 0;
-       return matchers[m->type](m, obj, filter);
-} /* sdb_store_matcher_matches */
-
-/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
-
diff --git a/src/core/store_query.c b/src/core/store_query.c
deleted file mode 100644 (file)
index ff7089c..0000000
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * SysDB - src/core/store_query.c
- * Copyright (C) 2014-2015 Sebastian 'tokkee' Harl <sh@tokkee.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "core/object.h"
-#include "core/store-private.h"
-#include "parser/ast.h"
-#include "utils/error.h"
-
-#include <assert.h>
-
-static sdb_store_matcher_t *
-node_to_matcher(sdb_ast_node_t *n);
-
-static sdb_store_expr_t *
-node_to_expr(sdb_ast_node_t *n)
-{
-       sdb_store_expr_t *left = NULL, *right = NULL;
-       sdb_store_expr_t *e;
-       int op;
-
-       if (! n) {
-               sdb_log(SDB_LOG_ERR, "store: Encountered empty AST expression node");
-               return NULL;
-       }
-
-       switch (n->type) {
-       case SDB_AST_TYPE_OPERATOR:
-               if (! SDB_AST_IS_ARITHMETIC(n)) {
-                       sdb_log(SDB_LOG_ERR, "store: Invalid arithmetic operator of "
-                                       "type %s (%#x)", SDB_AST_TYPE_TO_STRING(n), n->type);
-                       return NULL;
-               }
-
-               left = node_to_expr(SDB_AST_OP(n)->left);
-               if (! left)
-                       return NULL;
-               right = node_to_expr(SDB_AST_OP(n)->right);
-               if (! right) {
-                       sdb_object_deref(SDB_OBJ(left));
-                       return NULL;
-               }
-               op = SDB_AST_OP_TO_DATA_OP(SDB_AST_OP(n)->kind);
-               e = sdb_store_expr_create(op, left, right);
-               break;
-
-       case SDB_AST_TYPE_CONST:
-               return sdb_store_expr_constvalue(&SDB_AST_CONST(n)->value);
-
-       case SDB_AST_TYPE_VALUE:
-               if (SDB_AST_VALUE(n)->type == SDB_ATTRIBUTE)
-                       return sdb_store_expr_attrvalue(SDB_AST_VALUE(n)->name);
-               return sdb_store_expr_fieldvalue(SDB_AST_VALUE(n)->type);
-
-       case SDB_AST_TYPE_TYPED:
-               right = node_to_expr(SDB_AST_TYPED(n)->expr);
-               if (! right)
-                       return NULL;
-               e = sdb_store_expr_typed(SDB_AST_TYPED(n)->type, right);
-               break;
-
-       default:
-               sdb_log(SDB_LOG_ERR, "store: Invalid matcher node of type %s (%#x)",
-                               SDB_AST_TYPE_TO_STRING(n), n->type);
-               e = NULL;
-       }
-
-       /* expressions take a reference */
-       sdb_object_deref(SDB_OBJ(left));
-       sdb_object_deref(SDB_OBJ(right));
-       return e;
-} /* node_to_expr */
-
-static sdb_store_matcher_t *
-logical_to_matcher(sdb_ast_node_t *n)
-{
-       sdb_store_matcher_t *left = NULL, *right;
-       sdb_store_matcher_t *m;
-
-       if (SDB_AST_OP(n)->left) {
-               left = node_to_matcher(SDB_AST_OP(n)->left);
-               if (! left)
-                       return NULL;
-       }
-       right = node_to_matcher(SDB_AST_OP(n)->right);
-       if (! right) {
-               sdb_object_deref(SDB_OBJ(left));
-               return NULL;
-       }
-
-       switch (SDB_AST_OP(n)->kind) {
-       case SDB_AST_AND:
-               m = sdb_store_con_matcher(left, right);
-               break;
-       case SDB_AST_OR:
-               m = sdb_store_dis_matcher(left, right);
-               break;
-       case SDB_AST_NOT:
-               m = sdb_store_inv_matcher(right);
-               break;
-
-       default:
-               m = NULL;
-       }
-
-       /* matchers take a reference */
-       sdb_object_deref(SDB_OBJ(left));
-       sdb_object_deref(SDB_OBJ(right));
-       return m;
-} /* logical_to_matcher */
-
-static sdb_store_matcher_t *
-cmp_to_matcher(sdb_ast_node_t *n)
-{
-       sdb_store_expr_t *left = NULL, *right;
-       sdb_store_matcher_t *m;
-
-       if (SDB_AST_OP(n)->left) {
-               left = node_to_expr(SDB_AST_OP(n)->left);
-               if (! left)
-                       return NULL;
-       }
-       right = node_to_expr(SDB_AST_OP(n)->right);
-       if (! right) {
-               sdb_object_deref(SDB_OBJ(left));
-               return NULL;
-       }
-
-       switch (SDB_AST_OP(n)->kind) {
-       case SDB_AST_LT:
-               m = sdb_store_lt_matcher(left, right);
-               break;
-       case SDB_AST_LE:
-               m = sdb_store_le_matcher(left, right);
-               break;
-       case SDB_AST_EQ:
-               m = sdb_store_eq_matcher(left, right);
-               break;
-       case SDB_AST_NE:
-               m = sdb_store_ne_matcher(left, right);
-               break;
-       case SDB_AST_GE:
-               m = sdb_store_ge_matcher(left, right);
-               break;
-       case SDB_AST_GT:
-               m = sdb_store_gt_matcher(left, right);
-               break;
-       case SDB_AST_REGEX:
-               m = sdb_store_regex_matcher(left, right);
-               break;
-       case SDB_AST_NREGEX:
-               m = sdb_store_nregex_matcher(left, right);
-               break;
-       case SDB_AST_ISNULL:
-               m = sdb_store_isnull_matcher(right);
-               break;
-       case SDB_AST_ISTRUE:
-               m = sdb_store_istrue_matcher(right);
-               break;
-       case SDB_AST_ISFALSE:
-               m = sdb_store_isfalse_matcher(right);
-               break;
-       case SDB_AST_IN:
-               m = sdb_store_in_matcher(left, right);
-               break;
-
-       default:
-               sdb_log(SDB_LOG_ERR, "store: Invalid matcher node of type %s (%#x)",
-                               SDB_AST_TYPE_TO_STRING(n), n->type);
-               m = NULL;
-       }
-
-       /* matchers take a reference */
-       sdb_object_deref(SDB_OBJ(left));
-       sdb_object_deref(SDB_OBJ(right));
-       return m;
-} /* cmp_to_matcher */
-
-static sdb_store_matcher_t *
-iter_to_matcher(sdb_ast_node_t *n)
-{
-       sdb_store_expr_t *iter;
-       sdb_store_matcher_t *expr, *m;
-
-       assert((SDB_AST_ITER(n)->expr->type == SDB_AST_TYPE_OPERATOR)
-                       && (! SDB_AST_OP(SDB_AST_ITER(n)->expr)->left));
-
-       iter = node_to_expr(SDB_AST_ITER(n)->iter);
-       if (! iter)
-               return NULL;
-       expr = cmp_to_matcher(SDB_AST_ITER(n)->expr);
-       if (! expr) {
-               sdb_object_deref(SDB_OBJ(iter));
-               return NULL;
-       }
-
-       switch (SDB_AST_ITER(n)->kind) {
-       case SDB_AST_ALL:
-               m = sdb_store_all_matcher(iter, expr);
-               break;
-       case SDB_AST_ANY:
-               m = sdb_store_any_matcher(iter, expr);
-               break;
-
-       default:
-               sdb_log(SDB_LOG_ERR, "store: Invalid iterator node of type %s (%#x)",
-                               SDB_AST_OP_TO_STRING(SDB_AST_ITER(n)->kind), SDB_AST_ITER(n)->kind);
-               m = NULL;
-       }
-
-       /* matchers take a reference */
-       sdb_object_deref(SDB_OBJ(iter));
-       sdb_object_deref(SDB_OBJ(expr));
-       return m;
-} /* iter_to_matcher */
-
-static sdb_store_matcher_t *
-node_to_matcher(sdb_ast_node_t *n)
-{
-       int kind;
-
-       if (! n) {
-               sdb_log(SDB_LOG_ERR, "store: Encountered empty AST matcher node");
-               return NULL;
-       }
-
-       switch (n->type) {
-       case SDB_AST_TYPE_OPERATOR:
-               if (! SDB_AST_IS_LOGICAL(n)) {
-                       sdb_log(SDB_LOG_ERR, "store: Invalid logical operator of "
-                                       "type %s (%#x)", SDB_AST_TYPE_TO_STRING(n), n->type);
-                       return NULL;
-               }
-
-               kind = SDB_AST_OP(n)->kind;
-               if ((kind == SDB_AST_AND) || (kind == SDB_AST_OR) || (kind == SDB_AST_NOT))
-                       return logical_to_matcher(n);
-               else
-                       return cmp_to_matcher(n);
-
-       case SDB_AST_TYPE_ITERATOR:
-               return iter_to_matcher(n);
-       }
-
-       sdb_log(SDB_LOG_ERR, "store: Invalid matcher node of type %s (%#x)",
-                       SDB_AST_TYPE_TO_STRING(n), n->type);
-       return NULL;
-} /* node_to_matcher */
-
-/*
- * query type
- */
-
-static int
-query_init(sdb_object_t *obj, va_list ap)
-{
-       sdb_ast_node_t *ast = va_arg(ap, sdb_ast_node_t *);
-       sdb_ast_node_t *matcher = NULL, *filter = NULL;
-
-       QUERY(obj)->ast = ast;
-       sdb_object_ref(SDB_OBJ(ast));
-
-       switch (ast->type) {
-       case SDB_AST_TYPE_FETCH:
-               filter = SDB_AST_FETCH(ast)->filter;
-               break;
-       case SDB_AST_TYPE_LIST:
-               filter = SDB_AST_LIST(ast)->filter;
-               break;
-       case SDB_AST_TYPE_LOOKUP:
-               matcher = SDB_AST_LOOKUP(ast)->matcher;
-               filter = SDB_AST_LOOKUP(ast)->filter;
-               break;
-       case SDB_AST_TYPE_STORE:
-       case SDB_AST_TYPE_TIMESERIES:
-               /* nothing to do */
-               break;
-
-       default:
-               sdb_log(SDB_LOG_ERR, "store: Invalid top-level AST node "
-                               "of type %#x", ast->type);
-               return -1;
-       }
-
-       if (matcher) {
-               QUERY(obj)->matcher = node_to_matcher(matcher);
-               if (! QUERY(obj)->matcher)
-                       return -1;
-       }
-       if (filter) {
-               QUERY(obj)->filter = node_to_matcher(filter);
-               if (! QUERY(obj)->filter)
-                       return -1;
-       }
-
-       return 0;
-} /* query_init */
-
-static void
-query_destroy(sdb_object_t *obj)
-{
-       sdb_object_deref(SDB_OBJ(QUERY(obj)->ast));
-       sdb_object_deref(SDB_OBJ(QUERY(obj)->matcher));
-       sdb_object_deref(SDB_OBJ(QUERY(obj)->filter));
-} /* query_destroy */
-
-static sdb_type_t query_type = {
-       /* size = */ sizeof(sdb_store_query_t),
-       /* init = */ query_init,
-       /* destroy = */ query_destroy,
-};
-
-/*
- * public API
- */
-
-sdb_store_query_t *
-sdb_store_query_prepare(sdb_ast_node_t *ast)
-{
-       if (! ast)
-               return NULL;
-       return QUERY(sdb_object_create(SDB_AST_TYPE_TO_STRING(ast), query_type, ast));
-} /* sdb_store_query_prepare */
-
-sdb_store_matcher_t *
-sdb_store_query_prepare_matcher(sdb_ast_node_t *ast)
-{
-       return node_to_matcher(ast);
-} /* sdb_store_query_prepare_matcher */
-
-/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
index acdc699c107f11294905fc58fc8ed655551ba49e..03e58e5e51e25fa4bf9ea747d2f2607f259c9b86 100644 (file)
@@ -83,193 +83,6 @@ struct sdb_conn {
 };
 #define CONN(obj) ((sdb_conn_t *)(obj))
 
-/*
- * node types
- */
-
-typedef struct {
-       sdb_conn_node_t super;
-       sdb_store_expr_t *expr;
-} conn_expr_t;
-#define CONN_EXPR(obj) ((conn_expr_t *)(obj))
-
-typedef struct {
-       sdb_conn_node_t super;
-       sdb_store_matcher_t *matcher;
-} conn_matcher_t;
-#define CONN_MATCHER(obj) ((conn_matcher_t *)(obj))
-
-typedef struct {
-       sdb_conn_node_t super;
-       int type;
-       conn_matcher_t *filter;
-} conn_list_t;
-#define CONN_LIST(obj) ((conn_list_t *)(obj))
-
-typedef struct {
-       sdb_conn_node_t super;
-       int type;
-       char *host;
-       char *name; /* NULL for type == SDB_HOST */
-       conn_matcher_t *filter;
-} conn_fetch_t;
-#define CONN_FETCH(obj) ((conn_fetch_t *)(obj))
-
-typedef struct {
-       sdb_conn_node_t super;
-       int type;
-       conn_matcher_t *matcher;
-       conn_matcher_t *filter;
-} conn_lookup_t;
-#define CONN_LOOKUP(obj) ((conn_lookup_t *)(obj))
-
-typedef struct {
-       sdb_conn_node_t super;
-       char *name;
-       sdb_time_t last_update;
-} conn_store_host_t;
-#define CONN_STORE_HOST(obj) ((conn_store_host_t *)(obj))
-
-typedef struct {
-       sdb_conn_node_t super;
-       char *hostname;
-       char *name;
-       sdb_time_t last_update;
-} conn_store_svc_t;
-#define CONN_STORE_SVC(obj) ((conn_store_svc_t *)(obj))
-
-typedef struct {
-       sdb_conn_node_t super;
-       char *hostname;
-       char *name;
-       char *store_type; /* optional */
-       char *store_id;   /* optional */
-       sdb_time_t last_update;
-} conn_store_metric_t;
-#define CONN_STORE_METRIC(obj) ((conn_store_metric_t *)(obj))
-
-typedef struct {
-       sdb_conn_node_t super;
-       int parent_type;
-       char *hostname; /* optional */
-       char *parent;
-       char *key;
-       sdb_data_t value;
-       sdb_time_t last_update;
-} conn_store_attr_t;
-#define CONN_STORE_ATTR(obj) ((conn_store_attr_t *)(obj))
-
-typedef struct {
-       sdb_conn_node_t super;
-       char *hostname;
-       char *metric;
-       sdb_timeseries_opts_t opts;
-} conn_ts_t;
-#define CONN_TS(obj) ((conn_ts_t *)(obj))
-
-/*
- * type helper functions
- */
-
-static void __attribute__((unused))
-conn_expr_destroy(sdb_object_t *obj)
-{
-       sdb_object_deref(SDB_OBJ(CONN_EXPR(obj)->expr));
-} /* conn_expr_destroy */
-
-static void __attribute__((unused))
-conn_matcher_destroy(sdb_object_t *obj)
-{
-       sdb_object_deref(SDB_OBJ(CONN_MATCHER(obj)->matcher));
-} /* conn_matcher_destroy */
-
-static void __attribute__((unused))
-conn_list_destroy(sdb_object_t *obj)
-{
-       sdb_object_deref(SDB_OBJ(CONN_LIST(obj)->filter));
-} /* conn_list_destroy */
-
-static void __attribute__((unused))
-conn_fetch_destroy(sdb_object_t *obj)
-{
-       if (CONN_FETCH(obj)->host)
-               free(CONN_FETCH(obj)->host);
-       if (CONN_FETCH(obj)->name)
-               free(CONN_FETCH(obj)->name);
-       sdb_object_deref(SDB_OBJ(CONN_FETCH(obj)->filter));
-} /* conn_fetch_destroy */
-
-static void __attribute__((unused))
-conn_lookup_destroy(sdb_object_t *obj)
-{
-       sdb_object_deref(SDB_OBJ(CONN_LOOKUP(obj)->matcher));
-       sdb_object_deref(SDB_OBJ(CONN_LOOKUP(obj)->filter));
-} /* conn_lookup_destroy */
-
-static void __attribute__((unused))
-conn_store_host_destroy(sdb_object_t *obj)
-{
-       conn_store_host_t *host = CONN_STORE_HOST(obj);
-       if (host->name)
-               free((void *)host->name);
-       host->name = NULL;
-} /* conn_store_host_destroy */
-
-static void __attribute__((unused))
-conn_store_svc_destroy(sdb_object_t *obj)
-{
-       conn_store_svc_t *svc = CONN_STORE_SVC(obj);
-       if (svc->hostname)
-               free((void *)svc->hostname);
-       svc->hostname = NULL;
-       if (svc->name)
-               free((void *)svc->name);
-       svc->name = NULL;
-} /* conn_store_svc_destroy */
-
-static void __attribute__((unused))
-conn_store_metric_destroy(sdb_object_t *obj)
-{
-       conn_store_metric_t *metric = CONN_STORE_METRIC(obj);
-       if (metric->hostname)
-               free((void *)metric->hostname);
-       metric->hostname = NULL;
-       if (metric->name)
-               free((void *)metric->name);
-       metric->name = NULL;
-       if (metric->store_type)
-               free((void *)metric->store_type);
-       metric->store_type = NULL;
-       if (metric->store_id)
-               free((void *)metric->store_id);
-       metric->store_id = NULL;
-} /* conn_store_metric_destroy */
-
-static void __attribute__((unused))
-conn_store_attr_destroy(sdb_object_t *obj)
-{
-       conn_store_attr_t *attr = CONN_STORE_ATTR(obj);
-       if (attr->hostname)
-               free((void *)attr->hostname);
-       attr->hostname = NULL;
-       if (attr->parent)
-               free((void *)attr->parent);
-       attr->parent = NULL;
-       if (attr->key)
-               free((void *)attr->key);
-       attr->key = NULL;
-       sdb_data_free_datum(&attr->value);
-} /* conn_store_attr_destroy */
-
-static void __attribute__((unused))
-conn_ts_destroy(sdb_object_t *obj)
-{
-       if (CONN_TS(obj)->hostname)
-               free(CONN_TS(obj)->hostname);
-       if (CONN_TS(obj)->metric)
-               free(CONN_TS(obj)->metric);
-} /* conn_ts_destroy */
-
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
index 9a157fb892d10888e35a74c84d77d5a18e635599..4ae4f64a5e0a1373f5ff6ddfb416c277aa546f36 100644 (file)
@@ -46,8 +46,6 @@
 /*
  * metric fetcher:
  * Implements the callbacks necessary to read a metric object.
- * TODO: FETCH should allow to ignore child elements (attributes); then, we'd
- * only need store_host/store_metric.
  */
 
 typedef struct {
@@ -77,15 +75,8 @@ metric_fetcher_metric(sdb_store_metric_t *metric, sdb_object_t *user_data)
        return 0;
 } /* metric_fetcher_metric */
 
-static int
-metric_fetcher_attr(sdb_store_attribute_t __attribute__((unused)) *attr,
-               sdb_object_t __attribute__((unused)) *user_data)
-{
-       return 0;
-} /* metric_fetcher_attr */
-
 static sdb_store_writer_t metric_fetcher = {
-       metric_fetcher_host, NULL, metric_fetcher_metric, metric_fetcher_attr,
+       metric_fetcher_host, NULL, metric_fetcher_metric, NULL,
 };
 
 /*
@@ -403,8 +394,9 @@ sdb_conn_fetch(sdb_conn_t *conn)
 
        ast = sdb_ast_fetch_create((int)type,
                        hostname[0] ? strdup(hostname) : NULL,
+                       -1, NULL,
                        name[0] ? strdup(name) : NULL,
-                       /* filter = */ NULL);
+                       /* full */ 1, /* filter = */ NULL);
        status = exec_cmd(conn, ast);
        sdb_object_deref(SDB_OBJ(ast));
        return status;
diff --git a/src/include/core/memstore.h b/src/include/core/memstore.h
new file mode 100644 (file)
index 0000000..8c1739e
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ * SysDB - src/include/core/memstore.h
+ * Copyright (C) 2012-2015 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SDB_CORE_MEMSTORE_H
+#define SDB_CORE_MEMSTORE_H 1
+
+#include "sysdb.h"
+#include "core/object.h"
+#include "core/data.h"
+#include "core/store.h"
+#include "core/time.h"
+#include "parser/ast.h"
+#include "utils/strbuf.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * sdb_memstore_t represents an in-memory store. It inherits from sdb_object_t
+ * and may safely be case to a generic object.
+ */
+struct sdb_memstore;
+typedef struct sdb_memstore sdb_memstore_t;
+#define SDB_MEMSTORE(obj) ((sdb_memstore_t *)(obj))
+
+/*
+ * sdb_memstore_obj_t represents the super-class of any stored object. It
+ * inherits from sdb_object_t and may safely be cast to a generic object to
+ * access its name.
+ */
+struct sdb_memstore_obj;
+typedef struct sdb_memstore_obj sdb_memstore_obj_t;
+
+/*
+ * Expressions represent arithmetic expressions based on stored objects and
+ * their various attributes.
+ *
+ * An expression object inherits from sdb_object_t and, thus, may safely be
+ * cast to a generic object.
+ */
+struct sdb_memstore_expr;
+typedef struct sdb_memstore_expr sdb_memstore_expr_t;
+#define SDB_MEMSTORE_EXPR(obj) ((sdb_memstore_expr_t *)(obj))
+
+/*
+ * An expression iterator iterates over the values of an iterable expression.
+ */
+struct sdb_memstore_expr_iter;
+typedef struct sdb_memstore_expr_iter sdb_memstore_expr_iter_t;
+
+/*
+ * Store matchers may be used to lookup hosts from the store based on their
+ * various attributes. Service and attribute matchers are applied to a host's
+ * services and attributes and evaluate to true if *any* service or attribute
+ * matches.
+ *
+ * A store matcher object inherits from sdb_object_t and, thus, may safely be
+ * cast to a generic object.
+ */
+struct sdb_memstore_matcher;
+typedef struct sdb_memstore_matcher sdb_memstore_matcher_t;
+#define SDB_MEMSTORE_MATCHER(obj) ((sdb_memstore_matcher_t *)(obj))
+
+/*
+ * sdb_memstore_writer:
+ * A store writer implementation that provides an in-memory object store. It
+ * expects a store object as its user-data argument.
+ */
+extern sdb_store_writer_t sdb_memstore_writer;
+
+/*
+ * sdb_memstore_reader:
+ * A store reader implementation that uses an in-memory object store. It
+ * expects a store object as its user-data argument.
+ */
+extern sdb_store_reader_t sdb_memstore_reader;
+
+/*
+ * sdb_memstore_create:
+ * Allocate a new in-memory store.
+ */
+sdb_memstore_t *
+sdb_memstore_create(void);
+
+/*
+ * sdb_memstore_host, sdb_memstore_service, sdb_memstore_metric,
+ * sdb_memstore_attribute, sdb_memstore_metric_attr:
+ * Store an object in the specified store. The hostname is expected to be
+ * canonical.
+ */
+int
+sdb_memstore_host(sdb_memstore_t *store, const char *name,
+               sdb_time_t last_update, sdb_time_t interval);
+int
+sdb_memstore_service(sdb_memstore_t *store, const char *hostname, const char *name,
+               sdb_time_t last_update, sdb_time_t interval);
+int
+sdb_memstore_metric(sdb_memstore_t *store, const char *hostname, const char *name,
+               sdb_metric_store_t *metric_store,
+               sdb_time_t last_update, sdb_time_t interval);
+int
+sdb_memstore_attribute(sdb_memstore_t *store, const char *hostname,
+               const char *key, const sdb_data_t *value,
+               sdb_time_t last_update, sdb_time_t interval);
+int
+sdb_memstore_service_attr(sdb_memstore_t *store, const char *hostname,
+               const char *service, const char *key, const sdb_data_t *value,
+               sdb_time_t last_update, sdb_time_t interval);
+int
+sdb_memstore_metric_attr(sdb_memstore_t *store, const char *hostname,
+               const char *metric, const char *key, const sdb_data_t *value,
+               sdb_time_t last_update, sdb_time_t interval);
+
+/*
+ * sdb_memstore_get_host:
+ * Query the specified store for a host by its (canonicalized) name.
+ *
+ * The function increments the ref count of the host object. The caller needs
+ * to deref it when no longer using it.
+ */
+sdb_memstore_obj_t *
+sdb_memstore_get_host(sdb_memstore_t *store, const char *name);
+
+/*
+ * sdb_memstore_get_child:
+ * Retrieve an object's child object of the specified type and name. The
+ * reference count of the child object will be incremented before returning
+ * it. The caller is responsible for releasing the object once it's no longer
+ * used.
+ *
+ * Returns:
+ *  - the child object on success
+ *  - NULL else
+ */
+sdb_memstore_obj_t *
+sdb_memstore_get_child(sdb_memstore_obj_t *obj, int type, const char *name);
+
+/*
+ * sdb_memstore_get_field:
+ * Get the value of a stored object's queryable field. The caller is
+ * responsible for freeing any dynamically allocated memory possibly stored in
+ * the returned value. If 'res' is NULL, the function will return whether the
+ * field exists.
+ *
+ * Returns:
+ *  - 0 on success
+ *  - a negative value else
+ */
+int
+sdb_memstore_get_field(sdb_memstore_obj_t *obj, int field, sdb_data_t *res);
+
+/*
+ * sdb_memstore_get_attr:
+ * Get the value of a stored object's attribute. The caller is responsible for
+ * freeing any dynamically allocated memory possibly stored in the returned
+ * value. If 'res' is NULL, the function will return whether the attribute
+ * exists. If specified, only attributes matching the filter will be
+ * considered.
+ *
+ * Returns:
+ *  - 0 if the attribute exists
+ *  - a negative value else
+ */
+int
+sdb_memstore_get_attr(sdb_memstore_obj_t *obj, const char *name, sdb_data_t *res,
+               sdb_memstore_matcher_t *filter);
+
+/*
+ * Querying a store:
+ *
+ *  - Query interface: A query is a formal description of an interaction with
+ *    the store. It can be used, both, for read and write access. The query is
+ *    described by its abstract syntax tree (AST). The parser package provides
+ *    means to parse a string (SysQL) representation of the query into an AST.
+ *
+ *  - Matcher / expression interface: This low-level interface provides direct
+ *    control over how to access the store. It is used by the query
+ *    implementation internally and can only be used for read access.
+ */
+
+/*
+ * sdb_memstore_query_t:
+ * A parsed query readily prepared for execution.
+ */
+struct sdb_memstore_query;
+typedef struct sdb_memstore_query sdb_memstore_query_t;
+
+/*
+ * sdb_memstore_query_prepare:
+ * Prepare the query described by 'ast' for execution in a store.
+ *
+ * Returns:
+ *  - a store query on success
+ *  - NULL else
+ */
+sdb_memstore_query_t *
+sdb_memstore_query_prepare(sdb_ast_node_t *ast);
+
+/*
+ * sdb_memstore_query_prepare_matcher:
+ * Prepare the logical expression described by 'ast' for execution as a store
+ * matcher.
+ *
+ * Returns:
+ *  - a matcher on success
+ *  - NULL else
+ */
+sdb_memstore_matcher_t *
+sdb_memstore_query_prepare_matcher(sdb_ast_node_t *ast);
+
+/*
+ * sdb_memstore_query_execute:
+ * Execute a previously prepared query in the specified store. The query
+ * result will be written to 'buf' and any errors to 'errbuf'.
+ *
+ * Returns:
+ *  - the result type (to be used by the server reply)
+ *  - a negative value on error
+ */
+int
+sdb_memstore_query_execute(sdb_memstore_t *store, sdb_memstore_query_t *m,
+               sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf);
+
+/*
+ * sdb_memstore_expr_create:
+ * Creates an arithmetic expression implementing the specified operator on the
+ * specified left and right operand.
+ *
+ * Returns:
+ *  - an expression object on success
+ *  - NULL else
+ */
+sdb_memstore_expr_t *
+sdb_memstore_expr_create(int op,
+               sdb_memstore_expr_t *left, sdb_memstore_expr_t *right);
+
+/*
+ * sdb_memstore_expr_typed:
+ * Creates an expression which evaluates in the context of an object's sibling
+ * as specified by the given type.
+ *
+ * Returns:
+ *  - an expression object on success
+ *  - NULL else
+ */
+sdb_memstore_expr_t *
+sdb_memstore_expr_typed(int typ, sdb_memstore_expr_t *expr);
+
+/*
+ * sdb_memstore_expr_fieldvalue:
+ * Creates an expression which evaluates to the value of the specified
+ * queryable field of a stored object.
+ *
+ * Returns:
+ *  - an expression object on success
+ *  - NULL else
+ */
+sdb_memstore_expr_t *
+sdb_memstore_expr_fieldvalue(int field);
+
+/*
+ * sdb_memstore_expr_attrvalue:
+ * Creates an expression which evaluates to the value of the specified
+ * attribute of a stored object. Evaluates to a NULL value if the attribute
+ * does not exist.
+ *
+ * Returns:
+ *  - an expression object on success
+ *  - NULL else
+ */
+sdb_memstore_expr_t *
+sdb_memstore_expr_attrvalue(const char *name);
+
+/*
+ * sdb_memstore_expr_constvalue:
+ * Creates an expression which evaluates to the specified constant value.
+ *
+ * Returns:
+ *  - an expression object on success
+ *  - NULL else
+ */
+sdb_memstore_expr_t *
+sdb_memstore_expr_constvalue(const sdb_data_t *value);
+
+/*
+ * sdb_memstore_expr_eval:
+ * Evaluate an expression for the specified stored object and stores the
+ * result in 'res'. The result's value will be allocated dynamically if
+ * necessary and, thus, should be free'd by the caller (e.g. using
+ * sdb_data_free_datum). The object may be NULL, in which case the expression
+ * needs to evaluate to a constant value. If specified, only objects matching
+ * the filter will be used during the evaluation.
+ *
+ * Returns:
+ *  - 0 on success
+ *  - a negative value else
+ */
+int
+sdb_memstore_expr_eval(sdb_memstore_expr_t *expr, sdb_memstore_obj_t *obj,
+               sdb_data_t *res, sdb_memstore_matcher_t *filter);
+
+/*
+ * sdb_memstore_expr_iter:
+ * Iterate over the elements of an iterable expression. sdb_memstore_expr_iter
+ * returns NULL if the expression is not iterable (for the specified object).
+ *
+ * sdb_memstore_expr_iter_get_next returns NULL if there is no next element.
+ */
+sdb_memstore_expr_iter_t *
+sdb_memstore_expr_iter(sdb_memstore_expr_t *expr, sdb_memstore_obj_t *obj,
+               sdb_memstore_matcher_t *filter);
+void
+sdb_memstore_expr_iter_destroy(sdb_memstore_expr_iter_t *iter);
+
+bool
+sdb_memstore_expr_iter_has_next(sdb_memstore_expr_iter_t *iter);
+sdb_data_t
+sdb_memstore_expr_iter_get_next(sdb_memstore_expr_iter_t *iter);
+
+/*
+ * sdb_memstore_dis_matcher:
+ * Creates a matcher matching the disjunction (logical OR) of two matchers.
+ */
+sdb_memstore_matcher_t *
+sdb_memstore_dis_matcher(sdb_memstore_matcher_t *left, sdb_memstore_matcher_t *right);
+
+/*
+ * sdb_memstore_con_matcher:
+ * Creates a matcher matching the conjunction (logical AND) of two matchers.
+ */
+sdb_memstore_matcher_t *
+sdb_memstore_con_matcher(sdb_memstore_matcher_t *left, sdb_memstore_matcher_t *right);
+
+/*
+ * sdb_memstore_inv_matcher:
+ * Creates a matcher matching the inverse (logical NOT) of a matcher.
+ */
+sdb_memstore_matcher_t *
+sdb_memstore_inv_matcher(sdb_memstore_matcher_t *m);
+
+/*
+ * sdb_memstore_any_matcher:
+ * Creates a matcher iterating over values of the first expression (which has
+ * to be iterable). It matches if *any* of those elements match 'm'. 'm' has
+ * to be an ary operation with the left operand unset.
+ */
+sdb_memstore_matcher_t *
+sdb_memstore_any_matcher(sdb_memstore_expr_t *iter, sdb_memstore_matcher_t *m);
+
+/*
+ * sdb_memstore_all_matcher:
+ * Creates a matcher iterating over values of the first expression (which has
+ * to be iterable). It matches if *all* of those elements match 'm'. 'm' has
+ * to be an ary operation with the left operand unset.
+ */
+sdb_memstore_matcher_t *
+sdb_memstore_all_matcher(sdb_memstore_expr_t *iter, sdb_memstore_matcher_t *m);
+
+/*
+ * sdb_memstore_in_matcher:
+ * Creates a matcher which matches if the right value evaluates to an array
+ * value and the left value is included in that array. See sdb_data_inarray
+ * for more details.
+ */
+sdb_memstore_matcher_t *
+sdb_memstore_in_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right);
+
+/*
+ * sdb_memstore_lt_matcher, sdb_memstore_le_matcher, sdb_memstore_eq_matcher,
+ * sdb_memstore_ge_matcher, sdb_memstore_gt_matcher:
+ * Create conditional matchers comparing the values of two expressions. The
+ * matcher matches if the left expression compres less than, less or equal
+ * than, equal to, not equal to, greater or equal than, or greater than the
+ * right expression.
+ */
+sdb_memstore_matcher_t *
+sdb_memstore_lt_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right);
+sdb_memstore_matcher_t *
+sdb_memstore_le_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right);
+sdb_memstore_matcher_t *
+sdb_memstore_eq_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right);
+sdb_memstore_matcher_t *
+sdb_memstore_ne_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right);
+sdb_memstore_matcher_t *
+sdb_memstore_ge_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right);
+sdb_memstore_matcher_t *
+sdb_memstore_gt_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right);
+
+/*
+ * sdb_memstore_regex_matcher:
+ * Creates a matcher which matches the string value the left expression
+ * evaluates to against the regular expression the right expression evaluates
+ * to. The right expression may either be a constant value regular expression
+ * or string or a dynamic value evaluating to a string. In the latter case,
+ * the string is compiled to a regex every time the matcher is executed.
+ */
+sdb_memstore_matcher_t *
+sdb_memstore_regex_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right);
+
+/*
+ * sdb_memstore_nregex_matcher:
+ * Creates a regex matcher just like sdb_memstore_regex_matcher except that it
+ * matches in case the regular expression does not match.
+ */
+sdb_memstore_matcher_t *
+sdb_memstore_nregex_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right);
+
+/*
+ * sdb_memstore_isnull_matcher:
+ * Creates a matcher matching NULL values.
+ */
+sdb_memstore_matcher_t *
+sdb_memstore_isnull_matcher(sdb_memstore_expr_t *expr);
+
+/*
+ * sdb_memstore_istrue_matcher, sdb_memstore_isfalse_matcher:
+ * Creates a matcher matching boolean values.
+ */
+sdb_memstore_matcher_t *
+sdb_memstore_istrue_matcher(sdb_memstore_expr_t *expr);
+sdb_memstore_matcher_t *
+sdb_memstore_isfalse_matcher(sdb_memstore_expr_t *expr);
+
+/*
+ * sdb_memstore_matcher_matches:
+ * Check whether the specified matcher matches the specified store object. If
+ * specified, the filter will be used to preselect objects for further
+ * evaluation. It is applied to any object that's used during the evaluation
+ * of the matcher. Only those objects matching the filter will be considered.
+ *
+ * Note that the filter is applied to all object types (hosts, service,
+ * metric, attribute). Thus, any object-specific matchers are mostly unsuited
+ * for this purpose and, if used, may result in unexpected behavior.
+ *
+ * Returns:
+ *  - 1 if the object matches
+ *  - 0 else
+ */
+int
+sdb_memstore_matcher_matches(sdb_memstore_matcher_t *m, sdb_memstore_obj_t *obj,
+               sdb_memstore_matcher_t *filter);
+
+/*
+ * sdb_memstore_matcher_op_cb:
+ * Callback constructing a matcher operator.
+ */
+typedef sdb_memstore_matcher_t *(*sdb_memstore_matcher_op_cb)
+       (sdb_memstore_expr_t *, sdb_memstore_expr_t *);
+
+/*
+ * sdb_memstore_lookup_cb:
+ * Lookup callback. It is called for each matching object when looking up data
+ * in the store passing on the lookup filter and the specified user-data. The
+ * lookup aborts early if the callback returns non-zero.
+ */
+typedef int (*sdb_memstore_lookup_cb)(sdb_memstore_obj_t *obj,
+               sdb_memstore_matcher_t *filter, void *user_data);
+
+/*
+ * sdb_memstore_scan:
+ * Look up objects of the specified type in the specified store. The specified
+ * callback function is called for each object in the store matching 'm'. The
+ * function performs a full scan of all stored objects. If specified, the
+ * filter will be used to preselect objects for further evaluation. See the
+ * description of 'sdb_memstore_matcher_matches' for details.
+ *
+ * Returns:
+ *  - 0 on success
+ *  - a negative value else
+ */
+int
+sdb_memstore_scan(sdb_memstore_t *store, int type,
+               sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter,
+               sdb_memstore_lookup_cb cb, void *user_data);
+
+/*
+ * sdb_memstore_emit:
+ * Send a single object to the specified store writer. Attributes or any child
+ * objects are not included. Use sdb_memstore_emit_full() to emit a full
+ * (filtered) object.
+ *
+ * Returns:
+ *  - 0 on success
+ *  - a negative value else
+ */
+int
+sdb_memstore_emit(sdb_memstore_obj_t *obj, sdb_store_writer_t *w, sdb_object_t *wd);
+
+/*
+ * sdb_memstore_emit_full:
+ * Send a single object and its attributes and all children to the specified
+ * store writer. The filter, if specified, is applied to each attribute and
+ * child object. Only matching objects will be emitted.
+ *
+ * Returns:
+ *  - 0 on success
+ *  - a negative value else
+ */
+int
+sdb_memstore_emit_full(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter,
+               sdb_store_writer_t *w, sdb_object_t *wd);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ! SDB_CORE_MEMSTORE_H */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
index 4038fe4da91c0fc0c70a68b4ba833e3cba67da5c..5f60c8dfb0a4a1091953ab3a82d8d4a36632fefb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * SysDB - src/include/core/store.h
- * Copyright (C) 2012 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * Copyright (C) 2012-2015 Sebastian 'tokkee' Harl <sh@tokkee.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include "core/object.h"
 #include "core/data.h"
 #include "core/time.h"
-#include "core/timeseries.h"
 #include "parser/ast.h"
 #include "utils/strbuf.h"
 
-#include <stdbool.h>
 #include <stdio.h>
 
 #ifdef __cplusplus
@@ -94,22 +92,6 @@ enum {
                : ((f) == SDB_FIELD_TIMESERIES) ? SDB_TYPE_BOOLEAN \
                : -1)
 
-/*
- * sdb_store_t represents an in-memory store. It inherits from sdb_object_t
- * and may safely be case to a generic object.
- */
-struct sdb_store;
-typedef struct sdb_store sdb_store_t;
-#define SDB_STORE(obj) ((sdb_store_t *)(obj))
-
-/*
- * sdb_store_obj_t represents the super-class of any stored object. It
- * inherits from sdb_object_t and may safely be cast to a generic object to
- * access its name.
- */
-struct sdb_store_obj;
-typedef struct sdb_store_obj sdb_store_obj_t;
-
 /*
  * sdb_store_host_t represents the meta-data of a stored host object.
  */
@@ -180,36 +162,6 @@ typedef struct {
 } sdb_store_attribute_t;
 #define SDB_STORE_ATTRIBUTE_INIT { NULL, 0, NULL, NULL, SDB_DATA_INIT, 0, 0, NULL, 0 }
 
-/*
- * Expressions represent arithmetic expressions based on stored objects and
- * their various attributes.
- *
- * An expression object inherits from sdb_object_t and, thus, may safely be
- * cast to a generic object.
- */
-struct sdb_store_expr;
-typedef struct sdb_store_expr sdb_store_expr_t;
-#define SDB_STORE_EXPR(obj) ((sdb_store_expr_t *)(obj))
-
-/*
- * An expression iterator iterates over the values of an iterable expression.
- */
-struct sdb_store_expr_iter;
-typedef struct sdb_store_expr_iter sdb_store_expr_iter_t;
-
-/*
- * Store matchers may be used to lookup hosts from the store based on their
- * various attributes. Service and attribute matchers are applied to a host's
- * services and attributes and evaluate to true if *any* service or attribute
- * matches.
- *
- * A store matcher object inherits from sdb_object_t and, thus, may safely be
- * cast to a generic object.
- */
-struct sdb_store_matcher;
-typedef struct sdb_store_matcher sdb_store_matcher_t;
-#define SDB_STORE_MATCHER(obj) ((sdb_store_matcher_t *)(obj))
-
 /*
  * A JSON formatter converts stored objects into the JSON format.
  * See http://www.ietf.org/rfc/rfc4627.txt
@@ -270,13 +222,6 @@ typedef struct {
        int (*store_attribute)(sdb_store_attribute_t *attr, sdb_object_t *user_data);
 } sdb_store_writer_t;
 
-/*
- * sdb_store_writer:
- * A store writer implementation that provides an in-memory object store. It
- * expects a store object as its user-data argument.
- */
-extern sdb_store_writer_t sdb_store_writer;
-
 /*
  * A store reader describes the interface to query a store implementation.
  */
@@ -300,422 +245,6 @@ typedef struct {
                        sdb_strbuf_t *errbuf, sdb_object_t *user_data);
 } sdb_store_reader_t;
 
-/*
- * sdb_store_reader:
- * A store reader implementation that uses an in-memory object store. It
- * expects a store object as its user-data argument.
- */
-extern sdb_store_reader_t sdb_store_reader;
-
-/*
- * sdb_store_create:
- * Allocate a new in-memory store.
- */
-sdb_store_t *
-sdb_store_create(void);
-
-/*
- * sdb_store_host, sdb_store_service, sdb_store_metric, sdb_store_attribute,
- * sdb_store_metric_attr:
- * Store an object in the specified store. The hostname is expected to be
- * canonical.
- */
-int
-sdb_store_host(sdb_store_t *store, const char *name, sdb_time_t last_update);
-int
-sdb_store_service(sdb_store_t *store, const char *hostname, const char *name,
-               sdb_time_t last_update);
-int
-sdb_store_metric(sdb_store_t *store, const char *hostname, const char *name,
-               sdb_metric_store_t *metric_store, sdb_time_t last_update);
-int
-sdb_store_attribute(sdb_store_t *store, const char *hostname,
-               const char *key, const sdb_data_t *value, sdb_time_t last_update);
-int
-sdb_store_service_attr(sdb_store_t *store, const char *hostname,
-               const char *service, const char *key, const sdb_data_t *value,
-               sdb_time_t last_update);
-int
-sdb_store_metric_attr(sdb_store_t *store, const char *hostname,
-               const char *metric, const char *key, const sdb_data_t *value,
-               sdb_time_t last_update);
-
-/*
- * sdb_store_get_host:
- * Query the specified store for a host by its (canonicalized) name.
- *
- * The function increments the ref count of the host object. The caller needs
- * to deref it when no longer using it.
- */
-sdb_store_obj_t *
-sdb_store_get_host(sdb_store_t *store, const char *name);
-
-/*
- * sdb_store_fetch_timeseries:
- * Fetch the time-series described by the specified host's metric and
- * serialize it as JSON into the provided string buffer. The host data is
- * retrieved from the specified store.
- *
- * Returns:
- *  - 0 on success
- *  - a negative value else
- */
-int
-sdb_store_fetch_timeseries(sdb_store_t *store,
-               const char *hostname, const char *metric,
-               sdb_timeseries_opts_t *opts, sdb_strbuf_t *buf);
-
-/*
- * sdb_store_get_child:
- * Retrieve a host's child object of the specified type and name. The
- * reference count of the child object will be incremented before returning
- * it. The caller is responsible for releasing the object once it's no longer
- * used.
- *
- * Returns:
- *  - the child object on success
- *  - NULL else
- */
-sdb_store_obj_t *
-sdb_store_get_child(sdb_store_obj_t *host, int type, const char *name);
-
-/*
- * sdb_store_get_field:
- * Get the value of a stored object's queryable field. The caller is
- * responsible for freeing any dynamically allocated memory possibly stored in
- * the returned value. If 'res' is NULL, the function will return whether the
- * field exists.
- *
- * Returns:
- *  - 0 on success
- *  - a negative value else
- */
-int
-sdb_store_get_field(sdb_store_obj_t *obj, int field, sdb_data_t *res);
-
-/*
- * sdb_store_get_attr:
- * Get the value of a stored object's attribute. The caller is responsible for
- * freeing any dynamically allocated memory possibly stored in the returned
- * value. If 'res' is NULL, the function will return whether the attribute
- * exists. If specified, only attributes matching the filter will be
- * considered.
- *
- * Returns:
- *  - 0 if the attribute exists
- *  - a negative value else
- */
-int
-sdb_store_get_attr(sdb_store_obj_t *obj, const char *name, sdb_data_t *res,
-               sdb_store_matcher_t *filter);
-
-/*
- * Querying a store:
- *
- *  - Query interface: A query is a formal description of an interaction with
- *    the store. It can be used, both, for read and write access. The query is
- *    described by its abstract syntax tree (AST). The parser package provides
- *    means to parse a string (SysQL) representation of the query into an AST.
- *
- *  - Matcher / expression interface: This low-level interface provides direct
- *    control over how to access the store. It is used by the query
- *    implementation internally and can only be used for read access.
- */
-
-/*
- * sdb_store_query_t:
- * A parsed query readily prepared for execution.
- */
-struct sdb_store_query;
-typedef struct sdb_store_query sdb_store_query_t;
-
-/*
- * sdb_store_query_prepare:
- * Prepare the query described by 'ast' for execution in a store.
- *
- * Returns:
- *  - a store query on success
- *  - NULL else
- */
-sdb_store_query_t *
-sdb_store_query_prepare(sdb_ast_node_t *ast);
-
-/*
- * sdb_store_query_prepare_matcher:
- * Prepare the logical expression described by 'ast' for execution as a store
- * matcher.
- *
- * Returns:
- *  - a matcher on success
- *  - NULL else
- */
-sdb_store_matcher_t *
-sdb_store_query_prepare_matcher(sdb_ast_node_t *ast);
-
-/*
- * sdb_store_query_execute:
- * Execute a previously prepared query in the specified store. The query
- * result will be written to 'buf' and any errors to 'errbuf'.
- *
- * Returns:
- *  - the result type (to be used by the server reply)
- *  - a negative value on error
- */
-int
-sdb_store_query_execute(sdb_store_t *store, sdb_store_query_t *m,
-               sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf);
-
-/*
- * sdb_store_expr_create:
- * Creates an arithmetic expression implementing the specified operator on the
- * specified left and right operand.
- *
- * Returns:
- *  - an expression object on success
- *  - NULL else
- */
-sdb_store_expr_t *
-sdb_store_expr_create(int op, sdb_store_expr_t *left, sdb_store_expr_t *right);
-
-/*
- * sdb_store_expr_typed:
- * Creates an expression which evaluates in the context of an object's sibling
- * as specified by the given type.
- *
- * Returns:
- *  - an expression object on success
- *  - NULL else
- */
-sdb_store_expr_t *
-sdb_store_expr_typed(int typ, sdb_store_expr_t *expr);
-
-/*
- * sdb_store_expr_fieldvalue:
- * Creates an expression which evaluates to the value of the specified
- * queryable field of a stored object.
- *
- * Returns:
- *  - an expression object on success
- *  - NULL else
- */
-sdb_store_expr_t *
-sdb_store_expr_fieldvalue(int field);
-
-/*
- * sdb_store_expr_attrvalue:
- * Creates an expression which evaluates to the value of the specified
- * attribute of a stored object. Evaluates to a NULL value if the attribute
- * does not exist.
- *
- * Returns:
- *  - an expression object on success
- *  - NULL else
- */
-sdb_store_expr_t *
-sdb_store_expr_attrvalue(const char *name);
-
-/*
- * sdb_store_expr_constvalue:
- * Creates an expression which evaluates to the specified constant value.
- *
- * Returns:
- *  - an expression object on success
- *  - NULL else
- */
-sdb_store_expr_t *
-sdb_store_expr_constvalue(const sdb_data_t *value);
-
-/*
- * sdb_store_expr_eval:
- * Evaluate an expression for the specified stored object and stores the
- * result in 'res'. The result's value will be allocated dynamically if
- * necessary and, thus, should be free'd by the caller (e.g. using
- * sdb_data_free_datum). The object may be NULL, in which case the expression
- * needs to evaluate to a constant value. If specified, only objects matching
- * the filter will be used during the evaluation.
- *
- * Returns:
- *  - 0 on success
- *  - a negative value else
- */
-int
-sdb_store_expr_eval(sdb_store_expr_t *expr, sdb_store_obj_t *obj,
-               sdb_data_t *res, sdb_store_matcher_t *filter);
-
-/*
- * sdb_store_expr_iter:
- * Iterate over the elements of an iterable expression. sdb_store_expr_iter
- * returns NULL if the expression is not iterable (for the specified object).
- *
- * sdb_store_expr_iter_get_next returns NULL if there is no next element.
- */
-sdb_store_expr_iter_t *
-sdb_store_expr_iter(sdb_store_expr_t *expr, sdb_store_obj_t *obj,
-               sdb_store_matcher_t *filter);
-void
-sdb_store_expr_iter_destroy(sdb_store_expr_iter_t *iter);
-
-bool
-sdb_store_expr_iter_has_next(sdb_store_expr_iter_t *iter);
-sdb_data_t
-sdb_store_expr_iter_get_next(sdb_store_expr_iter_t *iter);
-
-/*
- * sdb_store_dis_matcher:
- * Creates a matcher matching the disjunction (logical OR) of two matchers.
- */
-sdb_store_matcher_t *
-sdb_store_dis_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right);
-
-/*
- * sdb_store_con_matcher:
- * Creates a matcher matching the conjunction (logical AND) of two matchers.
- */
-sdb_store_matcher_t *
-sdb_store_con_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right);
-
-/*
- * sdb_store_inv_matcher::
- * Creates a matcher matching the inverse (logical NOT) of a matcher.
- */
-sdb_store_matcher_t *
-sdb_store_inv_matcher(sdb_store_matcher_t *m);
-
-/*
- * sdb_store_any_matcher:
- * Creates a matcher iterating over values of the first expression (which has
- * to be iterable). It matches if *any* of those elements match 'm'. 'm' has
- * to be an ary operation with the left operand unset.
- */
-sdb_store_matcher_t *
-sdb_store_any_matcher(sdb_store_expr_t *iter, sdb_store_matcher_t *m);
-
-/*
- * sdb_store_all_matcher:
- * Creates a matcher iterating over values of the first expression (which has
- * to be iterable). It matches if *all* of those elements match 'm'. 'm' has
- * to be an ary operation with the left operand unset.
- */
-sdb_store_matcher_t *
-sdb_store_all_matcher(sdb_store_expr_t *iter, sdb_store_matcher_t *m);
-
-/*
- * sdb_store_in_matcher:
- * Creates a matcher which matches if the right value evaluates to an array
- * value and the left value is included in that array. See sdb_data_inarray
- * for more details.
- */
-sdb_store_matcher_t *
-sdb_store_in_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right);
-
-/*
- * sdb_store_lt_matcher, sdb_store_le_matcher, sdb_store_eq_matcher,
- * sdb_store_ge_matcher, sdb_store_gt_matcher:
- * Create conditional matchers comparing the values of two expressions. The
- * matcher matches if the left expression compres less than, less or equal
- * than, equal to, not equal to, greater or equal than, or greater than the
- * right expression.
- */
-sdb_store_matcher_t *
-sdb_store_lt_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right);
-sdb_store_matcher_t *
-sdb_store_le_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right);
-sdb_store_matcher_t *
-sdb_store_eq_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right);
-sdb_store_matcher_t *
-sdb_store_ne_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right);
-sdb_store_matcher_t *
-sdb_store_ge_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right);
-sdb_store_matcher_t *
-sdb_store_gt_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right);
-
-/*
- * sdb_store_regex_matcher:
- * Creates a matcher which matches the string value the left expression
- * evaluates to against the regular expression the right expression evaluates
- * to. The right expression may either be a constant value regular expression
- * or string or a dynamic value evaluating to a string. In the latter case,
- * the string is compiled to a regex every time the matcher is executed.
- */
-sdb_store_matcher_t *
-sdb_store_regex_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right);
-
-/*
- * sdb_store_nregex_matcher:
- * Creates a regex matcher just like sdb_store_regex_matcher except that it
- * matches in case the regular expression does not match.
- */
-sdb_store_matcher_t *
-sdb_store_nregex_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right);
-
-/*
- * sdb_store_isnull_matcher:
- * Creates a matcher matching NULL values.
- */
-sdb_store_matcher_t *
-sdb_store_isnull_matcher(sdb_store_expr_t *expr);
-
-/*
- * sdb_store_istrue_matcher, sdb_store_isfalse_matcher:
- * Creates a matcher matching boolean values.
- */
-sdb_store_matcher_t *
-sdb_store_istrue_matcher(sdb_store_expr_t *expr);
-sdb_store_matcher_t *
-sdb_store_isfalse_matcher(sdb_store_expr_t *expr);
-
-/*
- * sdb_store_matcher_matches:
- * Check whether the specified matcher matches the specified store object. If
- * specified, the filter will be used to preselect objects for further
- * evaluation. It is applied to any object that's used during the evaluation
- * of the matcher. Only those objects matching the filter will be considered.
- *
- * Note that the filter is applied to all object types (hosts, service,
- * metric, attribute). Thus, any object-specific matchers are mostly unsuited
- * for this purpose and, if used, may result in unexpected behavior.
- *
- * Returns:
- *  - 1 if the object matches
- *  - 0 else
- */
-int
-sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
-               sdb_store_matcher_t *filter);
-
-/*
- * sdb_store_matcher_op_cb:
- * Callback constructing a matcher operator.
- */
-typedef sdb_store_matcher_t *(*sdb_store_matcher_op_cb)
-       (sdb_store_expr_t *, sdb_store_expr_t *);
-
-/*
- * sdb_store_lookup_cb:
- * Lookup callback. It is called for each matching object when looking up data
- * in the store passing on the lookup filter and the specified user-data. The
- * lookup aborts early if the callback returns non-zero.
- */
-typedef int (*sdb_store_lookup_cb)(sdb_store_obj_t *obj,
-               sdb_store_matcher_t *filter, void *user_data);
-
-/*
- * sdb_store_scan:
- * Look up objects of the specified type in the specified store. The specified
- * callback function is called for each object in the store matching 'm'. The
- * function performs a full scan of all stored objects. If specified, the
- * filter will be used to preselect objects for further evaluation. See the
- * description of 'sdb_store_matcher_matches' for details.
- *
- * Returns:
- *  - 0 on success
- *  - a negative value else
- */
-int
-sdb_store_scan(sdb_store_t *store, int type,
-               sdb_store_matcher_t *m, sdb_store_matcher_t *filter,
-               sdb_store_lookup_cb cb, void *user_data);
-
 /*
  * Flags for JSON formatting.
  */
@@ -731,42 +260,6 @@ enum {
 sdb_store_json_formatter_t *
 sdb_store_json_formatter(sdb_strbuf_t *buf, int type, int flags);
 
-/*
- * sdb_store_emit:
- * Serialize a single object to JSON adding it to the string buffer associated
- * with the formatter object. The serialized object will not include
- * attributes or any child objects. Instead, call the function again for each
- * of those objects. All attributes have to be emitted before any other
- * children types. Use sdb_store_emit_full() to emit a full (filtered) object.
- *
- * Note that the output might not be valid JSON before calling
- * sdb_store_json_finish().
- *
- * Returns:
- *  - 0 on success
- *  - a negative value else
- */
-int
-sdb_store_emit(sdb_store_obj_t *obj, sdb_store_writer_t *w, sdb_object_t *wd);
-
-/*
- * sdb_store_emit_full:
- * Serialize a single object including it's attributes and all children to
- * JSON, adding it to the string buffer associated with the formatter object.
- * The filter, if specified, is applied to each attribute and child object.
- * Only matching objects will be included in the output.
- *
- * Note that the output might not be valid JSON before calling
- * sdb_store_json_finish().
- *
- * Returns:
- *  - 0 on success
- *  - a negative value else
- */
-int
-sdb_store_emit_full(sdb_store_obj_t *obj, sdb_store_matcher_t *filter,
-               sdb_store_writer_t *w, sdb_object_t *wd);
-
 /*
  * sdb_store_json_finish:
  * Finish the JSON output. This function has to be called once after emiting
index 8533fc705e6467b91840ce97b86cc20a09f14b14..01446abbd84b86e4b0395e2715f700fbad04a9dd 100644 (file)
@@ -257,12 +257,17 @@ typedef struct {
        sdb_ast_node_t super;
        int obj_type;
        char *hostname; /* optional */
+       int parent_type; /* optional */
+       char *parent; /* optional */
        char *name;
+       /* whether to include the full object, that is,
+        * including all attributes and all children */
+       bool full;
        sdb_ast_node_t *filter; /* optional */
 } sdb_ast_fetch_t;
 #define SDB_AST_FETCH(obj) ((sdb_ast_fetch_t *)(obj))
 #define SDB_AST_FETCH_INIT \
-       { { SDB_OBJECT_INIT, SDB_AST_TYPE_FETCH, -1 }, -1, NULL, NULL, NULL }
+       { { SDB_OBJECT_INIT, SDB_AST_TYPE_FETCH, -1 }, -1, NULL, -1, NULL, NULL, 0, NULL }
 
 /*
  * sdb_ast_list_t represents a LIST command.
@@ -384,8 +389,9 @@ sdb_ast_value_create(int type, char *name);
  * takes ownership of the strings and the filter node.
  */
 sdb_ast_node_t *
-sdb_ast_fetch_create(int obj_type, char *hostname, char *name,
-               sdb_ast_node_t *filter);
+sdb_ast_fetch_create(int obj_type, char *hostname,
+               int parent_type, char *parent, char *name,
+               bool full, sdb_ast_node_t *filter);
 
 /*
  * sdb_ast_list_create:
index ecae40f890c2842d82f92d701ab0a8e3137025f9..4adeafc66f02651bbc85c665059503647d792ffb 100644 (file)
@@ -85,6 +85,79 @@ iter_error(sdb_strbuf_t *errbuf, sdb_ast_iter_t *iter, const char *reason, ...)
                        r);
 } /* iter_error */
 
+/*
+ * generic checks
+ */
+
+typedef struct {
+       int obj_type;
+       const char *hostname;
+       int parent_type;
+       const char *parent;
+       const char *name;
+} parent_child_t;
+
+static int
+analyze_parent_child(const char *cmd, parent_child_t *pc, sdb_strbuf_t *errbuf)
+{
+       if ((pc->obj_type != SDB_ATTRIBUTE)
+                       && (! VALID_OBJ_TYPE(pc->obj_type))) {
+               sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
+                               "in %s command", pc->obj_type, cmd);
+               return -1;
+       }
+       if (! pc->name) {
+               sdb_strbuf_sprintf(errbuf, "Missing object name in "
+                               "%s %s command", cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type));
+               return -1;
+       }
+
+       if ((pc->obj_type == SDB_HOST) && pc->hostname) {
+               sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
+                               "in %s HOST command", pc->hostname, cmd);
+               return -1;
+       }
+       else if ((pc->obj_type != SDB_HOST) && (! pc->hostname)) {
+               sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' "
+                               "in %s %s command", pc->name,
+                               cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type));
+               return -1;
+       }
+
+       if (pc->obj_type == SDB_ATTRIBUTE) {
+               if ((pc->parent_type <= 0) && pc->parent) {
+                       sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
+                                       "in %s %s command", pc->parent,
+                                       cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type));
+                       return -1;
+               }
+               else if (pc->parent_type > 0) {
+                       if (! VALID_OBJ_TYPE(pc->parent_type)) {
+                               sdb_strbuf_sprintf(errbuf, "Invalid parent type %#x "
+                                               "in %s %s command", pc->parent_type,
+                                               cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type));
+                               return -1;
+                       }
+                       if (! pc->parent) {
+                               sdb_strbuf_sprintf(errbuf, "Missing %s parent name "
+                                               "in %s %s command",
+                                               SDB_STORE_TYPE_TO_NAME(pc->parent_type),
+                                               cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type));
+                               return -1;
+                       }
+               }
+       }
+       else if ((pc->parent_type > 0) || pc->parent) {
+               sdb_strbuf_sprintf(errbuf, "Unexpected %s parent name '%s' "
+                               "in %s %s command",
+                               SDB_STORE_TYPE_TO_NAME(pc->parent_type),
+                               pc->parent ? pc->parent : "<unknown>",
+                               cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type));
+               return -1;
+       }
+       return 0;
+} /* analyze_parent_child */
+
 /*
  * expression nodes
  */
@@ -426,28 +499,13 @@ analyze_node(context_t ctx, sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
 static int
 analyze_fetch(sdb_ast_fetch_t *fetch, sdb_strbuf_t *errbuf)
 {
-       if (! VALID_OBJ_TYPE(fetch->obj_type)) {
-               sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
-                               "in FETCH command", fetch->obj_type);
-               return -1;
-       }
-       if (! fetch->name) {
-               sdb_strbuf_sprintf(errbuf, "Missing object name in "
-                               "FETCH %s command", SDB_STORE_TYPE_TO_NAME(fetch->obj_type));
-               return -1;
-       }
+       parent_child_t pc = {
+               fetch->obj_type, fetch->hostname,
+               fetch->parent_type, fetch->parent, fetch->name,
+       };
 
-       if ((fetch->obj_type == SDB_HOST) && fetch->hostname) {
-               sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
-                               "in FETCH HOST command", fetch->hostname);
+       if (analyze_parent_child("FETCH", &pc, errbuf))
                return -1;
-       }
-       else if ((fetch->obj_type != SDB_HOST) && (! fetch->hostname)) {
-               sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' "
-                               "in FETCH %s command", fetch->name,
-                               SDB_STORE_TYPE_TO_NAME(fetch->obj_type));
-               return -1;
-       }
 
        if (fetch->filter)
                return analyze_node(FILTER_CTX, fetch->filter, errbuf);
@@ -488,61 +546,13 @@ analyze_lookup(sdb_ast_lookup_t *lookup, sdb_strbuf_t *errbuf)
 static int
 analyze_store(sdb_ast_store_t *st, sdb_strbuf_t *errbuf)
 {
-       if ((st->obj_type != SDB_ATTRIBUTE)
-                       && (! VALID_OBJ_TYPE(st->obj_type))) {
-               sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
-                               "in STORE command", st->obj_type);
-               return -1;
-       }
-       if (! st->name) {
-               sdb_strbuf_sprintf(errbuf, "Missing object name in "
-                               "STORE %s command", SDB_STORE_TYPE_TO_NAME(st->obj_type));
-               return -1;
-       }
-
-       if ((st->obj_type == SDB_HOST) && st->hostname) {
-               sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
-                               "in STORE HOST command", st->hostname);
-               return -1;
-       }
-       else if ((st->obj_type != SDB_HOST) && (! st->hostname)) {
-               sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' "
-                               "in STORE %s command", st->name,
-                               SDB_STORE_TYPE_TO_NAME(st->obj_type));
-               return -1;
-       }
+       parent_child_t pc = {
+               st->obj_type, st->hostname,
+               st->parent_type, st->parent, st->name,
+       };
 
-       if (st->obj_type == SDB_ATTRIBUTE) {
-               if ((st->parent_type <= 0) && st->parent) {
-                       sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
-                                       "in STORE %s command", st->parent,
-                                       SDB_STORE_TYPE_TO_NAME(st->obj_type));
-                       return -1;
-               }
-               else if (st->parent_type > 0) {
-                       if (! VALID_OBJ_TYPE(st->parent_type)) {
-                               sdb_strbuf_sprintf(errbuf, "Invalid parent type %#x "
-                                               "in STORE %s command", st->parent_type,
-                                               SDB_STORE_TYPE_TO_NAME(st->obj_type));
-                               return -1;
-                       }
-                       if (! st->parent) {
-                               sdb_strbuf_sprintf(errbuf, "Missing %s parent name "
-                                               "in STORE %s command",
-                                               SDB_STORE_TYPE_TO_NAME(st->parent_type),
-                                               SDB_STORE_TYPE_TO_NAME(st->obj_type));
-                               return -1;
-                       }
-               }
-       }
-       else if ((st->parent_type > 0) || st->parent) {
-               sdb_strbuf_sprintf(errbuf, "Unexpected %s parent name '%s' "
-                               "in STORE %s command",
-                               SDB_STORE_TYPE_TO_NAME(st->parent_type),
-                               st->parent ? st->parent : "<unknown>",
-                               SDB_STORE_TYPE_TO_NAME(st->obj_type));
+       if (analyze_parent_child("STORE", &pc, errbuf))
                return -1;
-       }
 
        if (st->obj_type == SDB_METRIC) {
                if ((! st->store_type) != (! st->store_id)) {
index 81a4c343e37e4d2edf5e80e2f9398c510d6da1c1..dcfe7862bd0b73c891ea017796a28cc626cf0589 100644 (file)
@@ -85,6 +85,8 @@ fetch_destroy(sdb_object_t *obj)
        sdb_ast_fetch_t *fetch = SDB_AST_FETCH(obj);
        if (fetch->hostname)
                free(fetch->hostname);
+       if (fetch->parent)
+               free(fetch->parent);
        if (fetch->name)
                free(fetch->name);
        fetch->hostname = fetch->name = NULL;
@@ -289,8 +291,9 @@ sdb_ast_value_create(int type, char *name)
 } /* sdb_ast_value_create */
 
 sdb_ast_node_t *
-sdb_ast_fetch_create(int obj_type, char *hostname, char *name,
-               sdb_ast_node_t *filter)
+sdb_ast_fetch_create(int obj_type, char *hostname,
+               int parent_type, char *parent, char *name,
+               bool full, sdb_ast_node_t *filter)
 {
        sdb_ast_fetch_t *fetch;
        fetch = SDB_AST_FETCH(sdb_object_create("FETCH", fetch_type));
@@ -301,7 +304,10 @@ sdb_ast_fetch_create(int obj_type, char *hostname, char *name,
 
        fetch->obj_type = obj_type;
        fetch->hostname = hostname;
+       fetch->parent_type = parent_type;
+       fetch->parent = parent;
        fetch->name = name;
+       fetch->full = full;
        fetch->filter = filter;
        return SDB_AST_NODE(fetch);
 } /* sdb_ast_fetch_create */
index 1b6d208c385736bdb828adeedc4bb460d7d35782..c350d54365a03c5d9d8cb9faaf00234064f4ace5 100644 (file)
@@ -281,13 +281,13 @@ statement:
 fetch_statement:
        FETCH object_type STRING filter_clause
                {
-                       $$ = sdb_ast_fetch_create($2, NULL, $3, $4);
+                       $$ = sdb_ast_fetch_create($2, NULL, -1, NULL, $3, 1, $4);
                        CK_OOM($$);
                }
        |
        FETCH object_type STRING '.' STRING filter_clause
                {
-                       $$ = sdb_ast_fetch_create($2, $3, $5, $6);
+                       $$ = sdb_ast_fetch_create($2, $3, -1, NULL, $5, 1, $6);
                        CK_OOM($$);
                }
        ;
index 3cbc1e87c1c2ecd10d858539059b1d0fff98bd64..703696fb38dde4ce1ac1c72109f9c19d15917f16 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "sysdb.h"
 #include "core/plugin.h"
+#include "core/memstore.h"
 #include "core/store.h"
 #include "utils/error.h"
 
@@ -43,19 +44,19 @@ SDB_PLUGIN_MAGIC;
 static int
 mem_init(sdb_object_t *user_data)
 {
-       sdb_store_t *store = SDB_STORE(user_data);
+       sdb_memstore_t *store = SDB_MEMSTORE(user_data);
 
        if (! store) {
                sdb_log(SDB_LOG_ERR, "store: Failed to allocate store");
                return -1;
        }
        if (sdb_plugin_register_writer("memstore",
-                               &sdb_store_writer, SDB_OBJ(store))) {
+                               &sdb_memstore_writer, SDB_OBJ(store))) {
                sdb_object_deref(SDB_OBJ(store));
                return -1;
        }
        if (sdb_plugin_register_reader("memstore",
-                               &sdb_store_reader, SDB_OBJ(store))) {
+                               &sdb_memstore_reader, SDB_OBJ(store))) {
                sdb_object_deref(SDB_OBJ(store));
                return -1;
        }
@@ -73,7 +74,7 @@ int
 sdb_module_init(sdb_plugin_info_t *info)
 {
        /* store singleton */
-       static sdb_store_t *store;
+       static sdb_memstore_t *store;
 
        sdb_plugin_set_info(info, SDB_PLUGIN_INFO_DESC, "in-memory object store");
        sdb_plugin_set_info(info, SDB_PLUGIN_INFO_COPYRIGHT,
@@ -83,7 +84,7 @@ sdb_module_init(sdb_plugin_info_t *info)
        sdb_plugin_set_info(info, SDB_PLUGIN_INFO_PLUGIN_VERSION, SDB_VERSION);
 
        if (! store) {
-               if (! (store = sdb_store_create())) {
+               if (! (store = sdb_memstore_create())) {
                        sdb_log(SDB_LOG_ERR, "store::memory plugin: "
                                        "Failed to create store object");
                        return -1;
index 3f21a82f9f21952dd684a6361d13deefac662aae..c73ab3475bca6eb6b17b17565edd84e6601fe88b 100644 (file)
 #endif
 
 #include "core/store.h"
-#include "core/store-private.h"
+#include "core/memstore-private.h"
 #include "parser/parser.h"
 #include "testutils.h"
 
 #include <check.h>
 
-static sdb_store_t *store;
+static sdb_memstore_t *store;
 
 static void
 populate(void)
@@ -94,43 +94,43 @@ populate(void)
 
        size_t i;
 
-       store = sdb_store_create();
+       store = sdb_memstore_create();
        ck_assert(store != NULL);
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(hosts); ++i) {
-               int status = sdb_store_host(store, hosts[i], 1);
+               int status = sdb_memstore_host(store, hosts[i], 1, 0);
                ck_assert(status == 0);
        }
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(metrics); ++i) {
-               int status = sdb_store_metric(store, metrics[i].host,
-                               metrics[i].metric, /* store */ NULL, 1);
+               int status = sdb_memstore_metric(store, metrics[i].host,
+                               metrics[i].metric, /* store */ NULL, 1, 0);
                ck_assert(status == 0);
        }
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(services); ++i) {
-               int status = sdb_store_service(store, services[i].host,
-                               services[i].service, 1);
+               int status = sdb_memstore_service(store, services[i].host,
+                               services[i].service, 1, 0);
                ck_assert(status == 0);
        }
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(attrs); ++i) {
-               int status = sdb_store_attribute(store, attrs[i].host,
-                               attrs[i].name, &attrs[i].value, 1);
+               int status = sdb_memstore_attribute(store, attrs[i].host,
+                               attrs[i].name, &attrs[i].value, 1, 0);
                ck_assert(status == 0);
        }
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(svc_attrs); ++i) {
-               int status = sdb_store_service_attr(store, svc_attrs[i].host,
+               int status = sdb_memstore_service_attr(store, svc_attrs[i].host,
                                svc_attrs[i].service, svc_attrs[i].name,
-                               &svc_attrs[i].value, 1);
+                               &svc_attrs[i].value, 1, 0);
                ck_assert(status == 0);
        }
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(metric_attrs); ++i) {
-               int status = sdb_store_metric_attr(store, metric_attrs[i].host,
+               int status = sdb_memstore_metric_attr(store, metric_attrs[i].host,
                                metric_attrs[i].metric, metric_attrs[i].name,
-                               &metric_attrs[i].value, 1);
+                               &metric_attrs[i].value, 1, 0);
                ck_assert(status == 0);
        }
 } /* populate */
@@ -151,7 +151,7 @@ turndown(void)
 #define SERVICES { SDB_TYPE_INTEGER, { .integer = SDB_SERVICE } }
 #define METRICS { SDB_TYPE_INTEGER, { .integer = SDB_METRIC } }
 #define ATTRS { SDB_TYPE_INTEGER, { .integer = SDB_ATTRIBUTE } }
-static sdb_store_expr_t namer = {
+static sdb_memstore_expr_t namer = {
        SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, NAME,
 };
 static int64_t int_values[] = { 1, 2, 3, 4, 5 };
@@ -163,7 +163,7 @@ static struct {
        unsigned char *datum;
 } bin_values[] = { { 4, (unsigned char *)"\3\2\0\1" } };
 struct {
-       sdb_store_expr_t expr;
+       sdb_memstore_expr_t expr;
        bool iterable;
 
        char *host;
@@ -555,19 +555,19 @@ struct {
 
 START_TEST(test_expr_iter)
 {
-       sdb_store_obj_t *obj = NULL;
-       sdb_store_matcher_t *filter = NULL;
+       sdb_memstore_obj_t *obj = NULL;
+       sdb_memstore_matcher_t *filter = NULL;
        int context = SDB_HOST;
 
-       sdb_store_expr_iter_t *iter;
+       sdb_memstore_expr_iter_t *iter;
        size_t i;
 
        if (expr_iter_data[_i].host) {
-               obj = sdb_store_get_host(store, expr_iter_data[_i].host);
+               obj = sdb_memstore_get_host(store, expr_iter_data[_i].host);
                ck_assert(obj != NULL);
 
                if (expr_iter_data[_i].child) {
-                       sdb_store_obj_t *child = sdb_store_get_child(obj,
+                       sdb_memstore_obj_t *child = sdb_memstore_get_child(obj,
                                        expr_iter_data[_i].child_type, expr_iter_data[_i].child);
                        ck_assert(child != NULL);
                        sdb_object_deref(SDB_OBJ(obj));
@@ -580,14 +580,14 @@ START_TEST(test_expr_iter)
        if (expr_iter_data[_i].filter) {
                sdb_ast_node_t *ast;
                ast = sdb_parser_parse_conditional(context, expr_iter_data[_i].filter, -1, NULL);
-               filter = sdb_store_query_prepare_matcher(ast);
+               filter = sdb_memstore_query_prepare_matcher(ast);
                sdb_object_deref(SDB_OBJ(ast));
                ck_assert(filter != NULL);
        }
 
-       iter = sdb_store_expr_iter(&expr_iter_data[_i].expr, obj, filter);
+       iter = sdb_memstore_expr_iter(&expr_iter_data[_i].expr, obj, filter);
        fail_unless((iter != NULL) == expr_iter_data[_i].iterable,
-                       "sdb_store_expr_iter(%s expression, %s, %s) = %s; expected: %s",
+                       "sdb_memstore_expr_iter(%s expression, %s, %s) = %s; expected: %s",
                        EXPR_TO_STRING(&expr_iter_data[_i].expr),
                        obj ? SDB_STORE_TYPE_TO_NAME(obj->type) : "<array>",
                        expr_iter_data[_i].filter, iter ? "<iter>" : "NULL",
@@ -598,7 +598,7 @@ START_TEST(test_expr_iter)
        sdb_object_deref(SDB_OBJ(filter)); filter = NULL;
 
        i = 0;
-       while (sdb_store_expr_iter_has_next(iter)) {
+       while (sdb_memstore_expr_iter_has_next(iter)) {
                char v_str[64], expected_str[64];
                sdb_data_t v;
 
@@ -608,7 +608,7 @@ START_TEST(test_expr_iter)
                                SDB_STORE_TYPE_TO_NAME(context), expr_iter_data[_i].filter,
                                i + 1, expr_iter_data[_i].expected_len);
 
-               v = sdb_store_expr_iter_get_next(iter);
+               v = sdb_memstore_expr_iter_get_next(iter);
                sdb_data_format(&v, v_str, sizeof(v_str), SDB_DOUBLE_QUOTED);
                sdb_data_format(&expr_iter_data[_i].expected[i],
                                expected_str, sizeof(expected_str), SDB_DOUBLE_QUOTED);
@@ -627,12 +627,12 @@ START_TEST(test_expr_iter)
                        "expected: %zu", EXPR_TO_STRING(&expr_iter_data[_i].expr),
                        SDB_STORE_TYPE_TO_NAME(context), expr_iter_data[_i].filter,
                        i, expr_iter_data[_i].expected_len);
-       fail_unless(sdb_store_expr_iter_get_next(iter).type == SDB_TYPE_NULL,
+       fail_unless(sdb_memstore_expr_iter_get_next(iter).type == SDB_TYPE_NULL,
                        "iter<%s expression, %s, %s> returned further elements "
                        "passed the end", EXPR_TO_STRING(&expr_iter_data[_i].expr),
                        SDB_STORE_TYPE_TO_NAME(context), expr_iter_data[_i].filter);
 
-       sdb_store_expr_iter_destroy(iter);
+       sdb_memstore_expr_iter_destroy(iter);
 }
 END_TEST
 
index b880f7b99a43c5bf9c5381491b9649d43bd53c5a..a0447b639e8b5ea73de65ab8b15f4d9289c3da1a 100644 (file)
@@ -29,6 +29,7 @@
 #      include "config.h"
 #endif
 
+#include "core/memstore.h"
 #include "core/store.h"
 #include "testutils.h"
 
 #undef SDB_INTERVAL_SECOND
 #define SDB_INTERVAL_SECOND 1000000000L
 
-static sdb_store_t *store;
+static sdb_memstore_t *store;
 
 static void
 populate(void)
 {
        sdb_data_t datum;
 
-       store = sdb_store_create();
+       store = sdb_memstore_create();
        ck_assert(store != NULL);
 
-       sdb_store_host(store, "h1", 1 * SDB_INTERVAL_SECOND);
-       sdb_store_host(store, "h2", 3 * SDB_INTERVAL_SECOND);
+       sdb_memstore_host(store, "h1", 1 * SDB_INTERVAL_SECOND, 0);
+       sdb_memstore_host(store, "h2", 3 * SDB_INTERVAL_SECOND, 0);
 
        datum.type = SDB_TYPE_STRING;
        datum.data.string = "v1";
-       sdb_store_attribute(store, "h1", "k1", &datum, 1 * SDB_INTERVAL_SECOND);
+       sdb_memstore_attribute(store, "h1", "k1", &datum, 1 * SDB_INTERVAL_SECOND, 0);
        datum.data.string = "v2";
-       sdb_store_attribute(store, "h1", "k2", &datum, 2 * SDB_INTERVAL_SECOND);
+       sdb_memstore_attribute(store, "h1", "k2", &datum, 2 * SDB_INTERVAL_SECOND, 0);
        datum.data.string = "v3";
-       sdb_store_attribute(store, "h1", "k3", &datum, 2 * SDB_INTERVAL_SECOND);
+       sdb_memstore_attribute(store, "h1", "k3", &datum, 2 * SDB_INTERVAL_SECOND, 0);
 
+/* TODO: move these tests into generic store tests */
+#if 0
        /* make sure that older updates don't overwrite existing values */
        datum.data.string = "fail";
-       sdb_store_attribute(store, "h1", "k2", &datum, 1 * SDB_INTERVAL_SECOND);
-       sdb_store_attribute(store, "h1", "k3", &datum, 2 * SDB_INTERVAL_SECOND);
+       sdb_memstore_attribute(store, "h1", "k2", &datum, 1 * SDB_INTERVAL_SECOND, 0);
+       sdb_memstore_attribute(store, "h1", "k3", &datum, 2 * SDB_INTERVAL_SECOND, 0);
+#endif
 
-       sdb_store_metric(store, "h1", "m1", /* store */ NULL, 2 * SDB_INTERVAL_SECOND);
-       sdb_store_metric(store, "h1", "m2", /* store */ NULL, 1 * SDB_INTERVAL_SECOND);
-       sdb_store_metric(store, "h2", "m1", /* store */ NULL, 1 * SDB_INTERVAL_SECOND);
+       sdb_memstore_metric(store, "h1", "m1", /* store */ NULL, 2 * SDB_INTERVAL_SECOND, 0);
+       sdb_memstore_metric(store, "h1", "m2", /* store */ NULL, 1 * SDB_INTERVAL_SECOND, 0);
+       sdb_memstore_metric(store, "h2", "m1", /* store */ NULL, 1 * SDB_INTERVAL_SECOND, 0);
 
-       sdb_store_service(store, "h2", "s1", 1 * SDB_INTERVAL_SECOND);
-       sdb_store_service(store, "h2", "s2", 2 * SDB_INTERVAL_SECOND);
+       sdb_memstore_service(store, "h2", "s1", 1 * SDB_INTERVAL_SECOND, 0);
+       sdb_memstore_service(store, "h2", "s2", 2 * SDB_INTERVAL_SECOND, 0);
 
        datum.type = SDB_TYPE_INTEGER;
        datum.data.integer = 42;
-       sdb_store_metric_attr(store, "h1", "m1", "k3",
-                       &datum, 2 * SDB_INTERVAL_SECOND);
+       sdb_memstore_metric_attr(store, "h1", "m1", "k3",
+                       &datum, 2 * SDB_INTERVAL_SECOND, 0);
 
        datum.data.integer = 123;
-       sdb_store_service_attr(store, "h2", "s2", "k1",
-                       &datum, 2 * SDB_INTERVAL_SECOND);
+       sdb_memstore_service_attr(store, "h2", "s2", "k1",
+                       &datum, 2 * SDB_INTERVAL_SECOND, 0);
        datum.data.integer = 4711;
-       sdb_store_service_attr(store, "h2", "s2", "k2",
-                       &datum, 1 * SDB_INTERVAL_SECOND);
-
-       /* don't overwrite k1 */
-       datum.data.integer = 666;
-       sdb_store_service_attr(store, "h2", "s2", "k1",
-                       &datum, 2 * SDB_INTERVAL_SECOND);
+       sdb_memstore_service_attr(store, "h2", "s2", "k2",
+                       &datum, 1 * SDB_INTERVAL_SECOND, 0);
 } /* populate */
 
 static void
@@ -98,18 +97,18 @@ turndown(void)
 } /* turndown */
 
 static int
-scan_tojson(sdb_store_obj_t *obj,
-               sdb_store_matcher_t __attribute__((unused)) *filter,
+scan_tojson(sdb_memstore_obj_t *obj,
+               sdb_memstore_matcher_t __attribute__((unused)) *filter,
                void *user_data)
 {
-       return sdb_store_emit(obj, &sdb_store_json_writer, user_data);
+       return sdb_memstore_emit(obj, &sdb_store_json_writer, user_data);
 } /* scan_tojson */
 
 static int
-scan_tojson_full(sdb_store_obj_t *obj, sdb_store_matcher_t *filter,
+scan_tojson_full(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter,
                void *user_data)
 {
-       return sdb_store_emit_full(obj, filter, &sdb_store_json_writer, user_data);
+       return sdb_memstore_emit_full(obj, filter, &sdb_store_json_writer, user_data);
 } /* scan_tojson_full */
 
 static void
@@ -140,12 +139,12 @@ verify_json_output(sdb_strbuf_t *buf, const char *expected)
 
 struct {
        struct {
-               sdb_store_matcher_t *(*m)(sdb_store_expr_t *, sdb_store_expr_t *);
+               sdb_memstore_matcher_t *(*m)(sdb_memstore_expr_t *, sdb_memstore_expr_t *);
                int field;
                sdb_data_t value;
        } filter;
        int type;
-       int (*f)(sdb_store_obj_t *, sdb_store_matcher_t *, void *);
+       int (*f)(sdb_memstore_obj_t *, sdb_memstore_matcher_t *, void *);
        const char *expected;
 } store_tojson_data[] = {
        { { NULL, 0, SDB_DATA_INIT },
@@ -212,14 +211,14 @@ struct {
                        "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", "
                                "\"update_interval\": \"0s\", \"backends\": []}"
                "]" },
-       { { sdb_store_eq_matcher, SDB_FIELD_NAME,
+       { { sdb_memstore_eq_matcher, SDB_FIELD_NAME,
                        { SDB_TYPE_STRING, { .string = "h1" } } },
                SDB_HOST, scan_tojson_full,
                "["
                        "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", "
                                "\"update_interval\": \"0s\", \"backends\": []}"
                "]" },
-       { { sdb_store_gt_matcher, SDB_FIELD_LAST_UPDATE,
+       { { sdb_memstore_gt_matcher, SDB_FIELD_LAST_UPDATE,
                        { SDB_TYPE_DATETIME, { .datetime = 1 * SDB_INTERVAL_SECOND } } },
                SDB_HOST, scan_tojson_full,
                "["
@@ -236,7 +235,7 @@ struct {
                                                "]}"
                                "]}"
                "]" },
-       { { sdb_store_le_matcher, SDB_FIELD_LAST_UPDATE,
+       { { sdb_memstore_le_matcher, SDB_FIELD_LAST_UPDATE,
                        { SDB_TYPE_DATETIME, { .datetime = 1 * SDB_INTERVAL_SECOND } } },
                SDB_HOST, scan_tojson_full,
                "["
@@ -254,14 +253,14 @@ struct {
                                                "\"update_interval\": \"0s\", \"backends\": []}"
                                "]}"
                "]" },
-       { { sdb_store_ge_matcher, SDB_FIELD_LAST_UPDATE,
+       { { sdb_memstore_ge_matcher, SDB_FIELD_LAST_UPDATE,
                        { SDB_TYPE_DATETIME, { .datetime = 3 * SDB_INTERVAL_SECOND } } },
                SDB_HOST, scan_tojson_full,
                "["
                        "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", "
                                "\"update_interval\": \"0s\", \"backends\": []}"
                "]" },
-       { { sdb_store_lt_matcher, SDB_FIELD_LAST_UPDATE,
+       { { sdb_memstore_lt_matcher, SDB_FIELD_LAST_UPDATE,
                        { SDB_TYPE_DATETIME, { .datetime = 0 } } },
                SDB_HOST, scan_tojson_full,
                "[]" },
@@ -294,7 +293,7 @@ struct {
                                "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
                                "\"update_interval\": \"0s\", \"backends\": []}"
                "]" },
-       { { sdb_store_gt_matcher, SDB_FIELD_LAST_UPDATE,
+       { { sdb_memstore_gt_matcher, SDB_FIELD_LAST_UPDATE,
                        { SDB_TYPE_DATETIME, { .datetime = 1 * SDB_INTERVAL_SECOND } } },
                SDB_SERVICE, scan_tojson_full,
                "["
@@ -307,7 +306,7 @@ struct {
                                                "\"update_interval\": \"0s\", \"backends\": []}"
                                "]}"
                "]" },
-       { { sdb_store_lt_matcher, SDB_FIELD_LAST_UPDATE,
+       { { sdb_memstore_lt_matcher, SDB_FIELD_LAST_UPDATE,
                        { SDB_TYPE_DATETIME, { .datetime = 0 } } },
                SDB_SERVICE, scan_tojson_full,
                "[]" },
@@ -348,7 +347,7 @@ struct {
                                "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
                                "\"update_interval\": \"0s\", \"backends\": []}"
                "]" },
-       { { sdb_store_le_matcher, SDB_FIELD_LAST_UPDATE,
+       { { sdb_memstore_le_matcher, SDB_FIELD_LAST_UPDATE,
                        { SDB_TYPE_DATETIME, { .datetime = 1 * SDB_INTERVAL_SECOND } } },
                SDB_METRIC, scan_tojson_full,
                "["
@@ -357,7 +356,7 @@ struct {
                                "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
                                "\"update_interval\": \"0s\", \"backends\": []}"
                "]" },
-       { { sdb_store_lt_matcher, SDB_FIELD_LAST_UPDATE,
+       { { sdb_memstore_lt_matcher, SDB_FIELD_LAST_UPDATE,
                        { SDB_TYPE_DATETIME, { .datetime = 0 } } },
                SDB_METRIC, scan_tojson_full,
                "[]" },
@@ -366,24 +365,24 @@ struct {
 START_TEST(test_store_tojson)
 {
        sdb_strbuf_t *buf = sdb_strbuf_create(0);
-       sdb_store_matcher_t *filter = NULL;
+       sdb_memstore_matcher_t *filter = NULL;
        sdb_store_json_formatter_t *f;
        int status;
 
        if (store_tojson_data[_i].filter.m) {
-               sdb_store_expr_t *field;
-               sdb_store_expr_t *value;
+               sdb_memstore_expr_t *field;
+               sdb_memstore_expr_t *value;
 
-               field = sdb_store_expr_fieldvalue(store_tojson_data[_i].filter.field);
+               field = sdb_memstore_expr_fieldvalue(store_tojson_data[_i].filter.field);
                fail_unless(field != NULL,
-                               "INTERNAL ERROR: sdb_store_expr_fieldvalue() = NULL");
-               value = sdb_store_expr_constvalue(&store_tojson_data[_i].filter.value);
+                               "INTERNAL ERROR: sdb_memstore_expr_fieldvalue() = NULL");
+               value = sdb_memstore_expr_constvalue(&store_tojson_data[_i].filter.value);
                fail_unless(value != NULL,
-                               "INTERNAL ERROR: sdb_store_expr_constvalue() = NULL");
+                               "INTERNAL ERROR: sdb_memstore_expr_constvalue() = NULL");
 
                filter = store_tojson_data[_i].filter.m(field, value);
                fail_unless(filter != NULL,
-                               "INTERNAL ERROR: sdb_store_*_matcher() = NULL");
+                               "INTERNAL ERROR: sdb_memstore_*_matcher() = NULL");
 
                sdb_object_deref(SDB_OBJ(field));
                sdb_object_deref(SDB_OBJ(value));
@@ -393,10 +392,10 @@ START_TEST(test_store_tojson)
        f = sdb_store_json_formatter(buf, store_tojson_data[_i].type, SDB_WANT_ARRAY);
        ck_assert(f != NULL);
 
-       status = sdb_store_scan(store, store_tojson_data[_i].type,
+       status = sdb_memstore_scan(store, store_tojson_data[_i].type,
                        /* m = */ NULL, filter, store_tojson_data[_i].f, f);
        fail_unless(status == 0,
-                       "sdb_store_scan(HOST, ..., tojson) = %d; expected: 0",
+                       "sdb_memstore_scan(HOST, ..., tojson) = %d; expected: 0",
                        status);
        sdb_store_json_finish(f);
 
index d2c006494ab04f95cffce6fb2f4494dc6b740242..0c30160b9eff10f8df9be6eaab96e9da6c6ca6f3 100644 (file)
 
 #include "core/plugin.h"
 #include "core/store.h"
-#include "core/store-private.h"
+#include "core/memstore-private.h"
 #include "parser/parser.h"
 #include "testutils.h"
 
 #include <check.h>
 #include <string.h>
 
-static sdb_store_t *store;
+static sdb_memstore_t *store;
 
 static void
 populate(void)
@@ -76,37 +76,37 @@ populate(void)
 
        size_t i;
 
-       store = sdb_store_create();
+       store = sdb_memstore_create();
        ck_assert(store != NULL);
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(hosts); ++i) {
-               int status = sdb_store_host(store, hosts[i], 1);
+               int status = sdb_memstore_host(store, hosts[i], 1, 0);
                fail_unless(status == 0,
-                               "sdb_store_host(%s, 1) = %d; expected: 0",
+                               "sdb_memstore_host(%s, 1, 0) = %d; expected: 0",
                                hosts[i], status);
        }
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(metrics); ++i) {
-               int status = sdb_store_metric(store, metrics[i].host,
-                               metrics[i].metric, /* store */ NULL, 1);
+               int status = sdb_memstore_metric(store, metrics[i].host,
+                               metrics[i].metric, /* store */ NULL, 1, 0);
                fail_unless(status == 0,
-                               "sdb_store_metric(%s, %s, NULL, 1) = %d; expected: 0",
+                               "sdb_memstore_metric(%s, %s, NULL, 1, 0) = %d; expected: 0",
                                metrics[i].host, metrics[i].metric, status);
        }
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(services); ++i) {
-               int status = sdb_store_service(store, services[i].host,
-                               services[i].service, 1);
+               int status = sdb_memstore_service(store, services[i].host,
+                               services[i].service, 1, 0);
                fail_unless(status == 0,
-                               "sdb_store_service(%s, %s, 1) = %d; expected: 0",
+                               "sdb_memstore_service(%s, %s, 1, 0) = %d; expected: 0",
                                services[i].host, services[i].service, status);
        }
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(attrs); ++i) {
-               int status = sdb_store_attribute(store, attrs[i].host,
-                               attrs[i].name, &attrs[i].value, 1);
+               int status = sdb_memstore_attribute(store, attrs[i].host,
+                               attrs[i].name, &attrs[i].value, 1, 0);
                fail_unless(status == 0,
-                               "sdb_store_attribute(%s, %s, <val>, 1) = %d; expected: 0",
+                               "sdb_memstore_attribute(%s, %s, <val>, 1, 0) = %d; expected: 0",
                                attrs[i].host, attrs[i].name, status);
        }
 } /* populate */
@@ -161,41 +161,41 @@ struct {
 
 START_TEST(test_cmp_name)
 {
-       sdb_store_obj_t *host;
+       sdb_memstore_obj_t *host;
        sdb_data_t datum;
-       sdb_store_expr_t *obj = NULL, *value;
-       sdb_store_matcher_t *m, *n;
+       sdb_memstore_expr_t *obj = NULL, *value;
+       sdb_memstore_matcher_t *m, *n;
        int status;
 
-       host = sdb_store_get_host(store, "a");
+       host = sdb_memstore_get_host(store, "a");
        fail_unless(host != NULL,
-                       "sdb_store_get_host(a) = NULL; expected: <host>");
+                       "sdb_memstore_get_host(a) = NULL; expected: <host>");
 
        datum.type = SDB_TYPE_STRING;
        datum.data.string = cmp_name_data[_i].name;
 
        if (cmp_name_data[_i].type == SDB_HOST) {
-               obj = sdb_store_expr_fieldvalue(SDB_FIELD_NAME);
+               obj = sdb_memstore_expr_fieldvalue(SDB_FIELD_NAME);
                fail_unless(obj != NULL,
-                               "sdb_store_expr_fieldvalue(SDB_STORE_NAME) = NULL; "
+                               "sdb_memstore_expr_fieldvalue(SDB_STORE_NAME) = NULL; "
                                "expected: <expr>");
        }
-       value = sdb_store_expr_constvalue(&datum);
+       value = sdb_memstore_expr_constvalue(&datum);
        fail_unless(value != NULL,
-                       "sdb_store_expr_constvalue(%s) = NULL; "
+                       "sdb_memstore_expr_constvalue(%s) = NULL; "
                        "expected: <expr>", cmp_name_data[_i].name);
 
        if (cmp_name_data[_i].re)
-               m = sdb_store_regex_matcher(obj, value);
+               m = sdb_memstore_regex_matcher(obj, value);
        else
-               m = sdb_store_eq_matcher(obj, value);
+               m = sdb_memstore_eq_matcher(obj, value);
 
        if (cmp_name_data[_i].type != SDB_HOST) {
-               sdb_store_expr_t *iter;
-               sdb_store_matcher_t *tmp;
-               obj = sdb_store_expr_fieldvalue(SDB_FIELD_NAME);
-               iter = sdb_store_expr_typed(cmp_name_data[_i].type, obj);
-               tmp = sdb_store_any_matcher(iter, m);
+               sdb_memstore_expr_t *iter;
+               sdb_memstore_matcher_t *tmp;
+               obj = sdb_memstore_expr_fieldvalue(SDB_FIELD_NAME);
+               iter = sdb_memstore_expr_typed(cmp_name_data[_i].type, obj);
+               tmp = sdb_memstore_any_matcher(iter, m);
                ck_assert(iter && m);
                sdb_object_deref(SDB_OBJ(iter));
                sdb_object_deref(SDB_OBJ(m));
@@ -204,27 +204,27 @@ START_TEST(test_cmp_name)
        sdb_object_deref(SDB_OBJ(obj));
        sdb_object_deref(SDB_OBJ(value));
        fail_unless(m != NULL,
-                       "sdb_store_%s_matcher(%s, %s) = NULL; "
+                       "sdb_memstore_%s_matcher(%s, %s) = NULL; "
                        "expected: <matcher>",
                        cmp_name_data[_i].re ? "regex" : "eq",
                        SDB_STORE_TYPE_TO_NAME(cmp_name_data[_i].type),
                        cmp_name_data[_i].name);
 
-       status = sdb_store_matcher_matches(m, host, /* filter */ NULL);
+       status = sdb_memstore_matcher_matches(m, host, /* filter */ NULL);
        fail_unless(status == cmp_name_data[_i].expected,
-                       "sdb_store_matcher_matches(%s->%s, <host a>, NULL) = %d; "
+                       "sdb_memstore_matcher_matches(%s->%s, <host a>, NULL) = %d; "
                        "expected: %d", SDB_STORE_TYPE_TO_NAME(cmp_name_data[_i].type),
                        cmp_name_data[_i].name, status, cmp_name_data[_i].expected);
 
-       n = sdb_store_inv_matcher(m);
+       n = sdb_memstore_inv_matcher(m);
        fail_unless(n != NULL,
-                       "sdb_store_inv_matcher() = NULL; expected: <matcher>");
+                       "sdb_memstore_inv_matcher() = NULL; expected: <matcher>");
        sdb_object_deref(SDB_OBJ(m));
 
        /* now match the inverted set of objects */
-       status = sdb_store_matcher_matches(n, host, /* filter */ NULL);
+       status = sdb_memstore_matcher_matches(n, host, /* filter */ NULL);
        fail_unless(status == !cmp_name_data[_i].expected,
-                       "sdb_store_matcher_matches(%s->%s, <host a>, NULL) = %d; "
+                       "sdb_memstore_matcher_matches(%s->%s, <host a>, NULL) = %d; "
                        "expected: %d", SDB_STORE_TYPE_TO_NAME(cmp_name_data[_i].type),
                        cmp_name_data[_i].name, status, !cmp_name_data[_i].expected);
 
@@ -256,55 +256,55 @@ struct {
 
 START_TEST(test_cmp_attr)
 {
-       sdb_store_obj_t *host;
-       sdb_store_expr_t *attr;
-       sdb_store_expr_t *value;
+       sdb_memstore_obj_t *host;
+       sdb_memstore_expr_t *attr;
+       sdb_memstore_expr_t *value;
        char value_str[1024];
        int status;
        size_t j;
 
        struct {
-               sdb_store_matcher_t *(*matcher)(sdb_store_expr_t *,
-                               sdb_store_expr_t *);
+               sdb_memstore_matcher_t *(*matcher)(sdb_memstore_expr_t *,
+                               sdb_memstore_expr_t *);
                int expected;
        } tests[] = {
-               { sdb_store_lt_matcher, cmp_attr_data[_i].expected_lt },
-               { sdb_store_le_matcher, cmp_attr_data[_i].expected_le },
-               { sdb_store_eq_matcher, cmp_attr_data[_i].expected_eq },
-               { sdb_store_ge_matcher, cmp_attr_data[_i].expected_ge },
-               { sdb_store_gt_matcher, cmp_attr_data[_i].expected_gt },
+               { sdb_memstore_lt_matcher, cmp_attr_data[_i].expected_lt },
+               { sdb_memstore_le_matcher, cmp_attr_data[_i].expected_le },
+               { sdb_memstore_eq_matcher, cmp_attr_data[_i].expected_eq },
+               { sdb_memstore_ge_matcher, cmp_attr_data[_i].expected_ge },
+               { sdb_memstore_gt_matcher, cmp_attr_data[_i].expected_gt },
        };
 
        const char *op_str[] = { "<", "<=", "=", ">=", ">" };
        ck_assert(SDB_STATIC_ARRAY_LEN(tests) == SDB_STATIC_ARRAY_LEN(op_str));
 
-       host = sdb_store_get_host(store, "a");
+       host = sdb_memstore_get_host(store, "a");
        fail_unless(host != NULL,
-                       "sdb_store_get_host(a) = NULL; expected: <host>");
+                       "sdb_memstore_get_host(a) = NULL; expected: <host>");
 
        sdb_data_format(&cmp_attr_data[_i].value,
                        value_str, sizeof(value_str), SDB_UNQUOTED);
 
-       attr = sdb_store_expr_attrvalue(cmp_attr_data[_i].attr);
+       attr = sdb_memstore_expr_attrvalue(cmp_attr_data[_i].attr);
        fail_unless(attr != NULL,
-                       "sdb_store_expr_attrvalue(%s) = NULL; expected: <expr>",
+                       "sdb_memstore_expr_attrvalue(%s) = NULL; expected: <expr>",
                        cmp_attr_data[_i].attr);
 
-       value = sdb_store_expr_constvalue(&cmp_attr_data[_i].value);
+       value = sdb_memstore_expr_constvalue(&cmp_attr_data[_i].value);
        fail_unless(value != NULL,
-                       "sdb_store_expr_constvalue(%s) = NULL; expected: <expr>",
+                       "sdb_memstore_expr_constvalue(%s) = NULL; expected: <expr>",
                        value_str);
 
        for (j = 0; j < SDB_STATIC_ARRAY_LEN(tests); ++j) {
-               sdb_store_matcher_t *m;
+               sdb_memstore_matcher_t *m;
 
                m = tests[j].matcher(attr, value);
                fail_unless(m != NULL,
-                               "sdb_store_<cond>_matcher() = NULL; expected: <matcher>");
+                               "sdb_memstore_<cond>_matcher() = NULL; expected: <matcher>");
 
-               status = sdb_store_matcher_matches(m, host, /* filter */ NULL);
+               status = sdb_memstore_matcher_matches(m, host, /* filter */ NULL);
                fail_unless(status == tests[j].expected,
-                               "sdb_store_matcher_matches(<attr[%s] %s %s>, "
+                               "sdb_memstore_matcher_matches(<attr[%s] %s %s>, "
                                "<host>, NULL) = %d; expected: %d",
                                cmp_attr_data[_i].attr, op_str[j], value_str,
                                status, tests[j].expected);
@@ -364,49 +364,49 @@ struct {
 
 START_TEST(test_cmp_obj)
 {
-       sdb_store_obj_t *host;
-       sdb_store_expr_t *field;
-       sdb_store_expr_t *value;
+       sdb_memstore_obj_t *host;
+       sdb_memstore_expr_t *field;
+       sdb_memstore_expr_t *value;
        char value_str[1024];
        int status;
        size_t j;
 
        struct {
-               sdb_store_matcher_t *(*matcher)(sdb_store_expr_t *,
-                               sdb_store_expr_t *);
+               sdb_memstore_matcher_t *(*matcher)(sdb_memstore_expr_t *,
+                               sdb_memstore_expr_t *);
                int expected;
        } tests[] = {
-               { sdb_store_lt_matcher, cmp_obj_data[_i].expected_lt },
-               { sdb_store_le_matcher, cmp_obj_data[_i].expected_le },
-               { sdb_store_eq_matcher, cmp_obj_data[_i].expected_eq },
-               { sdb_store_ge_matcher, cmp_obj_data[_i].expected_ge },
-               { sdb_store_gt_matcher, cmp_obj_data[_i].expected_gt },
+               { sdb_memstore_lt_matcher, cmp_obj_data[_i].expected_lt },
+               { sdb_memstore_le_matcher, cmp_obj_data[_i].expected_le },
+               { sdb_memstore_eq_matcher, cmp_obj_data[_i].expected_eq },
+               { sdb_memstore_ge_matcher, cmp_obj_data[_i].expected_ge },
+               { sdb_memstore_gt_matcher, cmp_obj_data[_i].expected_gt },
        };
        char *op_str[] = { "<", "<=", "=", ">=", ">" };
 
        ck_assert(SDB_STATIC_ARRAY_LEN(tests) == SDB_STATIC_ARRAY_LEN(op_str));
 
-       host = sdb_store_get_host(store, cmp_obj_data[_i].host);
+       host = sdb_memstore_get_host(store, cmp_obj_data[_i].host);
        fail_unless(host != NULL,
-                       "sdb_store_get_host(%s) = NULL; expected: <host>",
+                       "sdb_memstore_get_host(%s) = NULL; expected: <host>",
                        cmp_obj_data[_i].host);
 
        sdb_data_format(&cmp_obj_data[_i].value,
                        value_str, sizeof(value_str), SDB_UNQUOTED);
 
-       field = sdb_store_expr_fieldvalue(cmp_obj_data[_i].field);
+       field = sdb_memstore_expr_fieldvalue(cmp_obj_data[_i].field);
        fail_unless(field != NULL,
-                       "sdb_store_expr_fieldvalue(%d) = NULL; "
+                       "sdb_memstore_expr_fieldvalue(%d) = NULL; "
                        "expected: <expr>", cmp_obj_data[_i].field);
 
-       value = sdb_store_expr_constvalue(&cmp_obj_data[_i].value);
+       value = sdb_memstore_expr_constvalue(&cmp_obj_data[_i].value);
        fail_unless(value != NULL,
-                       "sdb_store_expr_constvalue(%s) = NULL; "
+                       "sdb_memstore_expr_constvalue(%s) = NULL; "
                        "expected: <expr>", value_str);
 
        for (j = 0; j < SDB_STATIC_ARRAY_LEN(tests); ++j) {
                char m_str[1024];
-               sdb_store_matcher_t *m;
+               sdb_memstore_matcher_t *m;
 
                snprintf(m_str, sizeof(m_str), "%s %s %s",
                                SDB_FIELD_TO_NAME(cmp_obj_data[_i].field),
@@ -414,11 +414,11 @@ START_TEST(test_cmp_obj)
 
                m = tests[j].matcher(field, value);
                fail_unless(m != NULL,
-                               "sdb_store_<cond>_matcher() = NULL; expected: <matcher>");
+                               "sdb_memstore_<cond>_matcher() = NULL; expected: <matcher>");
 
-               status = sdb_store_matcher_matches(m, host, /* filter */ NULL);
+               status = sdb_memstore_matcher_matches(m, host, /* filter */ NULL);
                fail_unless(status == tests[j].expected,
-                               "sdb_store_matcher_matches(<%s>, <host '%s'>, NULL) = %d; "
+                               "sdb_memstore_matcher_matches(<%s>, <host '%s'>, NULL) = %d; "
                                "expected: %d", m_str, cmp_obj_data[_i].host, status,
                                tests[j].expected);
 
@@ -433,18 +433,18 @@ END_TEST
 
 START_TEST(test_store_match_op)
 {
-       sdb_store_obj_t *obj;
+       sdb_memstore_obj_t *obj;
 
        sdb_data_t d = { SDB_TYPE_STRING, { .string = "a" } };
-       sdb_store_expr_t *e = sdb_store_expr_constvalue(&d);
+       sdb_memstore_expr_t *e = sdb_memstore_expr_constvalue(&d);
 
-       sdb_store_matcher_t *never = sdb_store_isnull_matcher(e);
-       sdb_store_matcher_t *always = sdb_store_inv_matcher(never);
+       sdb_memstore_matcher_t *never = sdb_memstore_isnull_matcher(e);
+       sdb_memstore_matcher_t *always = sdb_memstore_inv_matcher(never);
 
        struct {
                const char *op;
-               sdb_store_matcher_t *left;
-               sdb_store_matcher_t *right;
+               sdb_memstore_matcher_t *left;
+               sdb_memstore_matcher_t *right;
                int expected;
        } golden_data[] = {
                { "OR",  always, always, 1 },
@@ -460,23 +460,23 @@ START_TEST(test_store_match_op)
        int status;
        size_t i;
 
-       obj = sdb_store_get_host(store, "a");
+       obj = sdb_memstore_get_host(store, "a");
 
-       status = sdb_store_matcher_matches(always, obj, /* filter */ NULL);
+       status = sdb_memstore_matcher_matches(always, obj, /* filter */ NULL);
        fail_unless(status == 1,
                        "INTERNAL ERROR: 'always' did not match host");
-       status = sdb_store_matcher_matches(never, obj, /* filter */ NULL);
+       status = sdb_memstore_matcher_matches(never, obj, /* filter */ NULL);
        fail_unless(status == 0,
                        "INTERNAL ERROR: 'never' matches host");
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
-               sdb_store_matcher_t *m;
+               sdb_memstore_matcher_t *m;
 
                if (! strcmp(golden_data[i].op, "OR"))
-                       m = sdb_store_dis_matcher(golden_data[i].left,
+                       m = sdb_memstore_dis_matcher(golden_data[i].left,
                                        golden_data[i].right);
                else if (! strcmp(golden_data[i].op, "AND"))
-                       m = sdb_store_con_matcher(golden_data[i].left,
+                       m = sdb_memstore_con_matcher(golden_data[i].left,
                                        golden_data[i].right);
                else {
                        fail("INTERNAL ERROR: unexpected operator %s", golden_data[i].op);
@@ -486,7 +486,7 @@ START_TEST(test_store_match_op)
 #define TO_NAME(v) (((v) == always) ? "always" \
                : ((v) == never) ? "never" : "<unknown>")
 
-               status = sdb_store_matcher_matches(m, obj, /* filter */ NULL);
+               status = sdb_memstore_matcher_matches(m, obj, /* filter */ NULL);
                fail_unless(status == golden_data[i].expected,
                                "%s(%s, %s, NULL) = %d; expected: %d", golden_data[i].op,
                                TO_NAME(golden_data[i].left), TO_NAME(golden_data[i].right),
@@ -506,18 +506,18 @@ START_TEST(test_store_match_op)
 END_TEST
 
 static int
-scan_cb(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
+scan_cb(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter, void *user_data)
 {
        int *i = user_data;
 
-       if (! sdb_store_matcher_matches(filter, obj, NULL))
+       if (! sdb_memstore_matcher_matches(filter, obj, NULL))
                return 0;
 
        fail_unless(obj != NULL,
-                       "sdb_store_scan callback received NULL obj; expected: "
+                       "sdb_memstore_scan callback received NULL obj; expected: "
                        "<store base obj>");
        fail_unless(i != NULL,
-                       "sdb_store_scan callback received NULL user_data; "
+                       "sdb_memstore_scan callback received NULL user_data; "
                        "expected: <pointer to data>");
 
        ++(*i);
@@ -628,21 +628,21 @@ struct {
 START_TEST(test_scan)
 {
        sdb_strbuf_t *errbuf = sdb_strbuf_create(64);
-       sdb_store_matcher_t *m, *filter = NULL;
+       sdb_memstore_matcher_t *m, *filter = NULL;
        sdb_ast_node_t *ast;
        int check, n;
 
        n = 0;
-       check = sdb_store_scan(store, SDB_HOST,
+       check = sdb_memstore_scan(store, SDB_HOST,
                        /* matcher */ NULL, /* filter */ NULL,
                        scan_cb, &n);
        fail_unless(check == 0,
-                       "sdb_store_scan() = %d; expected: 0", check);
+                       "sdb_memstore_scan() = %d; expected: 0", check);
        fail_unless(n == 3,
-                       "sdb_store_scan called callback %d times; expected: 3", (int)n);
+                       "sdb_memstore_scan called callback %d times; expected: 3", (int)n);
 
        ast = sdb_parser_parse_conditional(SDB_HOST, scan_data[_i].query, -1, errbuf);
-       m = sdb_store_query_prepare_matcher(ast);
+       m = sdb_memstore_query_prepare_matcher(ast);
        sdb_object_deref(SDB_OBJ(ast));
        fail_unless(m != NULL,
                        "sdb_parser_parse_conditional(HOST, %s, -1) = NULL; expected: <ast> "
@@ -651,7 +651,7 @@ START_TEST(test_scan)
 
        if (scan_data[_i].filter) {
                ast = sdb_parser_parse_conditional(SDB_HOST, scan_data[_i].filter, -1, errbuf);
-               filter = sdb_store_query_prepare_matcher(ast);
+               filter = sdb_memstore_query_prepare_matcher(ast);
                sdb_object_deref(SDB_OBJ(ast));
                fail_unless(filter != NULL,
                                "sdb_parser_parse_conditional(HOST, %s, -1) = NULL; "
@@ -660,9 +660,9 @@ START_TEST(test_scan)
        }
 
        n = 0;
-       sdb_store_scan(store, SDB_HOST, m, filter, scan_cb, &n);
+       sdb_memstore_scan(store, SDB_HOST, m, filter, scan_cb, &n);
        fail_unless(n == scan_data[_i].expected,
-                       "sdb_store_scan(HOST, matcher{%s}, filter{%s}) "
+                       "sdb_memstore_scan(HOST, matcher{%s}, filter{%s}) "
                        "found %d hosts; expected: %d", scan_data[_i].query,
                        scan_data[_i].filter, n, scan_data[_i].expected);
 
index 1d524b6070bb966ca8c7ae74b3963fd3bd00281b..50d041ece884464501cd1768c2b6a990216a3662 100644 (file)
 
 #include "core/plugin.h"
 #include "core/store.h"
-#include "core/store-private.h"
+#include "core/memstore-private.h"
 #include "testutils.h"
 
 #include <check.h>
 #include <string.h>
 #include <strings.h>
 
-static sdb_store_t *store;
+static sdb_memstore_t *store;
 
 static void
 init(void)
 {
-       store = sdb_store_create();
+       store = sdb_memstore_create();
        ck_assert(store != NULL);
 }
 
@@ -52,41 +52,41 @@ populate(void)
 {
        sdb_data_t datum;
 
-       sdb_store_host(store, "h1", 1);
-       sdb_store_host(store, "h2", 3);
+       sdb_memstore_host(store, "h1", 1, 0);
+       sdb_memstore_host(store, "h2", 3, 0);
 
        datum.type = SDB_TYPE_STRING;
        datum.data.string = "v1";
-       sdb_store_attribute(store, "h1", "k1", &datum, 1);
+       sdb_memstore_attribute(store, "h1", "k1", &datum, 1, 0);
        datum.data.string = "v2";
-       sdb_store_attribute(store, "h1", "k2", &datum, 2);
+       sdb_memstore_attribute(store, "h1", "k2", &datum, 2, 0);
        datum.data.string = "v3";
-       sdb_store_attribute(store, "h1", "k3", &datum, 2);
+       sdb_memstore_attribute(store, "h1", "k3", &datum, 2, 0);
 
        /* make sure that older updates don't overwrite existing values */
        datum.data.string = "fail";
-       sdb_store_attribute(store, "h1", "k2", &datum, 1);
-       sdb_store_attribute(store, "h1", "k3", &datum, 2);
+       sdb_memstore_attribute(store, "h1", "k2", &datum, 1, 0);
+       sdb_memstore_attribute(store, "h1", "k3", &datum, 2, 0);
 
-       sdb_store_metric(store, "h1", "m1", /* store */ NULL, 2);
-       sdb_store_metric(store, "h1", "m2", /* store */ NULL, 1);
-       sdb_store_metric(store, "h2", "m1", /* store */ NULL, 1);
+       sdb_memstore_metric(store, "h1", "m1", /* store */ NULL, 2, 0);
+       sdb_memstore_metric(store, "h1", "m2", /* store */ NULL, 1, 0);
+       sdb_memstore_metric(store, "h2", "m1", /* store */ NULL, 1, 0);
 
-       sdb_store_service(store, "h2", "s1", 1);
-       sdb_store_service(store, "h2", "s2", 2);
+       sdb_memstore_service(store, "h2", "s1", 1, 0);
+       sdb_memstore_service(store, "h2", "s2", 2, 0);
 
        datum.type = SDB_TYPE_INTEGER;
        datum.data.integer = 42;
-       sdb_store_metric_attr(store, "h1", "m1", "k3", &datum, 2);
+       sdb_memstore_metric_attr(store, "h1", "m1", "k3", &datum, 2, 0);
 
        datum.data.integer = 123;
-       sdb_store_service_attr(store, "h2", "s2", "k1", &datum, 2);
+       sdb_memstore_service_attr(store, "h2", "s2", "k1", &datum, 2, 0);
        datum.data.integer = 4711;
-       sdb_store_service_attr(store, "h2", "s2", "k2", &datum, 1);
+       sdb_memstore_service_attr(store, "h2", "s2", "k2", &datum, 1, 0);
 
        /* don't overwrite k1 */
        datum.data.integer = 666;
-       sdb_store_service_attr(store, "h2", "s2", "k1", &datum, 2);
+       sdb_memstore_service_attr(store, "h2", "s2", "k1", &datum, 2, 0);
 } /* populate */
 
 static void
@@ -105,21 +105,17 @@ START_TEST(test_store_host)
        } golden_data[] = {
                { "a", 1, 0 },
                { "a", 2, 0 },
-               { "a", 1, 1 },
                { "b", 1, 0 },
-               { "b", 1, 1 },
-               { "A", 1, 1 }, /* case-insensitive */
-               { "A", 3, 0 },
        };
 
        struct {
                const char *name;
                bool        have;
        } golden_hosts[] = {
-               { "a", 1 == 1 },
-               { "b", 1 == 1 },
-               { "c", 0 == 1 },
-               { "A", 1 == 1 },
+               { "a", 1 },
+               { "b", 1 },
+               { "c", 0 },
+               { "A", 1 },
        };
 
        size_t i;
@@ -127,20 +123,20 @@ START_TEST(test_store_host)
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
                int status;
 
-               status = sdb_store_host(store, golden_data[i].name,
-                               golden_data[i].last_update);
+               status = sdb_memstore_host(store, golden_data[i].name,
+                               golden_data[i].last_update, 0);
                fail_unless(status == golden_data[i].expected,
-                               "sdb_store_host(%s, %d) = %d; expected: %d",
+                               "sdb_memstore_host(%s, %d, 0) = %d; expected: %d",
                                golden_data[i].name, (int)golden_data[i].last_update,
                                status, golden_data[i].expected);
        }
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
-               sdb_store_obj_t *have;
+               sdb_memstore_obj_t *have;
 
-               have = sdb_store_get_host(store, golden_hosts[i].name);
+               have = sdb_memstore_get_host(store, golden_hosts[i].name);
                fail_unless((have != NULL) == golden_hosts[i].have,
-                               "sdb_store_get_host(%s) = %p; expected: %s",
+                               "sdb_memstore_get_host(%s) = %p; expected: %s",
                                golden_hosts[i].name, have,
                                golden_hosts[i].have ? "<host>" : "NULL");
                sdb_object_deref(SDB_OBJ(have));
@@ -155,36 +151,36 @@ START_TEST(test_store_get_host)
        size_t i;
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
-               int status = sdb_store_host(store, golden_hosts[i], 1);
+               int status = sdb_memstore_host(store, golden_hosts[i], 1, 0);
                fail_unless(status >= 0,
-                               "sdb_store_host(%s) = %d; expected: >=0",
+                               "sdb_memstore_host(%s) = %d; expected: >=0",
                                golden_hosts[i], status);
        }
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
-               sdb_store_obj_t *sobj1, *sobj2;
+               sdb_memstore_obj_t *sobj1, *sobj2;
                int ref_cnt;
 
-               sobj1 = sdb_store_get_host(store, golden_hosts[i]);
+               sobj1 = sdb_memstore_get_host(store, golden_hosts[i]);
                fail_unless(sobj1 != NULL,
-                               "sdb_store_get_host(%s) = NULL; expected: <host>",
+                               "sdb_memstore_get_host(%s) = NULL; expected: <host>",
                                golden_hosts[i]);
                ref_cnt = SDB_OBJ(sobj1)->ref_cnt;
 
                fail_unless(ref_cnt > 1,
-                               "sdb_store_get_host(%s) did not increment ref count: "
+                               "sdb_memstore_get_host(%s) did not increment ref count: "
                                "got: %d; expected: >1", golden_hosts[i], ref_cnt);
 
-               sobj2 = sdb_store_get_host(store, golden_hosts[i]);
+               sobj2 = sdb_memstore_get_host(store, golden_hosts[i]);
                fail_unless(sobj2 != NULL,
-                               "sdb_store_get_host(%s) = NULL; expected: <host>",
+                               "sdb_memstore_get_host(%s) = NULL; expected: <host>",
                                golden_hosts[i]);
 
                fail_unless(sobj1 == sobj2,
-                               "sdb_store_get_host(%s) returned different objects "
+                               "sdb_memstore_get_host(%s) returned different objects "
                                "in successive calls", golden_hosts[i]);
                fail_unless(SDB_OBJ(sobj2)->ref_cnt == ref_cnt + 1,
-                               "sdb_store_get_hosts(%s) did not increment ref count "
+                               "sdb_memstore_get_hosts(%s) did not increment ref count "
                                "(first call: %d; second call: %d)",
                                golden_hosts[i], ref_cnt, SDB_OBJ(sobj2)->ref_cnt);
 
@@ -192,10 +188,10 @@ START_TEST(test_store_get_host)
                sdb_object_deref(SDB_OBJ(sobj2));
        }
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(unknown_hosts); ++i) {
-               sdb_store_obj_t *sobj;
+               sdb_memstore_obj_t *sobj;
 
-               sobj = sdb_store_get_host(store, unknown_hosts[i]);
-               fail_unless(!sobj, "sdb_store_get_host(%s) = <host:%s>; expected: NULL",
+               sobj = sdb_memstore_get_host(store, unknown_hosts[i]);
+               fail_unless(!sobj, "sdb_memstore_get_host(%s) = <host:%s>; expected: NULL",
                                unknown_hosts[i], sobj ? SDB_OBJ(sobj)->name : "NULL");
        }
 }
@@ -214,16 +210,14 @@ START_TEST(test_store_attr)
                { "k", "k",  "v",  1, -1 }, /* retry to ensure the host is not created */
                { "l", "k1", "v1", 1,  0 },
                { "l", "k1", "v2", 2,  0 },
-               { "l", "k1", "v3", 2,  1 },
                { "l", "k2", "v1", 1,  0 },
                { "m", "k",  "v1", 1,  0 },
-               { "m", "k",  "v2", 1,  1 },
        };
 
        size_t i;
 
-       sdb_store_host(store, "l", 1);
-       sdb_store_host(store, "m", 1);
+       sdb_memstore_host(store, "l", 1, 0);
+       sdb_memstore_host(store, "m", 1, 0);
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
                sdb_data_t datum;
                int status;
@@ -232,13 +226,13 @@ START_TEST(test_store_attr)
                datum.type = SDB_TYPE_STRING;
                datum.data.string = golden_data[i].value;
 
-               status = sdb_store_attribute(store, golden_data[i].host,
+               status = sdb_memstore_attribute(store, golden_data[i].host,
                                golden_data[i].key, &datum,
-                               golden_data[i].last_update);
+                               golden_data[i].last_update, 0);
                fail_unless(status == golden_data[i].expected,
-                               "sdb_store_attribute(%s, %s, %s, %d) = %d; expected: %d",
+                               "sdb_memstore_attribute(%s, %s, %s, %d) = %d; expected: %d",
                                golden_data[i].host, golden_data[i].key, golden_data[i].value,
-                               golden_data[i].last_update, status, golden_data[i].expected);
+                               golden_data[i].last_update, status, golden_data[i].expected, 0);
        }
 }
 END_TEST
@@ -261,13 +255,11 @@ START_TEST(test_store_metric)
                { "l", "m1", NULL,    1,  0 },
                { "l", "m1", &store1, 2,  0 },
                { "l", "m1", &store1, 3,  0 },
-               { "l", "m1", NULL,    3,  1 },
                { "l", "m2", &store1, 1,  0 },
                { "l", "m2", &store2, 2,  0 },
                { "l", "m2", NULL,    3,  0 },
                { "m", "m",  &store1, 1,  0 },
                { "m", "m",  NULL,    2,  0 },
-               { "m", "m",  NULL,    2,  1 },
                { "m", "m",  &store1, 3,  0 },
                { "m", "m",  &store2, 4,  0 },
                { "m", "m",  NULL,    5,  0 },
@@ -275,16 +267,16 @@ START_TEST(test_store_metric)
 
        size_t i;
 
-       sdb_store_host(store, "m", 1);
-       sdb_store_host(store, "l", 1);
+       sdb_memstore_host(store, "m", 1, 0);
+       sdb_memstore_host(store, "l", 1, 0);
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
                int status;
 
-               status = sdb_store_metric(store, golden_data[i].host,
+               status = sdb_memstore_metric(store, golden_data[i].host,
                                golden_data[i].metric, golden_data[i].store,
-                               golden_data[i].last_update);
+                               golden_data[i].last_update, 0);
                fail_unless(status == golden_data[i].expected,
-                               "sdb_store_metric(%s, %s, %p, %d) = %d; expected: %d",
+                               "sdb_memstore_metric(%s, %s, %p, %d, 0) = %d; expected: %d",
                                golden_data[i].host, golden_data[i].metric,
                                golden_data[i].store, golden_data[i].last_update,
                                status, golden_data[i].expected);
@@ -309,30 +301,28 @@ START_TEST(test_store_metric_attr)
                /* retry, it should still fail */
                { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
                { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
-               { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
                { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2,  0 },
                { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
-               { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
                { "l", "m2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
                { "m", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
        };
 
        size_t i;
 
-       sdb_store_host(store, "m", 1);
-       sdb_store_host(store, "l", 1);
-       sdb_store_metric(store, "m", "m1", NULL, 1);
-       sdb_store_metric(store, "l", "m1", NULL, 1);
-       sdb_store_metric(store, "l", "m2", NULL, 1);
+       sdb_memstore_host(store, "m", 1, 0);
+       sdb_memstore_host(store, "l", 1, 0);
+       sdb_memstore_metric(store, "m", "m1", NULL, 1, 0);
+       sdb_memstore_metric(store, "l", "m1", NULL, 1, 0);
+       sdb_memstore_metric(store, "l", "m2", NULL, 1, 0);
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
                int status;
 
-               status = sdb_store_metric_attr(store, golden_data[i].host,
+               status = sdb_memstore_metric_attr(store, golden_data[i].host,
                                golden_data[i].metric, golden_data[i].attr,
-                               &golden_data[i].value, golden_data[i].last_update);
+                               &golden_data[i].value, golden_data[i].last_update, 0);
                fail_unless(status == golden_data[i].expected,
-                               "sdb_store_metric_attr(%s, %s, %s, %d, %d) = %d; "
+                               "sdb_memstore_metric_attr(%s, %s, %s, %d, %d, 0) = %d; "
                                "expected: %d", golden_data[i].host, golden_data[i].metric,
                                golden_data[i].attr, golden_data[i].value.data.integer,
                                golden_data[i].last_update, status, golden_data[i].expected);
@@ -352,23 +342,21 @@ START_TEST(test_store_service)
                { "k", "s",  1, -1 }, /* retry to ensure the host is not created */
                { "l", "s1", 1,  0 },
                { "l", "s1", 2,  0 },
-               { "l", "s1", 2,  1 },
                { "l", "s2", 1,  0 },
                { "m", "s",  1,  0 },
-               { "m", "s",  1,  1 },
        };
 
        size_t i;
 
-       sdb_store_host(store, "m", 1);
-       sdb_store_host(store, "l", 1);
+       sdb_memstore_host(store, "m", 1, 0);
+       sdb_memstore_host(store, "l", 1, 0);
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
                int status;
 
-               status = sdb_store_service(store, golden_data[i].host,
-                               golden_data[i].svc, golden_data[i].last_update);
+               status = sdb_memstore_service(store, golden_data[i].host,
+                               golden_data[i].svc, golden_data[i].last_update, 0);
                fail_unless(status == golden_data[i].expected,
-                               "sdb_store_service(%s, %s, %d) = %d; expected: %d",
+                               "sdb_memstore_service(%s, %s, %d, 0) = %d; expected: %d",
                                golden_data[i].host, golden_data[i].svc,
                                golden_data[i].last_update, status, golden_data[i].expected);
        }
@@ -392,30 +380,28 @@ START_TEST(test_store_service_attr)
                /* retry, it should still fail */
                { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
                { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
-               { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
                { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2,  0 },
                { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
-               { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
                { "l", "s2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
                { "m", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
        };
 
        size_t i;
 
-       sdb_store_host(store, "m", 1);
-       sdb_store_host(store, "l", 1);
-       sdb_store_service(store, "m", "s1", 1);
-       sdb_store_service(store, "l", "s1", 1);
-       sdb_store_service(store, "l", "s2", 1);
+       sdb_memstore_host(store, "m", 1, 0);
+       sdb_memstore_host(store, "l", 1, 0);
+       sdb_memstore_service(store, "m", "s1", 1, 0);
+       sdb_memstore_service(store, "l", "s1", 1, 0);
+       sdb_memstore_service(store, "l", "s2", 1, 0);
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
                int status;
 
-               status = sdb_store_service_attr(store, golden_data[i].host,
+               status = sdb_memstore_service_attr(store, golden_data[i].host,
                                golden_data[i].svc, golden_data[i].attr,
-                               &golden_data[i].value, golden_data[i].last_update);
+                               &golden_data[i].value, golden_data[i].last_update, 0);
                fail_unless(status == golden_data[i].expected,
-                               "sdb_store_service_attr(%s, %s, %s, %d, %d) = %d; "
+                               "sdb_memstore_service_attr(%s, %s, %s, %d, %d, 0) = %d; "
                                "expected: %d", golden_data[i].host, golden_data[i].svc,
                                golden_data[i].attr, golden_data[i].value.data.integer,
                                golden_data[i].last_update, status, golden_data[i].expected);
@@ -471,37 +457,35 @@ static struct {
        (obj) ? SDB_OBJ(obj)->name : ""
 START_TEST(test_get_field)
 {
-       sdb_store_obj_t *obj = NULL;
+       sdb_memstore_obj_t *obj = NULL;
        sdb_data_t value = SDB_DATA_INIT;
        char value_str[128], expected_value_str[128];
        sdb_time_t now = sdb_gettime();
        int check;
 
-       sdb_store_host(store, "host", 10);
-       sdb_store_host(store, "host", 20);
-       sdb_store_attribute(store, "host", "attr", &get_field_data[_i].value, 10);
-       sdb_store_attribute(store, "host", "attr", &get_field_data[_i].value, 20);
+       sdb_memstore_host(store, "host", 20, 10);
+       sdb_memstore_attribute(store, "host", "attr", &get_field_data[_i].value, 20, 10);
 
        if (get_field_data[_i].hostname) {
-               obj = sdb_store_get_host(store, get_field_data[_i].hostname);
+               obj = sdb_memstore_get_host(store, get_field_data[_i].hostname);
                ck_assert(obj != NULL);
 
                if (get_field_data[_i].attr) {
-                       sdb_store_obj_t *tmp = sdb_store_get_child(obj,
+                       sdb_memstore_obj_t *tmp = sdb_memstore_get_child(obj,
                                        SDB_ATTRIBUTE, get_field_data[_i].attr);
                        sdb_object_deref(SDB_OBJ(obj));
                        obj = tmp;
                }
        }
 
-       check = sdb_store_get_field(obj, get_field_data[_i].field, NULL);
+       check = sdb_memstore_get_field(obj, get_field_data[_i].field, NULL);
        fail_unless(check == get_field_data[_i].expected,
-                       "sdb_store_get_field(%s %s, %s, NULL) = %d; expected: %d",
+                       "sdb_memstore_get_field(%s %s, %s, NULL) = %d; expected: %d",
                        OBJ_NAME(obj), SDB_FIELD_TO_NAME(get_field_data[_i].field),
                        check, get_field_data[_i].expected);
-       check = sdb_store_get_field(obj, get_field_data[_i].field, &value);
+       check = sdb_memstore_get_field(obj, get_field_data[_i].field, &value);
        fail_unless(check == get_field_data[_i].expected,
-                       "sdb_store_get_field(%s %s, %s, <value>) = %d; expected: %d",
+                       "sdb_memstore_get_field(%s %s, %s, <value>) = %d; expected: %d",
                        OBJ_NAME(obj), SDB_FIELD_TO_NAME(get_field_data[_i].field),
                        check, get_field_data[_i].expected);
 
@@ -522,14 +506,14 @@ START_TEST(test_get_field)
        if (get_field_data[_i].field == SDB_FIELD_AGE) {
                fail_unless((value.type == SDB_TYPE_DATETIME)
                                && (value.data.datetime >= now),
-                               "sdb_store_get_field(%s %s, %s, <value>) "
+                               "sdb_memstore_get_field(%s %s, %s, <value>) "
                                "returned value %s; expected >=%s", OBJ_NAME(obj),
                                SDB_FIELD_TO_NAME(get_field_data[_i].field),
                                value_str, expected_value_str);
        }
        else {
                fail_unless(! sdb_data_cmp(&value, &get_field_data[_i].value),
-                               "sdb_store_get_field(%s %s, %s, <value>) "
+                               "sdb_memstore_get_field(%s %s, %s, <value>) "
                                "returned value %s; expected %s", OBJ_NAME(obj),
                                SDB_FIELD_TO_NAME(get_field_data[_i].field),
                                value_str, expected_value_str);
@@ -544,28 +528,34 @@ START_TEST(test_get_child)
 {
        struct {
                const char *host;
+               int parent_type;
+               const char *parent;
                const char *name;
                int type;
                int expected;
        } golden_data[] = {
-               { "h1", NULL, SDB_HOST,       0 },
-               { "h1", NULL, SDB_SERVICE,   -1 },
-               { "h1", NULL, SDB_METRIC,    -1 },
-               { "h1", NULL, SDB_ATTRIBUTE, -1 },
-               { "h2", NULL, SDB_HOST,       0 },
-               { "h2", NULL, SDB_SERVICE,   -1 },
-               { "h2", NULL, SDB_METRIC,    -1 },
-               { "h2", NULL, SDB_ATTRIBUTE, -1 },
-               { "h3", NULL, SDB_HOST,      -1 },
-               { "h1", "k1", SDB_ATTRIBUTE,  0 },
-               { "h1", "x1", SDB_ATTRIBUTE, -1 },
-               { "h2", "k1", SDB_ATTRIBUTE, -1 },
-               { "h1", "k1", SDB_SERVICE,   -1 },
-               { "h1", "k1", SDB_METRIC,    -1 },
-               { "h1", "s1", SDB_SERVICE,   -1 },
-               { "h2", "s1", SDB_SERVICE,    0 },
-               { "h1", "m2", SDB_METRIC,     0 },
-               { "h2", "m2", SDB_METRIC,    -1 },
+               { "h1",          -1, NULL, NULL, SDB_HOST,       0 },
+               { "h1",          -1, NULL, NULL, SDB_SERVICE,   -1 },
+               { "h1",          -1, NULL, NULL, SDB_METRIC,    -1 },
+               { "h1",          -1, NULL, NULL, SDB_ATTRIBUTE, -1 },
+               { "h2",          -1, NULL, NULL, SDB_HOST,       0 },
+               { "h2",          -1, NULL, NULL, SDB_SERVICE,   -1 },
+               { "h2",          -1, NULL, NULL, SDB_METRIC,    -1 },
+               { "h2",          -1, NULL, NULL, SDB_ATTRIBUTE, -1 },
+               { "h3",          -1, NULL, NULL, SDB_HOST,      -1 },
+               { "h1",          -1, NULL, "k1", SDB_ATTRIBUTE,  0 },
+               { "h1",          -1, NULL, "x1", SDB_ATTRIBUTE, -1 },
+               { "h2",          -1, NULL, "k1", SDB_ATTRIBUTE, -1 },
+               { "h1",          -1, NULL, "k1", SDB_SERVICE,   -1 },
+               { "h1",          -1, NULL, "k1", SDB_METRIC,    -1 },
+               { "h1",          -1, NULL, "s1", SDB_SERVICE,   -1 },
+               { "h2",          -1, NULL, "s1", SDB_SERVICE,    0 },
+               { "h1",          -1, NULL, "m2", SDB_METRIC,     0 },
+               { "h2",          -1, NULL, "m2", SDB_METRIC,    -1 },
+               { "h1",  SDB_METRIC, "m1", "k3", SDB_ATTRIBUTE,  0 },
+               { "h1",  SDB_METRIC, "m1", "x1", SDB_ATTRIBUTE, -1 },
+               { "h2", SDB_SERVICE, "s2", "k1", SDB_ATTRIBUTE,  0 },
+               { "h2", SDB_SERVICE, "s2", "x1", SDB_ATTRIBUTE, -1 },
        };
 
        size_t i;
@@ -573,35 +563,42 @@ START_TEST(test_get_child)
        populate();
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
-               sdb_store_obj_t *obj;
+               sdb_memstore_obj_t *obj;
                const char *expected_name = golden_data[i].host;
 
-               obj = sdb_store_get_host(store, golden_data[i].host);
+               obj = sdb_memstore_get_host(store, golden_data[i].host);
+               if (golden_data[i].parent) {
+                       sdb_memstore_obj_t *o;
+                       o = sdb_memstore_get_child(obj,
+                                       golden_data[i].parent_type, golden_data[i].parent);
+                       sdb_object_deref(SDB_OBJ(obj));
+                       obj = o;
+               }
                if (golden_data[i].expected && (golden_data[i].type == SDB_HOST))
                        fail_unless(obj == NULL,
-                                       "sdb_store_get_host(%s) = %p; expected: NULL",
+                                       "sdb_memstore_get_host(%s) = %p; expected: NULL",
                                        golden_data[i].host, obj);
                else
                        fail_unless(obj != NULL,
-                                       "sdb_store_get_host(%s) = NULL; expected: <host>",
+                                       "sdb_memstore_get_host(%s) = NULL; expected: <host>",
                                        golden_data[i].host);
 
                if (golden_data[i].type != SDB_HOST) {
-                       sdb_store_obj_t *tmp;
+                       sdb_memstore_obj_t *tmp;
 
                        expected_name = golden_data[i].name;
 
-                       tmp = sdb_store_get_child(obj,
+                       tmp = sdb_memstore_get_child(obj,
                                        golden_data[i].type, golden_data[i].name);
                        if (golden_data[i].expected)
                                fail_unless(tmp == NULL,
-                                               "sdb_store_get_child(<%s>, %s, %s) = %p; "
+                                               "sdb_memstore_get_child(<%s>, %s, %s) = %p; "
                                                "expected: NULL", golden_data[i].host,
                                                SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
                                                golden_data[i].name, tmp);
                        else
                                fail_unless(tmp != NULL,
-                                               "sdb_store_get_child(<%s>, %s, %s) = NULL; "
+                                               "sdb_memstore_get_child(<%s>, %s, %s) = NULL; "
                                                "expected: <obj>", golden_data[i].host,
                                                SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
                                                golden_data[i].name);
@@ -614,12 +611,12 @@ START_TEST(test_get_child)
                        continue;
 
                fail_unless(obj->type == golden_data[i].type,
-                               "sdb_store_get_<%s>(%s, %s) returned object of type %d; "
+                               "sdb_memstore_get_<%s>(%s, %s) returned object of type %d; "
                                "expected: %d", SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
                                golden_data[i].host, golden_data[i].name, obj->type,
                                golden_data[i].type);
                fail_unless(! strcasecmp(SDB_OBJ(obj)->name, expected_name),
-                               "sdb_store_get_<%s>(%s, %s) returned object named '%s'; "
+                               "sdb_memstore_get_<%s>(%s, %s) returned object named '%s'; "
                                "expected: '%s'", SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
                                golden_data[i].host, golden_data[i].name, SDB_OBJ(obj)->name,
                                expected_name);
@@ -629,75 +626,78 @@ START_TEST(test_get_child)
 }
 END_TEST
 
+/* TODO: move these tests into generic store tests */
+#if 0
 START_TEST(test_interval)
 {
-       sdb_store_obj_t *host;
+       sdb_memstore_obj_t *host;
 
        /* 10 us interval */
-       sdb_store_host(store, "host", 10);
-       sdb_store_host(store, "host", 20);
-       sdb_store_host(store, "host", 30);
-       sdb_store_host(store, "host", 40);
+       sdb_memstore_host(store, "host", 10);
+       sdb_memstore_host(store, "host", 20);
+       sdb_memstore_host(store, "host", 30);
+       sdb_memstore_host(store, "host", 40);
 
-       host = sdb_store_get_host(store, "host");
+       host = sdb_memstore_get_host(store, "host");
        fail_unless(host != NULL,
                        "INTERNAL ERROR: store doesn't have host after adding it");
 
        fail_unless(host->interval == 10,
-                       "sdb_store_host() did not calculate interval correctly: "
+                       "sdb_memstore_host() did not calculate interval correctly: "
                        "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 10);
 
        /* multiple updates for the same timestamp don't modify the interval */
-       sdb_store_host(store, "host", 40);
-       sdb_store_host(store, "host", 40);
-       sdb_store_host(store, "host", 40);
-       sdb_store_host(store, "host", 40);
+       sdb_memstore_host(store, "host", 40);
+       sdb_memstore_host(store, "host", 40);
+       sdb_memstore_host(store, "host", 40);
+       sdb_memstore_host(store, "host", 40);
 
        fail_unless(host->interval == 10,
-                       "sdb_store_host() changed interval when doing multiple updates "
+                       "sdb_memstore_host() changed interval when doing multiple updates "
                        "using the same timestamp; got: %"PRIsdbTIME"; "
                        "expected: %"PRIsdbTIME, host->interval, 10);
 
        /* multiple updates using an timestamp don't modify the interval */
-       sdb_store_host(store, "host", 20);
-       sdb_store_host(store, "host", 20);
-       sdb_store_host(store, "host", 20);
-       sdb_store_host(store, "host", 20);
+       sdb_memstore_host(store, "host", 20);
+       sdb_memstore_host(store, "host", 20);
+       sdb_memstore_host(store, "host", 20);
+       sdb_memstore_host(store, "host", 20);
 
        fail_unless(host->interval == 10,
-                       "sdb_store_host() changed interval when doing multiple updates "
+                       "sdb_memstore_host() changed interval when doing multiple updates "
                        "using an old timestamp; got: %"PRIsdbTIME"; expected: %"PRIsdbTIME,
                        host->interval, 10);
 
        /* new interval: 20 us */
-       sdb_store_host(store, "host", 60);
+       sdb_memstore_host(store, "host", 60);
        fail_unless(host->interval == 11,
-                       "sdb_store_host() did not calculate interval correctly: "
+                       "sdb_memstore_host() did not calculate interval correctly: "
                        "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
 
        /* new interval: 40 us */
-       sdb_store_host(store, "host", 100);
+       sdb_memstore_host(store, "host", 100);
        fail_unless(host->interval == 13,
-                       "sdb_store_host() did not calculate interval correctly: "
+                       "sdb_memstore_host() did not calculate interval correctly: "
                        "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
 
        sdb_object_deref(SDB_OBJ(host));
 }
 END_TEST
+#endif
 
 static int
-scan_count(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
+scan_count(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter, void *user_data)
 {
        intptr_t *i = user_data;
 
-       if (! sdb_store_matcher_matches(filter, obj, NULL))
+       if (! sdb_memstore_matcher_matches(filter, obj, NULL))
                return 0;
 
        fail_unless(obj != NULL,
-                       "sdb_store_scan callback received NULL obj; expected: "
+                       "sdb_memstore_scan callback received NULL obj; expected: "
                        "<store base obj>");
        fail_unless(i != NULL,
-                       "sdb_store_scan callback received NULL user_data; "
+                       "sdb_memstore_scan callback received NULL user_data; "
                        "expected: <pointer to data>");
 
        ++(*i);
@@ -705,18 +705,18 @@ scan_count(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
 } /* scan_count */
 
 static int
-scan_error(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
+scan_error(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter, void *user_data)
 {
        intptr_t *i = user_data;
 
-       if (! sdb_store_matcher_matches(filter, obj, NULL))
+       if (! sdb_memstore_matcher_matches(filter, obj, NULL))
                return 0;
 
        fail_unless(obj != NULL,
-                       "sdb_store_scan callback received NULL obj; expected: "
+                       "sdb_memstore_scan callback received NULL obj; expected: "
                        "<store base obj>");
        fail_unless(i != NULL,
-                       "sdb_store_scan callback received NULL user_data; "
+                       "sdb_memstore_scan callback received NULL user_data; "
                        "expected: <pointer to data>");
 
        ++(*i);
@@ -729,49 +729,49 @@ START_TEST(test_scan)
        int check;
 
        /* empty store */
-       check = sdb_store_scan(store, SDB_HOST, /* m, filter = */ NULL, NULL,
+       check = sdb_memstore_scan(store, SDB_HOST, /* m, filter = */ NULL, NULL,
                        scan_count, &i);
        fail_unless(check == 0,
-                       "sdb_store_scan(HOST), empty store = %d; expected: 0", check);
+                       "sdb_memstore_scan(HOST), empty store = %d; expected: 0", check);
        fail_unless(i == 0,
-                       "sdb_store_scan(HOST) called callback %d times; "
+                       "sdb_memstore_scan(HOST) called callback %d times; "
                        "expected: 0", (int)i);
 
        populate();
 
-       check = sdb_store_scan(store, SDB_HOST, /* m, filter = */ NULL, NULL,
+       check = sdb_memstore_scan(store, SDB_HOST, /* m, filter = */ NULL, NULL,
                        scan_count, &i);
        fail_unless(check == 0,
-                       "sdb_store_scan(HOST) = %d; expected: 0", check);
+                       "sdb_memstore_scan(HOST) = %d; expected: 0", check);
        fail_unless(i == 2,
-                       "sdb_store_scan(HOST) called callback %d times; "
+                       "sdb_memstore_scan(HOST) called callback %d times; "
                        "expected: 1", (int)i);
 
        i = 0;
-       check = sdb_store_scan(store, SDB_HOST, /* m, filter = */ NULL, NULL,
+       check = sdb_memstore_scan(store, SDB_HOST, /* m, filter = */ NULL, NULL,
                        scan_error, &i);
        fail_unless(check == -1,
-                       "sdb_store_scan(HOST), error callback = %d; expected: -1", check);
+                       "sdb_memstore_scan(HOST), error callback = %d; expected: -1", check);
        fail_unless(i == 1,
-                       "sdb_store_scan(HOST) called callback %d times "
+                       "sdb_memstore_scan(HOST) called callback %d times "
                        "(callback returned error); expected: 1", (int)i);
 
        i = 0;
-       check = sdb_store_scan(store, SDB_SERVICE, /* m, filter = */ NULL, NULL,
+       check = sdb_memstore_scan(store, SDB_SERVICE, /* m, filter = */ NULL, NULL,
                        scan_count, &i);
        fail_unless(check == 0,
-                       "sdb_store_scan(SERVICE) = %d; expected: 0", check);
+                       "sdb_memstore_scan(SERVICE) = %d; expected: 0", check);
        fail_unless(i == 2,
-                       "sdb_store_scan(SERVICE) called callback %d times; "
+                       "sdb_memstore_scan(SERVICE) called callback %d times; "
                        "expected: 2", (int)i);
 
        i = 0;
-       check = sdb_store_scan(store, SDB_METRIC, /* m, filter = */ NULL, NULL,
+       check = sdb_memstore_scan(store, SDB_METRIC, /* m, filter = */ NULL, NULL,
                        scan_count, &i);
        fail_unless(check == 0,
-                       "sdb_store_scan(METRIC) = %d; expected: 0", check);
+                       "sdb_memstore_scan(METRIC) = %d; expected: 0", check);
        fail_unless(i == 3,
-                       "sdb_store_scan(METRIC) called callback %d times; "
+                       "sdb_memstore_scan(METRIC) called callback %d times; "
                        "expected: 3", (int)i);
 }
 END_TEST
@@ -789,7 +789,6 @@ TEST_MAIN("core::store")
        tcase_add_test(tc, test_store_service_attr);
        TC_ADD_LOOP_TEST(tc, get_field);
        tcase_add_test(tc, test_get_child);
-       tcase_add_test(tc, test_interval);
        tcase_add_test(tc, test_scan);
        ADD_TCASE(tc);
 }
index de8ab806843a34be4942f78939864dc275d06f1c..e81bb5841e4fe28f31431367fc068fb5af351067 100644 (file)
@@ -29,6 +29,7 @@
 #      include "config.h"
 #endif
 
+#include "core/memstore.h"
 #include "core/plugin.h"
 #include "frontend/connection.h"
 #include "frontend/connection-private.h"
 static void
 populate(void)
 {
-       sdb_store_t *store;
+       sdb_memstore_t *store;
        sdb_data_t datum;
 
        /* the frontend accesses the store via the plugin API */
-       store = sdb_store_create();
+       store = sdb_memstore_create();
        ck_assert(store != NULL);
        ck_assert(sdb_plugin_register_writer("test-writer",
-                               &sdb_store_writer, SDB_OBJ(store)) == 0);
+                               &sdb_memstore_writer, SDB_OBJ(store)) == 0);
        ck_assert(sdb_plugin_register_reader("test-reader",
-                               &sdb_store_reader, SDB_OBJ(store)) == 0);
+                               &sdb_memstore_reader, SDB_OBJ(store)) == 0);
        sdb_object_deref(SDB_OBJ(store));
 
        /* populate the store */
@@ -367,391 +368,390 @@ static struct {
        int query_len;
        int expected;
        uint32_t code;
-       size_t len;
        uint32_t type;
        const char *data;
 } query_data[] = {
        /* hosts */
        {
                SDB_CONNECTION_QUERY, "LIST hosts", -1,
-               0, SDB_CONNECTION_DATA, 205, SDB_CONNECTION_LIST,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LIST,
                "["HOST_H1_LISTING","HOST_H2_LISTING"]",
        },
        {
                SDB_CONNECTION_LIST, "\0\0\0\1", 4,
-               0, SDB_CONNECTION_DATA, 205, SDB_CONNECTION_LIST,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LIST,
                "["HOST_H1_LISTING","HOST_H2_LISTING"]",
        },
        {
                SDB_CONNECTION_LIST, "", 0, /* LIST defaults to hosts */
-               0, SDB_CONNECTION_DATA, 205, SDB_CONNECTION_LIST,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LIST,
                "["HOST_H1_LISTING","HOST_H2_LISTING"]",
        },
        {
                SDB_CONNECTION_QUERY, "LIST hosts; LIST hosts", -1, /* ignore second (and later) commands */
-               0, SDB_CONNECTION_DATA, 205, SDB_CONNECTION_LIST,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LIST,
                "["HOST_H1_LISTING","HOST_H2_LISTING"]",
        },
        {
                SDB_CONNECTION_QUERY, "LIST hosts FILTER name = 'h1'", -1,
-               0, SDB_CONNECTION_DATA, 105, SDB_CONNECTION_LIST, "["HOST_H1_LISTING"]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LIST, "["HOST_H1_LISTING"]",
        },
        {
                SDB_CONNECTION_QUERY, "LIST hosts FILTER name = 's1'", -1,
-               0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LIST, "[]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LIST, "[]",
        },
        /* SDB_CONNECTION_LIST doesn't support filters yet */
        {
                SDB_CONNECTION_QUERY, "FETCH host 'h1'", -1,
-               0, SDB_CONNECTION_DATA, 1110, SDB_CONNECTION_FETCH, HOST_H1,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_FETCH, HOST_H1,
        },
        {
                SDB_CONNECTION_FETCH, "\0\0\0\1""h1", 7,
-               0, SDB_CONNECTION_DATA, 1110, SDB_CONNECTION_FETCH, HOST_H1,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_FETCH, HOST_H1,
        },
        {
                SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING name = 'h1'", -1,
-               0, SDB_CONNECTION_DATA, 1112, SDB_CONNECTION_LOOKUP, HOST_H1_ARRAY,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, HOST_H1_ARRAY,
        },
        {
                SDB_CONNECTION_LOOKUP, "\0\0\0\1""name = 'h1'", 16,
-               0, SDB_CONNECTION_DATA, 1112, SDB_CONNECTION_LOOKUP, HOST_H1_ARRAY,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, HOST_H1_ARRAY,
        },
        {
                SDB_CONNECTION_QUERY, "FETCH host 'h1' FILTER age >= 0s", -1, /* always matches */
-               0, SDB_CONNECTION_DATA, 1110, SDB_CONNECTION_FETCH, HOST_H1,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_FETCH, HOST_H1,
        },
        /* SDB_CONNECTION_FETCH doesn't support filters yet */
        {
                SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING name = 'h1' FILTER age >= 0s", -1, /* always matches */
-               0, SDB_CONNECTION_DATA, 1112, SDB_CONNECTION_LOOKUP, HOST_H1_ARRAY,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, HOST_H1_ARRAY,
        },
        {
                SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING ANY backend = 'b'", -1,
-               0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, "[]",
        },
        {
                SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING ANY backend || 'b' = 'b'", -1,
-               0, SDB_CONNECTION_DATA, 2205, SDB_CONNECTION_LOOKUP, HOST_H12_ARRAY,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, HOST_H12_ARRAY,
        },
        {
                SDB_CONNECTION_QUERY, "FETCH host 'h1' FILTER age < 0s", -1, /* never matches */
-               -1, UINT32_MAX, 0, 0, NULL, /* FETCH fails if the object doesn't exist */
+               -1, UINT32_MAX, 0, NULL, /* FETCH fails if the object doesn't exist */
        },
        /* SDB_CONNECTION_FETCH doesn't support filters yet */
        {
                SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING name = 'h1' FILTER age < 0s", -1, /* never matches */
-               0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, "[]",
        },
        /* SDB_CONNECTION_LOOKUP doesn't support filters yet */
        {
                SDB_CONNECTION_QUERY, "FETCH host 'x1'", -1, /* does not exist */
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        {
                SDB_CONNECTION_FETCH, "\0\0\0\1x1", 7,
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        {
                SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING name = 'x1'", -1, /* does not exist */
-               0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, "[]",
        },
        {
                SDB_CONNECTION_LOOKUP, "\0\0\0\1""name = 'x1'", 16, /* does not exist */
-               0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, "[]",
        },
        {
                SDB_CONNECTION_QUERY, "FETCH host 'h1'.'s1'", -1, /* invalid args */
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        {
                SDB_CONNECTION_QUERY, "LOOKUP hosts BY name = 'x1'", -1, /* does not exist */
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        /* services */
        {
                SDB_CONNECTION_QUERY, "LIST services", -1,
-               0, SDB_CONNECTION_DATA, 320, SDB_CONNECTION_LIST, SERVICE_H2_S12_LISTING,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LIST, SERVICE_H2_S12_LISTING,
        },
        {
                SDB_CONNECTION_LIST, "\0\0\0\2", 4,
-               0, SDB_CONNECTION_DATA, 320, SDB_CONNECTION_LIST, SERVICE_H2_S12_LISTING,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LIST, SERVICE_H2_S12_LISTING,
        },
        {
                SDB_CONNECTION_QUERY, "LIST services FILTER host.name = 'h2'", -1,
-               0, SDB_CONNECTION_DATA, 320, SDB_CONNECTION_LIST, SERVICE_H2_S12_LISTING,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LIST, SERVICE_H2_S12_LISTING,
        },
        {
                SDB_CONNECTION_QUERY, "LIST services FILTER host.name = 'h1'", -1,
-               0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LIST, "[]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LIST, "[]",
        },
        /* SDB_CONNECTION_LIST doesn't support filters yet */
        {
                SDB_CONNECTION_QUERY, "FETCH service 'h2'.'s1'", -1,
-               0, SDB_CONNECTION_DATA, 356, SDB_CONNECTION_FETCH, SERVICE_H2_S1,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_FETCH, SERVICE_H2_S1,
        },
        /* SDB_CONNECTION_FETCH doesn't support services yet */
        {
                SDB_CONNECTION_QUERY, "LOOKUP services MATCHING name = 's1'", -1,
-               0, SDB_CONNECTION_DATA, 358, SDB_CONNECTION_LOOKUP, SERVICE_H2_S1_ARRAY,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, SERVICE_H2_S1_ARRAY,
        },
        {
                SDB_CONNECTION_QUERY, "LOOKUP services MATCHING host.name = 'h2'", -1,
-               0, SDB_CONNECTION_DATA, 825, SDB_CONNECTION_LOOKUP, "["SERVICE_H2_S12"]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, "["SERVICE_H2_S12"]",
        },
        {
                SDB_CONNECTION_QUERY, "LOOKUP services MATCHING ANY host.metric.name = 'm1'", -1,
-               0, SDB_CONNECTION_DATA, 825, SDB_CONNECTION_LOOKUP, "["SERVICE_H2_S12"]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, "["SERVICE_H2_S12"]",
        },
        {
                SDB_CONNECTION_QUERY, "LOOKUP services MATCHING ANY host.metric.last_update = 10s", -1,
-               0, SDB_CONNECTION_DATA, 825, SDB_CONNECTION_LOOKUP, "["SERVICE_H2_S12"]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, "["SERVICE_H2_S12"]",
        },
        {
                /* stupid but valid ;-) */
                SDB_CONNECTION_QUERY, "LOOKUP services MATCHING ANY host.host.metric.metric.interval = 5s", -1,
-               0, SDB_CONNECTION_DATA, 825, SDB_CONNECTION_LOOKUP, "["SERVICE_H2_S12"]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, "["SERVICE_H2_S12"]",
        },
        {
                SDB_CONNECTION_QUERY, "LOOKUP services MATCHING ANY host.metric.name = 'mX'", -1,
-               0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, "[]",
        },
        {
                SDB_CONNECTION_LOOKUP, "\0\0\0\2""name = 's1'", 16,
-               0, SDB_CONNECTION_DATA, 358, SDB_CONNECTION_LOOKUP, SERVICE_H2_S1_ARRAY,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, SERVICE_H2_S1_ARRAY,
        },
        {
                SDB_CONNECTION_QUERY, "FETCH service 'h2'.'s1' FILTER age >= 0s", -1, /* always matches */
-               0, SDB_CONNECTION_DATA, 356, SDB_CONNECTION_FETCH, SERVICE_H2_S1,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_FETCH, SERVICE_H2_S1,
        },
        /* SDB_CONNECTION_FETCH doesn't support services yet */
        {
                SDB_CONNECTION_QUERY, "LOOKUP services MATCHING name = 's1' FILTER age >= 0s", -1, /* always matches */
-               0, SDB_CONNECTION_DATA, 358, SDB_CONNECTION_LOOKUP, SERVICE_H2_S1_ARRAY,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, SERVICE_H2_S1_ARRAY,
        },
        {
                SDB_CONNECTION_QUERY, "FETCH service 'h2'.'s1' FILTER age < 0s", -1, /* never matches */
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        /* SDB_CONNECTION_FETCH doesn't support services yet */
        {
                SDB_CONNECTION_QUERY, "LOOKUP services MATCHING name = 's1' FILTER age < 0s", -1, /* never matches */
-               0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, "[]",
        },
        /* SDB_CONNECTION_LOOKUP doesn't support filters yet */
        {
                SDB_CONNECTION_QUERY, "FETCH service 'h2'.'s1' FILTER name = 'h2'", -1, /* only matches host */
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        /* SDB_CONNECTION_FETCH doesn't support services yet */
        {
                SDB_CONNECTION_QUERY, "LOOKUP services MATCHING name = 's1' FILTER name = 'h2'", -1, /* only matches host */
-               0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, "[]",
        },
        {
                SDB_CONNECTION_QUERY, "FETCH service 'h2'.'x1'", -1, /* does not exist */
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        /* SDB_CONNECTION_FETCH doesn't support services yet */
        {
                SDB_CONNECTION_QUERY, "FETCH service 'x2'.'s1'", -1, /* does not exist */
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        /* SDB_CONNECTION_FETCH doesn't support services yet */
        {
                SDB_CONNECTION_QUERY, "FETCH service 'h2'", -1, /* invalid args */
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        /* SDB_CONNECTION_FETCH doesn't support services yet */
        /* metrics */
        {
                SDB_CONNECTION_QUERY, "LIST metrics", -1,
-               0, SDB_CONNECTION_DATA, 596, SDB_CONNECTION_LIST, METRIC_H12_M12_LISTING,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LIST, METRIC_H12_M12_LISTING,
        },
        {
                SDB_CONNECTION_LIST, "\0\0\0\3", 4,
-               0, SDB_CONNECTION_DATA, 596, SDB_CONNECTION_LIST, METRIC_H12_M12_LISTING,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LIST, METRIC_H12_M12_LISTING,
        },
        {
                SDB_CONNECTION_QUERY, "LIST metrics FILTER age > 0s", -1,
-               0, SDB_CONNECTION_DATA, 596, SDB_CONNECTION_LIST, METRIC_H12_M12_LISTING,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LIST, METRIC_H12_M12_LISTING,
        },
        {
                SDB_CONNECTION_QUERY, "LIST metrics FILTER age < 0s", -1,
-               0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LIST, "[]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LIST, "[]",
        },
        /* SDB_CONNECTION_LIST doesn't support filters yet */
        {
                SDB_CONNECTION_QUERY, "FETCH metric 'h1'.'m1'", -1,
-               0, SDB_CONNECTION_DATA, 489, SDB_CONNECTION_FETCH, METRIC_H1_M1,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_FETCH, METRIC_H1_M1,
        },
        /* SDB_CONNECTION_FETCH doesn't support metrics yet */
        {
                SDB_CONNECTION_QUERY, "LOOKUP metrics MATCHING name = 'm1'", -1,
-               0, SDB_CONNECTION_DATA, 864, SDB_CONNECTION_LOOKUP, METRIC_H12_M1_ARRAY,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, METRIC_H12_M1_ARRAY,
        },
        {
                /* stupid but valid ;-) */
                SDB_CONNECTION_QUERY, "LOOKUP metrics MATCHING metric.metric.name = 'm1'", -1,
-               0, SDB_CONNECTION_DATA, 864, SDB_CONNECTION_LOOKUP, METRIC_H12_M1_ARRAY,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, METRIC_H12_M1_ARRAY,
        },
        {
                /* also stupid but valid ;-) */
                SDB_CONNECTION_QUERY, "LOOKUP metrics MATCHING metric.metric.host.host.last_update = 3s", -1,
-               0, SDB_CONNECTION_DATA, 378, SDB_CONNECTION_LOOKUP, "["METRIC_H2_M1"]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, "["METRIC_H2_M1"]",
        },
        {
                SDB_CONNECTION_LOOKUP, "\0\0\0\3""name = 'm1'", 16,
-               0, SDB_CONNECTION_DATA, 864, SDB_CONNECTION_LOOKUP, METRIC_H12_M1_ARRAY,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, METRIC_H12_M1_ARRAY,
        },
        {
                SDB_CONNECTION_QUERY, "FETCH metric 'h1'.'m1' FILTER age >= 0s", -1, /* always matches */
-               0, SDB_CONNECTION_DATA, 489, SDB_CONNECTION_FETCH, METRIC_H1_M1,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_FETCH, METRIC_H1_M1,
        },
        /* SDB_CONNECTION_FETCH doesn't support metrics yet */
        {
                SDB_CONNECTION_QUERY, "LOOKUP metrics MATCHING name = 'm1' FILTER age >= 0s", -1, /* always matches */
-               0, SDB_CONNECTION_DATA, 864, SDB_CONNECTION_LOOKUP, METRIC_H12_M1_ARRAY,
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, METRIC_H12_M1_ARRAY,
        },
        {
                SDB_CONNECTION_QUERY, "FETCH metric 'h1'.'m1' FILTER age < 0s", -1, /* never matches */
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        /* SDB_CONNECTION_FETCH doesn't support metrics yet */
        {
                SDB_CONNECTION_QUERY, "LOOKUP metrics MATCHING name = 'm1' FILTER age < 0s", -1, /* never matches */
-               0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, "[]",
        },
        /* SDB_CONEECTION_LOOKUP doesn't support filters yet */
        {
                SDB_CONNECTION_QUERY, "FETCH metric 'h1'.'m1' FILTER name = 'h1'", -1, /* only matches host */
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        /* SDB_CONNECTION_FETCH doesn't support metrics yet */
        {
                SDB_CONNECTION_QUERY, "LOOKUP metrics MATCHING name = 'm1' FILTER name = 'h1'", -1, /* only matches host */
-               0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
+               0, SDB_CONNECTION_DATA, SDB_CONNECTION_LOOKUP, "[]",
        },
        {
                SDB_CONNECTION_QUERY, "FETCH metric 'h1'.'x1'", -1, /* does not exist */
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        /* SDB_CONNECTION_FETCH doesn't support metrics yet */
        {
                SDB_CONNECTION_QUERY, "FETCH metric 'x1'.'m1'", -1, /* does not exist */
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        /* SDB_CONNECTION_FETCH doesn't support metrics yet */
        {
                SDB_CONNECTION_QUERY, "FETCH metric 'x1'", -1, /* invalid args */
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        /* SDB_CONNECTION_FETCH doesn't support metrics yet */
        /* timeseries */
        {
                SDB_CONNECTION_QUERY, "TIMESERIES 'h1'.'m1'", -1,
-               -1, UINT32_MAX, 0, 0, NULL, /* no data-store available */
+               -1, UINT32_MAX, 0, NULL, /* no data-store available */
        },
        {
                SDB_CONNECTION_QUERY, "TIMESERIES 'h1'.'x1'", -1,
-               -1, UINT32_MAX, 0, 0, NULL, /* does not exist */
+               -1, UINT32_MAX, 0, NULL, /* does not exist */
        },
        {
                SDB_CONNECTION_QUERY, "TIMESERIES 'x1'.'m1'", -1,
-               -1, UINT32_MAX, 0, 0, NULL, /* does not exist */
+               -1, UINT32_MAX, 0, NULL, /* does not exist */
        },
        /* store commands */
        {
                SDB_CONNECTION_QUERY, "STORE host 'hA' LAST UPDATE 01:00", -1,
-               0, SDB_CONNECTION_OK, 27, 0, "Successfully stored host hA",
+               0, SDB_CONNECTION_OK, 0, "Successfully stored host hA",
        },
        {
                SDB_CONNECTION_STORE, "\0\0\0\1""\0\0\0\0\xd6\x93\xa4\0""hA", 15,
-               0, SDB_CONNECTION_OK, 27, 0, "Successfully stored host hA",
+               0, SDB_CONNECTION_OK, 0, "Successfully stored host hA",
        },
        {
                SDB_CONNECTION_QUERY, "STORE host 'hA'", -1,
-               0, SDB_CONNECTION_OK, 27, 0, "Successfully stored host hA",
+               0, SDB_CONNECTION_OK, 0, "Successfully stored host hA",
        },
        {
                SDB_CONNECTION_QUERY, "STORE host attribute 'h1'.'aA' 'vA'", -1,
-               0, SDB_CONNECTION_OK, 40, 0, "Successfully stored host attribute h1.aA",
+               0, SDB_CONNECTION_OK, 0, "Successfully stored host attribute h1.aA",
        },
        {
                SDB_CONNECTION_STORE, "\0\0\0\x11""\0\0\0\0\xd6\x93\xa4\0""h1\0aA\0"VALUE, 18+VALUE_LEN,
-               0, SDB_CONNECTION_OK, 40, 0, "Successfully stored host attribute h1.aA",
+               0, SDB_CONNECTION_OK, 0, "Successfully stored host attribute h1.aA",
        },
        {
                SDB_CONNECTION_QUERY, "STORE host attribute 'x1'.'aA' 'vA'", -1,
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        {
                SDB_CONNECTION_STORE, "\0\0\0\x11""\0\0\0\0\xd6\x93\xa4\0""x1\0aA\0"VALUE, 18+VALUE_LEN,
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        {
                SDB_CONNECTION_QUERY, "STORE service 'h1'.'sA'", -1,
-               0, SDB_CONNECTION_OK, 33, 0, "Successfully stored service h1.sA",
+               0, SDB_CONNECTION_OK, 0, "Successfully stored service h1.sA",
        },
        {
                SDB_CONNECTION_STORE, "\0\0\0\2""\0\0\0\0\xd6\x93\xa4\0""h1\0sA", 18,
-               0, SDB_CONNECTION_OK, 33, 0, "Successfully stored service h1.sA",
+               0, SDB_CONNECTION_OK, 0, "Successfully stored service h1.sA",
        },
        {
                SDB_CONNECTION_QUERY, "STORE service 'x1'.'sA'", -1,
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        {
                SDB_CONNECTION_STORE, "\0\0\0\x12""\0\0\0\0\xd6\x93\xa4\0""x1\0sA", 18,
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        {
                SDB_CONNECTION_QUERY, "STORE service attribute 'h2'.'s1'.'aA' 'vA'", -1,
-               0, SDB_CONNECTION_OK, 46, 0, "Successfully stored service attribute h2.s1.aA",
+               0, SDB_CONNECTION_OK, 0, "Successfully stored service attribute h2.s1.aA",
        },
        {
                SDB_CONNECTION_STORE, "\0\0\0\x12""\0\0\0\0\xd6\x93\xa4\0""h2\0s1\0aA\0"VALUE,27+VALUE_LEN,
-               0, SDB_CONNECTION_OK, 46, 0, "Successfully stored service attribute h2.s1.aA",
+               0, SDB_CONNECTION_OK, 0, "Successfully stored service attribute h2.s1.aA",
        },
        {
                SDB_CONNECTION_QUERY, "STORE service attribute 'h2'.'x1'.'aA' 'vA'", -1,
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        {
                SDB_CONNECTION_STORE, "\0\0\0\x12""\0\0\0\0\xd6\x93\xa4\0""h2\0x1\0aA\0"VALUE,27+VALUE_LEN,
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        {
                SDB_CONNECTION_QUERY, "STORE metric 'h1'.'mA'", -1,
-               0, SDB_CONNECTION_OK, 32, 0, "Successfully stored metric h1.mA",
+               0, SDB_CONNECTION_OK, 0, "Successfully stored metric h1.mA",
        },
        {
                SDB_CONNECTION_STORE, "\0\0\0\3""\0\0\0\0\xd6\x93\xa4\0""h1\0mA", 18,
-               0, SDB_CONNECTION_OK, 32, 0, "Successfully stored metric h1.mA",
+               0, SDB_CONNECTION_OK, 0, "Successfully stored metric h1.mA",
        },
        {
                SDB_CONNECTION_QUERY, "STORE metric 'x1'.'mA'", -1,
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        {
                SDB_CONNECTION_STORE, "\0\0\0\3""\0\0\0\0\xd6\x93\xa4\0""x1\0mA", 18,
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        {
                SDB_CONNECTION_QUERY, "STORE metric attribute 'h1'.'m1'.'aA' 'vA'", -1,
-               0, SDB_CONNECTION_OK, 45, 0, "Successfully stored metric attribute h1.m1.aA",
+               0, SDB_CONNECTION_OK, 0, "Successfully stored metric attribute h1.m1.aA",
        },
        {
                SDB_CONNECTION_STORE, "\0\0\0\x13""\0\0\0\0\xd6\x93\xa4\0""h1\0m1\0aA\0"VALUE, 27+VALUE_LEN,
-               0, SDB_CONNECTION_OK, 45, 0, "Successfully stored metric attribute h1.m1.aA",
+               0, SDB_CONNECTION_OK, 0, "Successfully stored metric attribute h1.m1.aA",
        },
        {
                SDB_CONNECTION_QUERY, "STORE metric attribute 'h1'.'x1'.'aA' 'vA'", -1,
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
        {
                SDB_CONNECTION_STORE, "\0\0\0\x13""\0\0\0\0\xd6\x93\xa4\0""h1\0x1\0aA\0"VALUE, 27+VALUE_LEN,
-               -1, UINT32_MAX, 0, 0, NULL,
+               -1, UINT32_MAX, 0, NULL,
        },
 };
 
@@ -814,11 +814,9 @@ START_TEST(test_query)
        data += tmp;
        len -= tmp;
 
-       fail_unless((code == query_data[_i].code)
-                               && ((size_t)msg_len == query_data[_i].len),
-                       "sdb_conn_query(%s) returned %u, %u; expected: %u, %zu",
-                       query_data[_i].query, code, msg_len,
-                       query_data[_i].code, query_data[_i].len);
+       fail_unless(code == query_data[_i].code,
+                       "sdb_conn_query(%s) returned <%u>; expected: <%u>",
+                       query_data[_i].query, code, query_data[_i].code);
 
        if (code == SDB_CONNECTION_DATA) {
                tmp = sdb_proto_unmarshal_int32(data, len, &code);
index 8da4ef0cc722a639e178d9714c89fa0ee16b0395..f6601f164ed2f34cdfa652a0b23dbc5f667a8447 100644 (file)
@@ -31,7 +31,7 @@
 
 #include "parser/parser.h"
 #include "core/object.h"
-#include "core/store.h"
+#include "core/memstore.h"
 #include "testutils.h"
 
 #include <check.h>
@@ -678,7 +678,7 @@ START_TEST(test_parse)
        sdb_strbuf_t *errbuf = sdb_strbuf_create(64);
        sdb_llist_t *check;
        sdb_ast_node_t *node;
-       sdb_store_query_t *q;
+       sdb_memstore_query_t *q;
        _Bool ok;
 
        check = sdb_parser_parse(parse_data[_i].query,
@@ -741,9 +741,9 @@ START_TEST(test_parse)
        }
 
        /* TODO: this should move into front-end specific tests */
-       q = sdb_store_query_prepare(node);
+       q = sdb_memstore_query_prepare(node);
        fail_unless(q != NULL,
-                       "sdb_store_query_prepare(AST<%s>) = NULL; expected: <query>",
+                       "sdb_memstore_query_prepare(AST<%s>) = NULL; expected: <query>",
                        parse_data[_i].query);
 
        sdb_object_deref(SDB_OBJ(node));