1 | /* -*- c-basic-offset: 2 -*- */ |
2 | /* |
3 | Copyright(C) 2009-2017 Brazil |
4 | |
5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License version 2.1 as published by the Free Software Foundation. |
8 | |
9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with this library; if not, write to the Free Software |
16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ |
18 | |
19 | #include "grn.h" |
20 | #include <string.h> |
21 | #include "grn_request_canceler.h" |
22 | #include "grn_request_timer.h" |
23 | #include "grn_tokenizers.h" |
24 | #include "grn_ctx_impl.h" |
25 | #include "grn_ii.h" |
26 | #include "grn_pat.h" |
27 | #include "grn_index_column.h" |
28 | #include "grn_proc.h" |
29 | #include "grn_plugin.h" |
30 | #include "grn_snip.h" |
31 | #include "grn_output.h" |
32 | #include "grn_normalizer.h" |
33 | #include "grn_mrb.h" |
34 | #include "grn_ctx_impl_mrb.h" |
35 | #include "grn_logger.h" |
36 | #include "grn_cache.h" |
37 | #include "grn_expr.h" |
38 | #include <stdio.h> |
39 | #include <stdarg.h> |
40 | #include <time.h> |
41 | |
42 | #ifdef GRN_WITH_ONIGMO |
43 | # define GRN_SUPPORT_REGEXP |
44 | #endif /* GRN_WITH_ONIGMO */ |
45 | |
46 | #ifdef GRN_SUPPORT_REGEXP |
47 | # include <onigmo.h> |
48 | #endif /* GRN_SUPPORT_REGEXP */ |
49 | |
50 | #ifdef WIN32 |
51 | # include <share.h> |
52 | #else /* WIN32 */ |
53 | # include <netinet/in.h> |
54 | #endif /* WIN32 */ |
55 | |
56 | #define GRN_CTX_INITIALIZER(enc) \ |
57 | { GRN_SUCCESS, 0, enc, 0, GRN_LOG_NOTICE,\ |
58 | GRN_CTX_FIN, 0, 0, 0, 0, {0}, NULL, NULL, NULL, NULL, NULL, \ |
59 | {NULL, NULL,NULL, NULL,NULL, NULL,NULL, NULL,NULL, NULL,NULL, NULL,NULL, NULL,NULL, NULL}, ""} |
60 | |
61 | #define GRN_CTX_CLOSED(ctx) ((ctx)->stat == GRN_CTX_FIN) |
62 | |
63 | grn_ctx grn_gctx = GRN_CTX_INITIALIZER(GRN_ENC_DEFAULT); |
64 | int grn_pagesize; |
65 | grn_critical_section grn_glock; |
66 | uint32_t grn_gtick; |
67 | int grn_lock_timeout = GRN_LOCK_TIMEOUT; |
68 | |
69 | #ifdef USE_UYIELD |
70 | int grn_uyield_count = 0; |
71 | #endif |
72 | |
73 | static grn_bool grn_ctx_per_db = GRN_FALSE; |
74 | |
75 | static void |
76 | grn_init_from_env(void) |
77 | { |
78 | { |
79 | char grn_ctx_per_db_env[GRN_ENV_BUFFER_SIZE]; |
80 | grn_getenv("GRN_CTX_PER_DB" , |
81 | grn_ctx_per_db_env, |
82 | GRN_ENV_BUFFER_SIZE); |
83 | if (grn_ctx_per_db_env[0] && strcmp(grn_ctx_per_db_env, "yes" ) == 0) { |
84 | grn_ctx_per_db = GRN_TRUE; |
85 | } |
86 | } |
87 | |
88 | grn_alloc_init_from_env(); |
89 | grn_mrb_init_from_env(); |
90 | grn_ctx_impl_mrb_init_from_env(); |
91 | grn_io_init_from_env(); |
92 | grn_ii_init_from_env(); |
93 | grn_db_init_from_env(); |
94 | grn_expr_init_from_env(); |
95 | grn_index_column_init_from_env(); |
96 | grn_proc_init_from_env(); |
97 | grn_plugin_init_from_env(); |
98 | } |
99 | |
100 | static void |
101 | grn_init_external_libraries(void) |
102 | { |
103 | #ifdef GRN_SUPPORT_REGEXP |
104 | onig_init(); |
105 | #endif /* GRN_SUPPORT_REGEXP */ |
106 | } |
107 | |
108 | static void |
109 | grn_fin_external_libraries(void) |
110 | { |
111 | #ifdef GRN_SUPPORT_REGEXP |
112 | onig_end(); |
113 | #endif /* GRN_SUPPORT_REGEXP */ |
114 | } |
115 | |
116 | void |
117 | grn_sleep(uint32_t seconds) |
118 | { |
119 | #ifdef WIN32 |
120 | Sleep(seconds * 1000); |
121 | #else // WIN32 |
122 | sleep(seconds); |
123 | #endif // WIN32 |
124 | } |
125 | |
126 | void |
127 | grn_nanosleep(uint64_t nanoseconds) |
128 | { |
129 | #ifdef WIN32 |
130 | Sleep((DWORD)(nanoseconds / 1000000)); |
131 | #else // WIN32 |
132 | struct timespec interval; |
133 | interval.tv_sec = (time_t)(nanoseconds / 1000000000); |
134 | interval.tv_nsec = (long)(nanoseconds % 1000000000); |
135 | nanosleep(&interval, NULL); |
136 | #endif // WIN32 |
137 | } |
138 | |
139 | const char * |
140 | grn_get_global_error_message(void) |
141 | { |
142 | return grn_gctx.errbuf; |
143 | } |
144 | |
145 | static void |
146 | grn_loader_init(grn_loader *loader) |
147 | { |
148 | GRN_TEXT_INIT(&loader->values, 0); |
149 | GRN_UINT32_INIT(&loader->level, GRN_OBJ_VECTOR); |
150 | GRN_PTR_INIT(&loader->columns, GRN_OBJ_VECTOR, GRN_ID_NIL); |
151 | GRN_UINT32_INIT(&loader->ids, GRN_OBJ_VECTOR); |
152 | GRN_INT32_INIT(&loader->return_codes, GRN_OBJ_VECTOR); |
153 | GRN_TEXT_INIT(&loader->error_messages, GRN_OBJ_VECTOR); |
154 | loader->id_offset = -1; |
155 | loader->key_offset = -1; |
156 | loader->table = NULL; |
157 | loader->last = NULL; |
158 | loader->ifexists = NULL; |
159 | loader->each = NULL; |
160 | loader->values_size = 0; |
161 | loader->nrecords = 0; |
162 | loader->stat = GRN_LOADER_BEGIN; |
163 | loader->columns_status = GRN_LOADER_COLUMNS_UNSET; |
164 | loader->rc = GRN_SUCCESS; |
165 | loader->errbuf[0] = '\0'; |
166 | loader->output_ids = GRN_FALSE; |
167 | loader->output_errors = GRN_FALSE; |
168 | } |
169 | |
170 | void |
171 | grn_ctx_loader_clear(grn_ctx *ctx) |
172 | { |
173 | grn_loader *loader = &ctx->impl->loader; |
174 | grn_obj *v = (grn_obj *)(GRN_BULK_HEAD(&loader->values)); |
175 | grn_obj *ve = (grn_obj *)(GRN_BULK_CURR(&loader->values)); |
176 | grn_obj **p = (grn_obj **)GRN_BULK_HEAD(&loader->columns); |
177 | uint32_t i = GRN_BULK_VSIZE(&loader->columns) / sizeof(grn_obj *); |
178 | if (ctx->impl->db) { while (i--) { grn_obj_unlink(ctx, *p++); } } |
179 | if (loader->ifexists) { grn_obj_unlink(ctx, loader->ifexists); } |
180 | if (loader->each) { grn_obj_unlink(ctx, loader->each); } |
181 | while (v < ve) { GRN_OBJ_FIN(ctx, v++); } |
182 | GRN_OBJ_FIN(ctx, &loader->values); |
183 | GRN_OBJ_FIN(ctx, &loader->level); |
184 | GRN_OBJ_FIN(ctx, &loader->columns); |
185 | GRN_OBJ_FIN(ctx, &loader->ids); |
186 | GRN_OBJ_FIN(ctx, &loader->return_codes); |
187 | GRN_OBJ_FIN(ctx, &loader->error_messages); |
188 | grn_loader_init(loader); |
189 | } |
190 | |
191 | #define IMPL_SIZE ((sizeof(struct _grn_ctx_impl) + (grn_pagesize - 1)) & ~(grn_pagesize - 1)) |
192 | |
193 | #ifdef GRN_WITH_MESSAGE_PACK |
194 | static int |
195 | grn_msgpack_buffer_write(void *data, const char *buf, msgpack_size_t len) |
196 | { |
197 | grn_ctx *ctx = (grn_ctx *)data; |
198 | return grn_bulk_write(ctx, ctx->impl->output.buf, buf, len); |
199 | } |
200 | #endif |
201 | |
202 | static grn_rc |
203 | grn_ctx_impl_init(grn_ctx *ctx) |
204 | { |
205 | grn_io_mapinfo mi; |
206 | if (!(ctx->impl = grn_io_anon_map(ctx, &mi, IMPL_SIZE))) { |
207 | return ctx->rc; |
208 | } |
209 | grn_alloc_init_ctx_impl(ctx); |
210 | ctx->impl->encoding = ctx->encoding; |
211 | ctx->impl->lifoseg = -1; |
212 | ctx->impl->currseg = -1; |
213 | CRITICAL_SECTION_INIT(ctx->impl->lock); |
214 | if (!(ctx->impl->values = grn_array_create(ctx, NULL, sizeof(grn_db_obj *), |
215 | GRN_ARRAY_TINY))) { |
216 | CRITICAL_SECTION_FIN(ctx->impl->lock); |
217 | grn_io_anon_unmap(ctx, &mi, IMPL_SIZE); |
218 | ctx->impl = NULL; |
219 | return ctx->rc; |
220 | } |
221 | if (!(ctx->impl->temporary_columns = grn_pat_create(ctx, NULL, |
222 | GRN_TABLE_MAX_KEY_SIZE, |
223 | sizeof(grn_obj *), |
224 | 0))) { |
225 | grn_array_close(ctx, ctx->impl->values); |
226 | CRITICAL_SECTION_FIN(ctx->impl->lock); |
227 | grn_io_anon_unmap(ctx, &mi, IMPL_SIZE); |
228 | ctx->impl = NULL; |
229 | return ctx->rc; |
230 | } |
231 | if (!(ctx->impl->ios = grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE, |
232 | sizeof(grn_io *), |
233 | GRN_OBJ_KEY_VAR_SIZE|GRN_HASH_TINY))) { |
234 | grn_array_close(ctx, ctx->impl->values); |
235 | grn_pat_close(ctx, ctx->impl->temporary_columns); |
236 | CRITICAL_SECTION_FIN(ctx->impl->lock); |
237 | grn_io_anon_unmap(ctx, &mi, IMPL_SIZE); |
238 | ctx->impl = NULL; |
239 | return ctx->rc; |
240 | } |
241 | ctx->impl->db = NULL; |
242 | |
243 | ctx->impl->expr_vars = grn_hash_create(ctx, NULL, sizeof(grn_id), sizeof(grn_obj *), 0); |
244 | ctx->impl->stack_curr = 0; |
245 | ctx->impl->curr_expr = NULL; |
246 | GRN_TEXT_INIT(&ctx->impl->current_request_id, 0); |
247 | ctx->impl->current_request_timer_id = NULL; |
248 | ctx->impl->parser = NULL; |
249 | |
250 | GRN_TEXT_INIT(&ctx->impl->output.names, GRN_OBJ_VECTOR); |
251 | GRN_UINT32_INIT(&ctx->impl->output.levels, GRN_OBJ_VECTOR); |
252 | |
253 | ctx->impl->command.flags = 0; |
254 | if (ctx == &grn_gctx) { |
255 | ctx->impl->command.version = GRN_COMMAND_VERSION_STABLE; |
256 | } else { |
257 | ctx->impl->command.version = grn_get_default_command_version(); |
258 | } |
259 | ctx->impl->command.keep.command = NULL; |
260 | ctx->impl->command.keep.version = ctx->impl->command.version; |
261 | |
262 | if (ctx == &grn_gctx) { |
263 | ctx->impl->match_escalation_threshold = |
264 | GRN_DEFAULT_MATCH_ESCALATION_THRESHOLD; |
265 | } else { |
266 | ctx->impl->match_escalation_threshold = |
267 | grn_get_default_match_escalation_threshold(); |
268 | } |
269 | |
270 | ctx->impl->finalizer = NULL; |
271 | |
272 | ctx->impl->com = NULL; |
273 | ctx->impl->output.buf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_TEXT); |
274 | ctx->impl->output.func = NULL; |
275 | ctx->impl->output.data.ptr = NULL; |
276 | #ifdef GRN_WITH_MESSAGE_PACK |
277 | msgpack_packer_init(&ctx->impl->output.msgpacker, |
278 | ctx, grn_msgpack_buffer_write); |
279 | #endif |
280 | ctx->impl->tv.tv_sec = 0; |
281 | ctx->impl->tv.tv_nsec = 0; |
282 | ctx->impl->edge = NULL; |
283 | grn_loader_init(&ctx->impl->loader); |
284 | ctx->impl->plugin_path = NULL; |
285 | |
286 | GRN_TEXT_INIT(&ctx->impl->query_log_buf, 0); |
287 | |
288 | ctx->impl->previous_errbuf[0] = '\0'; |
289 | ctx->impl->n_same_error_messages = 0; |
290 | |
291 | grn_ctx_impl_mrb_init(ctx); |
292 | |
293 | GRN_TEXT_INIT(&(ctx->impl->temporary_open_spaces.stack), 0); |
294 | ctx->impl->temporary_open_spaces.current = NULL; |
295 | |
296 | return ctx->rc; |
297 | } |
298 | |
299 | void |
300 | grn_ctx_set_keep_command(grn_ctx *ctx, grn_obj *command) |
301 | { |
302 | ctx->impl->command.keep.command = command; |
303 | ctx->impl->command.keep.version = ctx->impl->command.version; |
304 | } |
305 | |
306 | static void |
307 | grn_ctx_impl_clear_n_same_error_messagges(grn_ctx *ctx) |
308 | { |
309 | if (ctx->impl->n_same_error_messages == 0) { |
310 | return; |
311 | } |
312 | |
313 | GRN_LOG(ctx, GRN_LOG_NOTICE, "(%u same messages are truncated)" , |
314 | ctx->impl->n_same_error_messages); |
315 | ctx->impl->n_same_error_messages = 0; |
316 | } |
317 | |
318 | grn_bool |
319 | grn_ctx_impl_should_log(grn_ctx *ctx) |
320 | { |
321 | if (!ctx->impl) { |
322 | return GRN_TRUE; |
323 | } |
324 | |
325 | if (strcmp(ctx->errbuf, ctx->impl->previous_errbuf) == 0) { |
326 | ctx->impl->n_same_error_messages++; |
327 | return GRN_FALSE; |
328 | } |
329 | |
330 | return GRN_TRUE; |
331 | } |
332 | |
333 | void |
334 | grn_ctx_impl_set_current_error_message(grn_ctx *ctx) |
335 | { |
336 | if (!ctx->impl) { |
337 | return; |
338 | } |
339 | |
340 | grn_ctx_impl_clear_n_same_error_messagges(ctx); |
341 | grn_strcpy(ctx->impl->previous_errbuf, GRN_CTX_MSGSIZE, ctx->errbuf); |
342 | } |
343 | |
344 | static grn_rc |
345 | grn_ctx_init_internal(grn_ctx *ctx, int flags) |
346 | { |
347 | if (!ctx) { return GRN_INVALID_ARGUMENT; } |
348 | // if (ctx->stat != GRN_CTX_FIN) { return GRN_INVALID_ARGUMENT; } |
349 | ctx->rc = GRN_SUCCESS; |
350 | ERRCLR(ctx); |
351 | ctx->flags = flags; |
352 | if (grn_ctx_per_db) { |
353 | ctx->flags |= GRN_CTX_PER_DB; |
354 | } |
355 | ctx->stat = GRN_CTX_INITED; |
356 | ctx->encoding = grn_gctx.encoding; |
357 | ctx->seqno = 0; |
358 | ctx->seqno2 = 0; |
359 | ctx->subno = 0; |
360 | ctx->impl = NULL; |
361 | ctx->user_data.ptr = NULL; |
362 | CRITICAL_SECTION_ENTER(grn_glock); |
363 | ctx->next = grn_gctx.next; |
364 | ctx->prev = &grn_gctx; |
365 | grn_gctx.next->prev = ctx; |
366 | grn_gctx.next = ctx; |
367 | CRITICAL_SECTION_LEAVE(grn_glock); |
368 | ctx->errline = 0; |
369 | ctx->errfile = "" ; |
370 | ctx->errfunc = "" ; |
371 | ctx->trace[0] = NULL; |
372 | ctx->errbuf[0] = '\0'; |
373 | return GRN_SUCCESS; |
374 | } |
375 | |
376 | grn_rc |
377 | grn_ctx_init(grn_ctx *ctx, int flags) |
378 | { |
379 | grn_rc rc; |
380 | |
381 | rc = grn_ctx_init_internal(ctx, flags); |
382 | if (rc == GRN_SUCCESS) { |
383 | grn_ctx_impl_init(ctx); |
384 | rc = ctx->rc; |
385 | if (rc != GRN_SUCCESS) { |
386 | grn_ctx_fin(ctx); |
387 | if (flags & GRN_CTX_ALLOCATED) { |
388 | CRITICAL_SECTION_ENTER(grn_glock); |
389 | ctx->next->prev = ctx->prev; |
390 | ctx->prev->next = ctx->next; |
391 | CRITICAL_SECTION_LEAVE(grn_glock); |
392 | } |
393 | } |
394 | } |
395 | |
396 | return rc; |
397 | } |
398 | |
399 | grn_ctx * |
400 | grn_ctx_open(int flags) |
401 | { |
402 | grn_ctx *ctx = GRN_GMALLOCN(grn_ctx, 1); |
403 | if (ctx) { |
404 | grn_ctx_init(ctx, flags|GRN_CTX_ALLOCATED); |
405 | if (ERRP(ctx, GRN_ERROR)) { |
406 | GRN_GFREE(ctx); |
407 | ctx = NULL; |
408 | } |
409 | } |
410 | return ctx; |
411 | } |
412 | |
413 | grn_rc |
414 | grn_ctx_fin(grn_ctx *ctx) |
415 | { |
416 | grn_rc rc = GRN_SUCCESS; |
417 | if (!ctx) { return GRN_INVALID_ARGUMENT; } |
418 | if (ctx->stat == GRN_CTX_FIN) { return GRN_INVALID_ARGUMENT; } |
419 | if (!(ctx->flags & GRN_CTX_ALLOCATED)) { |
420 | CRITICAL_SECTION_ENTER(grn_glock); |
421 | ctx->next->prev = ctx->prev; |
422 | ctx->prev->next = ctx->next; |
423 | CRITICAL_SECTION_LEAVE(grn_glock); |
424 | } |
425 | if (ctx->impl) { |
426 | grn_ctx_impl_clear_n_same_error_messagges(ctx); |
427 | if (ctx->impl->finalizer) { |
428 | ctx->impl->finalizer(ctx, 0, NULL, &(ctx->user_data)); |
429 | } |
430 | { |
431 | grn_obj *stack; |
432 | grn_obj *spaces; |
433 | unsigned int i, n_spaces; |
434 | |
435 | stack = &(ctx->impl->temporary_open_spaces.stack); |
436 | spaces = (grn_obj *)GRN_BULK_HEAD(stack); |
437 | n_spaces = GRN_BULK_VSIZE(stack) / sizeof(grn_obj); |
438 | for (i = 0; i < n_spaces; i++) { |
439 | grn_obj *space = spaces + (n_spaces - i - 1); |
440 | GRN_OBJ_FIN(ctx, space); |
441 | } |
442 | GRN_OBJ_FIN(ctx, stack); |
443 | } |
444 | grn_ctx_impl_mrb_fin(ctx); |
445 | grn_ctx_loader_clear(ctx); |
446 | if (ctx->impl->parser) { |
447 | grn_expr_parser_close(ctx); |
448 | } |
449 | GRN_OBJ_FIN(ctx, &ctx->impl->current_request_id); |
450 | if (ctx->impl->values) { |
451 | #ifndef USE_MEMORY_DEBUG |
452 | grn_db_obj *o; |
453 | GRN_ARRAY_EACH(ctx, ctx->impl->values, 0, 0, id, &o, { |
454 | grn_obj_close(ctx, *((grn_obj **)o)); |
455 | }); |
456 | #endif |
457 | grn_array_close(ctx, ctx->impl->values); |
458 | } |
459 | if (ctx->impl->temporary_columns) { |
460 | #ifndef USE_MEMORY_DEBUG |
461 | grn_obj *value; |
462 | GRN_PAT_EACH(ctx, ctx->impl->temporary_columns, id, NULL, NULL, &value, { |
463 | grn_obj_close(ctx, *((grn_obj **)value)); |
464 | }); |
465 | #endif |
466 | grn_pat_close(ctx, ctx->impl->temporary_columns); |
467 | } |
468 | if (ctx->impl->ios) { |
469 | grn_hash_close(ctx, ctx->impl->ios); |
470 | } |
471 | if (ctx->impl->com) { |
472 | if (ctx->stat != GRN_CTX_QUIT) { |
473 | int flags; |
474 | char *str; |
475 | unsigned int str_len; |
476 | grn_ctx_send(ctx, "quit" , 4, GRN_CTX_HEAD); |
477 | grn_ctx_recv(ctx, &str, &str_len, &flags); |
478 | } |
479 | grn_ctx_send(ctx, "ACK" , 3, GRN_CTX_HEAD); |
480 | rc = grn_com_close(ctx, ctx->impl->com); |
481 | } |
482 | GRN_OBJ_FIN(ctx, &ctx->impl->query_log_buf); |
483 | GRN_OBJ_FIN(ctx, &ctx->impl->output.names); |
484 | GRN_OBJ_FIN(ctx, &ctx->impl->output.levels); |
485 | rc = grn_obj_close(ctx, ctx->impl->output.buf); |
486 | { |
487 | grn_hash **vp; |
488 | grn_obj *value; |
489 | GRN_HASH_EACH(ctx, ctx->impl->expr_vars, eid, NULL, NULL, &vp, { |
490 | if (*vp) { |
491 | GRN_HASH_EACH(ctx, *vp, id, NULL, NULL, &value, { |
492 | GRN_OBJ_FIN(ctx, value); |
493 | }); |
494 | } |
495 | grn_hash_close(ctx, *vp); |
496 | }); |
497 | } |
498 | grn_hash_close(ctx, ctx->impl->expr_vars); |
499 | if (ctx->impl->db && ctx->flags & GRN_CTX_PER_DB) { |
500 | grn_obj *db = ctx->impl->db; |
501 | ctx->impl->db = NULL; |
502 | grn_obj_close(ctx, db); |
503 | } |
504 | grn_alloc_fin_ctx_impl(ctx); |
505 | grn_alloc_info_dump(ctx); |
506 | grn_alloc_info_free(ctx); |
507 | CRITICAL_SECTION_FIN(ctx->impl->lock); |
508 | { |
509 | grn_io_mapinfo mi; |
510 | mi.map = (void *)ctx->impl; |
511 | grn_io_anon_unmap(ctx, &mi, IMPL_SIZE); |
512 | } |
513 | ctx->impl = NULL; |
514 | } |
515 | ctx->stat = GRN_CTX_FIN; |
516 | return rc; |
517 | } |
518 | |
519 | grn_rc |
520 | grn_ctx_set_finalizer(grn_ctx *ctx, grn_proc_func *finalizer) |
521 | { |
522 | if (!ctx) { return GRN_INVALID_ARGUMENT; } |
523 | if (!ctx->impl) { |
524 | if (ERRP(ctx, GRN_ERROR)) { return ctx->rc; } |
525 | } |
526 | ctx->impl->finalizer = finalizer; |
527 | return GRN_SUCCESS; |
528 | } |
529 | |
530 | grn_timeval grn_starttime; |
531 | |
532 | static void |
533 | check_overcommit_memory(grn_ctx *ctx) |
534 | { |
535 | FILE *file; |
536 | int value; |
537 | file = grn_fopen("/proc/sys/vm/overcommit_memory" , "r" ); |
538 | if (!file) { return; } |
539 | value = fgetc(file); |
540 | if (value != '1') { |
541 | GRN_LOG(ctx, GRN_LOG_NOTICE, |
542 | "vm.overcommit_memory kernel parameter should be 1: <%c>: " |
543 | "See INFO level log to resolve this" , |
544 | value); |
545 | GRN_LOG(ctx, GRN_LOG_INFO, |
546 | "Some processings with vm.overcommit_memory != 1 " |
547 | "may break DB under low memory condition." ); |
548 | GRN_LOG(ctx, GRN_LOG_INFO, |
549 | "To set vm.overcommit_memory to 1" ); |
550 | GRN_LOG(ctx, GRN_LOG_INFO, |
551 | "add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and " |
552 | "restart your system or" ); |
553 | GRN_LOG(ctx, GRN_LOG_INFO, |
554 | "run 'sudo /sbin/sysctl vm.overcommit_memory=1' command." ); |
555 | } |
556 | fclose(file); |
557 | } |
558 | |
559 | grn_rc |
560 | grn_init(void) |
561 | { |
562 | grn_rc rc; |
563 | grn_ctx *ctx = &grn_gctx; |
564 | grn_init_from_env(); |
565 | grn_init_external_libraries(); |
566 | grn_alloc_info_init(); |
567 | grn_logger_init(); |
568 | grn_query_logger_init(); |
569 | CRITICAL_SECTION_INIT(grn_glock); |
570 | grn_gtick = 0; |
571 | ctx->next = ctx; |
572 | ctx->prev = ctx; |
573 | rc = grn_ctx_init_internal(ctx, 0); |
574 | if (rc) { |
575 | goto fail_ctx_init_internal; |
576 | } |
577 | ctx->encoding = grn_encoding_parse(GRN_DEFAULT_ENCODING); |
578 | rc = grn_timeval_now(ctx, &grn_starttime); |
579 | if (rc) { |
580 | goto fail_start_time; |
581 | } |
582 | #ifdef WIN32 |
583 | { |
584 | SYSTEM_INFO si; |
585 | GetSystemInfo(&si); |
586 | grn_pagesize = si.dwAllocationGranularity; |
587 | } |
588 | #else /* WIN32 */ |
589 | if ((grn_pagesize = sysconf(_SC_PAGESIZE)) == -1) { |
590 | SERR("_SC_PAGESIZE" ); |
591 | rc = ctx->rc; |
592 | goto fail_page_size; |
593 | } |
594 | #endif /* WIN32 */ |
595 | if (grn_pagesize & (grn_pagesize - 1)) { |
596 | GRN_LOG(ctx, GRN_LOG_CRIT, "pagesize=%x" , grn_pagesize); |
597 | } |
598 | // expand_stack(); |
599 | if ((rc = grn_com_init())) { |
600 | GRN_LOG(ctx, GRN_LOG_ALERT, "grn_com_init failed (%d)" , rc); |
601 | goto fail_com; |
602 | } |
603 | if ((rc = grn_ctx_impl_init(ctx))) { |
604 | GRN_LOG(ctx, GRN_LOG_ALERT, "grn_ctx_impl_init failed (%d)" , rc); |
605 | goto fail_ctx_impl; |
606 | } |
607 | if ((rc = grn_plugins_init())) { |
608 | GRN_LOG(ctx, GRN_LOG_ALERT, "grn_plugins_init failed (%d)" , rc); |
609 | goto fail_plugins; |
610 | } |
611 | if ((rc = grn_normalizer_init())) { |
612 | GRN_LOG(ctx, GRN_LOG_ALERT, "grn_normalizer_init failed (%d)" , rc); |
613 | goto fail_normalizer; |
614 | } |
615 | if ((rc = grn_tokenizers_init())) { |
616 | GRN_LOG(ctx, GRN_LOG_ALERT, "grn_tokenizers_init failed (%d)" , rc); |
617 | goto fail_tokenizer; |
618 | } |
619 | grn_cache_init(); |
620 | if (!grn_request_canceler_init()) { |
621 | rc = ctx->rc; |
622 | GRN_LOG(ctx, GRN_LOG_ALERT, |
623 | "failed to initialize request canceler (%d)" , rc); |
624 | goto fail_request_canceler; |
625 | } |
626 | if (!grn_request_timer_init()) { |
627 | rc = ctx->rc; |
628 | GRN_LOG(ctx, GRN_LOG_ALERT, |
629 | "failed to initialize request timer (%d)" , rc); |
630 | goto fail_request_timer; |
631 | } |
632 | GRN_LOG(ctx, GRN_LOG_NOTICE, "grn_init: <%s>" , grn_get_version()); |
633 | check_overcommit_memory(ctx); |
634 | return rc; |
635 | |
636 | fail_request_timer: |
637 | grn_request_canceler_fin(); |
638 | fail_request_canceler: |
639 | grn_cache_fin(); |
640 | fail_tokenizer: |
641 | grn_normalizer_fin(); |
642 | fail_normalizer: |
643 | grn_plugins_fin(); |
644 | fail_plugins: |
645 | grn_ctx_fin(ctx); |
646 | fail_ctx_impl: |
647 | grn_com_fin(); |
648 | fail_com: |
649 | #ifndef WIN32 |
650 | fail_page_size: |
651 | #endif /* WIN32 */ |
652 | fail_start_time: |
653 | fail_ctx_init_internal: |
654 | GRN_LOG(ctx, GRN_LOG_NOTICE, "grn_init: <%s>: failed" , grn_get_version()); |
655 | grn_query_logger_fin(ctx); |
656 | grn_logger_fin(ctx); |
657 | CRITICAL_SECTION_FIN(grn_glock); |
658 | grn_alloc_info_fin(); |
659 | grn_fin_external_libraries(); |
660 | return rc; |
661 | } |
662 | |
663 | grn_encoding |
664 | grn_get_default_encoding(void) |
665 | { |
666 | return grn_gctx.encoding; |
667 | } |
668 | |
669 | grn_rc |
670 | grn_set_default_encoding(grn_encoding encoding) |
671 | { |
672 | switch (encoding) { |
673 | case GRN_ENC_DEFAULT : |
674 | grn_gctx.encoding = grn_encoding_parse(GRN_DEFAULT_ENCODING); |
675 | return GRN_SUCCESS; |
676 | case GRN_ENC_NONE : |
677 | case GRN_ENC_EUC_JP : |
678 | case GRN_ENC_UTF8 : |
679 | case GRN_ENC_SJIS : |
680 | case GRN_ENC_LATIN1 : |
681 | case GRN_ENC_KOI8R : |
682 | grn_gctx.encoding = encoding; |
683 | return GRN_SUCCESS; |
684 | default : |
685 | return GRN_INVALID_ARGUMENT; |
686 | } |
687 | } |
688 | |
689 | grn_command_version |
690 | grn_get_default_command_version(void) |
691 | { |
692 | return grn_ctx_get_command_version(&grn_gctx); |
693 | } |
694 | |
695 | grn_rc |
696 | grn_set_default_command_version(grn_command_version version) |
697 | { |
698 | return grn_ctx_set_command_version(&grn_gctx, version); |
699 | } |
700 | |
701 | long long int |
702 | grn_get_default_match_escalation_threshold(void) |
703 | { |
704 | return grn_ctx_get_match_escalation_threshold(&grn_gctx); |
705 | } |
706 | |
707 | grn_rc |
708 | grn_set_default_match_escalation_threshold(long long int threshold) |
709 | { |
710 | return grn_ctx_set_match_escalation_threshold(&grn_gctx, threshold); |
711 | } |
712 | |
713 | int |
714 | grn_get_lock_timeout(void) |
715 | { |
716 | return grn_lock_timeout; |
717 | } |
718 | |
719 | grn_rc |
720 | grn_set_lock_timeout(int timeout) |
721 | { |
722 | grn_lock_timeout = timeout; |
723 | return GRN_SUCCESS; |
724 | } |
725 | |
726 | grn_rc |
727 | grn_fin(void) |
728 | { |
729 | grn_ctx *ctx, *ctx_; |
730 | if (grn_gctx.stat == GRN_CTX_FIN) { return GRN_INVALID_ARGUMENT; } |
731 | for (ctx = grn_gctx.next; ctx != &grn_gctx; ctx = ctx_) { |
732 | ctx_ = ctx->next; |
733 | if (ctx->stat != GRN_CTX_FIN) { grn_ctx_fin(ctx); } |
734 | if (ctx->flags & GRN_CTX_ALLOCATED) { |
735 | ctx->next->prev = ctx->prev; |
736 | ctx->prev->next = ctx->next; |
737 | GRN_GFREE(ctx); |
738 | } |
739 | } |
740 | grn_query_logger_fin(ctx); |
741 | grn_request_timer_fin(); |
742 | grn_request_canceler_fin(); |
743 | grn_cache_fin(); |
744 | grn_tokenizers_fin(); |
745 | grn_normalizer_fin(); |
746 | grn_plugins_fin(); |
747 | grn_ctx_fin(ctx); |
748 | grn_com_fin(); |
749 | GRN_LOG(ctx, GRN_LOG_NOTICE, "grn_fin (%d)" , grn_alloc_count()); |
750 | grn_logger_fin(ctx); |
751 | CRITICAL_SECTION_FIN(grn_glock); |
752 | grn_alloc_info_fin(); |
753 | grn_fin_external_libraries(); |
754 | return GRN_SUCCESS; |
755 | } |
756 | |
757 | grn_rc |
758 | grn_ctx_connect(grn_ctx *ctx, const char *host, int port, int flags) |
759 | { |
760 | GRN_API_ENTER; |
761 | if (!ctx->impl) { goto exit; } |
762 | { |
763 | grn_com *com = grn_com_copen(ctx, NULL, host, port); |
764 | if (com) { |
765 | ctx->impl->com = com; |
766 | } |
767 | } |
768 | exit : |
769 | GRN_API_RETURN(ctx->rc); |
770 | } |
771 | |
772 | grn_rc |
773 | grn_ctx_close(grn_ctx *ctx) |
774 | { |
775 | grn_rc rc = grn_ctx_fin(ctx); |
776 | CRITICAL_SECTION_ENTER(grn_glock); |
777 | ctx->next->prev = ctx->prev; |
778 | ctx->prev->next = ctx->next; |
779 | CRITICAL_SECTION_LEAVE(grn_glock); |
780 | GRN_GFREE(ctx); |
781 | return rc; |
782 | } |
783 | |
784 | grn_command_version |
785 | grn_ctx_get_command_version(grn_ctx *ctx) |
786 | { |
787 | if (ctx->impl) { |
788 | return ctx->impl->command.version; |
789 | } else { |
790 | return GRN_COMMAND_VERSION_STABLE; |
791 | } |
792 | } |
793 | |
794 | grn_rc |
795 | grn_ctx_set_command_version(grn_ctx *ctx, grn_command_version version) |
796 | { |
797 | switch (version) { |
798 | case GRN_COMMAND_VERSION_DEFAULT : |
799 | ctx->impl->command.version = GRN_COMMAND_VERSION_STABLE; |
800 | return GRN_SUCCESS; |
801 | default : |
802 | if (GRN_COMMAND_VERSION_MIN <= version && |
803 | version <= GRN_COMMAND_VERSION_MAX) { |
804 | ctx->impl->command.version = version; |
805 | return GRN_SUCCESS; |
806 | } else { |
807 | return GRN_UNSUPPORTED_COMMAND_VERSION; |
808 | } |
809 | } |
810 | } |
811 | |
812 | grn_content_type |
813 | grn_ctx_get_output_type(grn_ctx *ctx) |
814 | { |
815 | if (ctx->impl) { |
816 | return ctx->impl->output.type; |
817 | } else { |
818 | return GRN_CONTENT_NONE; |
819 | } |
820 | } |
821 | |
822 | grn_rc |
823 | grn_ctx_set_output_type(grn_ctx *ctx, grn_content_type type) |
824 | { |
825 | grn_rc rc = GRN_SUCCESS; |
826 | |
827 | if (ctx->impl) { |
828 | ctx->impl->output.type = type; |
829 | switch (ctx->impl->output.type) { |
830 | case GRN_CONTENT_NONE : |
831 | ctx->impl->output.mime_type = "application/octet-stream" ; |
832 | break; |
833 | case GRN_CONTENT_TSV : |
834 | ctx->impl->output.mime_type = "text/tab-separated-values" ; |
835 | break; |
836 | case GRN_CONTENT_JSON : |
837 | ctx->impl->output.mime_type = "application/json" ; |
838 | break; |
839 | case GRN_CONTENT_XML : |
840 | ctx->impl->output.mime_type = "text/xml" ; |
841 | break; |
842 | case GRN_CONTENT_MSGPACK : |
843 | ctx->impl->output.mime_type = "application/x-msgpack" ; |
844 | break; |
845 | case GRN_CONTENT_GROONGA_COMMAND_LIST : |
846 | ctx->impl->output.mime_type = "text/x-groonga-command-list" ; |
847 | break; |
848 | } |
849 | } else { |
850 | rc = GRN_INVALID_ARGUMENT; |
851 | } |
852 | |
853 | return rc; |
854 | } |
855 | |
856 | const char * |
857 | grn_ctx_get_mime_type(grn_ctx *ctx) |
858 | { |
859 | if (ctx->impl) { |
860 | return ctx->impl->output.mime_type; |
861 | } else { |
862 | return NULL; |
863 | } |
864 | } |
865 | |
866 | long long int |
867 | grn_ctx_get_match_escalation_threshold(grn_ctx *ctx) |
868 | { |
869 | if (ctx->impl) { |
870 | return ctx->impl->match_escalation_threshold; |
871 | } else { |
872 | return GRN_DEFAULT_MATCH_ESCALATION_THRESHOLD; |
873 | } |
874 | } |
875 | |
876 | grn_rc |
877 | grn_ctx_set_match_escalation_threshold(grn_ctx *ctx, long long int threshold) |
878 | { |
879 | ctx->impl->match_escalation_threshold = threshold; |
880 | return GRN_SUCCESS; |
881 | } |
882 | |
883 | grn_content_type |
884 | grn_get_ctype(grn_obj *var) |
885 | { |
886 | return grn_content_type_parse(NULL, var, GRN_CONTENT_JSON); |
887 | } |
888 | |
889 | grn_content_type |
890 | grn_content_type_parse(grn_ctx *ctx, |
891 | grn_obj *var, |
892 | grn_content_type default_value) |
893 | { |
894 | grn_content_type ct = default_value; |
895 | if (var->header.domain == GRN_DB_INT32) { |
896 | ct = GRN_INT32_VALUE(var); |
897 | } else if (GRN_TEXT_LEN(var)) { |
898 | switch (*(GRN_TEXT_VALUE(var))) { |
899 | case 't' : |
900 | case 'T' : |
901 | ct = GRN_CONTENT_TSV; |
902 | break; |
903 | case 'j' : |
904 | case 'J' : |
905 | ct = GRN_CONTENT_JSON; |
906 | break; |
907 | case 'x' : |
908 | case 'X' : |
909 | ct = GRN_CONTENT_XML; |
910 | break; |
911 | } |
912 | } |
913 | return ct; |
914 | } |
915 | |
916 | static void |
917 | get_content_mime_type(grn_ctx *ctx, const char *p, const char *pe) |
918 | { |
919 | ctx->impl->output.type = GRN_CONTENT_NONE; |
920 | ctx->impl->output.mime_type = "application/octet-stream" ; |
921 | |
922 | if (p + 2 <= pe) { |
923 | switch (*p) { |
924 | case 'c' : |
925 | if (p + 3 == pe && !memcmp(p, "css" , 3)) { |
926 | ctx->impl->output.type = GRN_CONTENT_NONE; |
927 | ctx->impl->output.mime_type = "text/css" ; |
928 | } |
929 | break; |
930 | case 'g' : |
931 | if (p + 3 == pe && !memcmp(p, "gif" , 3)) { |
932 | ctx->impl->output.type = GRN_CONTENT_NONE; |
933 | ctx->impl->output.mime_type = "image/gif" ; |
934 | } |
935 | break; |
936 | case 'h' : |
937 | if (p + 4 == pe && !memcmp(p, "html" , 4)) { |
938 | ctx->impl->output.type = GRN_CONTENT_NONE; |
939 | ctx->impl->output.mime_type = "text/html" ; |
940 | } |
941 | break; |
942 | case 'j' : |
943 | if (!memcmp(p, "js" , 2)) { |
944 | if (p + 2 == pe) { |
945 | ctx->impl->output.type = GRN_CONTENT_NONE; |
946 | ctx->impl->output.mime_type = "text/javascript" ; |
947 | } else if (p + 4 == pe && !memcmp(p + 2, "on" , 2)) { |
948 | ctx->impl->output.type = GRN_CONTENT_JSON; |
949 | ctx->impl->output.mime_type = "application/json" ; |
950 | } |
951 | } else if (p + 3 == pe && !memcmp(p, "jpg" , 3)) { |
952 | ctx->impl->output.type = GRN_CONTENT_NONE; |
953 | ctx->impl->output.mime_type = "image/jpeg" ; |
954 | } |
955 | break; |
956 | #ifdef GRN_WITH_MESSAGE_PACK |
957 | case 'm' : |
958 | if (p + 7 == pe && !memcmp(p, "msgpack" , 7)) { |
959 | ctx->impl->output.type = GRN_CONTENT_MSGPACK; |
960 | ctx->impl->output.mime_type = "application/x-msgpack" ; |
961 | } |
962 | break; |
963 | #endif |
964 | case 'p' : |
965 | if (p + 3 == pe && !memcmp(p, "png" , 3)) { |
966 | ctx->impl->output.type = GRN_CONTENT_NONE; |
967 | ctx->impl->output.mime_type = "image/png" ; |
968 | } |
969 | break; |
970 | case 't' : |
971 | if (p + 3 == pe && !memcmp(p, "txt" , 3)) { |
972 | ctx->impl->output.type = GRN_CONTENT_NONE; |
973 | ctx->impl->output.mime_type = "text/plain" ; |
974 | } else if (p + 3 == pe && !memcmp(p, "tsv" , 3)) { |
975 | ctx->impl->output.type = GRN_CONTENT_TSV; |
976 | ctx->impl->output.mime_type = "text/tab-separated-values" ; |
977 | } |
978 | break; |
979 | case 'x': |
980 | if (p + 3 == pe && !memcmp(p, "xml" , 3)) { |
981 | ctx->impl->output.type = GRN_CONTENT_XML; |
982 | ctx->impl->output.mime_type = "text/xml" ; |
983 | } |
984 | break; |
985 | } |
986 | } |
987 | } |
988 | |
989 | static void |
990 | grn_str_get_mime_type(grn_ctx *ctx, const char *p, const char *pe, |
991 | const char **key_end, const char **filename_end) |
992 | { |
993 | const char *pd = NULL; |
994 | for (; p < pe && *p != '?' && *p != '#'; p++) { |
995 | if (*p == '.') { pd = p; } |
996 | } |
997 | *filename_end = p; |
998 | if (pd && pd < p) { |
999 | get_content_mime_type(ctx, pd + 1, p); |
1000 | *key_end = pd; |
1001 | } else { |
1002 | *key_end = pe; |
1003 | } |
1004 | } |
1005 | |
1006 | static void |
1007 | get_command_version(grn_ctx *ctx, const char *p, const char *pe) |
1008 | { |
1009 | grn_command_version version; |
1010 | const char *rest; |
1011 | |
1012 | version = grn_atoui(p, pe, &rest); |
1013 | if (pe == rest) { |
1014 | grn_rc rc; |
1015 | rc = grn_ctx_set_command_version(ctx, version); |
1016 | if (rc == GRN_UNSUPPORTED_COMMAND_VERSION) { |
1017 | ERR(rc, |
1018 | "unsupported command version is specified: %d: " |
1019 | "stable command version: %d: " |
1020 | "available command versions: %d-%d" , |
1021 | version, |
1022 | GRN_COMMAND_VERSION_STABLE, |
1023 | GRN_COMMAND_VERSION_MIN, GRN_COMMAND_VERSION_MAX); |
1024 | } |
1025 | } |
1026 | } |
1027 | |
1028 | #define INDEX_HTML "index.html" |
1029 | #define OUTPUT_TYPE "output_type" |
1030 | #define COMMAND_VERSION "command_version" |
1031 | #define REQUEST_ID "request_id" |
1032 | #define REQUEST_TIMEOUT "request_timeout" |
1033 | #define OUTPUT_PRETTY "output_pretty" |
1034 | #define EXPR_MISSING "expr_missing" |
1035 | #define OUTPUT_TYPE_LEN (sizeof(OUTPUT_TYPE) - 1) |
1036 | #define COMMAND_VERSION_LEN (sizeof(COMMAND_VERSION) - 1) |
1037 | #define REQUEST_ID_LEN (sizeof(REQUEST_ID) - 1) |
1038 | #define REQUEST_TIMEOUT_LEN (sizeof(REQUEST_TIMEOUT) - 1) |
1039 | #define OUTPUT_PRETTY_LEN (sizeof(OUTPUT_PRETTY) - 1) |
1040 | |
1041 | #define HTTP_QUERY_PAIR_DELIMITER "=" |
1042 | #define HTTP_QUERY_PAIRS_DELIMITERS "&;" |
1043 | |
1044 | static inline int |
1045 | command_proc_p(grn_obj *expr) |
1046 | { |
1047 | return (expr->header.type == GRN_PROC && |
1048 | ((grn_proc *)expr)->type == GRN_PROC_COMMAND); |
1049 | } |
1050 | |
1051 | grn_obj * |
1052 | grn_ctx_qe_exec_uri(grn_ctx *ctx, const char *path, uint32_t path_len) |
1053 | { |
1054 | grn_obj buf, *expr, *val; |
1055 | grn_obj request_id; |
1056 | double request_timeout; |
1057 | const char *p = path, *e = path + path_len, *v, *key_end, *filename_end; |
1058 | |
1059 | request_timeout = grn_get_default_request_timeout(); |
1060 | |
1061 | GRN_TEXT_INIT(&buf, 0); |
1062 | GRN_TEXT_INIT(&request_id, 0); |
1063 | p = grn_text_urldec(ctx, &buf, p, e, '?'); |
1064 | if (!GRN_TEXT_LEN(&buf)) { GRN_TEXT_SETS(ctx, &buf, INDEX_HTML); } |
1065 | v = GRN_TEXT_VALUE(&buf); |
1066 | grn_str_get_mime_type(ctx, v, GRN_BULK_CURR(&buf), &key_end, &filename_end); |
1067 | if ((GRN_TEXT_LEN(&buf) >= 2 && v[0] == 'd' && v[1] == '/')) { |
1068 | const char *command_name = v + 2; |
1069 | int command_name_size = key_end - command_name; |
1070 | expr = grn_ctx_get(ctx, command_name, command_name_size); |
1071 | if (expr && command_proc_p(expr)) { |
1072 | while (p < e) { |
1073 | int l; |
1074 | GRN_BULK_REWIND(&buf); |
1075 | p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIR_DELIMITER); |
1076 | v = GRN_TEXT_VALUE(&buf); |
1077 | l = GRN_TEXT_LEN(&buf); |
1078 | if (l == OUTPUT_TYPE_LEN && !memcmp(v, OUTPUT_TYPE, OUTPUT_TYPE_LEN)) { |
1079 | GRN_BULK_REWIND(&buf); |
1080 | p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIRS_DELIMITERS); |
1081 | v = GRN_TEXT_VALUE(&buf); |
1082 | get_content_mime_type(ctx, v, GRN_BULK_CURR(&buf)); |
1083 | } else if (l == COMMAND_VERSION_LEN && |
1084 | !memcmp(v, COMMAND_VERSION, COMMAND_VERSION_LEN)) { |
1085 | GRN_BULK_REWIND(&buf); |
1086 | p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIRS_DELIMITERS); |
1087 | get_command_version(ctx, GRN_TEXT_VALUE(&buf), GRN_BULK_CURR(&buf)); |
1088 | if (ctx->rc) { goto exit; } |
1089 | } else if (l == REQUEST_ID_LEN && |
1090 | !memcmp(v, REQUEST_ID, REQUEST_ID_LEN)) { |
1091 | GRN_BULK_REWIND(&request_id); |
1092 | p = grn_text_cgidec(ctx, &request_id, p, e, |
1093 | HTTP_QUERY_PAIRS_DELIMITERS); |
1094 | } else if (l == REQUEST_TIMEOUT_LEN && |
1095 | !memcmp(v, REQUEST_TIMEOUT, REQUEST_TIMEOUT_LEN)) { |
1096 | GRN_BULK_REWIND(&buf); |
1097 | p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIRS_DELIMITERS); |
1098 | GRN_TEXT_PUTC(ctx, &buf, '\0'); |
1099 | request_timeout = strtod(GRN_TEXT_VALUE(&buf), NULL); |
1100 | } else if (l == OUTPUT_PRETTY_LEN && |
1101 | !memcmp(v, OUTPUT_PRETTY, OUTPUT_PRETTY_LEN)) { |
1102 | GRN_BULK_REWIND(&buf); |
1103 | p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIRS_DELIMITERS); |
1104 | if (GRN_TEXT_LEN(&buf) == strlen("yes" ) && |
1105 | !memcmp(GRN_TEXT_VALUE(&buf), "yes" , GRN_TEXT_LEN(&buf))) { |
1106 | ctx->impl->output.is_pretty = GRN_TRUE; |
1107 | } else { |
1108 | ctx->impl->output.is_pretty = GRN_FALSE; |
1109 | } |
1110 | } else { |
1111 | if (!(val = grn_expr_get_or_add_var(ctx, expr, v, l))) { |
1112 | val = &buf; |
1113 | } |
1114 | grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0); |
1115 | p = grn_text_cgidec(ctx, val, p, e, HTTP_QUERY_PAIRS_DELIMITERS); |
1116 | } |
1117 | } |
1118 | if (request_timeout > 0 && GRN_TEXT_LEN(&request_id) == 0) { |
1119 | grn_text_printf(ctx, &request_id, "%p" , ctx); |
1120 | } |
1121 | if (GRN_TEXT_LEN(&request_id) > 0) { |
1122 | GRN_TEXT_SET(ctx, &ctx->impl->current_request_id, |
1123 | GRN_TEXT_VALUE(&request_id), |
1124 | GRN_TEXT_LEN(&request_id)); |
1125 | grn_request_canceler_register(ctx, |
1126 | GRN_TEXT_VALUE(&request_id), |
1127 | GRN_TEXT_LEN(&request_id)); |
1128 | if (request_timeout > 0.0) { |
1129 | ctx->impl->current_request_timer_id = |
1130 | grn_request_timer_register(GRN_TEXT_VALUE(&request_id), |
1131 | GRN_TEXT_LEN(&request_id), |
1132 | request_timeout); |
1133 | } |
1134 | } |
1135 | ctx->impl->curr_expr = expr; |
1136 | grn_expr_exec(ctx, expr, 0); |
1137 | } else { |
1138 | ERR(GRN_INVALID_ARGUMENT, "invalid command name: %.*s" , |
1139 | command_name_size, command_name); |
1140 | } |
1141 | } else if ((expr = grn_ctx_get(ctx, GRN_EXPR_MISSING_NAME, |
1142 | strlen(GRN_EXPR_MISSING_NAME)))) { |
1143 | if ((val = grn_expr_get_var_by_offset(ctx, expr, 0))) { |
1144 | grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0); |
1145 | GRN_TEXT_SET(ctx, val, v, filename_end - v); |
1146 | } |
1147 | ctx->impl->curr_expr = expr; |
1148 | grn_expr_exec(ctx, expr, 0); |
1149 | } |
1150 | exit : |
1151 | GRN_OBJ_FIN(ctx, &request_id); |
1152 | GRN_OBJ_FIN(ctx, &buf); |
1153 | |
1154 | return expr; |
1155 | } |
1156 | |
1157 | grn_obj * |
1158 | grn_ctx_qe_exec(grn_ctx *ctx, const char *str, uint32_t str_len) |
1159 | { |
1160 | char tok_type; |
1161 | int offset = 0; |
1162 | grn_obj buf, *expr = NULL, *val = NULL; |
1163 | grn_obj request_id; |
1164 | double request_timeout; |
1165 | const char *p = str, *e = str + str_len, *v; |
1166 | |
1167 | request_timeout = grn_get_default_request_timeout(); |
1168 | |
1169 | GRN_TEXT_INIT(&buf, 0); |
1170 | GRN_TEXT_INIT(&request_id, 0); |
1171 | p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type); |
1172 | expr = grn_ctx_get(ctx, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf)); |
1173 | while (p < e) { |
1174 | GRN_BULK_REWIND(&buf); |
1175 | p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type); |
1176 | v = GRN_TEXT_VALUE(&buf); |
1177 | switch (tok_type) { |
1178 | case GRN_TOK_VOID : |
1179 | p = e; |
1180 | break; |
1181 | case GRN_TOK_SYMBOL : |
1182 | if (GRN_TEXT_LEN(&buf) > 2 && v[0] == '-' && v[1] == '-') { |
1183 | int l = GRN_TEXT_LEN(&buf) - 2; |
1184 | v += 2; |
1185 | if (l == OUTPUT_TYPE_LEN && !memcmp(v, OUTPUT_TYPE, OUTPUT_TYPE_LEN)) { |
1186 | GRN_BULK_REWIND(&buf); |
1187 | p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type); |
1188 | v = GRN_TEXT_VALUE(&buf); |
1189 | get_content_mime_type(ctx, v, GRN_BULK_CURR(&buf)); |
1190 | } else if (l == COMMAND_VERSION_LEN && |
1191 | !memcmp(v, COMMAND_VERSION, COMMAND_VERSION_LEN)) { |
1192 | GRN_BULK_REWIND(&buf); |
1193 | p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type); |
1194 | get_command_version(ctx, GRN_TEXT_VALUE(&buf), GRN_BULK_CURR(&buf)); |
1195 | if (ctx->rc) { goto exit; } |
1196 | } else if (l == REQUEST_ID_LEN && |
1197 | !memcmp(v, REQUEST_ID, REQUEST_ID_LEN)) { |
1198 | GRN_BULK_REWIND(&request_id); |
1199 | p = grn_text_unesc_tok(ctx, &request_id, p, e, &tok_type); |
1200 | } else if (l == REQUEST_TIMEOUT_LEN && |
1201 | !memcmp(v, REQUEST_TIMEOUT, REQUEST_TIMEOUT_LEN)) { |
1202 | GRN_BULK_REWIND(&buf); |
1203 | p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type); |
1204 | GRN_TEXT_PUTC(ctx, &buf, '\0'); |
1205 | request_timeout = strtod(GRN_TEXT_VALUE(&buf), NULL); |
1206 | } else if (l == OUTPUT_PRETTY_LEN && |
1207 | !memcmp(v, OUTPUT_PRETTY, OUTPUT_PRETTY_LEN)) { |
1208 | GRN_BULK_REWIND(&buf); |
1209 | p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type); |
1210 | if (GRN_TEXT_LEN(&buf) == strlen("yes" ) && |
1211 | !memcmp(GRN_TEXT_VALUE(&buf), "yes" , GRN_TEXT_LEN(&buf))) { |
1212 | ctx->impl->output.is_pretty = GRN_TRUE; |
1213 | } else { |
1214 | ctx->impl->output.is_pretty = GRN_FALSE; |
1215 | } |
1216 | } else if (expr && (val = grn_expr_get_or_add_var(ctx, expr, v, l))) { |
1217 | grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0); |
1218 | p = grn_text_unesc_tok(ctx, val, p, e, &tok_type); |
1219 | } else { |
1220 | p = e; |
1221 | } |
1222 | break; |
1223 | } |
1224 | // fallthru |
1225 | case GRN_TOK_STRING : |
1226 | case GRN_TOK_QUOTE : |
1227 | if (expr && (val = grn_expr_get_var_by_offset(ctx, expr, offset++))) { |
1228 | grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0); |
1229 | GRN_TEXT_PUT(ctx, val, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf)); |
1230 | } else { |
1231 | p = e; |
1232 | } |
1233 | break; |
1234 | } |
1235 | } |
1236 | if (request_timeout > 0 && GRN_TEXT_LEN(&request_id) == 0) { |
1237 | grn_text_printf(ctx, &request_id, "%p" , ctx); |
1238 | } |
1239 | if (GRN_TEXT_LEN(&request_id) > 0) { |
1240 | GRN_TEXT_SET(ctx, &ctx->impl->current_request_id, |
1241 | GRN_TEXT_VALUE(&request_id), |
1242 | GRN_TEXT_LEN(&request_id)); |
1243 | grn_request_canceler_register(ctx, |
1244 | GRN_TEXT_VALUE(&request_id), |
1245 | GRN_TEXT_LEN(&request_id)); |
1246 | if (request_timeout > 0.0) { |
1247 | ctx->impl->current_request_timer_id = |
1248 | grn_request_timer_register(GRN_TEXT_VALUE(&request_id), |
1249 | GRN_TEXT_LEN(&request_id), |
1250 | request_timeout); |
1251 | } |
1252 | } |
1253 | ctx->impl->curr_expr = expr; |
1254 | if (expr && command_proc_p(expr)) { |
1255 | grn_expr_exec(ctx, expr, 0); |
1256 | } else { |
1257 | GRN_BULK_REWIND(&buf); |
1258 | grn_text_unesc_tok(ctx, &buf, str, str + str_len, &tok_type); |
1259 | if (GRN_TEXT_LEN(&buf)) { |
1260 | ERR(GRN_INVALID_ARGUMENT, "invalid command name: %.*s" , |
1261 | (int)GRN_TEXT_LEN(&buf), GRN_TEXT_VALUE(&buf)); |
1262 | } |
1263 | } |
1264 | exit : |
1265 | GRN_OBJ_FIN(ctx, &request_id); |
1266 | GRN_OBJ_FIN(ctx, &buf); |
1267 | |
1268 | return expr; |
1269 | } |
1270 | |
1271 | grn_rc |
1272 | grn_ctx_sendv(grn_ctx *ctx, int argc, char **argv, int flags) |
1273 | { |
1274 | grn_obj buf; |
1275 | GRN_API_ENTER; |
1276 | GRN_TEXT_INIT(&buf, 0); |
1277 | while (argc--) { |
1278 | // todo : encode into json like syntax |
1279 | GRN_TEXT_PUTS(ctx, &buf, *argv); |
1280 | argv++; |
1281 | if (argc) { GRN_TEXT_PUTC(ctx, &buf, ' '); } |
1282 | } |
1283 | grn_ctx_send(ctx, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf), flags); |
1284 | GRN_OBJ_FIN(ctx, &buf); |
1285 | GRN_API_RETURN(ctx->rc); |
1286 | } |
1287 | |
1288 | static int |
1289 | comment_command_p(const char *command, unsigned int length) |
1290 | { |
1291 | const char *p, *e; |
1292 | |
1293 | e = command + length; |
1294 | for (p = command; p < e; p++) { |
1295 | switch (*p) { |
1296 | case '#' : |
1297 | return GRN_TRUE; |
1298 | case ' ' : |
1299 | case '\t' : |
1300 | break; |
1301 | default : |
1302 | return GRN_FALSE; |
1303 | } |
1304 | } |
1305 | return GRN_FALSE; |
1306 | } |
1307 | |
1308 | unsigned int |
1309 | grn_ctx_send(grn_ctx *ctx, const char *str, unsigned int str_len, int flags) |
1310 | { |
1311 | if (!ctx) { return 0; } |
1312 | GRN_API_ENTER; |
1313 | if (ctx->impl) { |
1314 | if ((flags & GRN_CTX_MORE)) { flags |= GRN_CTX_QUIET; } |
1315 | if (ctx->stat == GRN_CTX_QUIT) { flags |= GRN_CTX_QUIT; } |
1316 | |
1317 | ctx->impl->command.flags = flags; |
1318 | if (ctx->impl->com) { |
1319 | grn_rc rc; |
1320 | grn_com_header ; |
1321 | grn_timeval_now(ctx, &ctx->impl->tv); |
1322 | sheader.proto = GRN_COM_PROTO_GQTP; |
1323 | sheader.qtype = 0; |
1324 | sheader.keylen = 0; |
1325 | sheader.level = 0; |
1326 | sheader.flags = flags; |
1327 | sheader.status = 0; |
1328 | sheader.opaque = 0; |
1329 | sheader.cas = 0; |
1330 | if ((rc = grn_com_send(ctx, ctx->impl->com, &sheader, (char *)str, str_len, 0))) { |
1331 | ERR(rc, "grn_com_send failed" ); |
1332 | } |
1333 | goto exit; |
1334 | } else { |
1335 | grn_command_version command_version; |
1336 | grn_obj *expr = NULL; |
1337 | |
1338 | command_version = grn_ctx_get_command_version(ctx); |
1339 | if (ctx->impl->command.keep.command) { |
1340 | grn_obj *val; |
1341 | expr = ctx->impl->command.keep.command; |
1342 | ctx->impl->command.keep.command = NULL; |
1343 | grn_ctx_set_command_version(ctx, ctx->impl->command.keep.version); |
1344 | if ((val = grn_expr_get_var_by_offset(ctx, expr, 0))) { |
1345 | grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0); |
1346 | GRN_TEXT_PUT(ctx, val, str, str_len); |
1347 | } |
1348 | grn_expr_exec(ctx, expr, 0); |
1349 | } else { |
1350 | if (comment_command_p(str, str_len)) { goto output; }; |
1351 | GRN_BULK_REWIND(ctx->impl->output.buf); |
1352 | ctx->impl->output.type = GRN_CONTENT_JSON; |
1353 | ctx->impl->output.mime_type = "application/json" ; |
1354 | ctx->impl->output.is_pretty = GRN_FALSE; |
1355 | grn_timeval_now(ctx, &ctx->impl->tv); |
1356 | GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_COMMAND, |
1357 | ">" , "%.*s" , str_len, str); |
1358 | if (str_len && *str == '/') { |
1359 | expr = grn_ctx_qe_exec_uri(ctx, str + 1, str_len - 1); |
1360 | } else { |
1361 | expr = grn_ctx_qe_exec(ctx, str, str_len); |
1362 | } |
1363 | } |
1364 | if (ctx->stat == GRN_CTX_QUITTING) { ctx->stat = GRN_CTX_QUIT; } |
1365 | if (ctx->impl->command.keep.command) { |
1366 | ERRCLR(ctx); |
1367 | } else { |
1368 | if (ctx->impl->current_request_timer_id) { |
1369 | void *timer_id = ctx->impl->current_request_timer_id; |
1370 | ctx->impl->current_request_timer_id = NULL; |
1371 | grn_request_timer_unregister(timer_id); |
1372 | } |
1373 | if (GRN_TEXT_LEN(&ctx->impl->current_request_id) > 0) { |
1374 | grn_obj *request_id = &ctx->impl->current_request_id; |
1375 | grn_request_canceler_unregister(ctx, |
1376 | GRN_TEXT_VALUE(request_id), |
1377 | GRN_TEXT_LEN(request_id)); |
1378 | GRN_BULK_REWIND(&ctx->impl->current_request_id); |
1379 | } |
1380 | GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_RESULT_CODE, |
1381 | "<" , "rc=%d" , ctx->rc); |
1382 | } |
1383 | output : |
1384 | if (!(ctx->impl->command.flags & GRN_CTX_QUIET) && |
1385 | ctx->impl->output.func) { |
1386 | ctx->impl->output.func(ctx, GRN_CTX_TAIL, ctx->impl->output.data.ptr); |
1387 | } |
1388 | if (expr) { grn_expr_clear_vars(ctx, expr); } |
1389 | grn_ctx_set_command_version(ctx, command_version); |
1390 | goto exit; |
1391 | } |
1392 | } |
1393 | ERR(GRN_INVALID_ARGUMENT, "invalid ctx assigned" ); |
1394 | exit : |
1395 | GRN_API_RETURN(0); |
1396 | } |
1397 | |
1398 | unsigned int |
1399 | grn_ctx_recv(grn_ctx *ctx, char **str, unsigned int *str_len, int *flags) |
1400 | { |
1401 | if (!ctx) { return GRN_INVALID_ARGUMENT; } |
1402 | |
1403 | *flags = 0; |
1404 | |
1405 | if (ctx->stat == GRN_CTX_QUIT) { |
1406 | grn_bool have_buffer = GRN_FALSE; |
1407 | |
1408 | if (ctx->impl && |
1409 | !ctx->impl->com && |
1410 | GRN_TEXT_LEN(ctx->impl->output.buf) > 0) { |
1411 | have_buffer = GRN_TRUE; |
1412 | } |
1413 | |
1414 | *flags |= GRN_CTX_QUIT; |
1415 | if (!have_buffer) { |
1416 | *str = NULL; |
1417 | *str_len = 0; |
1418 | return 0; |
1419 | } |
1420 | } |
1421 | |
1422 | GRN_API_ENTER; |
1423 | if (ctx->impl) { |
1424 | if (ctx->impl->com) { |
1425 | grn_com_header ; |
1426 | if (grn_com_recv(ctx, ctx->impl->com, &header, ctx->impl->output.buf)) { |
1427 | *str = NULL; |
1428 | *str_len = 0; |
1429 | *flags = 0; |
1430 | } else { |
1431 | *str = GRN_BULK_HEAD(ctx->impl->output.buf); |
1432 | *str_len = GRN_BULK_VSIZE(ctx->impl->output.buf); |
1433 | if (header.flags & GRN_CTX_QUIT) { |
1434 | ctx->stat = GRN_CTX_QUIT; |
1435 | *flags |= GRN_CTX_QUIT; |
1436 | } else { |
1437 | if (!(header.flags & GRN_CTX_TAIL)) { |
1438 | *flags |= GRN_CTX_MORE; |
1439 | } |
1440 | } |
1441 | ctx->impl->output.type = header.qtype; |
1442 | ctx->rc = (int16_t)ntohs(header.status); |
1443 | ctx->errbuf[0] = '\0'; |
1444 | ctx->errline = 0; |
1445 | ctx->errfile = NULL; |
1446 | ctx->errfunc = NULL; |
1447 | } |
1448 | goto exit; |
1449 | } else { |
1450 | grn_obj *buf = ctx->impl->output.buf; |
1451 | unsigned int head = 0, tail = GRN_BULK_VSIZE(buf); |
1452 | *str = GRN_BULK_HEAD(buf) + head; |
1453 | *str_len = tail - head; |
1454 | GRN_BULK_REWIND(ctx->impl->output.buf); |
1455 | goto exit; |
1456 | } |
1457 | } |
1458 | ERR(GRN_INVALID_ARGUMENT, "invalid ctx assigned" ); |
1459 | exit : |
1460 | GRN_API_RETURN(0); |
1461 | } |
1462 | |
1463 | void |
1464 | grn_ctx_stream_out_func(grn_ctx *ctx, int flags, void *stream) |
1465 | { |
1466 | if (ctx && ctx->impl) { |
1467 | grn_obj *buf = ctx->impl->output.buf; |
1468 | uint32_t size = GRN_BULK_VSIZE(buf); |
1469 | if (size) { |
1470 | if (fwrite(GRN_BULK_HEAD(buf), 1, size, (FILE *)stream)) { |
1471 | fputc('\n', (FILE *)stream); |
1472 | fflush((FILE *)stream); |
1473 | } |
1474 | GRN_BULK_REWIND(buf); |
1475 | } |
1476 | } |
1477 | } |
1478 | |
1479 | void |
1480 | grn_ctx_recv_handler_set(grn_ctx *ctx, void (*func)(grn_ctx *, int, void *), void *func_arg) |
1481 | { |
1482 | if (ctx && ctx->impl) { |
1483 | ctx->impl->output.func = func; |
1484 | ctx->impl->output.data.ptr = func_arg; |
1485 | } |
1486 | } |
1487 | |
1488 | grn_rc |
1489 | grn_ctx_info_get(grn_ctx *ctx, grn_ctx_info *info) |
1490 | { |
1491 | if (!ctx || !ctx->impl) { return GRN_INVALID_ARGUMENT; } |
1492 | if (ctx->impl->com) { |
1493 | info->fd = ctx->impl->com->fd; |
1494 | info->com_status = ctx->impl->com_status; |
1495 | info->outbuf = ctx->impl->output.buf; |
1496 | info->stat = ctx->stat; |
1497 | } else { |
1498 | info->fd = -1; |
1499 | info->com_status = 0; |
1500 | info->outbuf = ctx->impl->output.buf; |
1501 | info->stat = ctx->stat; |
1502 | } |
1503 | return GRN_SUCCESS; |
1504 | } |
1505 | |
1506 | #define DB_P(s) ((s) && (s)->header.type == GRN_DB) |
1507 | |
1508 | grn_rc |
1509 | grn_ctx_use(grn_ctx *ctx, grn_obj *db) |
1510 | { |
1511 | GRN_API_ENTER; |
1512 | if (db && !DB_P(db)) { |
1513 | ctx->rc = GRN_INVALID_ARGUMENT; |
1514 | } else { |
1515 | if (!ctx->rc) { |
1516 | ctx->impl->db = db; |
1517 | if (db) { |
1518 | grn_obj buf; |
1519 | GRN_TEXT_INIT(&buf, 0); |
1520 | grn_obj_get_info(ctx, db, GRN_INFO_ENCODING, &buf); |
1521 | ctx->encoding = *(grn_encoding *)GRN_BULK_HEAD(&buf); |
1522 | grn_obj_close(ctx, &buf); |
1523 | } |
1524 | } |
1525 | } |
1526 | GRN_API_RETURN(ctx->rc); |
1527 | } |
1528 | |
1529 | /* don't handle error inside logger functions */ |
1530 | |
1531 | void |
1532 | grn_ctx_log(grn_ctx *ctx, const char *fmt, ...) |
1533 | { |
1534 | va_list ap; |
1535 | va_start(ap, fmt); |
1536 | grn_ctx_logv(ctx, fmt, ap); |
1537 | va_end(ap); |
1538 | } |
1539 | |
1540 | void |
1541 | grn_ctx_logv(grn_ctx *ctx, const char *fmt, va_list ap) |
1542 | { |
1543 | char buffer[GRN_CTX_MSGSIZE]; |
1544 | grn_vsnprintf(buffer, GRN_CTX_MSGSIZE, fmt, ap); |
1545 | grn_strcpy(ctx->errbuf, GRN_CTX_MSGSIZE, buffer); |
1546 | } |
1547 | |
1548 | void |
1549 | grn_assert(grn_ctx *ctx, int cond, const char* file, int line, const char* func) |
1550 | { |
1551 | if (!cond) { |
1552 | GRN_LOG(ctx, GRN_LOG_WARNING, "ASSERT fail on %s %s:%d" , func, file, line); |
1553 | } |
1554 | } |
1555 | |
1556 | const char * |
1557 | grn_get_version(void) |
1558 | { |
1559 | return GRN_VERSION; |
1560 | } |
1561 | |
1562 | const char * |
1563 | grn_get_package(void) |
1564 | { |
1565 | return PACKAGE; |
1566 | } |
1567 | |
1568 | const char * |
1569 | grn_get_package_label(void) |
1570 | { |
1571 | return PACKAGE_LABEL; |
1572 | } |
1573 | |
1574 | #if defined(HAVE_SIGNAL_H) && !defined(WIN32) |
1575 | static int segv_received = 0; |
1576 | static void |
1577 | segv_handler(int signal_number, siginfo_t *info, void *context) |
1578 | { |
1579 | grn_ctx *ctx = &grn_gctx; |
1580 | |
1581 | if (segv_received) { |
1582 | GRN_LOG(ctx, GRN_LOG_CRIT, "SEGV received in SEGV handler." ); |
1583 | exit(EXIT_FAILURE); |
1584 | } |
1585 | segv_received = 1; |
1586 | |
1587 | GRN_LOG(ctx, GRN_LOG_CRIT, "-- CRASHED!!! --" ); |
1588 | #ifdef HAVE_BACKTRACE |
1589 | # define N_TRACE_LEVEL 1024 |
1590 | { |
1591 | static void *trace[N_TRACE_LEVEL]; |
1592 | int n = backtrace(trace, N_TRACE_LEVEL); |
1593 | char **symbols = backtrace_symbols(trace, n); |
1594 | int i; |
1595 | |
1596 | if (symbols) { |
1597 | for (i = 0; i < n; i++) { |
1598 | GRN_LOG(ctx, GRN_LOG_CRIT, "%s" , symbols[i]); |
1599 | } |
1600 | free(symbols); |
1601 | } |
1602 | } |
1603 | #else /* HAVE_BACKTRACE */ |
1604 | GRN_LOG(ctx, GRN_LOG_CRIT, "backtrace() isn't available." ); |
1605 | #endif /* HAVE_BACKTRACE */ |
1606 | GRN_LOG(ctx, GRN_LOG_CRIT, "----------------" ); |
1607 | abort(); |
1608 | } |
1609 | #endif /* defined(HAVE_SIGNAL_H) && !defined(WIN32) */ |
1610 | |
1611 | grn_rc |
1612 | grn_set_segv_handler(void) |
1613 | { |
1614 | grn_rc rc = GRN_SUCCESS; |
1615 | #if defined(HAVE_SIGNAL_H) && !defined(WIN32) |
1616 | grn_ctx *ctx = &grn_gctx; |
1617 | struct sigaction action; |
1618 | |
1619 | sigemptyset(&action.sa_mask); |
1620 | action.sa_sigaction = segv_handler; |
1621 | action.sa_flags = SA_SIGINFO | SA_ONSTACK; |
1622 | |
1623 | if (sigaction(SIGSEGV, &action, NULL)) { |
1624 | SERR("failed to set SIGSEGV action" ); |
1625 | rc = ctx->rc; |
1626 | }; |
1627 | #endif |
1628 | return rc; |
1629 | } |
1630 | |
1631 | #if defined(HAVE_SIGNAL_H) && !defined(WIN32) |
1632 | static struct sigaction old_int_handler; |
1633 | static void |
1634 | int_handler(int signal_number, siginfo_t *info, void *context) |
1635 | { |
1636 | grn_gctx.stat = GRN_CTX_QUIT; |
1637 | sigaction(signal_number, &old_int_handler, NULL); |
1638 | } |
1639 | |
1640 | static struct sigaction old_term_handler; |
1641 | static void |
1642 | term_handler(int signal_number, siginfo_t *info, void *context) |
1643 | { |
1644 | grn_gctx.stat = GRN_CTX_QUIT; |
1645 | sigaction(signal_number, &old_term_handler, NULL); |
1646 | } |
1647 | #endif /* defined(HAVE_SIGNAL_H) && !defined(WIN32) */ |
1648 | |
1649 | grn_rc |
1650 | grn_set_int_handler(void) |
1651 | { |
1652 | grn_rc rc = GRN_SUCCESS; |
1653 | #if defined(HAVE_SIGNAL_H) && !defined(WIN32) |
1654 | grn_ctx *ctx = &grn_gctx; |
1655 | struct sigaction action; |
1656 | |
1657 | sigemptyset(&action.sa_mask); |
1658 | action.sa_sigaction = int_handler; |
1659 | action.sa_flags = SA_SIGINFO; |
1660 | |
1661 | if (sigaction(SIGINT, &action, &old_int_handler)) { |
1662 | SERR("failed to set SIGINT action" ); |
1663 | rc = ctx->rc; |
1664 | } |
1665 | #endif |
1666 | return rc; |
1667 | } |
1668 | |
1669 | grn_rc |
1670 | grn_set_term_handler(void) |
1671 | { |
1672 | grn_rc rc = GRN_SUCCESS; |
1673 | #if defined(HAVE_SIGNAL_H) && !defined(WIN32) |
1674 | grn_ctx *ctx = &grn_gctx; |
1675 | struct sigaction action; |
1676 | |
1677 | sigemptyset(&action.sa_mask); |
1678 | action.sa_sigaction = term_handler; |
1679 | action.sa_flags = SA_SIGINFO; |
1680 | |
1681 | if (sigaction(SIGTERM, &action, &old_term_handler)) { |
1682 | SERR("failed to set SIGTERM action" ); |
1683 | rc = ctx->rc; |
1684 | } |
1685 | #endif |
1686 | return rc; |
1687 | } |
1688 | |
1689 | void |
1690 | grn_ctx_output_flush(grn_ctx *ctx, int flags) |
1691 | { |
1692 | if (flags & GRN_CTX_QUIET) { |
1693 | return; |
1694 | } |
1695 | if (!ctx->impl->output.func) { |
1696 | return; |
1697 | } |
1698 | ctx->impl->output.func(ctx, 0, ctx->impl->output.data.ptr); |
1699 | } |
1700 | |
1701 | void |
1702 | grn_ctx_output_array_open(grn_ctx *ctx, const char *name, int nelements) |
1703 | { |
1704 | grn_output_array_open(ctx, |
1705 | ctx->impl->output.buf, |
1706 | ctx->impl->output.type, |
1707 | name, nelements); |
1708 | } |
1709 | |
1710 | void |
1711 | grn_ctx_output_array_close(grn_ctx *ctx) |
1712 | { |
1713 | grn_output_array_close(ctx, |
1714 | ctx->impl->output.buf, |
1715 | ctx->impl->output.type); |
1716 | } |
1717 | |
1718 | void |
1719 | grn_ctx_output_map_open(grn_ctx *ctx, const char *name, int nelements) |
1720 | { |
1721 | grn_output_map_open(ctx, |
1722 | ctx->impl->output.buf, |
1723 | ctx->impl->output.type, |
1724 | name, nelements); |
1725 | } |
1726 | |
1727 | void |
1728 | grn_ctx_output_map_close(grn_ctx *ctx) |
1729 | { |
1730 | grn_output_map_close(ctx, |
1731 | ctx->impl->output.buf, |
1732 | ctx->impl->output.type); |
1733 | } |
1734 | |
1735 | void |
1736 | grn_ctx_output_null(grn_ctx *ctx) |
1737 | { |
1738 | grn_output_null(ctx, |
1739 | ctx->impl->output.buf, |
1740 | ctx->impl->output.type); |
1741 | } |
1742 | |
1743 | void |
1744 | grn_ctx_output_int32(grn_ctx *ctx, int value) |
1745 | { |
1746 | grn_output_int32(ctx, |
1747 | ctx->impl->output.buf, |
1748 | ctx->impl->output.type, |
1749 | value); |
1750 | } |
1751 | |
1752 | void |
1753 | grn_ctx_output_int64(grn_ctx *ctx, int64_t value) |
1754 | { |
1755 | grn_output_int64(ctx, |
1756 | ctx->impl->output.buf, |
1757 | ctx->impl->output.type, |
1758 | value); |
1759 | } |
1760 | |
1761 | void |
1762 | grn_ctx_output_uint64(grn_ctx *ctx, uint64_t value) |
1763 | { |
1764 | grn_output_uint64(ctx, |
1765 | ctx->impl->output.buf, |
1766 | ctx->impl->output.type, |
1767 | value); |
1768 | } |
1769 | |
1770 | void |
1771 | grn_ctx_output_float(grn_ctx *ctx, double value) |
1772 | { |
1773 | grn_output_float(ctx, |
1774 | ctx->impl->output.buf, |
1775 | ctx->impl->output.type, |
1776 | value); |
1777 | } |
1778 | |
1779 | void |
1780 | grn_ctx_output_cstr(grn_ctx *ctx, const char *value) |
1781 | { |
1782 | grn_output_cstr(ctx, |
1783 | ctx->impl->output.buf, |
1784 | ctx->impl->output.type, |
1785 | value); |
1786 | } |
1787 | |
1788 | void |
1789 | grn_ctx_output_str(grn_ctx *ctx, const char *value, unsigned int value_len) |
1790 | { |
1791 | grn_output_str(ctx, |
1792 | ctx->impl->output.buf, |
1793 | ctx->impl->output.type, |
1794 | value, value_len); |
1795 | } |
1796 | |
1797 | void |
1798 | grn_ctx_output_bool(grn_ctx *ctx, grn_bool value) |
1799 | { |
1800 | grn_output_bool(ctx, |
1801 | ctx->impl->output.buf, |
1802 | ctx->impl->output.type, |
1803 | value); |
1804 | } |
1805 | |
1806 | void |
1807 | grn_ctx_output_obj(grn_ctx *ctx, grn_obj *value, grn_obj_format *format) |
1808 | { |
1809 | grn_output_obj(ctx, |
1810 | ctx->impl->output.buf, |
1811 | ctx->impl->output.type, |
1812 | value, format); |
1813 | } |
1814 | |
1815 | void |
1816 | grn_ctx_output_result_set_open(grn_ctx *ctx, |
1817 | grn_obj *result_set, |
1818 | grn_obj_format *format, |
1819 | uint32_t n_additional_elements) |
1820 | { |
1821 | grn_output_result_set_open(ctx, |
1822 | ctx->impl->output.buf, |
1823 | ctx->impl->output.type, |
1824 | result_set, |
1825 | format, |
1826 | n_additional_elements); |
1827 | } |
1828 | |
1829 | void |
1830 | grn_ctx_output_result_set_close(grn_ctx *ctx, |
1831 | grn_obj *result_set, |
1832 | grn_obj_format *format) |
1833 | { |
1834 | grn_output_result_set_close(ctx, |
1835 | ctx->impl->output.buf, |
1836 | ctx->impl->output.type, |
1837 | result_set, |
1838 | format); |
1839 | } |
1840 | |
1841 | void |
1842 | grn_ctx_output_result_set(grn_ctx *ctx, |
1843 | grn_obj *result_set, |
1844 | grn_obj_format *format) |
1845 | { |
1846 | grn_output_result_set(ctx, |
1847 | ctx->impl->output.buf, |
1848 | ctx->impl->output.type, |
1849 | result_set, |
1850 | format); |
1851 | } |
1852 | |
1853 | void |
1854 | grn_ctx_output_table_columns(grn_ctx *ctx, grn_obj *table, |
1855 | grn_obj_format *format) |
1856 | { |
1857 | grn_output_table_columns(ctx, |
1858 | ctx->impl->output.buf, |
1859 | ctx->impl->output.type, |
1860 | table, |
1861 | format); |
1862 | } |
1863 | |
1864 | void |
1865 | grn_ctx_output_table_records(grn_ctx *ctx, grn_obj *table, |
1866 | grn_obj_format *format) |
1867 | { |
1868 | grn_output_table_records(ctx, |
1869 | ctx->impl->output.buf, |
1870 | ctx->impl->output.type, |
1871 | table, |
1872 | format); |
1873 | } |
1874 | |