1
2 /*
3 * Redistribution and use in source and binary forms, with or
4 * without modification, are permitted provided that the following
5 * conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above
8 * copyright notice, this list of conditions and the
9 * following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials
14 * provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20 * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <stdlib.h>
32 #include <stdint.h>
33 #include <stdbool.h>
34 #include <inttypes.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <ctype.h>
39 #include <assert.h>
40
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <unistd.h>
44 #include <fcntl.h>
45 #include <errno.h>
46
47 #include <parser/queue.h>
48 #include <parser/utf8.h>
49 #include <parser/lex.h>
50
51 #include "nosqlbench.h"
52
53 extern struct nb nb;
54
55 enum nb_config_index_type {
56 NB_CONFIG_NONE,
57 NB_CONFIG_INT,
58 NB_CONFIG_STRING
59 };
60
61 struct nb_config_index {
62 int token;
63 enum nb_config_index_type type;
64 int *vi;
65 char **vs;
66 };
67
68 struct nb_config {
69 struct tnt_lex lex;
70 char *file;
71 };
72
73 enum {
74 NB_TK_CONFIGURATION = TNT_TK_CUSTOM,
75 NB_TK_BENCHMARK,
76 NB_TK_TIME_LIMIT,
77 NB_TK_REQUEST_COUNT,
78 NB_TK_REQUEST_BATCH_COUNT,
79 NB_TK_REPORT_INTERVAL,
80 NB_TK_REPORT_TYPE,
81 NB_TK_CSV_FILE,
82 NB_TK_CLIENT_HISTORY,
83 NB_TK_CLIENT_CREATION_POLICY,
84 NB_TK_CLIENT_CREATION_INTERVAL,
85 NB_TK_CLIENT_CREATION_INCREMENT,
86 NB_TK_CLIENT_START,
87 NB_TK_CLIENT_MAX,
88 NB_TK_DB_DRIVER,
89 NB_TK_KEY_DISTRIBUTION,
90 NB_TK_KEY_DISTRIBUTION_ITER,
91 NB_TK_KEY_TYPE,
92 NB_TK_VALUE_SIZE,
93 NB_TK_REPLACE,
94 NB_TK_UPDATE,
95 NB_TK_DELETE,
96 NB_TK_SELECT,
97 NB_TK_SERVER,
98 NB_TK_PORT,
99 NB_TK_BUF_RECV,
100 NB_TK_BUF_SEND
101 };
102
103 #define NB_DECLARE_KEYWORD_DEF(NAME, ID) { NAME, sizeof(NAME) - 1, ID }
104 #define NB_DECLARE_KEYWORD(NAME, ID) { NAME, sizeof(NAME) - 1, ID }
105 #define NB_DECLARE_KEYWORD_END() { 0, 0, 0 }
106
107 static struct tnt_lex_keyword nb_lex_keywords[] =
108 {
109 NB_DECLARE_KEYWORD("configuration", NB_TK_CONFIGURATION),
110 NB_DECLARE_KEYWORD("benchmark", NB_TK_BENCHMARK),
111 NB_DECLARE_KEYWORD("time_limit", NB_TK_TIME_LIMIT),
112 NB_DECLARE_KEYWORD("request_count", NB_TK_REQUEST_COUNT),
113 NB_DECLARE_KEYWORD("request_batch_count", NB_TK_REQUEST_BATCH_COUNT),
114 NB_DECLARE_KEYWORD("report_interval", NB_TK_REPORT_INTERVAL),
115 NB_DECLARE_KEYWORD("report_type", NB_TK_REPORT_TYPE),
116 NB_DECLARE_KEYWORD("csv_file", NB_TK_CSV_FILE),
117 NB_DECLARE_KEYWORD("client_history", NB_TK_CLIENT_HISTORY),
118 NB_DECLARE_KEYWORD("client_creation_policy", NB_TK_CLIENT_CREATION_POLICY),
119 NB_DECLARE_KEYWORD("client_creation_interval", NB_TK_CLIENT_CREATION_INTERVAL),
120 NB_DECLARE_KEYWORD("client_creation_increment", NB_TK_CLIENT_CREATION_INCREMENT),
121 NB_DECLARE_KEYWORD("client_start", NB_TK_CLIENT_START),
122 NB_DECLARE_KEYWORD("client_max", NB_TK_CLIENT_MAX),
123 NB_DECLARE_KEYWORD("db_driver", NB_TK_DB_DRIVER),
124 NB_DECLARE_KEYWORD("key_distribution", NB_TK_KEY_DISTRIBUTION),
125 NB_DECLARE_KEYWORD("key_distribution_iter", NB_TK_KEY_DISTRIBUTION_ITER),
126 NB_DECLARE_KEYWORD("key_type", NB_TK_KEY_TYPE),
127 NB_DECLARE_KEYWORD("value_size", NB_TK_VALUE_SIZE),
128 NB_DECLARE_KEYWORD("test_replace", NB_TK_REPLACE),
129 NB_DECLARE_KEYWORD("test_update", NB_TK_UPDATE),
130 NB_DECLARE_KEYWORD("test_delete", NB_TK_DELETE),
131 NB_DECLARE_KEYWORD("test_select", NB_TK_SELECT),
132 NB_DECLARE_KEYWORD("server", NB_TK_SERVER),
133 NB_DECLARE_KEYWORD("port", NB_TK_PORT),
134 NB_DECLARE_KEYWORD("buf_recv", NB_TK_BUF_RECV),
135 NB_DECLARE_KEYWORD("buf_send", NB_TK_BUF_SEND),
136 NB_DECLARE_KEYWORD_END()
137 };
138
139 #define NB_DECLARE_OPT(ID, TYPE, I, S) { ID, TYPE, I, S }
140 #define NB_DECLARE_OPT_INT(ID, VALUE) \
141 NB_DECLARE_OPT(ID, NB_CONFIG_INT, VALUE, NULL)
142 #define NB_DECLARE_OPT_STR(ID, VALUE) \
143 NB_DECLARE_OPT(ID, NB_CONFIG_STRING, NULL, VALUE)
144 #define NB_DECLARE_OPT_END() \
145 NB_DECLARE_OPT(0, NB_CONFIG_NONE, NULL, NULL)
146
147 struct nb_config_index nb_config_index[] =
148 {
149 NB_DECLARE_OPT_STR(NB_TK_BENCHMARK, &nb.opts.benchmark_policy_name),
150 NB_DECLARE_OPT_INT(NB_TK_TIME_LIMIT, &nb.opts.time_limit),
151 NB_DECLARE_OPT_INT(NB_TK_REQUEST_COUNT, &nb.opts.request_count),
152 NB_DECLARE_OPT_INT(NB_TK_REQUEST_BATCH_COUNT, &nb.opts.request_batch_count),
153 NB_DECLARE_OPT_INT(NB_TK_REPORT_INTERVAL, &nb.opts.report_interval),
154 NB_DECLARE_OPT_STR(NB_TK_REPORT_TYPE, &nb.opts.report),
155 NB_DECLARE_OPT_STR(NB_TK_CSV_FILE, &nb.opts.csv_file),
156 NB_DECLARE_OPT_INT(NB_TK_CLIENT_HISTORY, &nb.opts.history_per_batch),
157 NB_DECLARE_OPT_STR(NB_TK_CLIENT_CREATION_POLICY, &nb.opts.threads_policy_name),
158 NB_DECLARE_OPT_INT(NB_TK_CLIENT_CREATION_INTERVAL, &nb.opts.threads_interval),
159 NB_DECLARE_OPT_INT(NB_TK_CLIENT_CREATION_INCREMENT, &nb.opts.threads_increment),
160 NB_DECLARE_OPT_INT(NB_TK_CLIENT_START, &nb.opts.threads_start),
161 NB_DECLARE_OPT_INT(NB_TK_CLIENT_MAX, &nb.opts.threads_max),
162 NB_DECLARE_OPT_STR(NB_TK_DB_DRIVER, &nb.opts.db),
163 NB_DECLARE_OPT_STR(NB_TK_KEY_DISTRIBUTION, &nb.opts.key_dist),
164 NB_DECLARE_OPT_INT(NB_TK_KEY_DISTRIBUTION_ITER, &nb.opts.key_dist_iter),
165 NB_DECLARE_OPT_STR(NB_TK_KEY_TYPE, &nb.opts.key),
166 NB_DECLARE_OPT_INT(NB_TK_VALUE_SIZE, &nb.opts.value_size),
167 NB_DECLARE_OPT_INT(NB_TK_REPLACE, &nb.opts.dist_replace),
168 NB_DECLARE_OPT_INT(NB_TK_UPDATE, &nb.opts.dist_update),
169 NB_DECLARE_OPT_INT(NB_TK_DELETE, &nb.opts.dist_delete),
170 NB_DECLARE_OPT_INT(NB_TK_SELECT, &nb.opts.dist_select),
171 NB_DECLARE_OPT_STR(NB_TK_SERVER, &nb.opts.host),
172 NB_DECLARE_OPT_INT(NB_TK_PORT, &nb.opts.port),
173 NB_DECLARE_OPT_INT(NB_TK_BUF_RECV, &nb.opts.buf_recv),
174 NB_DECLARE_OPT_INT(NB_TK_BUF_SEND, &nb.opts.buf_send),
175 NB_DECLARE_OPT_END()
176 };
177
178 static int
nb_config_error(struct nb_config * cfg,struct tnt_tk * last,char * fmt,...)179 nb_config_error(struct nb_config *cfg, struct tnt_tk *last, char *fmt, ...)
180 {
181 char msgu[256];
182 va_list args;
183 va_start(args, fmt);
184 vsnprintf(msgu, sizeof(msgu), fmt, args);
185 va_end(args);
186 int line = (last) ? last->line : cfg->lex.line;
187 int col = (last) ? last->col : cfg->lex.col;
188 printf("%s %d:%d %s\n", cfg->file, line, col, msgu);
189 return TNT_TK_ERROR;
190 }
191
192 static int
nb_config_expect(struct nb_config * cfg,int tk,struct tnt_tk ** tkp)193 nb_config_expect(struct nb_config *cfg, int tk, struct tnt_tk **tkp)
194 {
195 struct tnt_tk *tkp_ = NULL;
196 int tk_ = tnt_lex(&cfg->lex, &tkp_);
197 if (tk_ == TNT_TK_ERROR)
198 return nb_config_error(cfg, NULL, "%s", cfg->lex.error);
199 if (tk_ != tk) {
200 if (tk < 0xff && ispunct(tk))
201 return nb_config_error(cfg, tkp_, "expected '%c'", tk);
202 return nb_config_error(cfg, tkp_, "expected '%s'",
203 tnt_lex_nameof(&cfg->lex, tk));
204 }
205 if (tkp)
206 *tkp = tkp_;
207 return 0;
208 }
209
nb_config_readint(struct nb_config * cfg,int * v)210 static int nb_config_readint(struct nb_config *cfg, int *v) {
211 struct tnt_tk *tk = NULL;
212 if (nb_config_expect(cfg, TNT_TK_NUM32, &tk) == -1)
213 return -1;
214 *v = TNT_TK_I32(tk);
215 return 0;
216 }
217
nb_config_readsz(struct nb_config * cfg,char ** v)218 static int nb_config_readsz(struct nb_config *cfg, char **v) {
219 struct tnt_tk *tk = NULL;
220 if (nb_config_expect(cfg, TNT_TK_STRING, &tk) == -1)
221 return -1;
222 if (*v)
223 free(*v);
224 *v = nb_malloc(TNT_TK_S(tk)->size + 1);
225 memcpy(*v, (char*)TNT_TK_S(tk)->data, TNT_TK_S(tk)->size + 1);
226 return 0;
227 }
228
nb_config_read(struct nb_config * cfg,struct tnt_tk * tk)229 static int nb_config_read(struct nb_config *cfg, struct tnt_tk *tk)
230 {
231 struct nb_config_index *it = &nb_config_index[0];
232 for (; it->type != NB_CONFIG_NONE; it++) {
233 if (it->token != tk->tk)
234 continue;
235 switch (it->type) {
236 case NB_CONFIG_INT:
237 if (!nb_config_readint(cfg, it->vi) == -1)
238 return -1;
239 break;
240 case NB_CONFIG_STRING:
241 if (!nb_config_readsz(cfg, it->vs) == -1)
242 return -1;
243 break;
244 case NB_CONFIG_NONE:
245 break;
246 }
247 return 0;
248 }
249 return -1;
250 }
251
nb_config_process(struct nb_config * cfg)252 static int nb_config_process(struct nb_config *cfg)
253 {
254 struct tnt_tk *tk;
255 if (nb_config_expect(cfg, NB_TK_CONFIGURATION, NULL) == -1)
256 return -1;
257 if (nb_config_expect(cfg, '{', NULL) == -1)
258 return -1;
259 int eoc = 0;
260 while (!eoc) {
261 tnt_lex(&cfg->lex, &tk);
262 if (nb_config_read(cfg, tk) == 0)
263 continue;
264 if (tk->tk == TNT_TK_PUNCT && tk->v.i32 == '}')
265 eoc = 1;
266 else
267 return nb_config_error(cfg, tk, "unknown option");
268 }
269 return 0;
270 }
271
nb_config_readfile(char * file,char ** buf,size_t * size)272 static int nb_config_readfile(char *file, char **buf, size_t *size)
273 {
274 struct stat st;
275 if (stat(file, &st) == -1) {
276 printf("error: config file '%s': %s\n", file, strerror(errno));
277 return -1;
278 }
279 int fd = open(file, O_RDONLY);
280 if (fd == -1)
281 return -1;
282 *buf = nb_malloc(st.st_size);
283 ssize_t off = 0;
284 do {
285 ssize_t r = read(fd, *buf + off, st.st_size - off);
286 if (r == -1) {
287 close(fd);
288 free(*buf);
289 printf("error: read(): %s\n", strerror(errno));
290 return -1;
291 }
292 off += r;
293 } while (off != st.st_size);
294 *size = st.st_size;
295 close(fd);
296 return 0;
297 }
298
nb_config_parse(char * file)299 int nb_config_parse(char *file)
300 {
301 char *buf = NULL;
302 size_t size;
303
304 if (nb_config_readfile(file, &buf, &size) == -1)
305 return -1;
306
307 struct nb_config cfg;
308 memset(&cfg, 0, sizeof(cfg));
309
310 if (tnt_lex_init(&cfg.lex, nb_lex_keywords, (unsigned char*)buf,
311 size) == -1) {
312 free(buf);
313 return -1;
314 }
315 free(buf);
316
317 cfg.file = file;
318 int rc = nb_config_process(&cfg);
319
320 tnt_lex_free(&cfg.lex);
321 return rc;
322 }
323