Code

Split the memstore module from the store module.
[sysdb.git] / src / core / memstore_expr.c
1 /*
2  * SysDB - src/core/memstore_expr.c
3  * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
28 /*
29  * This module implements arithmetic and logical expressions for in-memory
30  * stores.
31  */
33 #if HAVE_CONFIG_H
34 #       include "config.h"
35 #endif /* HAVE_CONFIG_H */
37 #include "sysdb.h"
38 #include "core/memstore-private.h"
39 #include "core/data.h"
40 #include "core/object.h"
42 #include <assert.h>
43 #include <stdbool.h>
44 #include <stdlib.h>
45 #include <string.h>
47 /*
48  * private data types
49  */
51 /* iterate through either a list of child nodes or arrays */
52 struct sdb_memstore_expr_iter {
53         sdb_memstore_obj_t *obj;
54         sdb_memstore_expr_t *expr;
56         sdb_avltree_iter_t *tree;
58         sdb_data_t array;
59         size_t array_idx;
60         bool free_array;
62         sdb_memstore_matcher_t *filter;
63 };
65 /*
66  * private types
67  */
69 static int
70 expr_init(sdb_object_t *obj, va_list ap)
71 {
72         int type = va_arg(ap, int);
73         sdb_memstore_expr_t *left  = va_arg(ap, sdb_memstore_expr_t *);
74         sdb_memstore_expr_t *right = va_arg(ap, sdb_memstore_expr_t *);
75         const sdb_data_t *value = va_arg(ap, const sdb_data_t *);
77         sdb_memstore_expr_t *expr = SDB_MEMSTORE_EXPR(obj);
79         if (type <= 0) {
80                 if (! value)
81                         return -1;
82                 if ((type == TYPED_EXPR) && (! left))
83                         return -1;
84         } else {
85                 if (value)
86                         return -1;
87                 if ((! left) || (! right))
88                         return -1;
89         }
91         if (value)
92                 expr->data = *value;
94         sdb_object_ref(SDB_OBJ(left));
95         sdb_object_ref(SDB_OBJ(right));
97         expr->type  = type;
98         expr->left  = left;
99         expr->right = right;
101         /* unknown for now */
102         expr->data_type = -1;
103         return 0;
104 } /* expr_init */
106 static void
107 expr_destroy(sdb_object_t *obj)
109         sdb_memstore_expr_t *expr = SDB_MEMSTORE_EXPR(obj);
110         sdb_object_deref(SDB_OBJ(expr->left));
111         sdb_object_deref(SDB_OBJ(expr->right));
113         if (expr->data.type)
114                 sdb_data_free_datum(&expr->data);
115 } /* expr_destroy */
117 static sdb_type_t expr_type = {
118         /* size = */ sizeof(sdb_memstore_expr_t),
119         /* init = */ expr_init,
120         /* destroy = */ expr_destroy,
121 };
123 /*
124  * public API
125  */
127 sdb_memstore_expr_t *
128 sdb_memstore_expr_create(int op, sdb_memstore_expr_t *left, sdb_memstore_expr_t *right)
130         sdb_data_t value = SDB_DATA_INIT;
131         sdb_memstore_expr_t *e;
133         if ((op < 0) || (SDB_DATA_CONCAT < op) || (! left) || (! right))
134                 return NULL;
136         if (left->type || right->type) {
137                 e = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-expr", expr_type,
138                                         op, left, right, NULL));
139                 e->data_type = sdb_data_expr_type(op, left->type, right->type);
140                 return e;
141         }
142         /* else: both expressions are constant values; evaluate now */
144         if (sdb_data_expr_eval(op, &left->data, &right->data, &value))
145                 return NULL;
146         e = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-constvalue", expr_type,
147                                 0, NULL, NULL, &value));
148         e->data_type = value.type;
149         return e;
150 } /* sdb_memstore_expr_create */
152 sdb_memstore_expr_t *
153 sdb_memstore_expr_typed(int typ, sdb_memstore_expr_t *expr)
155         sdb_data_t value = { SDB_TYPE_INTEGER, { .integer = typ } };
156         sdb_memstore_expr_t *e;
158         if ((typ < SDB_HOST) || (SDB_ATTRIBUTE < typ))
159                 return NULL;
161         e = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-typedexpr", expr_type,
162                                 TYPED_EXPR, expr, NULL, &value));
163         e->data_type = expr->data_type;
164         return e;
165 } /* sdb_memstore_expr_typed */
167 sdb_memstore_expr_t *
168 sdb_memstore_expr_fieldvalue(int field)
170         sdb_data_t value = { SDB_TYPE_INTEGER, { .integer = field } };
171         sdb_memstore_expr_t *e;
173         if ((field < SDB_FIELD_NAME) || (SDB_FIELD_TIMESERIES < field))
174                 return NULL;
175         e = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-fieldvalue", expr_type,
176                                 FIELD_VALUE, NULL, NULL, &value));
177         e->data_type = SDB_FIELD_TYPE(field);
178         return e;
179 } /* sdb_memstore_expr_fieldvalue */
181 sdb_memstore_expr_t *
182 sdb_memstore_expr_attrvalue(const char *name)
184         sdb_data_t value = { SDB_TYPE_STRING, { .string = NULL} };
185         sdb_memstore_expr_t *expr;
187         value.data.string = strdup(name);
188         if (! value.data.string)
189                 return NULL;
191         expr = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-attrvalue", expr_type,
192                                 ATTR_VALUE, NULL, NULL, &value));
193         if (! expr)
194                 free(value.data.string);
195         expr->data_type = -1;
196         return expr;
197 } /* sdb_memstore_expr_attrvalue */
199 sdb_memstore_expr_t *
200 sdb_memstore_expr_constvalue(const sdb_data_t *value)
202         sdb_data_t data = SDB_DATA_INIT;
203         sdb_memstore_expr_t *e;
205         if (sdb_data_copy(&data, value))
206                 return NULL;
207         e = SDB_MEMSTORE_EXPR(sdb_object_create("memstore-constvalue", expr_type,
208                                 0, NULL, NULL, &data));
209         e->data_type = data.type;
210         return e;
211 } /* sdb_memstore_expr_constvalue */
213 int
214 sdb_memstore_expr_eval(sdb_memstore_expr_t *expr, sdb_memstore_obj_t *obj,
215                 sdb_data_t *res, sdb_memstore_matcher_t *filter)
217         sdb_data_t v1 = SDB_DATA_INIT, v2 = SDB_DATA_INIT;
218         int status = 0;
220         if ((! expr) || (! res))
221                 return -1;
223         if (filter && obj && (! sdb_memstore_matcher_matches(filter, obj, NULL)))
224                 obj = NULL; /* this object does not exist */
226         if (! expr->type)
227                 return sdb_data_copy(res, &expr->data);
228         else if (expr->type == FIELD_VALUE)
229                 return sdb_memstore_get_field(obj, (int)expr->data.data.integer, res);
230         else if (expr->type == ATTR_VALUE) {
231                 status = sdb_memstore_get_attr(obj, expr->data.data.string, res, filter);
232                 if ((status < 0) && obj) {
233                         /* attribute does not exist => NULL */
234                         status = 0;
235                         res->type = SDB_TYPE_STRING;
236                         res->data.string = NULL;
237                 }
238                 return status;
239         }
240         else if (expr->type == TYPED_EXPR) {
241                 int typ = (int)expr->data.data.integer;
242                 if (typ != obj->type) {
243                         /* we support self-references and { service, metric } -> host */
244                         if ((typ != SDB_HOST)
245                                         || ((obj->type != SDB_SERVICE)
246                                                 && (obj->type != SDB_METRIC)))
247                                 return -1;
248                         obj = obj->parent;
249                 }
250                 return sdb_memstore_expr_eval(expr->left, obj, res, filter);
251         }
253         if (sdb_memstore_expr_eval(expr->left, obj, &v1, filter))
254                 return -1;
255         if (sdb_memstore_expr_eval(expr->right, obj, &v2, filter)) {
256                 sdb_data_free_datum(&v1);
257                 return -1;
258         }
260         if (sdb_data_expr_eval(expr->type, &v1, &v2, res))
261                 status = -1;
262         sdb_data_free_datum(&v1);
263         sdb_data_free_datum(&v2);
264         return status;
265 } /* sdb_memstore_expr_eval */
267 sdb_memstore_expr_iter_t *
268 sdb_memstore_expr_iter(sdb_memstore_expr_t *expr, sdb_memstore_obj_t *obj,
269                 sdb_memstore_matcher_t *filter)
271         sdb_memstore_expr_iter_t *iter;
272         sdb_avltree_iter_t *tree = NULL;
273         sdb_data_t array = SDB_DATA_INIT;
274         bool free_array = 0;
276         if (! expr)
277                 return NULL;
279         while (expr->type == TYPED_EXPR) {
280                 int type = (int)expr->data.data.integer;
282                 if (obj->type == type) {
283                         /* self reference */
284                 }
285                 else if ((type == SDB_HOST)
286                                 && ((obj->type == SDB_SERVICE)
287                                         || (obj->type == SDB_METRIC))) {
288                         /* reference to parent host */
289                         obj = obj->parent;
290                 }
291                 else
292                         break;
293                 expr = expr->left;
294         }
296         if (expr->type == TYPED_EXPR) {
297                 if (! obj)
298                         return NULL;
299                 if (obj->type == SDB_HOST) {
300                         if (expr->data.data.integer == SDB_SERVICE)
301                                 tree = sdb_avltree_get_iter(HOST(obj)->services);
302                         else if (expr->data.data.integer == SDB_METRIC)
303                                 tree = sdb_avltree_get_iter(HOST(obj)->metrics);
304                         else if (expr->data.data.integer == SDB_ATTRIBUTE)
305                                 tree = sdb_avltree_get_iter(HOST(obj)->attributes);
306                 }
307                 else if (obj->type == SDB_SERVICE) {
308                         if (expr->data.data.integer == SDB_ATTRIBUTE)
309                                 tree = sdb_avltree_get_iter(SVC(obj)->attributes);
310                 }
311                 else if (obj->type == SDB_METRIC) {
312                         if (expr->data.data.integer == SDB_ATTRIBUTE)
313                                 tree = sdb_avltree_get_iter(METRIC(obj)->attributes);
314                 }
315         }
316         else if (expr->type == FIELD_VALUE) {
317                 if (! obj)
318                         return NULL;
319                 if (expr->data.data.integer == SDB_FIELD_BACKEND) {
320                         /* while scanning the store, we hold a read lock, so it's safe to
321                          * access the data without copying */
322                         array.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING;
323                         array.data.array.length = obj->backends_num;
324                         array.data.array.values = obj->backends;
325                 }
326         }
327         else if (! expr->type) {
328                 if (expr->data.type & SDB_TYPE_ARRAY)
329                         array = expr->data;
330         }
331         else {
332                 sdb_data_t value = SDB_DATA_INIT;
333                 if (sdb_memstore_expr_eval(expr, obj, &value, filter))
334                         return NULL;
335                 if (! (value.type & SDB_TYPE_ARRAY)) {
336                         sdb_data_free_datum(&value);
337                         return NULL;
338                 }
339                 array = value;
340                 free_array = 1;
341         }
343         if ((! tree) && (array.type == SDB_TYPE_NULL))
344                 return NULL;
346         iter = calloc(1, sizeof(*iter));
347         if (! iter) {
348                 if (free_array)
349                         sdb_data_free_datum(&array);
350                 return NULL;
351         }
353         sdb_object_ref(SDB_OBJ(obj));
354         sdb_object_ref(SDB_OBJ(expr));
355         sdb_object_ref(SDB_OBJ(filter));
357         iter->obj = obj;
358         iter->expr = expr;
359         iter->tree = tree;
360         iter->array = array;
361         iter->free_array = free_array;
362         iter->filter = filter;
363         return iter;
364 } /* sdb_memstore_expr_iter */
366 void
367 sdb_memstore_expr_iter_destroy(sdb_memstore_expr_iter_t *iter)
369         sdb_data_t null = SDB_DATA_INIT;
371         if (! iter)
372                 return;
374         if (iter->tree)
375                 sdb_avltree_iter_destroy(iter->tree);
376         iter->tree = NULL;
378         if (iter->free_array)
379                 sdb_data_free_datum(&iter->array);
380         iter->array = null;
381         iter->array_idx = 0;
383         sdb_object_deref(SDB_OBJ(iter->obj));
384         sdb_object_deref(SDB_OBJ(iter->expr));
385         sdb_object_deref(SDB_OBJ(iter->filter));
386         free(iter);
387 } /* sdb_memstore_expr_iter_destroy */
389 bool
390 sdb_memstore_expr_iter_has_next(sdb_memstore_expr_iter_t *iter)
392         if (! iter)
393                 return 0;
395         if (iter->tree) {
396                 /* this function may be called before get_next,
397                  * so we'll have to apply filters here as well */
398                 if (iter->filter) {
399                         sdb_memstore_obj_t *child;
400                         while ((child = STORE_OBJ(sdb_avltree_iter_peek_next(iter->tree)))) {
401                                 if (sdb_memstore_matcher_matches(iter->filter, child, NULL))
402                                         break;
403                                 (void)sdb_avltree_iter_get_next(iter->tree);
404                         }
405                 }
407                 return sdb_avltree_iter_has_next(iter->tree);
408         }
410         return iter->array_idx < iter->array.data.array.length;
411 } /* sdb_memstore_expr_iter_has_next */
413 sdb_data_t
414 sdb_memstore_expr_iter_get_next(sdb_memstore_expr_iter_t *iter)
416         sdb_data_t null = SDB_DATA_INIT;
417         sdb_data_t ret = SDB_DATA_INIT;
418         sdb_data_t tmp = SDB_DATA_INIT;
420         if (! iter)
421                 return null;
423         if (iter->tree) {
424                 sdb_memstore_obj_t *child;
426                 while (42) {
427                         child = STORE_OBJ(sdb_avltree_iter_get_next(iter->tree));
428                         if (! child)
429                                 break;
430                         if (iter->filter
431                                         && (! sdb_memstore_matcher_matches(iter->filter, child, NULL)))
432                                 continue;
434                         if (sdb_memstore_expr_eval(iter->expr, child, &ret, iter->filter))
435                                 return null;
436                         break;
437                 }
439                 /* Skip over any filtered objects */
440                 if (iter->filter) {
441                         while ((child = STORE_OBJ(sdb_avltree_iter_peek_next(iter->tree)))) {
442                                 if (sdb_memstore_matcher_matches(iter->filter, child, NULL))
443                                         break;
444                                 (void)sdb_avltree_iter_get_next(iter->tree);
445                         }
446                 }
448                 return ret;
449         }
451         if (iter->array_idx >= iter->array.data.array.length)
452                 return null;
454         ++iter->array_idx;
455         if (sdb_data_array_get(&iter->array, iter->array_idx - 1, &ret))
456                 return null;
457         if (sdb_data_copy(&tmp, &ret))
458                 return null;
459         ret = tmp;
460         return ret;
461 } /* sdb_memstore_expr_iter_get_next */
463 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */