Code

Let the front-end handle STORE commands.
[sysdb.git] / src / core / store_exec.c
1 /*
2  * SysDB - src/core/store_exec.c
3  * Copyright (C) 2014-2015 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 #include "core/object.h"
29 #include "core/plugin.h"
30 #include "core/store-private.h"
31 #include "frontend/connection.h"
32 #include "parser/ast.h"
33 #include "utils/error.h"
35 #include <errno.h>
37 #include <arpa/inet.h>
38 #include <stdlib.h>
39 #include <string.h>
41 /*
42  * private helper functions
43  */
45 static int
46 list_tojson(sdb_store_obj_t *obj,
47                 sdb_store_matcher_t __attribute__((unused)) *filter,
48                 void *user_data)
49 {
50         sdb_store_json_formatter_t *f = user_data;
51         return sdb_store_json_emit(f, obj);
52 } /* list_tojson */
54 static int
55 lookup_tojson(sdb_store_obj_t *obj, sdb_store_matcher_t *filter,
56                 void *user_data)
57 {
58         sdb_store_json_formatter_t *f = user_data;
59         return sdb_store_json_emit_full(f, obj, filter);
60 } /* lookup_tojson */
62 /*
63  * query implementations
64  */
66 static int
67 exec_fetch(sdb_store_t *store, sdb_strbuf_t *buf, sdb_strbuf_t *errbuf,
68                 int type, const char *hostname, const char *name,
69                 sdb_store_matcher_t *filter)
70 {
71         uint32_t res_type = htonl(SDB_CONNECTION_FETCH);
73         sdb_store_obj_t *host;
74         sdb_store_obj_t *obj;
76         sdb_store_json_formatter_t *f;
78         if ((! name) || ((type == SDB_HOST) && hostname)
79                         || ((type != SDB_HOST) && (! hostname))) {
80                 /* This is a programming error, not something the client did wrong */
81                 sdb_strbuf_sprintf(errbuf, "INTERNAL ERROR: invalid "
82                                 "arguments to FETCH(%s, %s, %s)",
83                                 SDB_STORE_TYPE_TO_NAME(type), hostname, name);
84                 return -1;
85         }
86         if (type == SDB_HOST)
87                 hostname = name;
89         host = sdb_store_get_host(store, hostname);
90         if ((! host)
91                         || (filter && (! sdb_store_matcher_matches(filter, host, NULL)))) {
92                 sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s: "
93                                 "host %s not found", SDB_STORE_TYPE_TO_NAME(type),
94                                 name, hostname);
95                 sdb_object_deref(SDB_OBJ(host));
96                 return -1;
97         }
98         if (type == SDB_HOST) {
99                 obj = host;
100         }
101         else {
102                 obj = sdb_store_get_child(host, type, name);
103                 if ((! obj)
104                                 || (filter && (! sdb_store_matcher_matches(filter, obj, NULL)))) {
105                         sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s.%s: "
106                                         "%s not found", SDB_STORE_TYPE_TO_NAME(type),
107                                         hostname, name, name);
108                         if (obj)
109                                 sdb_object_deref(SDB_OBJ(obj));
110                         sdb_object_deref(SDB_OBJ(host));
111                         return -1;
112                 }
113                 sdb_object_deref(SDB_OBJ(host));
114         }
115         host = NULL;
117         f = sdb_store_json_formatter(buf, type, /* flags = */ 0);
118         if (! f) {
119                 char err[1024];
120                 sdb_log(SDB_LOG_ERR, "frontend: Failed to create "
121                                 "JSON formatter to handle FETCH command: %s",
122                                 sdb_strerror(errno, err, sizeof(err)));
124                 sdb_strbuf_sprintf(errbuf, "Out of memory");
125                 sdb_object_deref(SDB_OBJ(obj));
126                 return -1;
127         }
129         sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t));
130         if (sdb_store_json_emit_full(f, obj, filter)) {
131                 sdb_log(SDB_LOG_ERR, "frontend: Failed to serialize "
132                                 "%s %s.%s to JSON", SDB_STORE_TYPE_TO_NAME(type),
133                                 hostname, name);
134                 sdb_strbuf_sprintf(errbuf, "Out of memory");
135                 sdb_object_deref(SDB_OBJ(f));
136                 sdb_object_deref(SDB_OBJ(obj));
137                 return -1;
138         }
140         sdb_object_deref(SDB_OBJ(obj));
141         sdb_store_json_finish(f);
142         sdb_object_deref(SDB_OBJ(f));
144         return SDB_CONNECTION_DATA;
145 } /* exec_fetch */
147 static int
148 exec_list(sdb_store_t *store, sdb_strbuf_t *buf, sdb_strbuf_t *errbuf,
149                 int type, sdb_store_matcher_t *filter)
151         uint32_t res_type = htonl(SDB_CONNECTION_LIST);
152         sdb_store_json_formatter_t *f;
154         f = sdb_store_json_formatter(buf, type, SDB_WANT_ARRAY);
155         if (! f) {
156                 char err[1024];
157                 sdb_log(SDB_LOG_ERR, "frontend: Failed to create "
158                                 "JSON formatter to handle LIST command: %s",
159                                 sdb_strerror(errno, err, sizeof(err)));
161                 sdb_strbuf_sprintf(errbuf, "Out of memory");
162                 return -1;
163         }
165         sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t));
166         if (sdb_store_scan(store, type, /* m = */ NULL, filter, list_tojson, f)) {
167                 sdb_log(SDB_LOG_ERR, "frontend: Failed to serialize "
168                                 "store to JSON");
169                 sdb_strbuf_sprintf(errbuf, "Out of memory");
170                 sdb_object_deref(SDB_OBJ(f));
171                 return -1;
172         }
174         sdb_store_json_finish(f);
175         sdb_object_deref(SDB_OBJ(f));
177         return SDB_CONNECTION_DATA;
178 } /* exec_list */
180 static int
181 exec_lookup(sdb_store_t *store, sdb_strbuf_t *buf, sdb_strbuf_t *errbuf,
182                 int type, sdb_store_matcher_t *m, sdb_store_matcher_t *filter)
184         uint32_t res_type = htonl(SDB_CONNECTION_LOOKUP);
185         sdb_store_json_formatter_t *f;
187         f = sdb_store_json_formatter(buf, type, SDB_WANT_ARRAY);
188         if (! f) {
189                 char err[1024];
190                 sdb_log(SDB_LOG_ERR, "frontend: Failed to create "
191                                 "JSON formatter to handle LOOKUP command: %s",
192                                 sdb_strerror(errno, err, sizeof(err)));
194                 sdb_strbuf_sprintf(errbuf, "Out of memory");
195                 return -1;
196         }
198         sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t));
200         if (sdb_store_scan(store, type, m, filter, lookup_tojson, f)) {
201                 sdb_log(SDB_LOG_ERR, "frontend: Failed to lookup %ss",
202                                 SDB_STORE_TYPE_TO_NAME(type));
203                 sdb_strbuf_sprintf(errbuf, "Failed to lookup %ss",
204                                 SDB_STORE_TYPE_TO_NAME(type));
205                 sdb_object_deref(SDB_OBJ(f));
206                 return -1;
207         }
209         sdb_store_json_finish(f);
210         sdb_object_deref(SDB_OBJ(f));
212         return SDB_CONNECTION_DATA;
213 } /* exec_lookup */
215 static int
216 exec_timeseries(sdb_store_t *store, sdb_strbuf_t *buf, sdb_strbuf_t *errbuf,
217                 const char *hostname, const char *metric,
218                 sdb_timeseries_opts_t *opts)
220         uint32_t res_type = htonl(SDB_CONNECTION_TIMESERIES);
222         sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t));
223         if (sdb_store_fetch_timeseries(store, hostname, metric, opts, buf)) {
224                 sdb_log(SDB_LOG_ERR, "frontend: Failed to fetch time-series");
225                 sdb_strbuf_sprintf(errbuf, "Failed to fetch time-series");
226                 return -1;
227         }
229         return SDB_CONNECTION_DATA;
230 } /* exec_timeseries */
232 /*
233  * public API
234  */
236 int
237 sdb_store_query_execute(sdb_store_t *store, sdb_store_query_t *q,
238                 sdb_strbuf_t *buf, sdb_strbuf_t *errbuf)
240         sdb_timeseries_opts_t ts_opts;
241         sdb_ast_node_t *ast;
243         if (! q)
244                 return -1;
245         if (! q->ast) {
246                 sdb_log(SDB_LOG_ERR, "store: Invalid empty query");
247                 return -1;
248         }
250         ast = q->ast;
251         switch (ast->type) {
252         case SDB_AST_TYPE_FETCH:
253                 return exec_fetch(store, buf, errbuf, SDB_AST_FETCH(ast)->obj_type,
254                                 SDB_AST_FETCH(ast)->hostname, SDB_AST_FETCH(ast)->name,
255                                 q->filter);
257         case SDB_AST_TYPE_LIST:
258                 return exec_list(store, buf, errbuf, SDB_AST_LIST(ast)->obj_type,
259                                 q->filter);
261         case SDB_AST_TYPE_LOOKUP:
262                 return exec_lookup(store, buf, errbuf, SDB_AST_LOOKUP(ast)->obj_type,
263                                 q->matcher, q->filter);
265         case SDB_AST_TYPE_TIMESERIES:
266                 ts_opts.start = SDB_AST_TIMESERIES(ast)->start;
267                 ts_opts.end = SDB_AST_TIMESERIES(ast)->end;
268                 return exec_timeseries(store, buf, errbuf,
269                                 SDB_AST_TIMESERIES(ast)->hostname,
270                                 SDB_AST_TIMESERIES(ast)->metric, &ts_opts);
272         default:
273                 sdb_log(SDB_LOG_ERR, "store: Invalid query of type %s",
274                                 SDB_AST_TYPE_TO_STRING(ast));
275                 return -1;
276         }
278         return 0;
279 } /* sdb_store_query_execute */
281 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */