summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: b54d9ff)
raw | patch | inline | side by side (parent: b54d9ff)
author | Sebastian Harl <sh@tokkee.org> | |
Wed, 7 Oct 2015 21:45:51 +0000 (23:45 +0200) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Wed, 7 Oct 2015 21:45:51 +0000 (23:45 +0200) |
23 files changed:
diff --git a/src/Makefile.am b/src/Makefile.am
index f3bcae192846276a26dfbd868ba946868d5cbc19..886cc1ad2d80d562db0bba0fe71d141bb9518c9a 100644 (file)
--- a/src/Makefile.am
+++ b/src/Makefile.am
-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
--- /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
--- /dev/null
+++ b/src/core/memstore.c
@@ -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
--- /dev/null
+++ b/src/core/memstore_exec.c
@@ -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
--- /dev/null
+++ b/src/core/memstore_expr.c
@@ -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
--- /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, ®ex, obj, filter))
+ return 0;
+
+ status = match_regex_value(m->type, &v, ®ex);
+
+ expr_free_datum2(CMP_M(m)->left, &v, CMP_M(m)->right, ®ex);
+ 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
--- /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
--- a/src/core/store-private.h
+++ /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
--- a/src/core/store.c
+++ /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
--- a/src/core/store_exec.c
+++ /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
--- a/src/core/store_expr.c
+++ /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 : */
-
diff --git a/src/core/store_json.c b/src/core/store_json.c
index b39ff210a2aedfaf0d8b0064bad354234d8109bc..92666089870016beea0b0307f846d458b258b8fc 100644 (file)
--- a/src/core/store_json.c
+++ b/src/core/store_json.c
#endif /* HAVE_CONFIG_H */
#include "sysdb.h"
-#include "core/store-private.h"
+#include "core/store.h"
#include "utils/error.h"
#include <assert.h>
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
--- a/src/core/store_lookup.c
+++ /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, ®ex, obj, filter))
- return 0;
-
- status = match_regex_value(m->type, &v, ®ex);
-
- expr_free_datum2(CMP_M(m)->left, &v, CMP_M(m)->right, ®ex);
- 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
--- a/src/core/store_query.c
+++ /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
--- /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)
--- a/src/include/core/store.h
+++ b/src/include/core/store.h
/*
* 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
: ((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.
*/
} 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
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.
*/
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.
*/
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)
#include "sysdb.h"
#include "core/plugin.h"
+#include "core/memstore.h"
#include "core/store.h"
#include "utils/error.h"
index 04dfc8b9ee0b9b6e07b245de973c3a762aa04d92..1bf560ee68c23fb6481d57b628efbf72125022ca 100644 (file)
#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)
# include "config.h"
#endif
+#include "core/memstore.h"
#include "core/store.h"
#include "testutils.h"
index ef0900e8949805344a13b7e6a1320f50ece507c8..0c99ee1e294e7ef30b069e16d9b1d5ba6b6c05cd 100644 (file)
#include "core/plugin.h"
#include "core/store.h"
-#include "core/store-private.h"
+#include "core/memstore-private.h"
#include "parser/parser.h"
#include "testutils.h"
index 5299a318691d8d577db15c677ee97a84bcd926a6..9445c64176f7ec1a764a945e2c583f4a1051799c 100644 (file)
--- a/t/unit/core/store_test.c
+++ b/t/unit/core/store_test.c
#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)
# 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)
#include "parser/parser.h"
#include "core/object.h"
-#include "core/store.h"
+#include "core/memstore.h"
#include "testutils.h"
#include <check.h>
/* 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));