Code

Split the memstore module from the store module.
authorSebastian Harl <sh@tokkee.org>
Wed, 7 Oct 2015 21:45:51 +0000 (23:45 +0200)
committerSebastian Harl <sh@tokkee.org>
Wed, 7 Oct 2015 21:45:51 +0000 (23:45 +0200)
23 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/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/include/core/memstore.h [new file with mode: 0644]
src/include/core/store.h
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..d886a1f
--- /dev/null
@@ -0,0 +1,1107 @@
+/*
+ * 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;
+       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_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);
+
+       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_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 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_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);
+
+       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, "memstore: 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, "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);
+
+       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 */
+
+/*
+ * 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:
+               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, "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.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, 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_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.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.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_store_host_t host = {
+               name, last_update, 0, 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_store_service_t service = {
+               hostname, name, last_update, 0, 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_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_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_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_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_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_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_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_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 *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_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_avltree_t *tree = NULL;
+       sdb_memstore_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_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..802e70c
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * 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, const char *name,
+               sdb_memstore_matcher_t *filter)
+{
+       sdb_memstore_obj_t *host;
+       sdb_memstore_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_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;
+       }
+       if (type == SDB_HOST) {
+               obj = host;
+       }
+       else {
+               obj = sdb_memstore_get_child(host, 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);
+                       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_memstore_emit(obj->parent, w, wd);
+       if (status || sdb_memstore_emit_full(obj, filter, w, wd)) {
+               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");
+               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_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)->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, "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 : */
diff --git a/src/core/store-private.h b/src/core/store-private.h
deleted file mode 100644 (file)
index 2f9d96c..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 memstore 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_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
- * 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_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_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 7fc11e1..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_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;
-       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_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, "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_MEMSTORE(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_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);
-
-       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_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 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_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);
-
-       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(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_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, "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_memstore_t *st = SDB_MEMSTORE(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_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, "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_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, "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_memstore_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_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("store", store_type));
-} /* sdb_memstore_create */
-
-int
-sdb_memstore_host(sdb_memstore_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_memstore_host */
-
-int
-sdb_memstore_service(sdb_memstore_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_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_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_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_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_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_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_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_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_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 *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_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_avltree_t *tree = NULL;
-       sdb_memstore_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_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, "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_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, "store: 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, "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_memstore_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 9b4ea07..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_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, const char *name,
-               sdb_memstore_matcher_t *filter)
-{
-       sdb_memstore_obj_t *host;
-       sdb_memstore_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_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;
-       }
-       if (type == SDB_HOST) {
-               obj = host;
-       }
-       else {
-               obj = sdb_memstore_get_child(host, 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);
-                       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_memstore_emit(obj->parent, w, wd);
-       if (status || sdb_memstore_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_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, "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_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, "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_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, "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_memstore_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 c96b339..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_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("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_MEMSTORE_EXPR(sdb_object_create("store-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("store-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("store-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("store-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("store-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 : */
-
index b39ff210a2aedfaf0d8b0064bad354234d8109bc..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_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 */
-
 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 b69e7f9..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_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, "store: 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 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_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, "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_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, "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_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/store_query.c b/src/core/store_query.c
deleted file mode 100644 (file)
index 341cb16..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_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, "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_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, "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_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, "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_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, "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_memstore_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_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 : */
diff --git a/src/include/core/memstore.h b/src/include/core/memstore.h
new file mode 100644 (file)
index 0000000..8590156
--- /dev/null
@@ -0,0 +1,535 @@
+/*
+ * 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);
+int
+sdb_memstore_service(sdb_memstore_t *store, const char *hostname, const char *name,
+               sdb_time_t last_update);
+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);
+int
+sdb_memstore_attribute(sdb_memstore_t *store, const char *hostname,
+               const char *key, const sdb_data_t *value, sdb_time_t last_update);
+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);
+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_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 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_memstore_obj_t *
+sdb_memstore_get_child(sdb_memstore_obj_t *host, 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 03677e8feb33a2f5796ed39cc1d945db00a81fa3..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_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;
-
 /*
  * 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_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))
-
 /*
  * 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_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;
-
 /*
  * A store reader describes the interface to query a store implementation.
  */
@@ -300,408 +245,6 @@ typedef struct {
                        sdb_strbuf_t *errbuf, sdb_object_t *user_data);
 } sdb_store_reader_t;
 
-/*
- * 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);
-int
-sdb_memstore_service(sdb_memstore_t *store, const char *hostname, const char *name,
-               sdb_time_t last_update);
-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);
-int
-sdb_memstore_attribute(sdb_memstore_t *store, const char *hostname,
-               const char *key, const sdb_data_t *value, sdb_time_t last_update);
-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);
-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_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 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_memstore_obj_t *
-sdb_memstore_get_child(sdb_memstore_obj_t *host, 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);
-
 /*
  * Flags for JSON formatting.
  */
@@ -717,42 +260,6 @@ enum {
 sdb_store_json_formatter_t *
 sdb_store_json_formatter(sdb_strbuf_t *buf, int type, int flags);
 
-/*
- * sdb_memstore_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_memstore_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_memstore_emit(sdb_memstore_obj_t *obj, sdb_store_writer_t *w, sdb_object_t *wd);
-
-/*
- * sdb_memstore_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_memstore_emit_full(sdb_memstore_obj_t *obj, sdb_memstore_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 67a795b0ef3d7d1d6ba362ef7fc62fc6d9286004..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"
 
index 04dfc8b9ee0b9b6e07b245de973c3a762aa04d92..1bf560ee68c23fb6481d57b628efbf72125022ca 100644 (file)
@@ -30,7 +30,7 @@
 #endif
 
 #include "core/store.h"
-#include "core/store-private.h"
+#include "core/memstore-private.h"
 #include "parser/parser.h"
 #include "testutils.h"
 
index 40548c09340d444ed3d90064a2c4d82f84349858..461c583396583d87793809875659cac6ff02a941 100644 (file)
@@ -29,6 +29,7 @@
 #      include "config.h"
 #endif
 
+#include "core/memstore.h"
 #include "core/store.h"
 #include "testutils.h"
 
index ef0900e8949805344a13b7e6a1320f50ece507c8..0c99ee1e294e7ef30b069e16d9b1d5ba6b6c05cd 100644 (file)
@@ -31,7 +31,7 @@
 
 #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"
 
index 5299a318691d8d577db15c677ee97a84bcd926a6..9445c64176f7ec1a764a945e2c583f4a1051799c 100644 (file)
@@ -31,7 +31,7 @@
 
 #include "core/plugin.h"
 #include "core/store.h"
-#include "core/store-private.h"
+#include "core/memstore-private.h"
 #include "testutils.h"
 
 #include <check.h>
index d498ea0231208bca6178e7d2da469e169247830b..52fd58a4e0c75256fb5e3f77e7db604854534831 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"
index 83a5845a87f614e109f72d2f268574356a83e0c9..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>
@@ -743,7 +743,7 @@ START_TEST(test_parse)
        /* TODO: this should move into front-end specific tests */
        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));