From: Sebastian Harl Date: Wed, 7 Oct 2015 21:45:51 +0000 (+0200) Subject: Split the memstore module from the store module. X-Git-Tag: sysdb-0.8.0~10^2~5 X-Git-Url: https://git.tokkee.org/?p=sysdb.git;a=commitdiff_plain;h=98439daa576d4dbc533e9d4b8a5f493926389554;hp=b54d9fff4bc9e70efe83123403a4c9f935efb74e Split the memstore module from the store module. --- diff --git a/src/Makefile.am b/src/Makefile.am index f3bcae1..886cc1a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -72,16 +72,16 @@ libsysdb_fe_parser_la_CFLAGS = @COVERAGE_CFLAGS@ @PROFILING_CFLAGS@ \ -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\"" libsysdb_la_SOURCES = \ sysdb.c include/sysdb.h \ + core/data.c include/core/data.h \ + core/memstore.c include/core/memstore.h \ + core/memstore-private.h \ + core/memstore_exec.c \ + core/memstore_expr.c \ + core/memstore_lookup.c \ + core/memstore_query.c \ core/object.c include/core/object.h \ core/plugin.c include/core/plugin.h \ - core/store.c include/core/store.h \ - core/store-private.h \ - core/store_exec.c \ - core/store_expr.c \ - core/store_json.c \ - core/store_lookup.c \ - core/store_query.c \ - core/data.c include/core/data.h \ + core/store_json.c include/core/store.h \ core/time.c include/core/time.h \ core/timeseries.c include/core/timeseries.h \ frontend/connection.c include/frontend/connection.h \ diff --git a/src/core/memstore-private.h b/src/core/memstore-private.h new file mode 100644 index 0000000..cd0152d --- /dev/null +++ b/src/core/memstore-private.h @@ -0,0 +1,264 @@ +/* + * SysDB - src/core/memstore-private.h + * Copyright (C) 2012-2013 Sebastian 'tokkee' Harl + * 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 +#include + +#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) ? "" \ + : ((e)->type == ATTR_VALUE) ? "attribute" \ + : ((e)->type == FIELD_VALUE) ? SDB_FIELD_TO_NAME((e)->data.data.integer) \ + : ((e)->type == 0) ? "" \ + : ((e)->type > 0) ? SDB_DATA_OP_TO_STRING((e)->type) \ + : "") + +/* + * matchers + */ + +/* when adding to this, also update 'MATCHER_SYM' below and 'matchers' in + * memstore_lookup.c */ +enum { + MATCHER_OR, + MATCHER_AND, + MATCHER_NOT, + MATCHER_ANY, + MATCHER_ALL, + MATCHER_IN, + + /* unary operators */ + MATCHER_ISNULL, + MATCHER_ISTRUE, + MATCHER_ISFALSE, + + /* ary operators */ + MATCHER_LT, + MATCHER_LE, + MATCHER_EQ, + MATCHER_NE, + MATCHER_GE, + MATCHER_GT, + MATCHER_REGEX, + MATCHER_NREGEX, + + /* a generic query */ + MATCHER_QUERY, +}; + +#define MATCHER_SYM(t) \ + (((t) == MATCHER_OR) ? "OR" \ + : ((t) == MATCHER_AND) ? "AND" \ + : ((t) == MATCHER_NOT) ? "NOT" \ + : ((t) == MATCHER_ANY) ? "ANY" \ + : ((t) == MATCHER_ALL) ? "ALL" \ + : ((t) == MATCHER_IN) ? "IN" \ + : ((t) == MATCHER_ISNULL) ? "IS NULL" \ + : ((t) == MATCHER_ISTRUE) ? "IS TRUE" \ + : ((t) == MATCHER_ISFALSE) ? "IS FALSE" \ + : ((t) == MATCHER_LT) ? "<" \ + : ((t) == MATCHER_LE) ? "<=" \ + : ((t) == MATCHER_EQ) ? "=" \ + : ((t) == MATCHER_NE) ? "!=" \ + : ((t) == MATCHER_GE) ? ">=" \ + : ((t) == MATCHER_GT) ? ">" \ + : ((t) == MATCHER_REGEX) ? "=~" \ + : ((t) == MATCHER_NREGEX) ? "!~" \ + : ((t) == MATCHER_QUERY) ? "QUERY" \ + : "UNKNOWN") + +/* matcher base type */ +struct sdb_memstore_matcher { + sdb_object_t super; + /* type of the matcher */ + int type; +}; +#define M(m) ((sdb_memstore_matcher_t *)(m)) + +/* infix operator matcher */ +typedef struct { + sdb_memstore_matcher_t super; + + /* left and right hand operands */ + sdb_memstore_matcher_t *left; + sdb_memstore_matcher_t *right; +} op_matcher_t; +#define OP_M(m) ((op_matcher_t *)(m)) + +/* unary operator matcher */ +typedef struct { + sdb_memstore_matcher_t super; + + /* operand */ + sdb_memstore_matcher_t *op; +} uop_matcher_t; +#define UOP_M(m) ((uop_matcher_t *)(m)) + +/* iter matcher */ +typedef struct { + sdb_memstore_matcher_t super; + sdb_memstore_expr_t *iter; + sdb_memstore_matcher_t *m; +} iter_matcher_t; +#define ITER_M(m) ((iter_matcher_t *)(m)) + +/* compare operator matcher */ +typedef struct { + sdb_memstore_matcher_t super; + + /* left and right hand expressions */ + sdb_memstore_expr_t *left; + sdb_memstore_expr_t *right; +} cmp_matcher_t; +#define CMP_M(m) ((cmp_matcher_t *)(m)) + +typedef struct { + sdb_memstore_matcher_t super; + sdb_memstore_expr_t *expr; +} unary_matcher_t; +#define UNARY_M(m) ((unary_matcher_t *)(m)) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ! SDB_CORE_MEMSTORE_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/core/memstore.c b/src/core/memstore.c new file mode 100644 index 0000000..d886a1f --- /dev/null +++ b/src/core/memstore.c @@ -0,0 +1,1107 @@ +/* + * SysDB - src/core/memstore.c + * Copyright (C) 2012-2013 Sebastian 'tokkee' Harl + * 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 + +#include + +#include +#include +#include + +#include + +/* + * private types + */ + +struct sdb_memstore { + sdb_object_t super; + + /* hosts are the top-level entries and + * reference everything else */ + sdb_avltree_t *hosts; + pthread_rwlock_t host_lock; +}; + +/* internal representation of a to-be-stored object */ +typedef struct { + sdb_memstore_obj_t *parent; + sdb_avltree_t *parent_tree; + int type; + const char *name; + sdb_time_t last_update; + const char * const *backends; + size_t backends_num; +} store_obj_t; +#define STORE_OBJ_INIT { NULL, NULL, 0, NULL, 0, NULL, 0 } + +static sdb_type_t host_type; +static sdb_type_t service_type; +static sdb_type_t metric_type; +static sdb_type_t attribute_type; + +static int +store_init(sdb_object_t *obj, va_list __attribute__((unused)) ap) +{ + int err; + if (! (SDB_MEMSTORE(obj)->hosts = sdb_avltree_create())) + return -1; + if ((err = pthread_rwlock_init(&SDB_MEMSTORE(obj)->host_lock, + /* attr = */ NULL))) { + char errbuf[128]; + sdb_log(SDB_LOG_ERR, "memstore: Failed to initialize lock: %s", + sdb_strerror(err, errbuf, sizeof(errbuf))); + return -1; + } + return 0; +} /* store_init */ + +static void +store_destroy(sdb_object_t *obj) +{ + int err; + if ((err = pthread_rwlock_destroy(&SDB_MEMSTORE(obj)->host_lock))) { + char errbuf[128]; + sdb_log(SDB_LOG_ERR, "memstore: Failed to destroy lock: %s", + sdb_strerror(err, errbuf, sizeof(errbuf))); + return; + } + sdb_avltree_destroy(SDB_MEMSTORE(obj)->hosts); + SDB_MEMSTORE(obj)->hosts = NULL; +} /* store_destroy */ + +static int +store_obj_init(sdb_object_t *obj, va_list ap) +{ + sdb_memstore_obj_t *sobj = STORE_OBJ(obj); + + sobj->type = va_arg(ap, int); + + sobj->last_update = va_arg(ap, sdb_time_t); + sobj->interval = 0; + sobj->backends = NULL; + sobj->backends_num = 0; + sobj->parent = NULL; + return 0; +} /* store_obj_init */ + +static void +store_obj_destroy(sdb_object_t *obj) +{ + sdb_memstore_obj_t *sobj = STORE_OBJ(obj); + size_t i; + + for (i = 0; i < sobj->backends_num; ++i) + free(sobj->backends[i]); + free(sobj->backends); + sobj->backends = NULL; + sobj->backends_num = 0; + + // We don't currently keep an extra reference for parent objects to + // avoid circular self-references which are not handled correctly by + // the ref-count base management layer. + //sdb_object_deref(SDB_OBJ(sobj->parent)); +} /* store_obj_destroy */ + +static int +host_init(sdb_object_t *obj, va_list ap) +{ + host_t *sobj = HOST(obj); + int ret; + + /* this will consume the first argument (type) of ap */ + ret = store_obj_init(obj, ap); + if (ret) + return ret; + + sobj->services = sdb_avltree_create(); + if (! sobj->services) + return -1; + sobj->metrics = sdb_avltree_create(); + if (! sobj->metrics) + return -1; + sobj->attributes = sdb_avltree_create(); + if (! sobj->attributes) + return -1; + return 0; +} /* host_init */ + +static void +host_destroy(sdb_object_t *obj) +{ + host_t *sobj = HOST(obj); + assert(obj); + + store_obj_destroy(obj); + + if (sobj->services) + sdb_avltree_destroy(sobj->services); + if (sobj->metrics) + sdb_avltree_destroy(sobj->metrics); + if (sobj->attributes) + sdb_avltree_destroy(sobj->attributes); +} /* host_destroy */ + +static int +service_init(sdb_object_t *obj, va_list ap) +{ + service_t *sobj = SVC(obj); + int ret; + + /* this will consume the first argument (type) of ap */ + ret = store_obj_init(obj, ap); + if (ret) + return ret; + + sobj->attributes = sdb_avltree_create(); + if (! sobj->attributes) + return -1; + return 0; +} /* service_init */ + +static void +service_destroy(sdb_object_t *obj) +{ + service_t *sobj = SVC(obj); + assert(obj); + + store_obj_destroy(obj); + + if (sobj->attributes) + sdb_avltree_destroy(sobj->attributes); +} /* service_destroy */ + +static int +metric_init(sdb_object_t *obj, va_list ap) +{ + metric_t *sobj = METRIC(obj); + int ret; + + /* this will consume the first argument (type) of ap */ + ret = store_obj_init(obj, ap); + if (ret) + return ret; + + sobj->attributes = sdb_avltree_create(); + if (! sobj->attributes) + return -1; + + sobj->store.type = sobj->store.id = NULL; + return 0; +} /* metric_init */ + +static void +metric_destroy(sdb_object_t *obj) +{ + metric_t *sobj = METRIC(obj); + assert(obj); + + store_obj_destroy(obj); + + if (sobj->attributes) + sdb_avltree_destroy(sobj->attributes); + + if (sobj->store.type) + free(sobj->store.type); + if (sobj->store.id) + free(sobj->store.id); +} /* metric_destroy */ + +static int +attr_init(sdb_object_t *obj, va_list ap) +{ + const sdb_data_t *value; + int ret; + + /* this will consume the first two arguments + * (type and last_update) of ap */ + ret = store_obj_init(obj, ap); + if (ret) + return ret; + value = va_arg(ap, const sdb_data_t *); + + if (value) + if (sdb_data_copy(&ATTR(obj)->value, value)) + return -1; + return 0; +} /* attr_init */ + +static void +attr_destroy(sdb_object_t *obj) +{ + assert(obj); + + store_obj_destroy(obj); + sdb_data_free_datum(&ATTR(obj)->value); +} /* attr_destroy */ + +static sdb_type_t store_type = { + /* size = */ sizeof(sdb_memstore_t), + /* init = */ store_init, + /* destroy = */ store_destroy, +}; + +static sdb_type_t host_type = { + /* size = */ sizeof(host_t), + /* init = */ host_init, + /* destroy = */ host_destroy +}; + +static sdb_type_t service_type = { + /* size = */ sizeof(service_t), + /* init = */ service_init, + /* destroy = */ service_destroy +}; + +static sdb_type_t metric_type = { + /* size = */ sizeof(metric_t), + /* init = */ metric_init, + /* destroy = */ metric_destroy +}; + +static sdb_type_t attribute_type = { + /* size = */ sizeof(attr_t), + /* init = */ attr_init, + /* destroy = */ attr_destroy +}; + +/* + * private helper functions + */ + +static int +record_backends(sdb_memstore_obj_t *obj, + const char * const *backends, size_t backends_num) +{ + char **tmp; + size_t i; + + for (i = 0; i < backends_num; i++) { + bool found = 0; + size_t j; + + for (j = 0; j < obj->backends_num; ++j) { + if (!strcasecmp(obj->backends[j], backends[i])) { + found = 1; + break; + } + } + if (found) + continue; + + tmp = realloc(obj->backends, + (obj->backends_num + 1) * sizeof(*obj->backends)); + if (! tmp) + return -1; + + obj->backends = tmp; + obj->backends[obj->backends_num] = strdup(backends[i]); + if (! obj->backends[obj->backends_num]) + return -1; + + ++obj->backends_num; + } + return 0; +} /* record_backends */ + +static int +store_obj(store_obj_t *obj, sdb_memstore_obj_t **updated_obj) +{ + sdb_memstore_obj_t *old, *new; + int status = 0; + + assert(obj->parent_tree); + + if (obj->last_update <= 0) + obj->last_update = sdb_gettime(); + + old = STORE_OBJ(sdb_avltree_lookup(obj->parent_tree, obj->name)); + if (old) { + if (old->last_update > obj->last_update) { + sdb_log(SDB_LOG_DEBUG, "memstore: Cannot update %s '%s' - " + "value too old (%"PRIsdbTIME" < %"PRIsdbTIME")", + SDB_STORE_TYPE_TO_NAME(obj->type), obj->name, + obj->last_update, old->last_update); + /* don't report an error; the object may be updated by multiple + * backends */ + status = 1; + } + else if (old->last_update == obj->last_update) { + /* don't report an error and also don't even log this to avoid + * excessive noise on high sampling frequencies */ + status = 1; + } + else { + sdb_time_t interval = obj->last_update - old->last_update; + old->last_update = obj->last_update; + if (interval) { + if (old->interval) + old->interval = (sdb_time_t)((0.9 * (double)old->interval) + + (0.1 * (double)interval)); + else + old->interval = interval; + } + } + + new = old; + sdb_object_deref(SDB_OBJ(old)); + } + else { + if (obj->type == SDB_ATTRIBUTE) { + /* the value will be updated by the caller */ + new = STORE_OBJ(sdb_object_create(obj->name, attribute_type, + obj->type, obj->last_update, NULL)); + } + else { + sdb_type_t t; + t = obj->type == SDB_HOST + ? host_type + : obj->type == SDB_SERVICE + ? service_type + : metric_type; + new = STORE_OBJ(sdb_object_create(obj->name, t, + obj->type, obj->last_update)); + } + + if (new) { + status = sdb_avltree_insert(obj->parent_tree, SDB_OBJ(new)); + + /* pass control to the tree or destroy in case of an error */ + sdb_object_deref(SDB_OBJ(new)); + } + else { + char errbuf[1024]; + sdb_log(SDB_LOG_ERR, "memstore: Failed to create %s '%s': %s", + SDB_STORE_TYPE_TO_NAME(obj->type), obj->name, + sdb_strerror(errno, errbuf, sizeof(errbuf))); + status = -1; + } + } + + if (status < 0) + return status; + assert(new); + + if (new->parent != obj->parent) { + // Avoid circular self-references which are not handled + // correctly by the ref-count based management layer. + //sdb_object_deref(SDB_OBJ(new->parent)); + //sdb_object_ref(SDB_OBJ(obj->parent)); + new->parent = obj->parent; + } + + if (updated_obj) + *updated_obj = new; + + if (record_backends(new, obj->backends, obj->backends_num)) + return -1; + return status; +} /* store_obj */ + +static int +store_metric_store(metric_t *metric, sdb_store_metric_t *m) +{ + char *type = metric->store.type; + char *id = metric->store.id; + + if ((! metric->store.type) || strcasecmp(metric->store.type, m->store.type)) { + if (! (type = strdup(m->store.type))) + return -1; + } + if ((! metric->store.id) || strcasecmp(metric->store.id, m->store.id)) { + if (! (id = strdup(m->store.id))) { + if (type != metric->store.type) + free(type); + return -1; + } + } + + if (type != metric->store.type) { + if (metric->store.type) + free(metric->store.type); + metric->store.type = type; + } + if (id != metric->store.id) { + if (metric->store.id) + free(metric->store.id); + metric->store.id = id; + } + return 0; +} /* store_metric_store */ + +/* The store's host_lock has to be acquired before calling this function. */ +static sdb_avltree_t * +get_host_children(host_t *host, int type) +{ + if ((type != SDB_SERVICE) && (type != SDB_METRIC) + && (type != SDB_ATTRIBUTE)) + return NULL; + + if (! host) + return NULL; + + if (type == SDB_ATTRIBUTE) + return host->attributes; + else if (type == SDB_METRIC) + return host->metrics; + else + return host->services; +} /* get_host_children */ + +/* + * store writer API + */ + +static int +store_attribute(sdb_store_attribute_t *attr, sdb_object_t *user_data) +{ + sdb_memstore_t *st = SDB_MEMSTORE(user_data); + store_obj_t obj = STORE_OBJ_INIT; + sdb_memstore_obj_t *new = NULL; + const char *hostname; + host_t *host; + + sdb_avltree_t *children = NULL; + int status = 0; + + if ((! attr) || (! attr->parent) || (! attr->key)) + return -1; + + hostname = attr->hostname; + if (attr->parent_type == SDB_HOST) + hostname = attr->parent; + if (! hostname) + return -1; + + pthread_rwlock_wrlock(&st->host_lock); + host = HOST(sdb_avltree_lookup(st->hosts, hostname)); + if (! host) { + sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - " + "host '%s' not found", attr->key, hostname); + status = -1; + } + + switch (attr->parent_type) { + case SDB_HOST: + obj.parent = STORE_OBJ(host); + obj.parent_tree = get_host_children(host, SDB_ATTRIBUTE); + break; + case SDB_SERVICE: + children = get_host_children(host, SDB_SERVICE); + break; + case SDB_METRIC: + children = get_host_children(host, SDB_METRIC); + break; + default: + status = -1; + break; + } + + if (children) { + obj.parent = STORE_OBJ(sdb_avltree_lookup(children, attr->parent)); + if (! obj.parent) { + sdb_log(SDB_LOG_ERR, "memstore: Failed to store attribute '%s' - " + "%s '%s/%s' not found", attr->key, + SDB_STORE_TYPE_TO_NAME(attr->parent_type), + attr->hostname, attr->parent); + status = -1; + } + else + obj.parent_tree = attr->parent_type == SDB_SERVICE + ? SVC(obj.parent)->attributes + : METRIC(obj.parent)->attributes; + } + + obj.type = SDB_ATTRIBUTE; + obj.name = attr->key; + obj.last_update = attr->last_update; + obj.backends = attr->backends; + obj.backends_num = attr->backends_num; + if (! status) + status = store_obj(&obj, &new); + + if (! status) { + assert(new); + /* update the value if it changed */ + if (sdb_data_cmp(&ATTR(new)->value, &attr->value)) + if (sdb_data_copy(&ATTR(new)->value, &attr->value)) + status = -1; + } + + if (obj.parent != STORE_OBJ(host)) + sdb_object_deref(SDB_OBJ(obj.parent)); + sdb_object_deref(SDB_OBJ(host)); + pthread_rwlock_unlock(&st->host_lock); + + return status; +} /* store_attribute */ + +static int +store_host(sdb_store_host_t *host, sdb_object_t *user_data) +{ + sdb_memstore_t *st = SDB_MEMSTORE(user_data); + store_obj_t obj = { NULL, st->hosts, SDB_HOST, NULL, 0, NULL, 0 }; + int status = 0; + + if ((! host) || (! host->name)) + return -1; + + obj.name = host->name; + obj.last_update = host->last_update; + obj.backends = host->backends; + obj.backends_num = host->backends_num; + pthread_rwlock_wrlock(&st->host_lock); + status = store_obj(&obj, NULL); + pthread_rwlock_unlock(&st->host_lock); + + return status; +} /* store_host */ + +static int +store_service(sdb_store_service_t *service, sdb_object_t *user_data) +{ + sdb_memstore_t *st = SDB_MEMSTORE(user_data); + store_obj_t obj = STORE_OBJ_INIT; + host_t *host; + + int status = 0; + + if ((! service) || (! service->hostname) || (! service->name)) + return -1; + + pthread_rwlock_wrlock(&st->host_lock); + host = HOST(sdb_avltree_lookup(st->hosts, service->hostname)); + obj.parent = STORE_OBJ(host); + obj.parent_tree = get_host_children(host, SDB_SERVICE); + obj.type = SDB_SERVICE; + if (! obj.parent_tree) { + sdb_log(SDB_LOG_ERR, "memstore: Failed to store service '%s' - " + "host '%s' not found", service->name, service->hostname); + status = -1; + } + + obj.name = service->name; + obj.last_update = service->last_update; + obj.backends = service->backends; + obj.backends_num = service->backends_num; + if (! status) + status = store_obj(&obj, NULL); + + sdb_object_deref(SDB_OBJ(host)); + pthread_rwlock_unlock(&st->host_lock); + return status; +} /* store_service */ + +static int +store_metric(sdb_store_metric_t *metric, sdb_object_t *user_data) +{ + sdb_memstore_t *st = SDB_MEMSTORE(user_data); + store_obj_t obj = STORE_OBJ_INIT; + sdb_memstore_obj_t *new = NULL; + host_t *host; + + int status = 0; + + if ((! metric) || (! metric->hostname) || (! metric->name)) + return -1; + + if ((metric->store.type != NULL) != (metric->store.id != NULL)) + return -1; + + pthread_rwlock_wrlock(&st->host_lock); + host = HOST(sdb_avltree_lookup(st->hosts, metric->hostname)); + obj.parent = STORE_OBJ(host); + obj.parent_tree = get_host_children(host, SDB_METRIC); + obj.type = SDB_METRIC; + if (! obj.parent_tree) { + sdb_log(SDB_LOG_ERR, "memstore: Failed to store metric '%s' - " + "host '%s' not found", metric->name, metric->hostname); + status = -1; + } + + obj.name = metric->name; + obj.last_update = metric->last_update; + obj.backends = metric->backends; + obj.backends_num = metric->backends_num; + if (! status) + status = store_obj(&obj, &new); + sdb_object_deref(SDB_OBJ(host)); + + if (status) { + pthread_rwlock_unlock(&st->host_lock); + return status; + } + + assert(new); + if (metric->store.type && metric->store.id) + if (store_metric_store(METRIC(new), metric)) + status = -1; + pthread_rwlock_unlock(&st->host_lock); + return status; +} /* store_metric */ + +sdb_store_writer_t sdb_memstore_writer = { + store_host, store_service, store_metric, store_attribute, +}; + +/* + * store query API + */ + +static sdb_object_t * +prepare_query(sdb_ast_node_t *ast, + sdb_strbuf_t __attribute__((unused)) *errbuf, + sdb_object_t __attribute__((unused)) *user_data) +{ + return SDB_OBJ(sdb_memstore_query_prepare(ast)); +} /* prepare_query */ + +static int +execute_query(sdb_object_t *q, + sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf, + sdb_object_t *user_data) +{ + return sdb_memstore_query_execute(SDB_MEMSTORE(user_data), + QUERY(q), w, wd, errbuf); +} /* execute_query */ + +sdb_store_reader_t sdb_memstore_reader = { + prepare_query, execute_query, +}; + +/* + * public API + */ + +sdb_memstore_t * +sdb_memstore_create(void) +{ + return SDB_MEMSTORE(sdb_object_create("memstore", store_type)); +} /* sdb_memstore_create */ + +int +sdb_memstore_host(sdb_memstore_t *store, const char *name, sdb_time_t last_update) +{ + sdb_store_host_t host = { + name, last_update, 0, NULL, 0, + }; + return store_host(&host, SDB_OBJ(store)); +} /* sdb_memstore_host */ + +int +sdb_memstore_service(sdb_memstore_t *store, const char *hostname, const char *name, + sdb_time_t last_update) +{ + sdb_store_service_t service = { + hostname, name, last_update, 0, NULL, 0, + }; + return store_service(&service, SDB_OBJ(store)); +} /* sdb_memstore_service */ + +int +sdb_memstore_metric(sdb_memstore_t *store, const char *hostname, const char *name, + sdb_metric_store_t *metric_store, sdb_time_t last_update) +{ + sdb_store_metric_t metric = { + hostname, name, { NULL, NULL }, last_update, 0, NULL, 0, + }; + if (metric_store) { + metric.store.type = metric_store->type; + metric.store.id = metric_store->id; + } + return store_metric(&metric, SDB_OBJ(store)); +} /* sdb_memstore_metric */ + +int +sdb_memstore_attribute(sdb_memstore_t *store, const char *hostname, + const char *key, const sdb_data_t *value, sdb_time_t last_update) +{ + sdb_store_attribute_t attr = { + NULL, SDB_HOST, hostname, key, SDB_DATA_INIT, last_update, 0, NULL, 0, + }; + if (value) { + attr.value = *value; + } + return store_attribute(&attr, SDB_OBJ(store)); +} /* sdb_memstore_attribute */ + +int +sdb_memstore_service_attr(sdb_memstore_t *store, const char *hostname, + const char *service, const char *key, const sdb_data_t *value, + sdb_time_t last_update) +{ + sdb_store_attribute_t attr = { + hostname, SDB_SERVICE, service, key, SDB_DATA_INIT, last_update, 0, NULL, 0, + }; + if (value) { + attr.value = *value; + } + return store_attribute(&attr, SDB_OBJ(store)); +} /* sdb_memstore_service_attr */ + +int +sdb_memstore_metric_attr(sdb_memstore_t *store, const char *hostname, + const char *metric, const char *key, const sdb_data_t *value, + sdb_time_t last_update) +{ + sdb_store_attribute_t attr = { + hostname, SDB_METRIC, metric, key, SDB_DATA_INIT, last_update, 0, NULL, 0, + }; + if (value) { + attr.value = *value; + } + return store_attribute(&attr, SDB_OBJ(store)); +} /* sdb_memstore_metric_attr */ + +sdb_memstore_obj_t * +sdb_memstore_get_host(sdb_memstore_t *store, const char *name) +{ + host_t *host; + + if ((! store) || (! name)) + return NULL; + + host = HOST(sdb_avltree_lookup(store->hosts, name)); + if (! host) + return NULL; + + return STORE_OBJ(host); +} /* sdb_memstore_get_host */ + +sdb_memstore_obj_t * +sdb_memstore_get_child(sdb_memstore_obj_t *host, int type, const char *name) +{ + sdb_avltree_t *children; + + if ((! host) || (host->type != SDB_HOST) || (! name)) + return NULL; + + children = get_host_children(HOST(host), type); + if (! children) + return NULL; + return STORE_OBJ(sdb_avltree_lookup(children, name)); +} /* sdb_memstore_get_child */ + +int +sdb_memstore_get_field(sdb_memstore_obj_t *obj, int field, sdb_data_t *res) +{ + sdb_data_t tmp; + + if (! obj) + return -1; + + switch (field) { + case SDB_FIELD_NAME: + tmp.type = SDB_TYPE_STRING; + tmp.data.string = strdup(SDB_OBJ(obj)->name); + if (! tmp.data.string) + return -1; + break; + case SDB_FIELD_LAST_UPDATE: + tmp.type = SDB_TYPE_DATETIME; + tmp.data.datetime = obj->last_update; + break; + case SDB_FIELD_AGE: + tmp.type = SDB_TYPE_DATETIME; + tmp.data.datetime = sdb_gettime() - obj->last_update; + break; + case SDB_FIELD_INTERVAL: + tmp.type = SDB_TYPE_DATETIME; + tmp.data.datetime = obj->interval; + break; + case SDB_FIELD_BACKEND: + if (! res) + return 0; + tmp.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING; + tmp.data.array.length = obj->backends_num; + tmp.data.array.values = obj->backends; + return sdb_data_copy(res, &tmp); + case SDB_FIELD_VALUE: + if (obj->type != SDB_ATTRIBUTE) + return -1; + if (! res) + return 0; + return sdb_data_copy(res, &ATTR(obj)->value); + case SDB_FIELD_TIMESERIES: + if (obj->type != SDB_METRIC) + return -1; + tmp.type = SDB_TYPE_BOOLEAN; + tmp.data.boolean = METRIC(obj)->store.type != NULL; + default: + return -1; + } + if (res) + *res = tmp; + else + sdb_data_free_datum(&tmp); + return 0; +} /* sdb_memstore_get_field */ + +int +sdb_memstore_get_attr(sdb_memstore_obj_t *obj, const char *name, sdb_data_t *res, + sdb_memstore_matcher_t *filter) +{ + sdb_avltree_t *tree = NULL; + sdb_memstore_obj_t *attr; + + if ((! obj) || (! name)) + return -1; + + if (obj->type == SDB_HOST) + tree = HOST(obj)->attributes; + else if (obj->type == SDB_SERVICE) + tree = SVC(obj)->attributes; + else if (obj->type == SDB_METRIC) + tree = METRIC(obj)->attributes; + + if (! tree) + return -1; + + attr = STORE_OBJ(sdb_avltree_lookup(tree, name)); + if (! attr) + return -1; + if (filter && (! sdb_memstore_matcher_matches(filter, attr, NULL))) { + sdb_object_deref(SDB_OBJ(attr)); + return -1; + } + + assert(STORE_OBJ(attr)->type == SDB_ATTRIBUTE); + if (res) + sdb_data_copy(res, &ATTR(attr)->value); + sdb_object_deref(SDB_OBJ(attr)); + return 0; +} /* sdb_memstore_get_attr */ + +int +sdb_memstore_scan(sdb_memstore_t *store, int type, + sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter, + sdb_memstore_lookup_cb cb, void *user_data) +{ + sdb_avltree_iter_t *host_iter = NULL; + int status = 0; + + if ((! store) || (! cb)) + return -1; + + if ((type != SDB_HOST) && (type != SDB_SERVICE) && (type != SDB_METRIC)) { + sdb_log(SDB_LOG_ERR, "memstore: Cannot scan objects of type %d", type); + return -1; + } + + pthread_rwlock_rdlock(&store->host_lock); + host_iter = sdb_avltree_get_iter(store->hosts); + if (! host_iter) + status = -1; + + /* has_next returns false if the iterator is NULL */ + while (sdb_avltree_iter_has_next(host_iter)) { + sdb_memstore_obj_t *host; + sdb_avltree_iter_t *iter = NULL; + + host = STORE_OBJ(sdb_avltree_iter_get_next(host_iter)); + assert(host); + + if (! sdb_memstore_matcher_matches(filter, host, NULL)) + continue; + + if (type == SDB_SERVICE) + iter = sdb_avltree_get_iter(HOST(host)->services); + else if (type == SDB_METRIC) + iter = sdb_avltree_get_iter(HOST(host)->metrics); + + if (iter) { + while (sdb_avltree_iter_has_next(iter)) { + sdb_memstore_obj_t *obj; + obj = STORE_OBJ(sdb_avltree_iter_get_next(iter)); + assert(obj); + + if (sdb_memstore_matcher_matches(m, obj, filter)) { + if (cb(obj, filter, user_data)) { + sdb_log(SDB_LOG_ERR, "memstore: Callback returned " + "an error while scanning"); + status = -1; + break; + } + } + } + } + else if (sdb_memstore_matcher_matches(m, host, filter)) { + if (cb(host, filter, user_data)) { + sdb_log(SDB_LOG_ERR, "memstore: Callback returned " + "an error while scanning"); + status = -1; + } + } + + sdb_avltree_iter_destroy(iter); + if (status) + break; + } + + sdb_avltree_iter_destroy(host_iter); + pthread_rwlock_unlock(&store->host_lock); + return status; +} /* sdb_memstore_scan */ + +int +sdb_memstore_emit(sdb_memstore_obj_t *obj, sdb_store_writer_t *w, sdb_object_t *wd) +{ + if ((! obj) || (! w)) + return -1; + + switch (obj->type) { + case SDB_HOST: + { + sdb_store_host_t host = { + obj->_name, + obj->last_update, + obj->interval, + (const char * const *)obj->backends, + obj->backends_num, + }; + if (! w->store_host) + return -1; + return w->store_host(&host, wd); + } + case SDB_SERVICE: + { + sdb_store_service_t service = { + obj->parent ? obj->parent->_name : NULL, + obj->_name, + obj->last_update, + obj->interval, + (const char * const *)obj->backends, + obj->backends_num, + }; + if (! w->store_service) + return -1; + return w->store_service(&service, wd); + } + case SDB_METRIC: + { + sdb_store_metric_t metric = { + obj->parent ? obj->parent->_name : NULL, + obj->_name, + { + METRIC(obj)->store.type, + METRIC(obj)->store.id, + }, + obj->last_update, + obj->interval, + (const char * const *)obj->backends, + obj->backends_num, + }; + if (! w->store_metric) + return -1; + return w->store_metric(&metric, wd); + } + case SDB_ATTRIBUTE: + { + sdb_store_attribute_t attr = { + NULL, + obj->parent ? obj->parent->type : 0, + obj->parent ? obj->parent->_name : NULL, + obj->_name, + ATTR(obj)->value, + obj->last_update, + obj->interval, + (const char * const *)obj->backends, + obj->backends_num, + }; + if (obj->parent && (obj->parent->type != SDB_HOST) + && obj->parent->parent) + attr.hostname = obj->parent->parent->_name; + if (! w->store_attribute) + return -1; + return w->store_attribute(&attr, wd); + } + } + + return -1; +} /* sdb_memstore_emit */ + +int +sdb_memstore_emit_full(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter, + sdb_store_writer_t *w, sdb_object_t *wd) +{ + sdb_avltree_t *trees[] = { NULL, NULL, NULL }; + size_t i; + + if (sdb_memstore_emit(obj, w, wd)) + return -1; + + if (obj->type == SDB_HOST) { + trees[0] = HOST(obj)->attributes; + trees[1] = HOST(obj)->metrics; + trees[2] = HOST(obj)->services; + } + else if (obj->type == SDB_SERVICE) + trees[0] = SVC(obj)->attributes; + else if (obj->type == SDB_METRIC) + trees[0] = METRIC(obj)->attributes; + else if (obj->type == SDB_ATTRIBUTE) + return 0; + else + return -1; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(trees); ++i) { + sdb_avltree_iter_t *iter; + + if (! trees[i]) + continue; + + iter = sdb_avltree_get_iter(trees[i]); + while (sdb_avltree_iter_has_next(iter)) { + sdb_memstore_obj_t *child; + child = STORE_OBJ(sdb_avltree_iter_get_next(iter)); + + if (filter && (! sdb_memstore_matcher_matches(filter, child, NULL))) + continue; + + if (sdb_memstore_emit_full(child, filter, w, wd)) { + sdb_avltree_iter_destroy(iter); + return -1; + } + } + sdb_avltree_iter_destroy(iter); + } + return 0; +} /* sdb_memstore_emit_full */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/core/memstore_exec.c b/src/core/memstore_exec.c new file mode 100644 index 0000000..802e70c --- /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 + * 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 + +#include +#include +#include + +/* + * private helper functions + */ + +typedef struct { + sdb_memstore_obj_t *current_host; + + sdb_store_writer_t *w; + sdb_object_t *wd; +} iter_t; + +static int +maybe_emit_host(iter_t *iter, sdb_memstore_obj_t *obj) +{ + if ((obj->type == SDB_HOST) || (obj->type == SDB_ATTRIBUTE)) + return 0; + if (iter->current_host == obj->parent) + return 0; + iter->current_host = obj->parent; + return sdb_memstore_emit(obj->parent, iter->w, iter->wd); +} /* maybe_emit_host */ + +static int +list_tojson(sdb_memstore_obj_t *obj, + sdb_memstore_matcher_t __attribute__((unused)) *filter, + void *user_data) +{ + iter_t *iter = user_data; + maybe_emit_host(iter, obj); + return sdb_memstore_emit(obj, iter->w, iter->wd); +} /* list_tojson */ + +static int +lookup_tojson(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter, + void *user_data) +{ + iter_t *iter = user_data; + maybe_emit_host(iter, obj); + return sdb_memstore_emit_full(obj, filter, iter->w, iter->wd); +} /* lookup_tojson */ + +/* + * query implementations + */ + +static int +exec_fetch(sdb_memstore_t *store, + sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf, + int type, const char *hostname, const char *name, + sdb_memstore_matcher_t *filter) +{ + sdb_memstore_obj_t *host; + sdb_memstore_obj_t *obj; + + int status = 0; + + if ((! name) || ((type == SDB_HOST) && hostname) + || ((type != SDB_HOST) && (! hostname))) { + /* This is a programming error, not something the client did wrong */ + sdb_strbuf_sprintf(errbuf, "INTERNAL ERROR: invalid " + "arguments to FETCH(%s, %s, %s)", + SDB_STORE_TYPE_TO_NAME(type), hostname, name); + return -1; + } + if (type == SDB_HOST) + hostname = name; + + host = sdb_memstore_get_host(store, hostname); + if ((! host) + || (filter && (! sdb_memstore_matcher_matches(filter, host, NULL)))) { + sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s: " + "host %s not found", SDB_STORE_TYPE_TO_NAME(type), + name, hostname); + sdb_object_deref(SDB_OBJ(host)); + return -1; + } + if (type == SDB_HOST) { + obj = host; + } + else { + obj = sdb_memstore_get_child(host, type, name); + if ((! obj) + || (filter && (! sdb_memstore_matcher_matches(filter, obj, NULL)))) { + sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s.%s: " + "%s not found", SDB_STORE_TYPE_TO_NAME(type), + hostname, name, name); + if (obj) + sdb_object_deref(SDB_OBJ(obj)); + sdb_object_deref(SDB_OBJ(host)); + return -1; + } + sdb_object_deref(SDB_OBJ(host)); + } + host = NULL; + + if (type != SDB_HOST) + status = sdb_memstore_emit(obj->parent, w, wd); + if (status || sdb_memstore_emit_full(obj, filter, w, wd)) { + sdb_log(SDB_LOG_ERR, "memstore: Failed to serialize " + "%s %s.%s to JSON", SDB_STORE_TYPE_TO_NAME(type), + hostname, name); + sdb_strbuf_sprintf(errbuf, "Out of memory"); + sdb_object_deref(SDB_OBJ(obj)); + return -1; + } + + sdb_object_deref(SDB_OBJ(obj)); + return SDB_CONNECTION_DATA; +} /* exec_fetch */ + +static int +exec_list(sdb_memstore_t *store, + sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf, + int type, sdb_memstore_matcher_t *filter) +{ + iter_t iter = { NULL, w, wd }; + + if (sdb_memstore_scan(store, type, /* m = */ NULL, filter, list_tojson, &iter)) { + sdb_log(SDB_LOG_ERR, "memstore: Failed to serialize " + "store to JSON"); + sdb_strbuf_sprintf(errbuf, "Out of memory"); + return -1; + } + + return SDB_CONNECTION_DATA; +} /* exec_list */ + +static int +exec_lookup(sdb_memstore_t *store, + sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf, + int type, sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter) +{ + iter_t iter = { NULL, w, wd }; + + if (sdb_memstore_scan(store, type, m, filter, lookup_tojson, &iter)) { + sdb_log(SDB_LOG_ERR, "memstore: Failed to lookup %ss", + SDB_STORE_TYPE_TO_NAME(type)); + sdb_strbuf_sprintf(errbuf, "Failed to lookup %ss", + SDB_STORE_TYPE_TO_NAME(type)); + return -1; + } + + return SDB_CONNECTION_DATA; +} /* exec_lookup */ + +/* + * public API + */ + +int +sdb_memstore_query_execute(sdb_memstore_t *store, sdb_memstore_query_t *q, + sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf) +{ + sdb_ast_node_t *ast; + + if (! q) + return -1; + if (! q->ast) { + sdb_log(SDB_LOG_ERR, "memstore: Invalid empty query"); + return -1; + } + + ast = q->ast; + switch (ast->type) { + case SDB_AST_TYPE_FETCH: + return exec_fetch(store, w, wd, errbuf, SDB_AST_FETCH(ast)->obj_type, + SDB_AST_FETCH(ast)->hostname, SDB_AST_FETCH(ast)->name, + q->filter); + + case SDB_AST_TYPE_LIST: + return exec_list(store, w, wd, errbuf, SDB_AST_LIST(ast)->obj_type, + q->filter); + + case SDB_AST_TYPE_LOOKUP: + return exec_lookup(store, w, wd, errbuf, SDB_AST_LOOKUP(ast)->obj_type, + q->matcher, q->filter); + + default: + sdb_log(SDB_LOG_ERR, "memstore: Invalid query of type %s", + SDB_AST_TYPE_TO_STRING(ast)); + return -1; + } + + return 0; +} /* sdb_memstore_query_execute */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ diff --git a/src/core/memstore_expr.c b/src/core/memstore_expr.c new file mode 100644 index 0000000..8335584 --- /dev/null +++ b/src/core/memstore_expr.c @@ -0,0 +1,464 @@ +/* + * SysDB - src/core/memstore_expr.c + * Copyright (C) 2014 Sebastian 'tokkee' Harl + * 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 +#include +#include +#include + +/* + * private data types + */ + +/* iterate through either a list of child nodes or arrays */ +struct sdb_memstore_expr_iter { + sdb_memstore_obj_t *obj; + sdb_memstore_expr_t *expr; + + sdb_avltree_iter_t *tree; + + sdb_data_t array; + size_t array_idx; + bool free_array; + + sdb_memstore_matcher_t *filter; +}; + +/* + * private types + */ + +static int +expr_init(sdb_object_t *obj, va_list ap) +{ + int type = va_arg(ap, int); + sdb_memstore_expr_t *left = va_arg(ap, sdb_memstore_expr_t *); + sdb_memstore_expr_t *right = va_arg(ap, sdb_memstore_expr_t *); + const sdb_data_t *value = va_arg(ap, const sdb_data_t *); + + sdb_memstore_expr_t *expr = SDB_MEMSTORE_EXPR(obj); + + if (type <= 0) { + if (! value) + return -1; + if ((type == TYPED_EXPR) && (! left)) + return -1; + } else { + if (value) + return -1; + if ((! left) || (! right)) + return -1; + } + + if (value) + expr->data = *value; + + sdb_object_ref(SDB_OBJ(left)); + sdb_object_ref(SDB_OBJ(right)); + + expr->type = type; + expr->left = left; + expr->right = right; + + /* unknown for now */ + expr->data_type = -1; + return 0; +} /* expr_init */ + +static void +expr_destroy(sdb_object_t *obj) +{ + sdb_memstore_expr_t *expr = SDB_MEMSTORE_EXPR(obj); + sdb_object_deref(SDB_OBJ(expr->left)); + sdb_object_deref(SDB_OBJ(expr->right)); + + if (expr->data.type) + sdb_data_free_datum(&expr->data); +} /* expr_destroy */ + +static sdb_type_t expr_type = { + /* size = */ sizeof(sdb_memstore_expr_t), + /* init = */ expr_init, + /* destroy = */ expr_destroy, +}; + +/* + * public API + */ + +sdb_memstore_expr_t * +sdb_memstore_expr_create(int op, sdb_memstore_expr_t *left, sdb_memstore_expr_t *right) +{ + sdb_data_t value = SDB_DATA_INIT; + sdb_memstore_expr_t *e; + + if ((op < 0) || (SDB_DATA_CONCAT < op) || (! left) || (! right)) + return NULL; + + if (left->type || right->type) { + e = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-expr", expr_type, + op, left, right, NULL)); + e->data_type = sdb_data_expr_type(op, left->type, right->type); + return e; + } + /* else: both expressions are constant values; evaluate now */ + + if (sdb_data_expr_eval(op, &left->data, &right->data, &value)) + return NULL; + e = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-constvalue", expr_type, + 0, NULL, NULL, &value)); + e->data_type = value.type; + return e; +} /* sdb_memstore_expr_create */ + +sdb_memstore_expr_t * +sdb_memstore_expr_typed(int typ, sdb_memstore_expr_t *expr) +{ + sdb_data_t value = { SDB_TYPE_INTEGER, { .integer = typ } }; + sdb_memstore_expr_t *e; + + if ((typ < SDB_HOST) || (SDB_ATTRIBUTE < typ)) + return NULL; + + e = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-typedexpr", expr_type, + TYPED_EXPR, expr, NULL, &value)); + e->data_type = expr->data_type; + return e; +} /* sdb_memstore_expr_typed */ + +sdb_memstore_expr_t * +sdb_memstore_expr_fieldvalue(int field) +{ + sdb_data_t value = { SDB_TYPE_INTEGER, { .integer = field } }; + sdb_memstore_expr_t *e; + + if ((field < SDB_FIELD_NAME) || (SDB_FIELD_TIMESERIES < field)) + return NULL; + e = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-fieldvalue", expr_type, + FIELD_VALUE, NULL, NULL, &value)); + e->data_type = SDB_FIELD_TYPE(field); + return e; +} /* sdb_memstore_expr_fieldvalue */ + +sdb_memstore_expr_t * +sdb_memstore_expr_attrvalue(const char *name) +{ + sdb_data_t value = { SDB_TYPE_STRING, { .string = NULL} }; + sdb_memstore_expr_t *expr; + + value.data.string = strdup(name); + if (! value.data.string) + return NULL; + + expr = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-attrvalue", expr_type, + ATTR_VALUE, NULL, NULL, &value)); + if (! expr) + free(value.data.string); + expr->data_type = -1; + return expr; +} /* sdb_memstore_expr_attrvalue */ + +sdb_memstore_expr_t * +sdb_memstore_expr_constvalue(const sdb_data_t *value) +{ + sdb_data_t data = SDB_DATA_INIT; + sdb_memstore_expr_t *e; + + if (sdb_data_copy(&data, value)) + return NULL; + e = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-constvalue", expr_type, + 0, NULL, NULL, &data)); + e->data_type = data.type; + return e; +} /* sdb_memstore_expr_constvalue */ + +int +sdb_memstore_expr_eval(sdb_memstore_expr_t *expr, sdb_memstore_obj_t *obj, + sdb_data_t *res, sdb_memstore_matcher_t *filter) +{ + sdb_data_t v1 = SDB_DATA_INIT, v2 = SDB_DATA_INIT; + int status = 0; + + if ((! expr) || (! res)) + return -1; + + if (filter && obj && (! sdb_memstore_matcher_matches(filter, obj, NULL))) + obj = NULL; /* this object does not exist */ + + if (! expr->type) + return sdb_data_copy(res, &expr->data); + else if (expr->type == FIELD_VALUE) + return sdb_memstore_get_field(obj, (int)expr->data.data.integer, res); + else if (expr->type == ATTR_VALUE) { + status = sdb_memstore_get_attr(obj, expr->data.data.string, res, filter); + if ((status < 0) && obj) { + /* attribute does not exist => NULL */ + status = 0; + res->type = SDB_TYPE_STRING; + res->data.string = NULL; + } + return status; + } + else if (expr->type == TYPED_EXPR) { + int typ = (int)expr->data.data.integer; + if (typ != obj->type) { + /* we support self-references and { service, metric } -> host */ + if ((typ != SDB_HOST) + || ((obj->type != SDB_SERVICE) + && (obj->type != SDB_METRIC))) + return -1; + obj = obj->parent; + } + return sdb_memstore_expr_eval(expr->left, obj, res, filter); + } + + if (sdb_memstore_expr_eval(expr->left, obj, &v1, filter)) + return -1; + if (sdb_memstore_expr_eval(expr->right, obj, &v2, filter)) { + sdb_data_free_datum(&v1); + return -1; + } + + if (sdb_data_expr_eval(expr->type, &v1, &v2, res)) + status = -1; + sdb_data_free_datum(&v1); + sdb_data_free_datum(&v2); + return status; +} /* sdb_memstore_expr_eval */ + +sdb_memstore_expr_iter_t * +sdb_memstore_expr_iter(sdb_memstore_expr_t *expr, sdb_memstore_obj_t *obj, + sdb_memstore_matcher_t *filter) +{ + sdb_memstore_expr_iter_t *iter; + sdb_avltree_iter_t *tree = NULL; + sdb_data_t array = SDB_DATA_INIT; + bool free_array = 0; + + if (! expr) + return NULL; + + while (expr->type == TYPED_EXPR) { + int type = (int)expr->data.data.integer; + + if (obj->type == type) { + /* self reference */ + } + else if ((type == SDB_HOST) + && ((obj->type == SDB_SERVICE) + || (obj->type == SDB_METRIC))) { + /* reference to parent host */ + obj = obj->parent; + } + else + break; + expr = expr->left; + } + + if (expr->type == TYPED_EXPR) { + if (! obj) + return NULL; + if (obj->type == SDB_HOST) { + if (expr->data.data.integer == SDB_SERVICE) + tree = sdb_avltree_get_iter(HOST(obj)->services); + else if (expr->data.data.integer == SDB_METRIC) + tree = sdb_avltree_get_iter(HOST(obj)->metrics); + else if (expr->data.data.integer == SDB_ATTRIBUTE) + tree = sdb_avltree_get_iter(HOST(obj)->attributes); + } + else if (obj->type == SDB_SERVICE) { + if (expr->data.data.integer == SDB_ATTRIBUTE) + tree = sdb_avltree_get_iter(SVC(obj)->attributes); + } + else if (obj->type == SDB_METRIC) { + if (expr->data.data.integer == SDB_ATTRIBUTE) + tree = sdb_avltree_get_iter(METRIC(obj)->attributes); + } + } + else if (expr->type == FIELD_VALUE) { + if (! obj) + return NULL; + if (expr->data.data.integer == SDB_FIELD_BACKEND) { + /* while scanning the store, we hold a read lock, so it's safe to + * access the data without copying */ + array.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING; + array.data.array.length = obj->backends_num; + array.data.array.values = obj->backends; + } + } + else if (! expr->type) { + if (expr->data.type & SDB_TYPE_ARRAY) + array = expr->data; + } + else { + sdb_data_t value = SDB_DATA_INIT; + if (sdb_memstore_expr_eval(expr, obj, &value, filter)) + return NULL; + if (! (value.type & SDB_TYPE_ARRAY)) { + sdb_data_free_datum(&value); + return NULL; + } + array = value; + free_array = 1; + } + + if ((! tree) && (array.type == SDB_TYPE_NULL)) + return NULL; + + iter = calloc(1, sizeof(*iter)); + if (! iter) { + if (free_array) + sdb_data_free_datum(&array); + return NULL; + } + + sdb_object_ref(SDB_OBJ(obj)); + sdb_object_ref(SDB_OBJ(expr)); + sdb_object_ref(SDB_OBJ(filter)); + + iter->obj = obj; + iter->expr = expr; + iter->tree = tree; + iter->array = array; + iter->free_array = free_array; + iter->filter = filter; + return iter; +} /* sdb_memstore_expr_iter */ + +void +sdb_memstore_expr_iter_destroy(sdb_memstore_expr_iter_t *iter) +{ + sdb_data_t null = SDB_DATA_INIT; + + if (! iter) + return; + + if (iter->tree) + sdb_avltree_iter_destroy(iter->tree); + iter->tree = NULL; + + if (iter->free_array) + sdb_data_free_datum(&iter->array); + iter->array = null; + iter->array_idx = 0; + + sdb_object_deref(SDB_OBJ(iter->obj)); + sdb_object_deref(SDB_OBJ(iter->expr)); + sdb_object_deref(SDB_OBJ(iter->filter)); + free(iter); +} /* sdb_memstore_expr_iter_destroy */ + +bool +sdb_memstore_expr_iter_has_next(sdb_memstore_expr_iter_t *iter) +{ + if (! iter) + return 0; + + if (iter->tree) { + /* this function may be called before get_next, + * so we'll have to apply filters here as well */ + if (iter->filter) { + sdb_memstore_obj_t *child; + while ((child = STORE_OBJ(sdb_avltree_iter_peek_next(iter->tree)))) { + if (sdb_memstore_matcher_matches(iter->filter, child, NULL)) + break; + (void)sdb_avltree_iter_get_next(iter->tree); + } + } + + return sdb_avltree_iter_has_next(iter->tree); + } + + return iter->array_idx < iter->array.data.array.length; +} /* sdb_memstore_expr_iter_has_next */ + +sdb_data_t +sdb_memstore_expr_iter_get_next(sdb_memstore_expr_iter_t *iter) +{ + sdb_data_t null = SDB_DATA_INIT; + sdb_data_t ret = SDB_DATA_INIT; + sdb_data_t tmp = SDB_DATA_INIT; + + if (! iter) + return null; + + if (iter->tree) { + sdb_memstore_obj_t *child; + + while (42) { + child = STORE_OBJ(sdb_avltree_iter_get_next(iter->tree)); + if (! child) + break; + if (iter->filter + && (! sdb_memstore_matcher_matches(iter->filter, child, NULL))) + continue; + + if (sdb_memstore_expr_eval(iter->expr, child, &ret, iter->filter)) + return null; + break; + } + + /* Skip over any filtered objects */ + if (iter->filter) { + while ((child = STORE_OBJ(sdb_avltree_iter_peek_next(iter->tree)))) { + if (sdb_memstore_matcher_matches(iter->filter, child, NULL)) + break; + (void)sdb_avltree_iter_get_next(iter->tree); + } + } + + return ret; + } + + if (iter->array_idx >= iter->array.data.array.length) + return null; + + ++iter->array_idx; + if (sdb_data_array_get(&iter->array, iter->array_idx - 1, &ret)) + return null; + if (sdb_data_copy(&tmp, &ret)) + return null; + ret = tmp; + return ret; +} /* sdb_memstore_expr_iter_get_next */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/core/memstore_lookup.c b/src/core/memstore_lookup.c new file mode 100644 index 0000000..2752a66 --- /dev/null +++ b/src/core/memstore_lookup.c @@ -0,0 +1,694 @@ +/* + * SysDB - src/core/memstore_lookup.c + * Copyright (C) 2014 Sebastian 'tokkee' Harl + * 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 + +#include +#include + +#include +#include + +#include + +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 */ +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 new file mode 100644 index 0000000..eb1e82f --- /dev/null +++ b/src/core/memstore_query.c @@ -0,0 +1,354 @@ +/* + * SysDB - src/core/memstore_query.c + * Copyright (C) 2014-2015 Sebastian 'tokkee' Harl + * 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 + +static sdb_memstore_matcher_t * +node_to_matcher(sdb_ast_node_t *n); + +static sdb_memstore_expr_t * +node_to_expr(sdb_ast_node_t *n) +{ + sdb_memstore_expr_t *left = NULL, *right = NULL; + sdb_memstore_expr_t *e; + int op; + + if (! n) { + sdb_log(SDB_LOG_ERR, "memstore: Encountered empty AST expression node"); + return NULL; + } + + switch (n->type) { + case SDB_AST_TYPE_OPERATOR: + if (! SDB_AST_IS_ARITHMETIC(n)) { + sdb_log(SDB_LOG_ERR, "memstore: Invalid arithmetic operator of " + "type %s (%#x)", SDB_AST_TYPE_TO_STRING(n), n->type); + return NULL; + } + + left = node_to_expr(SDB_AST_OP(n)->left); + if (! left) + return NULL; + right = node_to_expr(SDB_AST_OP(n)->right); + if (! right) { + sdb_object_deref(SDB_OBJ(left)); + return NULL; + } + op = SDB_AST_OP_TO_DATA_OP(SDB_AST_OP(n)->kind); + e = sdb_memstore_expr_create(op, left, right); + break; + + case SDB_AST_TYPE_CONST: + return sdb_memstore_expr_constvalue(&SDB_AST_CONST(n)->value); + + case SDB_AST_TYPE_VALUE: + if (SDB_AST_VALUE(n)->type == SDB_ATTRIBUTE) + return sdb_memstore_expr_attrvalue(SDB_AST_VALUE(n)->name); + return sdb_memstore_expr_fieldvalue(SDB_AST_VALUE(n)->type); + + case SDB_AST_TYPE_TYPED: + right = node_to_expr(SDB_AST_TYPED(n)->expr); + if (! right) + return NULL; + e = sdb_memstore_expr_typed(SDB_AST_TYPED(n)->type, right); + break; + + default: + sdb_log(SDB_LOG_ERR, "memstore: Invalid matcher node of type %s (%#x)", + SDB_AST_TYPE_TO_STRING(n), n->type); + e = NULL; + } + + /* expressions take a reference */ + sdb_object_deref(SDB_OBJ(left)); + sdb_object_deref(SDB_OBJ(right)); + return e; +} /* node_to_expr */ + +static sdb_memstore_matcher_t * +logical_to_matcher(sdb_ast_node_t *n) +{ + sdb_memstore_matcher_t *left = NULL, *right; + sdb_memstore_matcher_t *m; + + if (SDB_AST_OP(n)->left) { + left = node_to_matcher(SDB_AST_OP(n)->left); + if (! left) + return NULL; + } + right = node_to_matcher(SDB_AST_OP(n)->right); + if (! right) { + sdb_object_deref(SDB_OBJ(left)); + return NULL; + } + + switch (SDB_AST_OP(n)->kind) { + case SDB_AST_AND: + m = sdb_memstore_con_matcher(left, right); + break; + case SDB_AST_OR: + m = sdb_memstore_dis_matcher(left, right); + break; + case SDB_AST_NOT: + m = sdb_memstore_inv_matcher(right); + break; + + default: + m = NULL; + } + + /* matchers take a reference */ + sdb_object_deref(SDB_OBJ(left)); + sdb_object_deref(SDB_OBJ(right)); + return m; +} /* logical_to_matcher */ + +static sdb_memstore_matcher_t * +cmp_to_matcher(sdb_ast_node_t *n) +{ + sdb_memstore_expr_t *left = NULL, *right; + sdb_memstore_matcher_t *m; + + if (SDB_AST_OP(n)->left) { + left = node_to_expr(SDB_AST_OP(n)->left); + if (! left) + return NULL; + } + right = node_to_expr(SDB_AST_OP(n)->right); + if (! right) { + sdb_object_deref(SDB_OBJ(left)); + return NULL; + } + + switch (SDB_AST_OP(n)->kind) { + case SDB_AST_LT: + m = sdb_memstore_lt_matcher(left, right); + break; + case SDB_AST_LE: + m = sdb_memstore_le_matcher(left, right); + break; + case SDB_AST_EQ: + m = sdb_memstore_eq_matcher(left, right); + break; + case SDB_AST_NE: + m = sdb_memstore_ne_matcher(left, right); + break; + case SDB_AST_GE: + m = sdb_memstore_ge_matcher(left, right); + break; + case SDB_AST_GT: + m = sdb_memstore_gt_matcher(left, right); + break; + case SDB_AST_REGEX: + m = sdb_memstore_regex_matcher(left, right); + break; + case SDB_AST_NREGEX: + m = sdb_memstore_nregex_matcher(left, right); + break; + case SDB_AST_ISNULL: + m = sdb_memstore_isnull_matcher(right); + break; + case SDB_AST_ISTRUE: + m = sdb_memstore_istrue_matcher(right); + break; + case SDB_AST_ISFALSE: + m = sdb_memstore_isfalse_matcher(right); + break; + case SDB_AST_IN: + m = sdb_memstore_in_matcher(left, right); + break; + + default: + sdb_log(SDB_LOG_ERR, "memstore: Invalid matcher node of type %s (%#x)", + SDB_AST_TYPE_TO_STRING(n), n->type); + m = NULL; + } + + /* matchers take a reference */ + sdb_object_deref(SDB_OBJ(left)); + sdb_object_deref(SDB_OBJ(right)); + return m; +} /* cmp_to_matcher */ + +static sdb_memstore_matcher_t * +iter_to_matcher(sdb_ast_node_t *n) +{ + sdb_memstore_expr_t *iter; + sdb_memstore_matcher_t *expr, *m; + + assert((SDB_AST_ITER(n)->expr->type == SDB_AST_TYPE_OPERATOR) + && (! SDB_AST_OP(SDB_AST_ITER(n)->expr)->left)); + + iter = node_to_expr(SDB_AST_ITER(n)->iter); + if (! iter) + return NULL; + expr = cmp_to_matcher(SDB_AST_ITER(n)->expr); + if (! expr) { + sdb_object_deref(SDB_OBJ(iter)); + return NULL; + } + + switch (SDB_AST_ITER(n)->kind) { + case SDB_AST_ALL: + m = sdb_memstore_all_matcher(iter, expr); + break; + case SDB_AST_ANY: + m = sdb_memstore_any_matcher(iter, expr); + break; + + default: + sdb_log(SDB_LOG_ERR, "memstore: Invalid iterator node of type %s (%#x)", + SDB_AST_OP_TO_STRING(SDB_AST_ITER(n)->kind), SDB_AST_ITER(n)->kind); + m = NULL; + } + + /* matchers take a reference */ + sdb_object_deref(SDB_OBJ(iter)); + sdb_object_deref(SDB_OBJ(expr)); + return m; +} /* iter_to_matcher */ + +static sdb_memstore_matcher_t * +node_to_matcher(sdb_ast_node_t *n) +{ + int kind; + + if (! n) { + sdb_log(SDB_LOG_ERR, "memstore: Encountered empty AST matcher node"); + return NULL; + } + + switch (n->type) { + case SDB_AST_TYPE_OPERATOR: + if (! SDB_AST_IS_LOGICAL(n)) { + sdb_log(SDB_LOG_ERR, "memstore: Invalid logical operator of " + "type %s (%#x)", SDB_AST_TYPE_TO_STRING(n), n->type); + return NULL; + } + + kind = SDB_AST_OP(n)->kind; + if ((kind == SDB_AST_AND) || (kind == SDB_AST_OR) || (kind == SDB_AST_NOT)) + return logical_to_matcher(n); + else + return cmp_to_matcher(n); + + case SDB_AST_TYPE_ITERATOR: + return iter_to_matcher(n); + } + + sdb_log(SDB_LOG_ERR, "memstore: Invalid matcher node of type %s (%#x)", + SDB_AST_TYPE_TO_STRING(n), n->type); + return NULL; +} /* node_to_matcher */ + +/* + * query type + */ + +static int +query_init(sdb_object_t *obj, va_list ap) +{ + sdb_ast_node_t *ast = va_arg(ap, sdb_ast_node_t *); + sdb_ast_node_t *matcher = NULL, *filter = NULL; + + QUERY(obj)->ast = ast; + sdb_object_ref(SDB_OBJ(ast)); + + switch (ast->type) { + case SDB_AST_TYPE_FETCH: + filter = SDB_AST_FETCH(ast)->filter; + break; + case SDB_AST_TYPE_LIST: + filter = SDB_AST_LIST(ast)->filter; + break; + case SDB_AST_TYPE_LOOKUP: + matcher = SDB_AST_LOOKUP(ast)->matcher; + filter = SDB_AST_LOOKUP(ast)->filter; + break; + case SDB_AST_TYPE_STORE: + case SDB_AST_TYPE_TIMESERIES: + /* nothing to do */ + break; + + default: + sdb_log(SDB_LOG_ERR, "memstore: Invalid top-level AST node " + "of type %#x", ast->type); + return -1; + } + + if (matcher) { + QUERY(obj)->matcher = node_to_matcher(matcher); + if (! QUERY(obj)->matcher) + return -1; + } + if (filter) { + QUERY(obj)->filter = node_to_matcher(filter); + if (! QUERY(obj)->filter) + return -1; + } + + return 0; +} /* query_init */ + +static void +query_destroy(sdb_object_t *obj) +{ + sdb_object_deref(SDB_OBJ(QUERY(obj)->ast)); + sdb_object_deref(SDB_OBJ(QUERY(obj)->matcher)); + sdb_object_deref(SDB_OBJ(QUERY(obj)->filter)); +} /* query_destroy */ + +static sdb_type_t query_type = { + /* size = */ sizeof(sdb_memstore_query_t), + /* init = */ query_init, + /* destroy = */ query_destroy, +}; + +/* + * public API + */ + +sdb_memstore_query_t * +sdb_memstore_query_prepare(sdb_ast_node_t *ast) +{ + if (! ast) + return NULL; + return QUERY(sdb_object_create(SDB_AST_TYPE_TO_STRING(ast), query_type, ast)); +} /* sdb_memstore_query_prepare */ + +sdb_memstore_matcher_t * +sdb_memstore_query_prepare_matcher(sdb_ast_node_t *ast) +{ + return node_to_matcher(ast); +} /* sdb_memstore_query_prepare_matcher */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ diff --git a/src/core/store-private.h b/src/core/store-private.h deleted file mode 100644 index 2f9d96c..0000000 --- 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 - * 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 -#include - -#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) ? "" \ - : ((e)->type == ATTR_VALUE) ? "attribute" \ - : ((e)->type == FIELD_VALUE) ? SDB_FIELD_TO_NAME((e)->data.data.integer) \ - : ((e)->type == 0) ? "" \ - : ((e)->type > 0) ? SDB_DATA_OP_TO_STRING((e)->type) \ - : "") - -/* - * matchers - */ - -/* when adding to this, also update 'MATCHER_SYM' below and 'matchers' in - * store_lookup.c */ -enum { - MATCHER_OR, - MATCHER_AND, - MATCHER_NOT, - MATCHER_ANY, - MATCHER_ALL, - MATCHER_IN, - - /* unary operators */ - MATCHER_ISNULL, - MATCHER_ISTRUE, - MATCHER_ISFALSE, - - /* ary operators */ - MATCHER_LT, - MATCHER_LE, - MATCHER_EQ, - MATCHER_NE, - MATCHER_GE, - MATCHER_GT, - MATCHER_REGEX, - MATCHER_NREGEX, - - /* a generic query */ - MATCHER_QUERY, -}; - -#define MATCHER_SYM(t) \ - (((t) == MATCHER_OR) ? "OR" \ - : ((t) == MATCHER_AND) ? "AND" \ - : ((t) == MATCHER_NOT) ? "NOT" \ - : ((t) == MATCHER_ANY) ? "ANY" \ - : ((t) == MATCHER_ALL) ? "ALL" \ - : ((t) == MATCHER_IN) ? "IN" \ - : ((t) == MATCHER_ISNULL) ? "IS NULL" \ - : ((t) == MATCHER_ISTRUE) ? "IS TRUE" \ - : ((t) == MATCHER_ISFALSE) ? "IS FALSE" \ - : ((t) == MATCHER_LT) ? "<" \ - : ((t) == MATCHER_LE) ? "<=" \ - : ((t) == MATCHER_EQ) ? "=" \ - : ((t) == MATCHER_NE) ? "!=" \ - : ((t) == MATCHER_GE) ? ">=" \ - : ((t) == MATCHER_GT) ? ">" \ - : ((t) == MATCHER_REGEX) ? "=~" \ - : ((t) == MATCHER_NREGEX) ? "!~" \ - : ((t) == MATCHER_QUERY) ? "QUERY" \ - : "UNKNOWN") - -/* matcher base type */ -struct sdb_memstore_matcher { - sdb_object_t super; - /* type of the matcher */ - int type; -}; -#define M(m) ((sdb_memstore_matcher_t *)(m)) - -/* infix operator matcher */ -typedef struct { - sdb_memstore_matcher_t super; - - /* left and right hand operands */ - sdb_memstore_matcher_t *left; - sdb_memstore_matcher_t *right; -} op_matcher_t; -#define OP_M(m) ((op_matcher_t *)(m)) - -/* unary operator matcher */ -typedef struct { - sdb_memstore_matcher_t super; - - /* operand */ - sdb_memstore_matcher_t *op; -} uop_matcher_t; -#define UOP_M(m) ((uop_matcher_t *)(m)) - -/* iter matcher */ -typedef struct { - sdb_memstore_matcher_t super; - sdb_memstore_expr_t *iter; - sdb_memstore_matcher_t *m; -} iter_matcher_t; -#define ITER_M(m) ((iter_matcher_t *)(m)) - -/* compare operator matcher */ -typedef struct { - sdb_memstore_matcher_t super; - - /* left and right hand expressions */ - sdb_memstore_expr_t *left; - sdb_memstore_expr_t *right; -} cmp_matcher_t; -#define CMP_M(m) ((cmp_matcher_t *)(m)) - -typedef struct { - sdb_memstore_matcher_t super; - sdb_memstore_expr_t *expr; -} unary_matcher_t; -#define UNARY_M(m) ((unary_matcher_t *)(m)) - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* ! SDB_CORE_STORE_H */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/src/core/store.c b/src/core/store.c deleted file mode 100644 index 7fc11e1..0000000 --- a/src/core/store.c +++ /dev/null @@ -1,978 +0,0 @@ -/* - * SysDB - src/core/store.c - * Copyright (C) 2012-2013 Sebastian 'tokkee' Harl - * 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 - -#include - -#include -#include -#include - -#include - -/* - * private types - */ - -struct sdb_memstore { - sdb_object_t super; - - /* hosts are the top-level entries and - * reference everything else */ - sdb_avltree_t *hosts; - pthread_rwlock_t host_lock; -}; - -/* internal representation of a to-be-stored object */ -typedef struct { - sdb_memstore_obj_t *parent; - sdb_avltree_t *parent_tree; - int type; - const char *name; - sdb_time_t last_update; - const char * const *backends; - size_t backends_num; -} store_obj_t; -#define STORE_OBJ_INIT { NULL, NULL, 0, NULL, 0, NULL, 0 } - -static sdb_type_t host_type; -static sdb_type_t service_type; -static sdb_type_t metric_type; -static sdb_type_t attribute_type; - -static int -store_init(sdb_object_t *obj, va_list __attribute__((unused)) ap) -{ - int err; - if (! (SDB_MEMSTORE(obj)->hosts = sdb_avltree_create())) - return -1; - if ((err = pthread_rwlock_init(&SDB_MEMSTORE(obj)->host_lock, - /* attr = */ NULL))) { - char errbuf[128]; - sdb_log(SDB_LOG_ERR, "store: Failed to initialize lock: %s", - sdb_strerror(err, errbuf, sizeof(errbuf))); - return -1; - } - return 0; -} /* store_init */ - -static void -store_destroy(sdb_object_t *obj) -{ - int err; - if ((err = pthread_rwlock_destroy(&SDB_MEMSTORE(obj)->host_lock))) { - char errbuf[128]; - sdb_log(SDB_LOG_ERR, "store: Failed to destroy lock: %s", - sdb_strerror(err, errbuf, sizeof(errbuf))); - return; - } - sdb_avltree_destroy(SDB_MEMSTORE(obj)->hosts); - SDB_MEMSTORE(obj)->hosts = NULL; -} /* store_destroy */ - -static int -store_obj_init(sdb_object_t *obj, va_list ap) -{ - sdb_memstore_obj_t *sobj = STORE_OBJ(obj); - - sobj->type = va_arg(ap, int); - - sobj->last_update = va_arg(ap, sdb_time_t); - sobj->interval = 0; - sobj->backends = NULL; - sobj->backends_num = 0; - sobj->parent = NULL; - return 0; -} /* store_obj_init */ - -static void -store_obj_destroy(sdb_object_t *obj) -{ - sdb_memstore_obj_t *sobj = STORE_OBJ(obj); - size_t i; - - for (i = 0; i < sobj->backends_num; ++i) - free(sobj->backends[i]); - free(sobj->backends); - sobj->backends = NULL; - sobj->backends_num = 0; - - // We don't currently keep an extra reference for parent objects to - // avoid circular self-references which are not handled correctly by - // the ref-count base management layer. - //sdb_object_deref(SDB_OBJ(sobj->parent)); -} /* store_obj_destroy */ - -static int -host_init(sdb_object_t *obj, va_list ap) -{ - host_t *sobj = HOST(obj); - int ret; - - /* this will consume the first argument (type) of ap */ - ret = store_obj_init(obj, ap); - if (ret) - return ret; - - sobj->services = sdb_avltree_create(); - if (! sobj->services) - return -1; - sobj->metrics = sdb_avltree_create(); - if (! sobj->metrics) - return -1; - sobj->attributes = sdb_avltree_create(); - if (! sobj->attributes) - return -1; - return 0; -} /* host_init */ - -static void -host_destroy(sdb_object_t *obj) -{ - host_t *sobj = HOST(obj); - assert(obj); - - store_obj_destroy(obj); - - if (sobj->services) - sdb_avltree_destroy(sobj->services); - if (sobj->metrics) - sdb_avltree_destroy(sobj->metrics); - if (sobj->attributes) - sdb_avltree_destroy(sobj->attributes); -} /* host_destroy */ - -static int -service_init(sdb_object_t *obj, va_list ap) -{ - service_t *sobj = SVC(obj); - int ret; - - /* this will consume the first argument (type) of ap */ - ret = store_obj_init(obj, ap); - if (ret) - return ret; - - sobj->attributes = sdb_avltree_create(); - if (! sobj->attributes) - return -1; - return 0; -} /* service_init */ - -static void -service_destroy(sdb_object_t *obj) -{ - service_t *sobj = SVC(obj); - assert(obj); - - store_obj_destroy(obj); - - if (sobj->attributes) - sdb_avltree_destroy(sobj->attributes); -} /* service_destroy */ - -static int -metric_init(sdb_object_t *obj, va_list ap) -{ - metric_t *sobj = METRIC(obj); - int ret; - - /* this will consume the first argument (type) of ap */ - ret = store_obj_init(obj, ap); - if (ret) - return ret; - - sobj->attributes = sdb_avltree_create(); - if (! sobj->attributes) - return -1; - - sobj->store.type = sobj->store.id = NULL; - return 0; -} /* metric_init */ - -static void -metric_destroy(sdb_object_t *obj) -{ - metric_t *sobj = METRIC(obj); - assert(obj); - - store_obj_destroy(obj); - - if (sobj->attributes) - sdb_avltree_destroy(sobj->attributes); - - if (sobj->store.type) - free(sobj->store.type); - if (sobj->store.id) - free(sobj->store.id); -} /* metric_destroy */ - -static int -attr_init(sdb_object_t *obj, va_list ap) -{ - const sdb_data_t *value; - int ret; - - /* this will consume the first two arguments - * (type and last_update) of ap */ - ret = store_obj_init(obj, ap); - if (ret) - return ret; - value = va_arg(ap, const sdb_data_t *); - - if (value) - if (sdb_data_copy(&ATTR(obj)->value, value)) - return -1; - return 0; -} /* attr_init */ - -static void -attr_destroy(sdb_object_t *obj) -{ - assert(obj); - - store_obj_destroy(obj); - sdb_data_free_datum(&ATTR(obj)->value); -} /* attr_destroy */ - -static sdb_type_t store_type = { - /* size = */ sizeof(sdb_memstore_t), - /* init = */ store_init, - /* destroy = */ store_destroy, -}; - -static sdb_type_t host_type = { - /* size = */ sizeof(host_t), - /* init = */ host_init, - /* destroy = */ host_destroy -}; - -static sdb_type_t service_type = { - /* size = */ sizeof(service_t), - /* init = */ service_init, - /* destroy = */ service_destroy -}; - -static sdb_type_t metric_type = { - /* size = */ sizeof(metric_t), - /* init = */ metric_init, - /* destroy = */ metric_destroy -}; - -static sdb_type_t attribute_type = { - /* size = */ sizeof(attr_t), - /* init = */ attr_init, - /* destroy = */ attr_destroy -}; - -/* - * private helper functions - */ - -static int -record_backends(sdb_memstore_obj_t *obj, - const char * const *backends, size_t backends_num) -{ - char **tmp; - size_t i; - - for (i = 0; i < backends_num; i++) { - bool found = 0; - size_t j; - - for (j = 0; j < obj->backends_num; ++j) { - if (!strcasecmp(obj->backends[j], backends[i])) { - found = 1; - break; - } - } - if (found) - continue; - - tmp = realloc(obj->backends, - (obj->backends_num + 1) * sizeof(*obj->backends)); - if (! tmp) - return -1; - - obj->backends = tmp; - obj->backends[obj->backends_num] = strdup(backends[i]); - if (! obj->backends[obj->backends_num]) - return -1; - - ++obj->backends_num; - } - return 0; -} /* record_backends */ - -static int -store_obj(store_obj_t *obj, sdb_memstore_obj_t **updated_obj) -{ - sdb_memstore_obj_t *old, *new; - int status = 0; - - assert(obj->parent_tree); - - if (obj->last_update <= 0) - obj->last_update = sdb_gettime(); - - old = STORE_OBJ(sdb_avltree_lookup(obj->parent_tree, obj->name)); - if (old) { - if (old->last_update > obj->last_update) { - sdb_log(SDB_LOG_DEBUG, "store: Cannot update %s '%s' - " - "value too old (%"PRIsdbTIME" < %"PRIsdbTIME")", - SDB_STORE_TYPE_TO_NAME(obj->type), obj->name, - obj->last_update, old->last_update); - /* don't report an error; the object may be updated by multiple - * backends */ - status = 1; - } - else if (old->last_update == obj->last_update) { - /* don't report an error and also don't even log this to avoid - * excessive noise on high sampling frequencies */ - status = 1; - } - else { - sdb_time_t interval = obj->last_update - old->last_update; - old->last_update = obj->last_update; - if (interval) { - if (old->interval) - old->interval = (sdb_time_t)((0.9 * (double)old->interval) - + (0.1 * (double)interval)); - else - old->interval = interval; - } - } - - new = old; - sdb_object_deref(SDB_OBJ(old)); - } - else { - if (obj->type == SDB_ATTRIBUTE) { - /* the value will be updated by the caller */ - new = STORE_OBJ(sdb_object_create(obj->name, attribute_type, - obj->type, obj->last_update, NULL)); - } - else { - sdb_type_t t; - t = obj->type == SDB_HOST - ? host_type - : obj->type == SDB_SERVICE - ? service_type - : metric_type; - new = STORE_OBJ(sdb_object_create(obj->name, t, - obj->type, obj->last_update)); - } - - if (new) { - status = sdb_avltree_insert(obj->parent_tree, SDB_OBJ(new)); - - /* pass control to the tree or destroy in case of an error */ - sdb_object_deref(SDB_OBJ(new)); - } - else { - char errbuf[1024]; - sdb_log(SDB_LOG_ERR, "store: Failed to create %s '%s': %s", - SDB_STORE_TYPE_TO_NAME(obj->type), obj->name, - sdb_strerror(errno, errbuf, sizeof(errbuf))); - status = -1; - } - } - - if (status < 0) - return status; - assert(new); - - if (new->parent != obj->parent) { - // Avoid circular self-references which are not handled - // correctly by the ref-count based management layer. - //sdb_object_deref(SDB_OBJ(new->parent)); - //sdb_object_ref(SDB_OBJ(obj->parent)); - new->parent = obj->parent; - } - - if (updated_obj) - *updated_obj = new; - - if (record_backends(new, obj->backends, obj->backends_num)) - return -1; - return status; -} /* store_obj */ - -static int -store_metric_store(metric_t *metric, sdb_store_metric_t *m) -{ - char *type = metric->store.type; - char *id = metric->store.id; - - if ((! metric->store.type) || strcasecmp(metric->store.type, m->store.type)) { - if (! (type = strdup(m->store.type))) - return -1; - } - if ((! metric->store.id) || strcasecmp(metric->store.id, m->store.id)) { - if (! (id = strdup(m->store.id))) { - if (type != metric->store.type) - free(type); - return -1; - } - } - - if (type != metric->store.type) { - if (metric->store.type) - free(metric->store.type); - metric->store.type = type; - } - if (id != metric->store.id) { - if (metric->store.id) - free(metric->store.id); - metric->store.id = id; - } - return 0; -} /* store_metric_store */ - -/* The store's host_lock has to be acquired before calling this function. */ -static sdb_avltree_t * -get_host_children(host_t *host, int type) -{ - if ((type != SDB_SERVICE) && (type != SDB_METRIC) - && (type != SDB_ATTRIBUTE)) - return NULL; - - if (! host) - return NULL; - - if (type == SDB_ATTRIBUTE) - return host->attributes; - else if (type == SDB_METRIC) - return host->metrics; - else - return host->services; -} /* get_host_children */ - -/* - * store writer API - */ - -static int -store_attribute(sdb_store_attribute_t *attr, sdb_object_t *user_data) -{ - sdb_memstore_t *st = SDB_MEMSTORE(user_data); - store_obj_t obj = STORE_OBJ_INIT; - sdb_memstore_obj_t *new = NULL; - const char *hostname; - host_t *host; - - sdb_avltree_t *children = NULL; - int status = 0; - - if ((! attr) || (! attr->parent) || (! attr->key)) - return -1; - - hostname = attr->hostname; - if (attr->parent_type == SDB_HOST) - hostname = attr->parent; - if (! hostname) - return -1; - - pthread_rwlock_wrlock(&st->host_lock); - host = HOST(sdb_avltree_lookup(st->hosts, hostname)); - if (! host) { - sdb_log(SDB_LOG_ERR, "store: Failed to store attribute '%s' - " - "host '%s' not found", attr->key, hostname); - status = -1; - } - - switch (attr->parent_type) { - case SDB_HOST: - obj.parent = STORE_OBJ(host); - obj.parent_tree = get_host_children(host, SDB_ATTRIBUTE); - break; - case SDB_SERVICE: - children = get_host_children(host, SDB_SERVICE); - break; - case SDB_METRIC: - children = get_host_children(host, SDB_METRIC); - break; - default: - status = -1; - break; - } - - if (children) { - obj.parent = STORE_OBJ(sdb_avltree_lookup(children, attr->parent)); - if (! obj.parent) { - sdb_log(SDB_LOG_ERR, "store: Failed to store attribute '%s' - " - "%s '%s/%s' not found", attr->key, - SDB_STORE_TYPE_TO_NAME(attr->parent_type), - attr->hostname, attr->parent); - status = -1; - } - else - obj.parent_tree = attr->parent_type == SDB_SERVICE - ? SVC(obj.parent)->attributes - : METRIC(obj.parent)->attributes; - } - - obj.type = SDB_ATTRIBUTE; - obj.name = attr->key; - obj.last_update = attr->last_update; - obj.backends = attr->backends; - obj.backends_num = attr->backends_num; - if (! status) - status = store_obj(&obj, &new); - - if (! status) { - assert(new); - /* update the value if it changed */ - if (sdb_data_cmp(&ATTR(new)->value, &attr->value)) - if (sdb_data_copy(&ATTR(new)->value, &attr->value)) - status = -1; - } - - if (obj.parent != STORE_OBJ(host)) - sdb_object_deref(SDB_OBJ(obj.parent)); - sdb_object_deref(SDB_OBJ(host)); - pthread_rwlock_unlock(&st->host_lock); - - return status; -} /* store_attribute */ - -static int -store_host(sdb_store_host_t *host, sdb_object_t *user_data) -{ - sdb_memstore_t *st = SDB_MEMSTORE(user_data); - store_obj_t obj = { NULL, st->hosts, SDB_HOST, NULL, 0, NULL, 0 }; - int status = 0; - - if ((! host) || (! host->name)) - return -1; - - obj.name = host->name; - obj.last_update = host->last_update; - obj.backends = host->backends; - obj.backends_num = host->backends_num; - pthread_rwlock_wrlock(&st->host_lock); - status = store_obj(&obj, NULL); - pthread_rwlock_unlock(&st->host_lock); - - return status; -} /* store_host */ - -static int -store_service(sdb_store_service_t *service, sdb_object_t *user_data) -{ - sdb_memstore_t *st = SDB_MEMSTORE(user_data); - store_obj_t obj = STORE_OBJ_INIT; - host_t *host; - - int status = 0; - - if ((! service) || (! service->hostname) || (! service->name)) - return -1; - - pthread_rwlock_wrlock(&st->host_lock); - host = HOST(sdb_avltree_lookup(st->hosts, service->hostname)); - obj.parent = STORE_OBJ(host); - obj.parent_tree = get_host_children(host, SDB_SERVICE); - obj.type = SDB_SERVICE; - if (! obj.parent_tree) { - sdb_log(SDB_LOG_ERR, "store: Failed to store service '%s' - " - "host '%s' not found", service->name, service->hostname); - status = -1; - } - - obj.name = service->name; - obj.last_update = service->last_update; - obj.backends = service->backends; - obj.backends_num = service->backends_num; - if (! status) - status = store_obj(&obj, NULL); - - sdb_object_deref(SDB_OBJ(host)); - pthread_rwlock_unlock(&st->host_lock); - return status; -} /* store_service */ - -static int -store_metric(sdb_store_metric_t *metric, sdb_object_t *user_data) -{ - sdb_memstore_t *st = SDB_MEMSTORE(user_data); - store_obj_t obj = STORE_OBJ_INIT; - sdb_memstore_obj_t *new = NULL; - host_t *host; - - int status = 0; - - if ((! metric) || (! metric->hostname) || (! metric->name)) - return -1; - - if ((metric->store.type != NULL) != (metric->store.id != NULL)) - return -1; - - pthread_rwlock_wrlock(&st->host_lock); - host = HOST(sdb_avltree_lookup(st->hosts, metric->hostname)); - obj.parent = STORE_OBJ(host); - obj.parent_tree = get_host_children(host, SDB_METRIC); - obj.type = SDB_METRIC; - if (! obj.parent_tree) { - sdb_log(SDB_LOG_ERR, "store: Failed to store metric '%s' - " - "host '%s' not found", metric->name, metric->hostname); - status = -1; - } - - obj.name = metric->name; - obj.last_update = metric->last_update; - obj.backends = metric->backends; - obj.backends_num = metric->backends_num; - if (! status) - status = store_obj(&obj, &new); - sdb_object_deref(SDB_OBJ(host)); - - if (status) { - pthread_rwlock_unlock(&st->host_lock); - return status; - } - - assert(new); - if (metric->store.type && metric->store.id) - if (store_metric_store(METRIC(new), metric)) - status = -1; - pthread_rwlock_unlock(&st->host_lock); - return status; -} /* store_metric */ - -sdb_store_writer_t sdb_memstore_writer = { - store_host, store_service, store_metric, store_attribute, -}; - -static sdb_object_t * -prepare_query(sdb_ast_node_t *ast, - sdb_strbuf_t __attribute__((unused)) *errbuf, - sdb_object_t __attribute__((unused)) *user_data) -{ - return SDB_OBJ(sdb_memstore_query_prepare(ast)); -} /* prepare_query */ - -static int -execute_query(sdb_object_t *q, - sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf, - sdb_object_t *user_data) -{ - return sdb_memstore_query_execute(SDB_MEMSTORE(user_data), - QUERY(q), w, wd, errbuf); -} /* execute_query */ - -sdb_store_reader_t sdb_memstore_reader = { - prepare_query, execute_query, -}; - -/* - * public API - */ - -sdb_memstore_t * -sdb_memstore_create(void) -{ - return SDB_MEMSTORE(sdb_object_create("store", store_type)); -} /* sdb_memstore_create */ - -int -sdb_memstore_host(sdb_memstore_t *store, const char *name, sdb_time_t last_update) -{ - sdb_store_host_t host = { - name, last_update, 0, NULL, 0, - }; - return store_host(&host, SDB_OBJ(store)); -} /* sdb_memstore_host */ - -int -sdb_memstore_service(sdb_memstore_t *store, const char *hostname, const char *name, - sdb_time_t last_update) -{ - sdb_store_service_t service = { - hostname, name, last_update, 0, NULL, 0, - }; - return store_service(&service, SDB_OBJ(store)); -} /* sdb_memstore_service */ - -int -sdb_memstore_metric(sdb_memstore_t *store, const char *hostname, const char *name, - sdb_metric_store_t *metric_store, sdb_time_t last_update) -{ - sdb_store_metric_t metric = { - hostname, name, { NULL, NULL }, last_update, 0, NULL, 0, - }; - if (metric_store) { - metric.store.type = metric_store->type; - metric.store.id = metric_store->id; - } - return store_metric(&metric, SDB_OBJ(store)); -} /* sdb_memstore_metric */ - -int -sdb_memstore_attribute(sdb_memstore_t *store, const char *hostname, - const char *key, const sdb_data_t *value, sdb_time_t last_update) -{ - sdb_store_attribute_t attr = { - NULL, SDB_HOST, hostname, key, SDB_DATA_INIT, last_update, 0, NULL, 0, - }; - if (value) { - attr.value = *value; - } - return store_attribute(&attr, SDB_OBJ(store)); -} /* sdb_memstore_attribute */ - -int -sdb_memstore_service_attr(sdb_memstore_t *store, const char *hostname, - const char *service, const char *key, const sdb_data_t *value, - sdb_time_t last_update) -{ - sdb_store_attribute_t attr = { - hostname, SDB_SERVICE, service, key, SDB_DATA_INIT, last_update, 0, NULL, 0, - }; - if (value) { - attr.value = *value; - } - return store_attribute(&attr, SDB_OBJ(store)); -} /* sdb_memstore_service_attr */ - -int -sdb_memstore_metric_attr(sdb_memstore_t *store, const char *hostname, - const char *metric, const char *key, const sdb_data_t *value, - sdb_time_t last_update) -{ - sdb_store_attribute_t attr = { - hostname, SDB_METRIC, metric, key, SDB_DATA_INIT, last_update, 0, NULL, 0, - }; - if (value) { - attr.value = *value; - } - return store_attribute(&attr, SDB_OBJ(store)); -} /* sdb_memstore_metric_attr */ - -sdb_memstore_obj_t * -sdb_memstore_get_host(sdb_memstore_t *store, const char *name) -{ - host_t *host; - - if ((! store) || (! name)) - return NULL; - - host = HOST(sdb_avltree_lookup(store->hosts, name)); - if (! host) - return NULL; - - return STORE_OBJ(host); -} /* sdb_memstore_get_host */ - -sdb_memstore_obj_t * -sdb_memstore_get_child(sdb_memstore_obj_t *host, int type, const char *name) -{ - sdb_avltree_t *children; - - if ((! host) || (host->type != SDB_HOST) || (! name)) - return NULL; - - children = get_host_children(HOST(host), type); - if (! children) - return NULL; - return STORE_OBJ(sdb_avltree_lookup(children, name)); -} /* sdb_memstore_get_child */ - -int -sdb_memstore_get_field(sdb_memstore_obj_t *obj, int field, sdb_data_t *res) -{ - sdb_data_t tmp; - - if (! obj) - return -1; - - switch (field) { - case SDB_FIELD_NAME: - tmp.type = SDB_TYPE_STRING; - tmp.data.string = strdup(SDB_OBJ(obj)->name); - if (! tmp.data.string) - return -1; - break; - case SDB_FIELD_LAST_UPDATE: - tmp.type = SDB_TYPE_DATETIME; - tmp.data.datetime = obj->last_update; - break; - case SDB_FIELD_AGE: - tmp.type = SDB_TYPE_DATETIME; - tmp.data.datetime = sdb_gettime() - obj->last_update; - break; - case SDB_FIELD_INTERVAL: - tmp.type = SDB_TYPE_DATETIME; - tmp.data.datetime = obj->interval; - break; - case SDB_FIELD_BACKEND: - if (! res) - return 0; - tmp.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING; - tmp.data.array.length = obj->backends_num; - tmp.data.array.values = obj->backends; - return sdb_data_copy(res, &tmp); - case SDB_FIELD_VALUE: - if (obj->type != SDB_ATTRIBUTE) - return -1; - if (! res) - return 0; - return sdb_data_copy(res, &ATTR(obj)->value); - case SDB_FIELD_TIMESERIES: - if (obj->type != SDB_METRIC) - return -1; - tmp.type = SDB_TYPE_BOOLEAN; - tmp.data.boolean = METRIC(obj)->store.type != NULL; - default: - return -1; - } - if (res) - *res = tmp; - else - sdb_data_free_datum(&tmp); - return 0; -} /* sdb_memstore_get_field */ - -int -sdb_memstore_get_attr(sdb_memstore_obj_t *obj, const char *name, sdb_data_t *res, - sdb_memstore_matcher_t *filter) -{ - sdb_avltree_t *tree = NULL; - sdb_memstore_obj_t *attr; - - if ((! obj) || (! name)) - return -1; - - if (obj->type == SDB_HOST) - tree = HOST(obj)->attributes; - else if (obj->type == SDB_SERVICE) - tree = SVC(obj)->attributes; - else if (obj->type == SDB_METRIC) - tree = METRIC(obj)->attributes; - - if (! tree) - return -1; - - attr = STORE_OBJ(sdb_avltree_lookup(tree, name)); - if (! attr) - return -1; - if (filter && (! sdb_memstore_matcher_matches(filter, attr, NULL))) { - sdb_object_deref(SDB_OBJ(attr)); - return -1; - } - - assert(STORE_OBJ(attr)->type == SDB_ATTRIBUTE); - if (res) - sdb_data_copy(res, &ATTR(attr)->value); - sdb_object_deref(SDB_OBJ(attr)); - return 0; -} /* sdb_memstore_get_attr */ - -int -sdb_memstore_scan(sdb_memstore_t *store, int type, - sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter, - sdb_memstore_lookup_cb cb, void *user_data) -{ - sdb_avltree_iter_t *host_iter = NULL; - int status = 0; - - if ((! store) || (! cb)) - return -1; - - if ((type != SDB_HOST) && (type != SDB_SERVICE) && (type != SDB_METRIC)) { - sdb_log(SDB_LOG_ERR, "store: Cannot scan objects of type %d", type); - return -1; - } - - pthread_rwlock_rdlock(&store->host_lock); - host_iter = sdb_avltree_get_iter(store->hosts); - if (! host_iter) - status = -1; - - /* has_next returns false if the iterator is NULL */ - while (sdb_avltree_iter_has_next(host_iter)) { - sdb_memstore_obj_t *host; - sdb_avltree_iter_t *iter = NULL; - - host = STORE_OBJ(sdb_avltree_iter_get_next(host_iter)); - assert(host); - - if (! sdb_memstore_matcher_matches(filter, host, NULL)) - continue; - - if (type == SDB_SERVICE) - iter = sdb_avltree_get_iter(HOST(host)->services); - else if (type == SDB_METRIC) - iter = sdb_avltree_get_iter(HOST(host)->metrics); - - if (iter) { - while (sdb_avltree_iter_has_next(iter)) { - sdb_memstore_obj_t *obj; - obj = STORE_OBJ(sdb_avltree_iter_get_next(iter)); - assert(obj); - - if (sdb_memstore_matcher_matches(m, obj, filter)) { - if (cb(obj, filter, user_data)) { - sdb_log(SDB_LOG_ERR, "store: Callback returned " - "an error while scanning"); - status = -1; - break; - } - } - } - } - else if (sdb_memstore_matcher_matches(m, host, filter)) { - if (cb(host, filter, user_data)) { - sdb_log(SDB_LOG_ERR, "store: Callback returned " - "an error while scanning"); - status = -1; - } - } - - sdb_avltree_iter_destroy(iter); - if (status) - break; - } - - sdb_avltree_iter_destroy(host_iter); - pthread_rwlock_unlock(&store->host_lock); - return status; -} /* sdb_memstore_scan */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/src/core/store_exec.c b/src/core/store_exec.c deleted file mode 100644 index 9b4ea07..0000000 --- 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 - * 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 - -#include -#include -#include - -/* - * private helper functions - */ - -typedef struct { - sdb_memstore_obj_t *current_host; - - sdb_store_writer_t *w; - sdb_object_t *wd; -} iter_t; - -static int -maybe_emit_host(iter_t *iter, sdb_memstore_obj_t *obj) -{ - if ((obj->type == SDB_HOST) || (obj->type == SDB_ATTRIBUTE)) - return 0; - if (iter->current_host == obj->parent) - return 0; - iter->current_host = obj->parent; - return sdb_memstore_emit(obj->parent, iter->w, iter->wd); -} /* maybe_emit_host */ - -static int -list_tojson(sdb_memstore_obj_t *obj, - sdb_memstore_matcher_t __attribute__((unused)) *filter, - void *user_data) -{ - iter_t *iter = user_data; - maybe_emit_host(iter, obj); - return sdb_memstore_emit(obj, iter->w, iter->wd); -} /* list_tojson */ - -static int -lookup_tojson(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter, - void *user_data) -{ - iter_t *iter = user_data; - maybe_emit_host(iter, obj); - return sdb_memstore_emit_full(obj, filter, iter->w, iter->wd); -} /* lookup_tojson */ - -/* - * query implementations - */ - -static int -exec_fetch(sdb_memstore_t *store, - sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf, - int type, const char *hostname, const char *name, - sdb_memstore_matcher_t *filter) -{ - sdb_memstore_obj_t *host; - sdb_memstore_obj_t *obj; - - int status = 0; - - if ((! name) || ((type == SDB_HOST) && hostname) - || ((type != SDB_HOST) && (! hostname))) { - /* This is a programming error, not something the client did wrong */ - sdb_strbuf_sprintf(errbuf, "INTERNAL ERROR: invalid " - "arguments to FETCH(%s, %s, %s)", - SDB_STORE_TYPE_TO_NAME(type), hostname, name); - return -1; - } - if (type == SDB_HOST) - hostname = name; - - host = sdb_memstore_get_host(store, hostname); - if ((! host) - || (filter && (! sdb_memstore_matcher_matches(filter, host, NULL)))) { - sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s: " - "host %s not found", SDB_STORE_TYPE_TO_NAME(type), - name, hostname); - sdb_object_deref(SDB_OBJ(host)); - return -1; - } - if (type == SDB_HOST) { - obj = host; - } - else { - obj = sdb_memstore_get_child(host, type, name); - if ((! obj) - || (filter && (! sdb_memstore_matcher_matches(filter, obj, NULL)))) { - sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s.%s: " - "%s not found", SDB_STORE_TYPE_TO_NAME(type), - hostname, name, name); - if (obj) - sdb_object_deref(SDB_OBJ(obj)); - sdb_object_deref(SDB_OBJ(host)); - return -1; - } - sdb_object_deref(SDB_OBJ(host)); - } - host = NULL; - - if (type != SDB_HOST) - status = sdb_memstore_emit(obj->parent, w, wd); - if (status || sdb_memstore_emit_full(obj, filter, w, wd)) { - sdb_log(SDB_LOG_ERR, "frontend: Failed to serialize " - "%s %s.%s to JSON", SDB_STORE_TYPE_TO_NAME(type), - hostname, name); - sdb_strbuf_sprintf(errbuf, "Out of memory"); - sdb_object_deref(SDB_OBJ(obj)); - return -1; - } - - sdb_object_deref(SDB_OBJ(obj)); - return SDB_CONNECTION_DATA; -} /* exec_fetch */ - -static int -exec_list(sdb_memstore_t *store, - sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf, - int type, sdb_memstore_matcher_t *filter) -{ - iter_t iter = { NULL, w, wd }; - - if (sdb_memstore_scan(store, type, /* m = */ NULL, filter, list_tojson, &iter)) { - sdb_log(SDB_LOG_ERR, "frontend: Failed to serialize " - "store to JSON"); - sdb_strbuf_sprintf(errbuf, "Out of memory"); - return -1; - } - - return SDB_CONNECTION_DATA; -} /* exec_list */ - -static int -exec_lookup(sdb_memstore_t *store, - sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf, - int type, sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter) -{ - iter_t iter = { NULL, w, wd }; - - if (sdb_memstore_scan(store, type, m, filter, lookup_tojson, &iter)) { - sdb_log(SDB_LOG_ERR, "frontend: Failed to lookup %ss", - SDB_STORE_TYPE_TO_NAME(type)); - sdb_strbuf_sprintf(errbuf, "Failed to lookup %ss", - SDB_STORE_TYPE_TO_NAME(type)); - return -1; - } - - return SDB_CONNECTION_DATA; -} /* exec_lookup */ - -/* - * public API - */ - -int -sdb_memstore_query_execute(sdb_memstore_t *store, sdb_memstore_query_t *q, - sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf) -{ - sdb_ast_node_t *ast; - - if (! q) - return -1; - if (! q->ast) { - sdb_log(SDB_LOG_ERR, "store: Invalid empty query"); - return -1; - } - - ast = q->ast; - switch (ast->type) { - case SDB_AST_TYPE_FETCH: - return exec_fetch(store, w, wd, errbuf, SDB_AST_FETCH(ast)->obj_type, - SDB_AST_FETCH(ast)->hostname, SDB_AST_FETCH(ast)->name, - q->filter); - - case SDB_AST_TYPE_LIST: - return exec_list(store, w, wd, errbuf, SDB_AST_LIST(ast)->obj_type, - q->filter); - - case SDB_AST_TYPE_LOOKUP: - return exec_lookup(store, w, wd, errbuf, SDB_AST_LOOKUP(ast)->obj_type, - q->matcher, q->filter); - - default: - sdb_log(SDB_LOG_ERR, "store: Invalid query of type %s", - SDB_AST_TYPE_TO_STRING(ast)); - return -1; - } - - return 0; -} /* sdb_memstore_query_execute */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ diff --git a/src/core/store_expr.c b/src/core/store_expr.c deleted file mode 100644 index c96b339..0000000 --- a/src/core/store_expr.c +++ /dev/null @@ -1,463 +0,0 @@ -/* - * SysDB - src/core/store_expr.c - * Copyright (C) 2014 Sebastian 'tokkee' Harl - * 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 -#include -#include -#include - -/* - * 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 b39ff21..9266608 100644 --- a/src/core/store_json.c +++ b/src/core/store_json.c @@ -34,7 +34,7 @@ #endif /* HAVE_CONFIG_H */ #include "sysdb.h" -#include "core/store-private.h" +#include "core/store.h" #include "utils/error.h" #include @@ -379,133 +379,6 @@ sdb_store_json_formatter(sdb_strbuf_t *buf, int type, int flags) buf, type, flags)); } /* sdb_store_json_formatter */ -/* TODO: Move sdb_store_emit* somewhere else. */ - -int -sdb_memstore_emit(sdb_memstore_obj_t *obj, sdb_store_writer_t *w, sdb_object_t *wd) -{ - if ((! obj) || (! w)) - return -1; - - switch (obj->type) { - case SDB_HOST: - { - sdb_store_host_t host = { - obj->_name, - obj->last_update, - obj->interval, - (const char * const *)obj->backends, - obj->backends_num, - }; - if (! w->store_host) - return -1; - return w->store_host(&host, wd); - } - case SDB_SERVICE: - { - sdb_store_service_t service = { - obj->parent ? obj->parent->_name : NULL, - obj->_name, - obj->last_update, - obj->interval, - (const char * const *)obj->backends, - obj->backends_num, - }; - if (! w->store_service) - return -1; - return w->store_service(&service, wd); - } - case SDB_METRIC: - { - sdb_store_metric_t metric = { - obj->parent ? obj->parent->_name : NULL, - obj->_name, - { - METRIC(obj)->store.type, - METRIC(obj)->store.id, - }, - obj->last_update, - obj->interval, - (const char * const *)obj->backends, - obj->backends_num, - }; - if (! w->store_metric) - return -1; - return w->store_metric(&metric, wd); - } - case SDB_ATTRIBUTE: - { - sdb_store_attribute_t attr = { - NULL, - obj->parent ? obj->parent->type : 0, - obj->parent ? obj->parent->_name : NULL, - obj->_name, - ATTR(obj)->value, - obj->last_update, - obj->interval, - (const char * const *)obj->backends, - obj->backends_num, - }; - if (obj->parent && (obj->parent->type != SDB_HOST) - && obj->parent->parent) - attr.hostname = obj->parent->parent->_name; - if (! w->store_attribute) - return -1; - return w->store_attribute(&attr, wd); - } - } - - return -1; -} /* sdb_memstore_emit */ - -int -sdb_memstore_emit_full(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter, - sdb_store_writer_t *w, sdb_object_t *wd) -{ - sdb_avltree_t *trees[] = { NULL, NULL, NULL }; - size_t i; - - if (sdb_memstore_emit(obj, w, wd)) - return -1; - - if (obj->type == SDB_HOST) { - trees[0] = HOST(obj)->attributes; - trees[1] = HOST(obj)->metrics; - trees[2] = HOST(obj)->services; - } - else if (obj->type == SDB_SERVICE) - trees[0] = SVC(obj)->attributes; - else if (obj->type == SDB_METRIC) - trees[0] = METRIC(obj)->attributes; - else if (obj->type == SDB_ATTRIBUTE) - return 0; - else - return -1; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(trees); ++i) { - sdb_avltree_iter_t *iter; - - if (! trees[i]) - continue; - - iter = sdb_avltree_get_iter(trees[i]); - while (sdb_avltree_iter_has_next(iter)) { - sdb_memstore_obj_t *child; - child = STORE_OBJ(sdb_avltree_iter_get_next(iter)); - - if (filter && (! sdb_memstore_matcher_matches(filter, child, NULL))) - continue; - - if (sdb_memstore_emit_full(child, filter, w, wd)) { - sdb_avltree_iter_destroy(iter); - return -1; - } - } - sdb_avltree_iter_destroy(iter); - } - return 0; -} /* sdb_memstore_emit_full */ - int sdb_store_json_finish(sdb_store_json_formatter_t *f) { diff --git a/src/core/store_lookup.c b/src/core/store_lookup.c deleted file mode 100644 index b69e7f9..0000000 --- a/src/core/store_lookup.c +++ /dev/null @@ -1,694 +0,0 @@ -/* - * SysDB - src/core/store_lookup.c - * Copyright (C) 2014 Sebastian 'tokkee' Harl - * 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 - -#include -#include - -#include -#include - -#include - -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 */ -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 deleted file mode 100644 index 341cb16..0000000 --- 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 - * 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 - -static sdb_memstore_matcher_t * -node_to_matcher(sdb_ast_node_t *n); - -static sdb_memstore_expr_t * -node_to_expr(sdb_ast_node_t *n) -{ - sdb_memstore_expr_t *left = NULL, *right = NULL; - sdb_memstore_expr_t *e; - int op; - - if (! n) { - sdb_log(SDB_LOG_ERR, "store: Encountered empty AST expression node"); - return NULL; - } - - switch (n->type) { - case SDB_AST_TYPE_OPERATOR: - if (! SDB_AST_IS_ARITHMETIC(n)) { - sdb_log(SDB_LOG_ERR, "store: Invalid arithmetic operator of " - "type %s (%#x)", SDB_AST_TYPE_TO_STRING(n), n->type); - return NULL; - } - - left = node_to_expr(SDB_AST_OP(n)->left); - if (! left) - return NULL; - right = node_to_expr(SDB_AST_OP(n)->right); - if (! right) { - sdb_object_deref(SDB_OBJ(left)); - return NULL; - } - op = SDB_AST_OP_TO_DATA_OP(SDB_AST_OP(n)->kind); - e = sdb_memstore_expr_create(op, left, right); - break; - - case SDB_AST_TYPE_CONST: - return sdb_memstore_expr_constvalue(&SDB_AST_CONST(n)->value); - - case SDB_AST_TYPE_VALUE: - if (SDB_AST_VALUE(n)->type == SDB_ATTRIBUTE) - return sdb_memstore_expr_attrvalue(SDB_AST_VALUE(n)->name); - return sdb_memstore_expr_fieldvalue(SDB_AST_VALUE(n)->type); - - case SDB_AST_TYPE_TYPED: - right = node_to_expr(SDB_AST_TYPED(n)->expr); - if (! right) - return NULL; - e = sdb_memstore_expr_typed(SDB_AST_TYPED(n)->type, right); - break; - - default: - sdb_log(SDB_LOG_ERR, "store: Invalid matcher node of type %s (%#x)", - SDB_AST_TYPE_TO_STRING(n), n->type); - e = NULL; - } - - /* expressions take a reference */ - sdb_object_deref(SDB_OBJ(left)); - sdb_object_deref(SDB_OBJ(right)); - return e; -} /* node_to_expr */ - -static sdb_memstore_matcher_t * -logical_to_matcher(sdb_ast_node_t *n) -{ - sdb_memstore_matcher_t *left = NULL, *right; - sdb_memstore_matcher_t *m; - - if (SDB_AST_OP(n)->left) { - left = node_to_matcher(SDB_AST_OP(n)->left); - if (! left) - return NULL; - } - right = node_to_matcher(SDB_AST_OP(n)->right); - if (! right) { - sdb_object_deref(SDB_OBJ(left)); - return NULL; - } - - switch (SDB_AST_OP(n)->kind) { - case SDB_AST_AND: - m = sdb_memstore_con_matcher(left, right); - break; - case SDB_AST_OR: - m = sdb_memstore_dis_matcher(left, right); - break; - case SDB_AST_NOT: - m = sdb_memstore_inv_matcher(right); - break; - - default: - m = NULL; - } - - /* matchers take a reference */ - sdb_object_deref(SDB_OBJ(left)); - sdb_object_deref(SDB_OBJ(right)); - return m; -} /* logical_to_matcher */ - -static sdb_memstore_matcher_t * -cmp_to_matcher(sdb_ast_node_t *n) -{ - sdb_memstore_expr_t *left = NULL, *right; - sdb_memstore_matcher_t *m; - - if (SDB_AST_OP(n)->left) { - left = node_to_expr(SDB_AST_OP(n)->left); - if (! left) - return NULL; - } - right = node_to_expr(SDB_AST_OP(n)->right); - if (! right) { - sdb_object_deref(SDB_OBJ(left)); - return NULL; - } - - switch (SDB_AST_OP(n)->kind) { - case SDB_AST_LT: - m = sdb_memstore_lt_matcher(left, right); - break; - case SDB_AST_LE: - m = sdb_memstore_le_matcher(left, right); - break; - case SDB_AST_EQ: - m = sdb_memstore_eq_matcher(left, right); - break; - case SDB_AST_NE: - m = sdb_memstore_ne_matcher(left, right); - break; - case SDB_AST_GE: - m = sdb_memstore_ge_matcher(left, right); - break; - case SDB_AST_GT: - m = sdb_memstore_gt_matcher(left, right); - break; - case SDB_AST_REGEX: - m = sdb_memstore_regex_matcher(left, right); - break; - case SDB_AST_NREGEX: - m = sdb_memstore_nregex_matcher(left, right); - break; - case SDB_AST_ISNULL: - m = sdb_memstore_isnull_matcher(right); - break; - case SDB_AST_ISTRUE: - m = sdb_memstore_istrue_matcher(right); - break; - case SDB_AST_ISFALSE: - m = sdb_memstore_isfalse_matcher(right); - break; - case SDB_AST_IN: - m = sdb_memstore_in_matcher(left, right); - break; - - default: - sdb_log(SDB_LOG_ERR, "store: Invalid matcher node of type %s (%#x)", - SDB_AST_TYPE_TO_STRING(n), n->type); - m = NULL; - } - - /* matchers take a reference */ - sdb_object_deref(SDB_OBJ(left)); - sdb_object_deref(SDB_OBJ(right)); - return m; -} /* cmp_to_matcher */ - -static sdb_memstore_matcher_t * -iter_to_matcher(sdb_ast_node_t *n) -{ - sdb_memstore_expr_t *iter; - sdb_memstore_matcher_t *expr, *m; - - assert((SDB_AST_ITER(n)->expr->type == SDB_AST_TYPE_OPERATOR) - && (! SDB_AST_OP(SDB_AST_ITER(n)->expr)->left)); - - iter = node_to_expr(SDB_AST_ITER(n)->iter); - if (! iter) - return NULL; - expr = cmp_to_matcher(SDB_AST_ITER(n)->expr); - if (! expr) { - sdb_object_deref(SDB_OBJ(iter)); - return NULL; - } - - switch (SDB_AST_ITER(n)->kind) { - case SDB_AST_ALL: - m = sdb_memstore_all_matcher(iter, expr); - break; - case SDB_AST_ANY: - m = sdb_memstore_any_matcher(iter, expr); - break; - - default: - sdb_log(SDB_LOG_ERR, "store: Invalid iterator node of type %s (%#x)", - SDB_AST_OP_TO_STRING(SDB_AST_ITER(n)->kind), SDB_AST_ITER(n)->kind); - m = NULL; - } - - /* matchers take a reference */ - sdb_object_deref(SDB_OBJ(iter)); - sdb_object_deref(SDB_OBJ(expr)); - return m; -} /* iter_to_matcher */ - -static sdb_memstore_matcher_t * -node_to_matcher(sdb_ast_node_t *n) -{ - int kind; - - if (! n) { - sdb_log(SDB_LOG_ERR, "store: Encountered empty AST matcher node"); - return NULL; - } - - switch (n->type) { - case SDB_AST_TYPE_OPERATOR: - if (! SDB_AST_IS_LOGICAL(n)) { - sdb_log(SDB_LOG_ERR, "store: Invalid logical operator of " - "type %s (%#x)", SDB_AST_TYPE_TO_STRING(n), n->type); - return NULL; - } - - kind = SDB_AST_OP(n)->kind; - if ((kind == SDB_AST_AND) || (kind == SDB_AST_OR) || (kind == SDB_AST_NOT)) - return logical_to_matcher(n); - else - return cmp_to_matcher(n); - - case SDB_AST_TYPE_ITERATOR: - return iter_to_matcher(n); - } - - sdb_log(SDB_LOG_ERR, "store: Invalid matcher node of type %s (%#x)", - SDB_AST_TYPE_TO_STRING(n), n->type); - return NULL; -} /* node_to_matcher */ - -/* - * query type - */ - -static int -query_init(sdb_object_t *obj, va_list ap) -{ - sdb_ast_node_t *ast = va_arg(ap, sdb_ast_node_t *); - sdb_ast_node_t *matcher = NULL, *filter = NULL; - - QUERY(obj)->ast = ast; - sdb_object_ref(SDB_OBJ(ast)); - - switch (ast->type) { - case SDB_AST_TYPE_FETCH: - filter = SDB_AST_FETCH(ast)->filter; - break; - case SDB_AST_TYPE_LIST: - filter = SDB_AST_LIST(ast)->filter; - break; - case SDB_AST_TYPE_LOOKUP: - matcher = SDB_AST_LOOKUP(ast)->matcher; - filter = SDB_AST_LOOKUP(ast)->filter; - break; - case SDB_AST_TYPE_STORE: - case SDB_AST_TYPE_TIMESERIES: - /* nothing to do */ - break; - - default: - sdb_log(SDB_LOG_ERR, "store: Invalid top-level AST node " - "of type %#x", ast->type); - return -1; - } - - if (matcher) { - QUERY(obj)->matcher = node_to_matcher(matcher); - if (! QUERY(obj)->matcher) - return -1; - } - if (filter) { - QUERY(obj)->filter = node_to_matcher(filter); - if (! QUERY(obj)->filter) - return -1; - } - - return 0; -} /* query_init */ - -static void -query_destroy(sdb_object_t *obj) -{ - sdb_object_deref(SDB_OBJ(QUERY(obj)->ast)); - sdb_object_deref(SDB_OBJ(QUERY(obj)->matcher)); - sdb_object_deref(SDB_OBJ(QUERY(obj)->filter)); -} /* query_destroy */ - -static sdb_type_t query_type = { - /* size = */ sizeof(sdb_memstore_query_t), - /* init = */ query_init, - /* destroy = */ query_destroy, -}; - -/* - * public API - */ - -sdb_memstore_query_t * -sdb_memstore_query_prepare(sdb_ast_node_t *ast) -{ - if (! ast) - return NULL; - return QUERY(sdb_object_create(SDB_AST_TYPE_TO_STRING(ast), query_type, ast)); -} /* sdb_memstore_query_prepare */ - -sdb_memstore_matcher_t * -sdb_memstore_query_prepare_matcher(sdb_ast_node_t *ast) -{ - return node_to_matcher(ast); -} /* sdb_memstore_query_prepare_matcher */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ diff --git a/src/include/core/memstore.h b/src/include/core/memstore.h new file mode 100644 index 0000000..8590156 --- /dev/null +++ b/src/include/core/memstore.h @@ -0,0 +1,535 @@ +/* + * SysDB - src/include/core/memstore.h + * Copyright (C) 2012-2015 Sebastian 'tokkee' Harl + * 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 +#include + +#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 : */ + diff --git a/src/include/core/store.h b/src/include/core/store.h index 03677e8..5f60c8d 100644 --- a/src/include/core/store.h +++ b/src/include/core/store.h @@ -1,6 +1,6 @@ /* * SysDB - src/include/core/store.h - * Copyright (C) 2012 Sebastian 'tokkee' Harl + * Copyright (C) 2012-2015 Sebastian 'tokkee' Harl * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,11 +32,9 @@ #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 #include #ifdef __cplusplus @@ -94,22 +92,6 @@ enum { : ((f) == SDB_FIELD_TIMESERIES) ? SDB_TYPE_BOOLEAN \ : -1) -/* - * sdb_memstore_t represents an in-memory store. It inherits from sdb_object_t - * and may safely be case to a generic object. - */ -struct sdb_memstore; -typedef struct sdb_memstore sdb_memstore_t; -#define SDB_MEMSTORE(obj) ((sdb_memstore_t *)(obj)) - -/* - * sdb_memstore_obj_t represents the super-class of any stored object. It - * inherits from sdb_object_t and may safely be cast to a generic object to - * access its name. - */ -struct sdb_memstore_obj; -typedef struct sdb_memstore_obj sdb_memstore_obj_t; - /* * sdb_store_host_t represents the meta-data of a stored host object. */ @@ -180,36 +162,6 @@ typedef struct { } sdb_store_attribute_t; #define SDB_STORE_ATTRIBUTE_INIT { NULL, 0, NULL, NULL, SDB_DATA_INIT, 0, 0, NULL, 0 } -/* - * Expressions represent arithmetic expressions based on stored objects and - * their various attributes. - * - * An expression object inherits from sdb_object_t and, thus, may safely be - * cast to a generic object. - */ -struct sdb_memstore_expr; -typedef struct sdb_memstore_expr sdb_memstore_expr_t; -#define SDB_MEMSTORE_EXPR(obj) ((sdb_memstore_expr_t *)(obj)) - -/* - * An expression iterator iterates over the values of an iterable expression. - */ -struct sdb_memstore_expr_iter; -typedef struct sdb_memstore_expr_iter sdb_memstore_expr_iter_t; - -/* - * Store matchers may be used to lookup hosts from the store based on their - * various attributes. Service and attribute matchers are applied to a host's - * services and attributes and evaluate to true if *any* service or attribute - * matches. - * - * A store matcher object inherits from sdb_object_t and, thus, may safely be - * cast to a generic object. - */ -struct sdb_memstore_matcher; -typedef struct sdb_memstore_matcher sdb_memstore_matcher_t; -#define SDB_MEMSTORE_MATCHER(obj) ((sdb_memstore_matcher_t *)(obj)) - /* * A JSON formatter converts stored objects into the JSON format. * See http://www.ietf.org/rfc/rfc4627.txt @@ -270,13 +222,6 @@ typedef struct { int (*store_attribute)(sdb_store_attribute_t *attr, sdb_object_t *user_data); } sdb_store_writer_t; -/* - * sdb_memstore_writer: - * A store writer implementation that provides an in-memory object store. It - * expects a store object as its user-data argument. - */ -extern sdb_store_writer_t sdb_memstore_writer; - /* * A store reader describes the interface to query a store implementation. */ @@ -300,408 +245,6 @@ typedef struct { sdb_strbuf_t *errbuf, sdb_object_t *user_data); } sdb_store_reader_t; -/* - * sdb_memstore_reader: - * A store reader implementation that uses an in-memory object store. It - * expects a store object as its user-data argument. - */ -extern sdb_store_reader_t sdb_memstore_reader; - -/* - * sdb_memstore_create: - * Allocate a new in-memory store. - */ -sdb_memstore_t * -sdb_memstore_create(void); - -/* - * sdb_memstore_host, sdb_memstore_service, sdb_memstore_metric, - * sdb_memstore_attribute, sdb_memstore_metric_attr: - * Store an object in the specified store. The hostname is expected to be - * canonical. - */ -int -sdb_memstore_host(sdb_memstore_t *store, const char *name, sdb_time_t last_update); -int -sdb_memstore_service(sdb_memstore_t *store, const char *hostname, const char *name, - sdb_time_t last_update); -int -sdb_memstore_metric(sdb_memstore_t *store, const char *hostname, const char *name, - sdb_metric_store_t *metric_store, sdb_time_t last_update); -int -sdb_memstore_attribute(sdb_memstore_t *store, const char *hostname, - const char *key, const sdb_data_t *value, sdb_time_t last_update); -int -sdb_memstore_service_attr(sdb_memstore_t *store, const char *hostname, - const char *service, const char *key, const sdb_data_t *value, - sdb_time_t last_update); -int -sdb_memstore_metric_attr(sdb_memstore_t *store, const char *hostname, - const char *metric, const char *key, const sdb_data_t *value, - sdb_time_t last_update); - -/* - * sdb_memstore_get_host: - * Query the specified store for a host by its (canonicalized) name. - * - * The function increments the ref count of the host object. The caller needs - * to deref it when no longer using it. - */ -sdb_memstore_obj_t * -sdb_memstore_get_host(sdb_memstore_t *store, const char *name); - -/* - * sdb_memstore_get_child: - * Retrieve a host's child object of the specified type and name. The - * reference count of the child object will be incremented before returning - * it. The caller is responsible for releasing the object once it's no longer - * used. - * - * Returns: - * - the child object on success - * - NULL else - */ -sdb_memstore_obj_t * -sdb_memstore_get_child(sdb_memstore_obj_t *host, int type, const char *name); - -/* - * sdb_memstore_get_field: - * Get the value of a stored object's queryable field. The caller is - * responsible for freeing any dynamically allocated memory possibly stored in - * the returned value. If 'res' is NULL, the function will return whether the - * field exists. - * - * Returns: - * - 0 on success - * - a negative value else - */ -int -sdb_memstore_get_field(sdb_memstore_obj_t *obj, int field, sdb_data_t *res); - -/* - * sdb_memstore_get_attr: - * Get the value of a stored object's attribute. The caller is responsible for - * freeing any dynamically allocated memory possibly stored in the returned - * value. If 'res' is NULL, the function will return whether the attribute - * exists. If specified, only attributes matching the filter will be - * considered. - * - * Returns: - * - 0 if the attribute exists - * - a negative value else - */ -int -sdb_memstore_get_attr(sdb_memstore_obj_t *obj, const char *name, sdb_data_t *res, - sdb_memstore_matcher_t *filter); - -/* - * Querying a store: - * - * - Query interface: A query is a formal description of an interaction with - * the store. It can be used, both, for read and write access. The query is - * described by its abstract syntax tree (AST). The parser package provides - * means to parse a string (SysQL) representation of the query into an AST. - * - * - Matcher / expression interface: This low-level interface provides direct - * control over how to access the store. It is used by the query - * implementation internally and can only be used for read access. - */ - -/* - * sdb_memstore_query_t: - * A parsed query readily prepared for execution. - */ -struct sdb_memstore_query; -typedef struct sdb_memstore_query sdb_memstore_query_t; - -/* - * sdb_memstore_query_prepare: - * Prepare the query described by 'ast' for execution in a store. - * - * Returns: - * - a store query on success - * - NULL else - */ -sdb_memstore_query_t * -sdb_memstore_query_prepare(sdb_ast_node_t *ast); - -/* - * sdb_memstore_query_prepare_matcher: - * Prepare the logical expression described by 'ast' for execution as a store - * matcher. - * - * Returns: - * - a matcher on success - * - NULL else - */ -sdb_memstore_matcher_t * -sdb_memstore_query_prepare_matcher(sdb_ast_node_t *ast); - -/* - * sdb_memstore_query_execute: - * Execute a previously prepared query in the specified store. The query - * result will be written to 'buf' and any errors to 'errbuf'. - * - * Returns: - * - the result type (to be used by the server reply) - * - a negative value on error - */ -int -sdb_memstore_query_execute(sdb_memstore_t *store, sdb_memstore_query_t *m, - sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf); - -/* - * sdb_memstore_expr_create: - * Creates an arithmetic expression implementing the specified operator on the - * specified left and right operand. - * - * Returns: - * - an expression object on success - * - NULL else - */ -sdb_memstore_expr_t * -sdb_memstore_expr_create(int op, - sdb_memstore_expr_t *left, sdb_memstore_expr_t *right); - -/* - * sdb_memstore_expr_typed: - * Creates an expression which evaluates in the context of an object's sibling - * as specified by the given type. - * - * Returns: - * - an expression object on success - * - NULL else - */ -sdb_memstore_expr_t * -sdb_memstore_expr_typed(int typ, sdb_memstore_expr_t *expr); - -/* - * sdb_memstore_expr_fieldvalue: - * Creates an expression which evaluates to the value of the specified - * queryable field of a stored object. - * - * Returns: - * - an expression object on success - * - NULL else - */ -sdb_memstore_expr_t * -sdb_memstore_expr_fieldvalue(int field); - -/* - * sdb_memstore_expr_attrvalue: - * Creates an expression which evaluates to the value of the specified - * attribute of a stored object. Evaluates to a NULL value if the attribute - * does not exist. - * - * Returns: - * - an expression object on success - * - NULL else - */ -sdb_memstore_expr_t * -sdb_memstore_expr_attrvalue(const char *name); - -/* - * sdb_memstore_expr_constvalue: - * Creates an expression which evaluates to the specified constant value. - * - * Returns: - * - an expression object on success - * - NULL else - */ -sdb_memstore_expr_t * -sdb_memstore_expr_constvalue(const sdb_data_t *value); - -/* - * sdb_memstore_expr_eval: - * Evaluate an expression for the specified stored object and stores the - * result in 'res'. The result's value will be allocated dynamically if - * necessary and, thus, should be free'd by the caller (e.g. using - * sdb_data_free_datum). The object may be NULL, in which case the expression - * needs to evaluate to a constant value. If specified, only objects matching - * the filter will be used during the evaluation. - * - * Returns: - * - 0 on success - * - a negative value else - */ -int -sdb_memstore_expr_eval(sdb_memstore_expr_t *expr, sdb_memstore_obj_t *obj, - sdb_data_t *res, sdb_memstore_matcher_t *filter); - -/* - * sdb_memstore_expr_iter: - * Iterate over the elements of an iterable expression. sdb_memstore_expr_iter - * returns NULL if the expression is not iterable (for the specified object). - * - * sdb_memstore_expr_iter_get_next returns NULL if there is no next element. - */ -sdb_memstore_expr_iter_t * -sdb_memstore_expr_iter(sdb_memstore_expr_t *expr, sdb_memstore_obj_t *obj, - sdb_memstore_matcher_t *filter); -void -sdb_memstore_expr_iter_destroy(sdb_memstore_expr_iter_t *iter); - -bool -sdb_memstore_expr_iter_has_next(sdb_memstore_expr_iter_t *iter); -sdb_data_t -sdb_memstore_expr_iter_get_next(sdb_memstore_expr_iter_t *iter); - -/* - * sdb_memstore_dis_matcher: - * Creates a matcher matching the disjunction (logical OR) of two matchers. - */ -sdb_memstore_matcher_t * -sdb_memstore_dis_matcher(sdb_memstore_matcher_t *left, sdb_memstore_matcher_t *right); - -/* - * sdb_memstore_con_matcher: - * Creates a matcher matching the conjunction (logical AND) of two matchers. - */ -sdb_memstore_matcher_t * -sdb_memstore_con_matcher(sdb_memstore_matcher_t *left, sdb_memstore_matcher_t *right); - -/* - * sdb_memstore_inv_matcher: - * Creates a matcher matching the inverse (logical NOT) of a matcher. - */ -sdb_memstore_matcher_t * -sdb_memstore_inv_matcher(sdb_memstore_matcher_t *m); - -/* - * sdb_memstore_any_matcher: - * Creates a matcher iterating over values of the first expression (which has - * to be iterable). It matches if *any* of those elements match 'm'. 'm' has - * to be an ary operation with the left operand unset. - */ -sdb_memstore_matcher_t * -sdb_memstore_any_matcher(sdb_memstore_expr_t *iter, sdb_memstore_matcher_t *m); - -/* - * sdb_memstore_all_matcher: - * Creates a matcher iterating over values of the first expression (which has - * to be iterable). It matches if *all* of those elements match 'm'. 'm' has - * to be an ary operation with the left operand unset. - */ -sdb_memstore_matcher_t * -sdb_memstore_all_matcher(sdb_memstore_expr_t *iter, sdb_memstore_matcher_t *m); - -/* - * sdb_memstore_in_matcher: - * Creates a matcher which matches if the right value evaluates to an array - * value and the left value is included in that array. See sdb_data_inarray - * for more details. - */ -sdb_memstore_matcher_t * -sdb_memstore_in_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right); - -/* - * sdb_memstore_lt_matcher, sdb_memstore_le_matcher, sdb_memstore_eq_matcher, - * sdb_memstore_ge_matcher, sdb_memstore_gt_matcher: - * Create conditional matchers comparing the values of two expressions. The - * matcher matches if the left expression compres less than, less or equal - * than, equal to, not equal to, greater or equal than, or greater than the - * right expression. - */ -sdb_memstore_matcher_t * -sdb_memstore_lt_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right); -sdb_memstore_matcher_t * -sdb_memstore_le_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right); -sdb_memstore_matcher_t * -sdb_memstore_eq_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right); -sdb_memstore_matcher_t * -sdb_memstore_ne_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right); -sdb_memstore_matcher_t * -sdb_memstore_ge_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right); -sdb_memstore_matcher_t * -sdb_memstore_gt_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right); - -/* - * sdb_memstore_regex_matcher: - * Creates a matcher which matches the string value the left expression - * evaluates to against the regular expression the right expression evaluates - * to. The right expression may either be a constant value regular expression - * or string or a dynamic value evaluating to a string. In the latter case, - * the string is compiled to a regex every time the matcher is executed. - */ -sdb_memstore_matcher_t * -sdb_memstore_regex_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right); - -/* - * sdb_memstore_nregex_matcher: - * Creates a regex matcher just like sdb_memstore_regex_matcher except that it - * matches in case the regular expression does not match. - */ -sdb_memstore_matcher_t * -sdb_memstore_nregex_matcher(sdb_memstore_expr_t *left, sdb_memstore_expr_t *right); - -/* - * sdb_memstore_isnull_matcher: - * Creates a matcher matching NULL values. - */ -sdb_memstore_matcher_t * -sdb_memstore_isnull_matcher(sdb_memstore_expr_t *expr); - -/* - * sdb_memstore_istrue_matcher, sdb_memstore_isfalse_matcher: - * Creates a matcher matching boolean values. - */ -sdb_memstore_matcher_t * -sdb_memstore_istrue_matcher(sdb_memstore_expr_t *expr); -sdb_memstore_matcher_t * -sdb_memstore_isfalse_matcher(sdb_memstore_expr_t *expr); - -/* - * sdb_memstore_matcher_matches: - * Check whether the specified matcher matches the specified store object. If - * specified, the filter will be used to preselect objects for further - * evaluation. It is applied to any object that's used during the evaluation - * of the matcher. Only those objects matching the filter will be considered. - * - * Note that the filter is applied to all object types (hosts, service, - * metric, attribute). Thus, any object-specific matchers are mostly unsuited - * for this purpose and, if used, may result in unexpected behavior. - * - * Returns: - * - 1 if the object matches - * - 0 else - */ -int -sdb_memstore_matcher_matches(sdb_memstore_matcher_t *m, sdb_memstore_obj_t *obj, - sdb_memstore_matcher_t *filter); - -/* - * sdb_memstore_matcher_op_cb: - * Callback constructing a matcher operator. - */ -typedef sdb_memstore_matcher_t *(*sdb_memstore_matcher_op_cb) - (sdb_memstore_expr_t *, sdb_memstore_expr_t *); - -/* - * sdb_memstore_lookup_cb: - * Lookup callback. It is called for each matching object when looking up data - * in the store passing on the lookup filter and the specified user-data. The - * lookup aborts early if the callback returns non-zero. - */ -typedef int (*sdb_memstore_lookup_cb)(sdb_memstore_obj_t *obj, - sdb_memstore_matcher_t *filter, void *user_data); - -/* - * sdb_memstore_scan: - * Look up objects of the specified type in the specified store. The specified - * callback function is called for each object in the store matching 'm'. The - * function performs a full scan of all stored objects. If specified, the - * filter will be used to preselect objects for further evaluation. See the - * description of 'sdb_memstore_matcher_matches' for details. - * - * Returns: - * - 0 on success - * - a negative value else - */ -int -sdb_memstore_scan(sdb_memstore_t *store, int type, - sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter, - sdb_memstore_lookup_cb cb, void *user_data); - /* * Flags for JSON formatting. */ @@ -717,42 +260,6 @@ enum { sdb_store_json_formatter_t * sdb_store_json_formatter(sdb_strbuf_t *buf, int type, int flags); -/* - * sdb_memstore_emit: - * Serialize a single object to JSON adding it to the string buffer associated - * with the formatter object. The serialized object will not include - * attributes or any child objects. Instead, call the function again for each - * of those objects. All attributes have to be emitted before any other - * children types. Use sdb_memstore_emit_full() to emit a full (filtered) object. - * - * Note that the output might not be valid JSON before calling - * sdb_store_json_finish(). - * - * Returns: - * - 0 on success - * - a negative value else - */ -int -sdb_memstore_emit(sdb_memstore_obj_t *obj, sdb_store_writer_t *w, sdb_object_t *wd); - -/* - * sdb_memstore_emit_full: - * Serialize a single object including it's attributes and all children to - * JSON, adding it to the string buffer associated with the formatter object. - * The filter, if specified, is applied to each attribute and child object. - * Only matching objects will be included in the output. - * - * Note that the output might not be valid JSON before calling - * sdb_store_json_finish(). - * - * Returns: - * - 0 on success - * - a negative value else - */ -int -sdb_memstore_emit_full(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter, - sdb_store_writer_t *w, sdb_object_t *wd); - /* * sdb_store_json_finish: * Finish the JSON output. This function has to be called once after emiting diff --git a/src/plugins/store/memory.c b/src/plugins/store/memory.c index 67a795b..703696f 100644 --- a/src/plugins/store/memory.c +++ b/src/plugins/store/memory.c @@ -31,6 +31,7 @@ #include "sysdb.h" #include "core/plugin.h" +#include "core/memstore.h" #include "core/store.h" #include "utils/error.h" diff --git a/t/unit/core/store_expr_test.c b/t/unit/core/store_expr_test.c index 04dfc8b..1bf560e 100644 --- a/t/unit/core/store_expr_test.c +++ b/t/unit/core/store_expr_test.c @@ -30,7 +30,7 @@ #endif #include "core/store.h" -#include "core/store-private.h" +#include "core/memstore-private.h" #include "parser/parser.h" #include "testutils.h" diff --git a/t/unit/core/store_json_test.c b/t/unit/core/store_json_test.c index 40548c0..461c583 100644 --- a/t/unit/core/store_json_test.c +++ b/t/unit/core/store_json_test.c @@ -29,6 +29,7 @@ # include "config.h" #endif +#include "core/memstore.h" #include "core/store.h" #include "testutils.h" diff --git a/t/unit/core/store_lookup_test.c b/t/unit/core/store_lookup_test.c index ef0900e..0c99ee1 100644 --- a/t/unit/core/store_lookup_test.c +++ b/t/unit/core/store_lookup_test.c @@ -31,7 +31,7 @@ #include "core/plugin.h" #include "core/store.h" -#include "core/store-private.h" +#include "core/memstore-private.h" #include "parser/parser.h" #include "testutils.h" diff --git a/t/unit/core/store_test.c b/t/unit/core/store_test.c index 5299a31..9445c64 100644 --- a/t/unit/core/store_test.c +++ b/t/unit/core/store_test.c @@ -31,7 +31,7 @@ #include "core/plugin.h" #include "core/store.h" -#include "core/store-private.h" +#include "core/memstore-private.h" #include "testutils.h" #include diff --git a/t/unit/frontend/query_test.c b/t/unit/frontend/query_test.c index d498ea0..52fd58a 100644 --- a/t/unit/frontend/query_test.c +++ b/t/unit/frontend/query_test.c @@ -29,6 +29,7 @@ # include "config.h" #endif +#include "core/memstore.h" #include "core/plugin.h" #include "frontend/connection.h" #include "frontend/connection-private.h" diff --git a/t/unit/parser/parser_test.c b/t/unit/parser/parser_test.c index 83a5845..f6601f1 100644 --- a/t/unit/parser/parser_test.c +++ b/t/unit/parser/parser_test.c @@ -31,7 +31,7 @@ #include "parser/parser.h" #include "core/object.h" -#include "core/store.h" +#include "core/memstore.h" #include "testutils.h" #include @@ -743,7 +743,7 @@ START_TEST(test_parse) /* TODO: this should move into front-end specific tests */ q = sdb_memstore_query_prepare(node); fail_unless(q != NULL, - "sdb_store_query_prepare(AST<%s>) = NULL; expected: ", + "sdb_memstore_query_prepare(AST<%s>) = NULL; expected: ", parse_data[_i].query); sdb_object_deref(SDB_OBJ(node));