Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ctx.c
Go to the documentation of this file.
1 /* -*- c-basic-offset: 2 -*- */
2 /*
3  Copyright(C) 2009-2013 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 "groonga_in.h"
20 #include <string.h>
21 #include "token.h"
22 #include "ctx_impl.h"
23 #include "pat.h"
24 #include "plugin_in.h"
25 #include "snip.h"
26 #include "output.h"
27 #include "normalizer_in.h"
28 #include "ctx_impl_mrb.h"
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include <time.h>
32 #ifdef HAVE_NETINET_IN_H
33 #include <netinet/in.h>
34 #endif /* HAVE_NETINET_IN_H */
35 
36 #define GRN_CTX_INITIALIZER(enc) \
37  { GRN_SUCCESS, 0, enc, 0, GRN_LOG_NOTICE,\
38  GRN_CTX_FIN, 0, 0, 0, 0, {0}, NULL, NULL, NULL, NULL, NULL }
39 
40 #define GRN_CTX_CLOSED(ctx) ((ctx)->stat == GRN_CTX_FIN)
41 
42 #ifdef USE_EXACT_ALLOC_COUNT
43 #define GRN_ADD_ALLOC_COUNT(count) do { \
44  uint32_t alloced; \
45  GRN_ATOMIC_ADD_EX(&alloc_count, count, alloced); \
46 } while (0)
47 #else /* USE_EXACT_ALLOC_COUNT */
48 #define GRN_ADD_ALLOC_COUNT(count) do { \
49  alloc_count += count; \
50 } while (0)
51 #endif
52 
55 grn_critical_section grn_glock;
56 uint32_t grn_gtick;
57 
58 #ifdef USE_UYIELD
59 int grn_uyield_count = 0;
60 #endif
61 
62 void
63 grn_sleep(uint32_t seconds)
64 {
65 #ifdef WIN32
66  Sleep(seconds * 1000);
67 #else // WIN32
68  sleep(seconds);
69 #endif // WIN32
70 }
71 
72 void
73 grn_nanosleep(uint64_t nanoseconds)
74 {
75 #ifdef WIN32
76  Sleep((DWORD)(nanoseconds / 1000000));
77 #else // WIN32
78  struct timespec interval;
79  interval.tv_sec = (time_t)(nanoseconds / 1000000000);
80  interval.tv_nsec = (long)(nanoseconds % 1000000000);
81  nanosleep(&interval, NULL);
82 #endif // WIN32
83 }
84 
85 /* fixme by 2038 */
86 
87 grn_rc
89 {
90 #ifdef HAVE_CLOCK_GETTIME
91  struct timespec t;
92  if (clock_gettime(CLOCK_REALTIME, &t)) {
93  SERR("clock_gettime");
94  } else {
95  tv->tv_sec = t.tv_sec;
96  tv->tv_nsec = t.tv_nsec;
97  }
98  return ctx->rc;
99 #else /* HAVE_CLOCK_GETTIME */
100 #ifdef WIN32
101  time_t t;
102  struct _timeb tb;
103  time(&t);
104  _ftime(&tb);
105  tv->tv_sec = t;
106  tv->tv_nsec = tb.millitm * (GRN_TIME_NSEC_PER_SEC / 1000);
107  return GRN_SUCCESS;
108 #else /* WIN32 */
109  struct timeval t;
110  if (gettimeofday(&t, NULL)) {
111  SERR("gettimeofday");
112  } else {
113  tv->tv_sec = t.tv_sec;
114  tv->tv_nsec = GRN_TIME_USEC_TO_NSEC(t.tv_usec);
115  }
116  return ctx->rc;
117 #endif /* WIN32 */
118 #endif /* HAVE_CLOCK_GETTIME */
119 }
120 
121 void
123 {
124  grn_timeval tv;
125  grn_timeval_now(ctx, &tv);
126  GRN_TIME_SET(ctx, obj, GRN_TIME_PACK(tv.tv_sec,
128 }
129 
130 grn_rc
131 grn_timeval2str(grn_ctx *ctx, grn_timeval *tv, char *buf)
132 {
133  struct tm *ltm;
134 #ifdef HAVE_LOCALTIME_R
135  struct tm tm;
136  time_t t = tv->tv_sec;
137  ltm = localtime_r(&t, &tm);
138 #else /* HAVE_LOCALTIME_R */
139  time_t tvsec = (time_t) tv->tv_sec;
140  ltm = localtime(&tvsec);
141 #endif /* HAVE_LOCALTIME_R */
142  if (!ltm) { SERR("localtime"); }
143  snprintf(buf, GRN_TIMEVAL_STR_SIZE - 1, GRN_TIMEVAL_STR_FORMAT,
144  ltm->tm_year + 1900, ltm->tm_mon + 1, ltm->tm_mday,
145  ltm->tm_hour, ltm->tm_min, ltm->tm_sec,
146  (int)(GRN_TIME_NSEC_TO_USEC(tv->tv_nsec)));
147  buf[GRN_TIMEVAL_STR_SIZE - 1] = '\0';
148  return ctx->rc;
149 }
150 
151 grn_rc
152 grn_str2timeval(const char *str, uint32_t str_len, grn_timeval *tv)
153 {
154  struct tm tm;
155  const char *r1, *r2, *rend = str + str_len;
156  uint32_t uv;
157  memset(&tm, 0, sizeof(struct tm));
158 
159  tm.tm_year = (int)grn_atoui(str, rend, &r1) - 1900;
160  if ((r1 + 1) >= rend || (*r1 != '/' && *r1 != '-') ||
161  tm.tm_year < 0) { return GRN_INVALID_ARGUMENT; }
162  r1++;
163  tm.tm_mon = (int)grn_atoui(r1, rend, &r1) - 1;
164  if ((r1 + 1) >= rend || (*r1 != '/' && *r1 != '-') ||
165  tm.tm_mon < 0 || tm.tm_mon >= 12) { return GRN_INVALID_ARGUMENT; }
166  r1++;
167  tm.tm_mday = (int)grn_atoui(r1, rend, &r1);
168  if ((r1 + 1) >= rend || *r1 != ' ' ||
169  tm.tm_mday < 1 || tm.tm_mday > 31) { return GRN_INVALID_ARGUMENT; }
170 
171  tm.tm_hour = (int)grn_atoui(++r1, rend, &r2);
172  if ((r2 + 1) >= rend || r1 == r2 || *r2 != ':' ||
173  tm.tm_hour < 0 || tm.tm_hour >= 24) {
174  return GRN_INVALID_ARGUMENT;
175  }
176  r1 = r2 + 1;
177  tm.tm_min = (int)grn_atoui(r1, rend, &r2);
178  if ((r2 + 1) >= rend || r1 == r2 || *r2 != ':' ||
179  tm.tm_min < 0 || tm.tm_min >= 60) {
180  return GRN_INVALID_ARGUMENT;
181  }
182  r1 = r2 + 1;
183  tm.tm_sec = (int)grn_atoui(r1, rend, &r2);
184  if (r1 == r2 ||
185  tm.tm_sec < 0 || tm.tm_sec > 61 /* leap 2sec */) {
186  return GRN_INVALID_ARGUMENT;
187  }
188  r1 = r2;
189 
190  if ((tv->tv_sec = mktime(&tm)) == -1) { return GRN_INVALID_ARGUMENT; }
191  if ((r1 + 1) < rend && *r1 == '.') { r1++; }
192  uv = grn_atoi(r1, rend, &r2);
193  while (r2 < r1 + 6) {
194  uv *= 10;
195  r2++;
196  }
197  if (uv >= GRN_TIME_USEC_PER_SEC) { return GRN_INVALID_ARGUMENT; }
198  tv->tv_nsec = GRN_TIME_USEC_TO_NSEC(uv);
199  return GRN_SUCCESS;
200 }
201 
202 #ifdef USE_MEMORY_DEBUG
203 inline static void
204 grn_alloc_info_set_backtrace(char *buffer, size_t size)
205 {
206 # define N_TRACE_LEVEL 100
207  static void *trace[N_TRACE_LEVEL];
208  char **symbols;
209  int i, n, rest;
210 
211  rest = size;
212  n = backtrace(trace, N_TRACE_LEVEL);
213  symbols = backtrace_symbols(trace, n);
214  if (symbols) {
215  for (i = 0; i < n; i++) {
216  int symbol_length;
217 
218  symbol_length = strlen(symbols[i]);
219  if (symbol_length + 2 > rest) {
220  break;
221  }
222  memcpy(buffer, symbols[i], symbol_length);
223  buffer += symbol_length;
224  rest -= symbol_length;
225  buffer[0] = '\n';
226  buffer++;
227  rest--;
228  buffer[0] = '\0';
229  rest--;
230  }
231  free(symbols);
232  } else {
233  buffer[0] = '\0';
234  }
235 # undef N_TRACE_LEVEL
236 }
237 
238 inline static void
239 grn_alloc_info_add(void *address)
240 {
241  grn_ctx *ctx;
242  grn_alloc_info *new_alloc_info;
243 
244  ctx = &grn_gctx;
245  if (!ctx->impl) { return; }
246 
247  new_alloc_info = malloc(sizeof(grn_alloc_info));
248  new_alloc_info->address = address;
249  new_alloc_info->freed = GRN_FALSE;
250  grn_alloc_info_set_backtrace(new_alloc_info->alloc_backtrace,
251  sizeof(new_alloc_info->alloc_backtrace));
252  new_alloc_info->next = ctx->impl->alloc_info;
253  ctx->impl->alloc_info = new_alloc_info;
254 }
255 
256 inline static void
257 grn_alloc_info_change(void *old_address, void *new_address)
258 {
259  grn_ctx *ctx;
260  grn_alloc_info *alloc_info;
261 
262  ctx = &grn_gctx;
263  if (!ctx->impl) { return; }
264 
265  alloc_info = ctx->impl->alloc_info;
266  for (; alloc_info; alloc_info = alloc_info->next) {
267  if (alloc_info->address == old_address) {
268  alloc_info->address = new_address;
269  grn_alloc_info_set_backtrace(alloc_info->alloc_backtrace,
270  sizeof(alloc_info->alloc_backtrace));
271  }
272  }
273 }
274 
275 inline static void
277 {
278  int i = 0;
279  grn_alloc_info *alloc_info;
280 
281  if (!ctx) { return; }
282  if (!ctx->impl) { return; }
283 
284  alloc_info = ctx->impl->alloc_info;
285  for (; alloc_info; alloc_info = alloc_info->next) {
286  if (alloc_info->freed) {
287  printf("address[%d][freed]: %p\n", i, alloc_info->address);
288  } else {
289  printf("address[%d][not-freed]: %p:\n%s",
290  i, alloc_info->address, alloc_info->alloc_backtrace);
291  }
292  i++;
293  }
294 }
295 
296 inline static void
297 grn_alloc_info_check(void *address)
298 {
299  grn_ctx *ctx;
300  grn_alloc_info *alloc_info;
301 
302  ctx = &grn_gctx;
303  if (!ctx->impl) { return; }
304  /* grn_alloc_info_dump(ctx); */
305 
306  alloc_info = ctx->impl->alloc_info;
307  for (; alloc_info; alloc_info = alloc_info->next) {
308  if (alloc_info->address == address) {
309  if (alloc_info->freed) {
311  "double free: (%p):\nalloc backtrace:\n%sfree backtrace:\n%s",
312  alloc_info->address,
313  alloc_info->alloc_backtrace,
314  alloc_info->free_backtrace);
315  } else {
316  alloc_info->freed = GRN_TRUE;
317  grn_alloc_info_set_backtrace(alloc_info->free_backtrace,
318  sizeof(alloc_info->free_backtrace));
319  }
320  return;
321  }
322  }
323 }
324 
325 inline static void
327 {
328  grn_alloc_info *alloc_info;
329 
330  if (!ctx) { return; }
331  if (!ctx->impl) { return; }
332 
333  alloc_info = ctx->impl->alloc_info;
334  while (alloc_info) {
335  grn_alloc_info *current_alloc_info = alloc_info;
336  alloc_info = alloc_info->next;
337  current_alloc_info->next = NULL;
338  free(current_alloc_info);
339  }
340  ctx->impl->alloc_info = NULL;
341 }
342 
343 #else /* USE_MEMORY_DEBUG */
344 # define grn_alloc_info_add(address)
345 # define grn_alloc_info_change(old_address, new_address)
346 # define grn_alloc_info_check(address)
347 # define grn_alloc_info_dump(ctx)
348 # define grn_alloc_info_free(ctx)
349 #endif /* USE_MEMORY_DEBUG */
350 
351 #ifdef USE_FAIL_MALLOC
352 int grn_fmalloc_prob = 0;
353 char *grn_fmalloc_func = NULL;
354 char *grn_fmalloc_file = NULL;
355 int grn_fmalloc_line = 0;
356 #endif /* USE_FAIL_MALLOC */
357 
358 #define GRN_CTX_SEGMENT_SIZE (1<<22)
359 #define GRN_CTX_SEGMENT_MASK (GRN_CTX_SEGMENT_SIZE - 1)
360 
361 #define GRN_CTX_SEGMENT_WORD (1<<31)
362 #define GRN_CTX_SEGMENT_VLEN (1<<30)
363 #define GRN_CTX_SEGMENT_LIFO (1<<29)
364 #define GRN_CTX_SEGMENT_DIRTY (1<<28)
365 
366 #ifdef USE_DYNAMIC_MALLOC_CHANGE
367 static void
368 grn_ctx_impl_init_malloc(grn_ctx *ctx)
369 {
370 # ifdef USE_FAIL_MALLOC
371  ctx->impl->malloc_func = grn_malloc_fail;
372  ctx->impl->calloc_func = grn_calloc_fail;
373  ctx->impl->realloc_func = grn_realloc_fail;
374  ctx->impl->strdup_func = grn_strdup_fail;
375 # else
376  ctx->impl->malloc_func = grn_malloc_default;
377  ctx->impl->calloc_func = grn_calloc_default;
378  ctx->impl->realloc_func = grn_realloc_default;
379  ctx->impl->strdup_func = grn_strdup_default;
380 # endif
381 }
382 #endif
383 
384 static void
385 grn_loader_init(grn_loader *loader)
386 {
387  GRN_TEXT_INIT(&loader->values, 0);
390  loader->key_offset = -1;
391  loader->table = NULL;
392  loader->last = NULL;
393  loader->ifexists = NULL;
394  loader->each = NULL;
395  loader->values_size = 0;
396  loader->nrecords = 0;
397  loader->stat = GRN_LOADER_BEGIN;
398 }
399 
400 void
402 {
403  grn_loader *loader = &ctx->impl->loader;
404  grn_obj *v = (grn_obj *)(GRN_BULK_HEAD(&loader->values));
405  grn_obj *ve = (grn_obj *)(GRN_BULK_CURR(&loader->values));
406  grn_obj **p = (grn_obj **)GRN_BULK_HEAD(&loader->columns);
407  uint32_t i = GRN_BULK_VSIZE(&loader->columns) / sizeof(grn_obj *);
408  if (ctx->impl->db) { while (i--) { grn_obj_unlink(ctx, *p++); } }
409  if (loader->ifexists) { grn_obj_unlink(ctx, loader->ifexists); }
410  if (loader->each) { grn_obj_unlink(ctx, loader->each); }
411  while (v < ve) { GRN_OBJ_FIN(ctx, v++); }
412  GRN_OBJ_FIN(ctx, &loader->values);
413  GRN_OBJ_FIN(ctx, &loader->level);
414  GRN_OBJ_FIN(ctx, &loader->columns);
415  grn_loader_init(loader);
416 }
417 
418 #define IMPL_SIZE ((sizeof(struct _grn_ctx_impl) + (grn_pagesize - 1)) & ~(grn_pagesize - 1))
419 
420 #ifdef GRN_WITH_MESSAGE_PACK
421 static inline int
422 grn_msgpack_buffer_write(void *data, const char *buf, unsigned int len)
423 {
424  grn_ctx *ctx = (grn_ctx *)data;
425  return grn_bulk_write(ctx, ctx->impl->outbuf, buf, len);
426 }
427 #endif
428 
429 static void
430 grn_ctx_impl_init(grn_ctx *ctx)
431 {
432 
433  grn_io_mapinfo mi;
434  if (!(ctx->impl = grn_io_anon_map(ctx, &mi, IMPL_SIZE))) {
435  ctx->impl = NULL;
436  return;
437  }
438 #ifdef USE_DYNAMIC_MALLOC_CHANGE
439  grn_ctx_impl_init_malloc(ctx);
440 #endif
441 #ifdef USE_MEMORY_DEBUG
442  ctx->impl->alloc_info = NULL;
443 #endif
444  ctx->impl->encoding = ctx->encoding;
445  ctx->impl->lifoseg = -1;
446  ctx->impl->currseg = -1;
447  CRITICAL_SECTION_INIT(ctx->impl->lock);
448  if (!(ctx->impl->values = grn_array_create(ctx, NULL, sizeof(grn_db_obj *),
449  GRN_ARRAY_TINY))) {
450  CRITICAL_SECTION_FIN(ctx->impl->lock);
451  grn_io_anon_unmap(ctx, &mi, IMPL_SIZE);
452  ctx->impl = NULL;
453  return;
454  }
455  if (!(ctx->impl->ios = grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE,
456  sizeof(grn_io *),
458  grn_array_close(ctx, ctx->impl->values);
459  CRITICAL_SECTION_FIN(ctx->impl->lock);
460  grn_io_anon_unmap(ctx, &mi, IMPL_SIZE);
461  ctx->impl = NULL;
462  return;
463  }
464  ctx->impl->db = NULL;
465 
466  ctx->impl->expr_vars = grn_hash_create(ctx, NULL, sizeof(grn_id), sizeof(grn_obj *), 0);
467  ctx->impl->stack_curr = 0;
468  ctx->impl->curr_expr = NULL;
469  ctx->impl->qe_next = NULL;
470  ctx->impl->parser = NULL;
471 
474 
475  if (ctx == &grn_gctx) {
477  } else {
479  }
480 
481  if (ctx == &grn_gctx) {
484  } else {
487  }
488 
489  ctx->impl->finalizer = NULL;
490 
491  ctx->impl->op = GRN_OP_T0LVL;
492  ctx->impl->n_entries = 0;
493  ctx->impl->cur = NULL;
494  ctx->impl->str_end = NULL;
495  ctx->impl->batchmode = 0;
496  ctx->impl->inbuf = NULL;
497  ctx->impl->com = NULL;
498  ctx->impl->outbuf = grn_obj_open(ctx, GRN_BULK, 0, 0);
499  ctx->impl->output = NULL /* grn_ctx_concat_func */;
500  ctx->impl->data.ptr = NULL;
501  ctx->impl->tv.tv_sec = 0;
502  ctx->impl->tv.tv_nsec = 0;
503  GRN_TEXT_INIT(&ctx->impl->subbuf, 0);
504  ctx->impl->edge = NULL;
505  grn_loader_init(&ctx->impl->loader);
506  ctx->impl->plugin_path = NULL;
507 
508  ctx->impl->previous_errbuf[0] = '\0';
509  ctx->impl->n_same_error_messages = 0;
510 
511 #ifdef GRN_WITH_MESSAGE_PACK
512  msgpack_packer_init(&ctx->impl->msgpacker, ctx, grn_msgpack_buffer_write);
513 #endif
514 
516 }
517 
518 void
520 {
521  ctx->impl->qe_next = expr;
522 }
523 
524 void
526 {
527  if (ctx->impl) {
528  ctx->impl->cur = ctx->impl->str_end;
529  ctx->impl->op = GRN_OP_ERR0;
530  }
531 }
532 
533 static void
534 grn_ctx_impl_clear_n_same_error_mssagges(grn_ctx *ctx)
535 {
536  if (ctx->impl->n_same_error_messages == 0) {
537  return;
538  }
539 
540  GRN_LOG(ctx, GRN_LOG_NOTICE, "(%u same messages are truncated)",
542  ctx->impl->n_same_error_messages = 0;
543 }
544 
545 grn_bool
547 {
548  if (!ctx->impl) {
549  return GRN_TRUE;
550  }
551 
552  if (strcmp(ctx->errbuf, ctx->impl->previous_errbuf) == 0) {
553  ctx->impl->n_same_error_messages++;
554  return GRN_FALSE;
555  }
556 
557  return GRN_TRUE;
558 }
559 
560 void
562 {
563  if (!ctx->impl) {
564  return;
565  }
566 
567  grn_ctx_impl_clear_n_same_error_mssagges(ctx);
568  strcpy(ctx->impl->previous_errbuf, ctx->errbuf);
569 }
570 
571 grn_rc
572 grn_ctx_init(grn_ctx *ctx, int flags)
573 {
574  if (!ctx) { return GRN_INVALID_ARGUMENT; }
575  // if (ctx->stat != GRN_CTX_FIN) { return GRN_INVALID_ARGUMENT; }
576  ERRCLR(ctx);
577  ctx->flags = flags;
578  if (getenv("GRN_CTX_PER_DB") && strcmp(getenv("GRN_CTX_PER_DB"), "yes") == 0) {
579  ctx->flags |= GRN_CTX_PER_DB;
580  }
581  if (ERRP(ctx, GRN_ERROR)) { return ctx->rc; }
582  ctx->stat = GRN_CTX_INITED;
583  ctx->encoding = grn_gctx.encoding;
584  ctx->seqno = 0;
585  ctx->seqno2 = 0;
586  ctx->subno = 0;
587  ctx->impl = NULL;
588  if (flags & GRN_CTX_USE_QL) {
589  grn_ctx_impl_init(ctx);
590  if (ERRP(ctx, GRN_ERROR)) { return ctx->rc; }
591  if (flags & GRN_CTX_BATCH_MODE) { ctx->impl->batchmode = 1; }
592  }
593  ctx->user_data.ptr = NULL;
594  CRITICAL_SECTION_ENTER(grn_glock);
595  ctx->next = grn_gctx.next;
596  ctx->prev = &grn_gctx;
597  grn_gctx.next->prev = ctx;
598  grn_gctx.next = ctx;
599  CRITICAL_SECTION_LEAVE(grn_glock);
600  ctx->errline = 0;
601  ctx->errfile = "";
602  ctx->errfunc = "";
603  ctx->trace[0] = NULL;
604  ctx->errbuf[0] = '\0';
605  return ctx->rc;
606 }
607 
608 grn_ctx *
609 grn_ctx_open(int flags)
610 {
611  grn_ctx *ctx = GRN_GMALLOCN(grn_ctx, 1);
612  if (ctx) {
613  grn_ctx_init(ctx, flags|GRN_CTX_ALLOCATED);
614  if (ERRP(ctx, GRN_ERROR)) {
615  grn_ctx_fin(ctx);
616  GRN_GFREE(ctx);
617  ctx = NULL;
618  }
619  }
620  return ctx;
621 }
622 
623 grn_rc
625 {
626  grn_rc rc = GRN_SUCCESS;
627  if (!ctx) { return GRN_INVALID_ARGUMENT; }
628  if (ctx->stat == GRN_CTX_FIN) { return GRN_INVALID_ARGUMENT; }
629  if (!(ctx->flags & GRN_CTX_ALLOCATED)) {
630  CRITICAL_SECTION_ENTER(grn_glock);
631  ctx->next->prev = ctx->prev;
632  ctx->prev->next = ctx->next;
633  CRITICAL_SECTION_LEAVE(grn_glock);
634  }
635  if (ctx->impl) {
636  grn_ctx_impl_clear_n_same_error_mssagges(ctx);
637  if (ctx->impl->finalizer) {
638  ctx->impl->finalizer(ctx, 0, NULL, &(ctx->user_data));
639  }
642  if (ctx->impl->parser) {
644  }
645  if (ctx->impl->values) {
646 #ifndef USE_MEMORY_DEBUG
647  grn_db_obj *o;
648  GRN_ARRAY_EACH(ctx, ctx->impl->values, 0, 0, id, &o, {
649  grn_obj_close(ctx, *((grn_obj **)o));
650  });
651 #endif
652  grn_array_close(ctx, ctx->impl->values);
653  }
654  if (ctx->impl->ios) {
655  grn_hash_close(ctx, ctx->impl->ios);
656  }
657  if (ctx->impl->com) {
658  if (ctx->stat != GRN_CTX_QUIT) {
659  int flags;
660  char *str;
661  unsigned int str_len;
662  grn_ctx_send(ctx, "quit", 4, GRN_CTX_HEAD);
663  grn_ctx_recv(ctx, &str, &str_len, &flags);
664  }
665  grn_ctx_send(ctx, "ACK", 3, GRN_CTX_HEAD);
666  rc = grn_com_close(ctx, ctx->impl->com);
667  }
668  GRN_OBJ_FIN(ctx, &ctx->impl->names);
669  GRN_OBJ_FIN(ctx, &ctx->impl->levels);
670  rc = grn_obj_close(ctx, ctx->impl->outbuf);
671  rc = grn_bulk_fin(ctx, &ctx->impl->subbuf);
672  {
673  grn_hash **vp;
674  grn_obj *value;
675  GRN_HASH_EACH(ctx, ctx->impl->expr_vars, eid, NULL, NULL, &vp, {
676  if (*vp) {
677  GRN_HASH_EACH(ctx, *vp, id, NULL, NULL, &value, {
678  GRN_OBJ_FIN(ctx, value);
679  });
680  }
681  grn_hash_close(ctx, *vp);
682  });
683  }
684  grn_hash_close(ctx, ctx->impl->expr_vars);
685  if (ctx->impl->db && ctx->flags & GRN_CTX_PER_DB) {
686  grn_obj *db = ctx->impl->db;
687  ctx->impl->db = NULL;
688  grn_obj_close(ctx, db);
689  }
690  {
691  int i;
692  grn_io_mapinfo *mi;
693  for (i = 0, mi = ctx->impl->segs; i < GRN_CTX_N_SEGMENTS; i++, mi++) {
694  if (mi->map) {
695  //GRN_LOG(ctx, GRN_LOG_NOTICE, "unmap in ctx_fin(%d,%d,%d)", i, (mi->count & GRN_CTX_SEGMENT_MASK), mi->nref);
696  if (mi->count & GRN_CTX_SEGMENT_VLEN) {
697  grn_io_anon_unmap(ctx, mi, mi->nref * grn_pagesize);
698  } else {
700  }
701  }
702  }
703  }
704  grn_alloc_info_dump(ctx);
705  grn_alloc_info_free(ctx);
706  CRITICAL_SECTION_FIN(ctx->impl->lock);
707  {
708  grn_io_mapinfo mi;
709  mi.map = (void *)ctx->impl;
710  grn_io_anon_unmap(ctx, &mi, IMPL_SIZE);
711  }
712  ctx->impl = NULL;
713  }
714  ctx->stat = GRN_CTX_FIN;
715  return rc;
716 }
717 
718 grn_rc
720 {
721  if (!ctx) { return GRN_INVALID_ARGUMENT; }
722  if (!ctx->impl) {
723  grn_ctx_impl_init(ctx);
724  if (ERRP(ctx, GRN_ERROR)) { return ctx->rc; }
725  }
726  ctx->impl->finalizer = finalizer;
727  return GRN_SUCCESS;
728 }
729 
731 
732 static char *default_logger_path = NULL;
733 static FILE *default_logger_file = NULL;
734 static grn_critical_section default_logger_lock;
735 
736 static void
737 default_logger_log(grn_ctx *ctx, grn_log_level level,
738  const char *timestamp, const char *title,
739  const char *message, const char *location, void *user_data)
740 {
741  const char slev[] = " EACewnid-";
742  if (default_logger_path) {
743  CRITICAL_SECTION_ENTER(default_logger_lock);
744  if (!default_logger_file) {
745  default_logger_file = fopen(default_logger_path, "a");
746  }
747  if (default_logger_file) {
748  if (location && *location) {
749  fprintf(default_logger_file, "%s|%c|%s %s %s\n",
750  timestamp, *(slev + level), title, message, location);
751  } else {
752  fprintf(default_logger_file, "%s|%c|%s %s\n", timestamp,
753  *(slev + level), title, message);
754  }
755  fflush(default_logger_file);
756  }
757  CRITICAL_SECTION_LEAVE(default_logger_lock);
758  }
759 }
760 
761 static void
762 default_logger_reopen(grn_ctx *ctx, void *user_data)
763 {
764  GRN_LOG(ctx, GRN_LOG_NOTICE, "log will be closed.");
765  CRITICAL_SECTION_ENTER(default_logger_lock);
766  if (default_logger_file) {
767  fclose(default_logger_file);
768  default_logger_file = NULL;
769  }
770  CRITICAL_SECTION_LEAVE(default_logger_lock);
771  GRN_LOG(ctx, GRN_LOG_NOTICE, "log opened.");
772 }
773 
774 static void
775 default_logger_fin(grn_ctx *ctx, void *user_data)
776 {
777  CRITICAL_SECTION_ENTER(default_logger_lock);
778  if (default_logger_file) {
779  fclose(default_logger_file);
780  default_logger_file = NULL;
781  }
782  CRITICAL_SECTION_LEAVE(default_logger_lock);
783 }
784 
785 static grn_logger default_logger = {
788  NULL,
789  default_logger_log,
790  default_logger_reopen,
791  default_logger_fin
792 };
793 
794 static grn_logger current_logger = {
797  NULL,
798  NULL,
799  NULL,
800  NULL
801 };
802 
803 void
805 {
806  default_logger.max_level = max_level;
807  if (current_logger.log == default_logger_log) {
808  current_logger.max_level = max_level;
809  }
810 }
811 
814 {
815  return default_logger.max_level;
816 }
817 
818 void
820 {
821  if (default_logger_path) {
822  free(default_logger_path);
823  }
824 
825  if (path) {
826  default_logger_path = strdup(path);
827  } else {
828  default_logger_path = NULL;
829  }
830 }
831 
832 const char *
834 {
835  return default_logger_path;
836 }
837 
838 void
840 {
841  if (current_logger.reopen) {
842  current_logger.reopen(ctx, current_logger.user_data);
843  }
844 }
845 
846 static void
847 grn_logger_fin(grn_ctx *ctx)
848 {
849  if (current_logger.fin) {
850  current_logger.fin(ctx, current_logger.user_data);
851  }
852 }
853 
854 static void
855 logger_info_func_wrapper(grn_ctx *ctx, grn_log_level level,
856  const char *timestamp, const char *title,
857  const char *message, const char *location,
858  void *user_data)
859 {
860  grn_logger_info *info = user_data;
861  info->func(level, timestamp, title, message, location, info->func_arg);
862 }
863 
864 /* Deprecated since 2.1.2. */
865 grn_rc
867 {
868  if (info) {
869  grn_logger logger;
870 
871  memset(&logger, 0, sizeof(grn_logger));
872  logger.max_level = info->max_level;
873  logger.flags = info->flags;
874  if (info->func) {
875  logger.log = logger_info_func_wrapper;
876  logger.user_data = (grn_logger_info *)info;
877  } else {
878  logger.log = default_logger_log;
879  logger.reopen = default_logger_reopen;
880  logger.fin = default_logger_fin;
881  }
882  return grn_logger_set(ctx, &logger);
883  } else {
884  return grn_logger_set(ctx, NULL);
885  }
886 }
887 
888 grn_rc
889 grn_logger_set(grn_ctx *ctx, const grn_logger *logger)
890 {
891  grn_logger_fin(ctx);
892  if (logger) {
893  current_logger = *logger;
894  } else {
895  current_logger = default_logger;
896  }
897  return GRN_SUCCESS;
898 }
899 
900 void
902 {
903  current_logger.max_level = max_level;
904 }
905 
908 {
909  return current_logger.max_level;
910 }
911 
912 grn_bool
914 {
915  return level <= current_logger.max_level;
916 }
917 
918 #define TBUFSIZE GRN_TIMEVAL_STR_SIZE
919 #define MBUFSIZE 0x1000
920 #define LBUFSIZE 0x400
921 
922 void
924  const char *file, int line, const char *func, const char *fmt, ...)
925 {
926  if (level <= current_logger.max_level && current_logger.log) {
927  char tbuf[TBUFSIZE];
928  char mbuf[MBUFSIZE];
929  char lbuf[LBUFSIZE];
930  tbuf[0] = '\0';
931  if (current_logger.flags & GRN_LOG_TIME) {
932  grn_timeval tv;
933  grn_timeval_now(ctx, &tv);
934  grn_timeval2str(ctx, &tv, tbuf);
935  }
936  if (current_logger.flags & GRN_LOG_MESSAGE) {
937  va_list argp;
938  va_start(argp, fmt);
939  vsnprintf(mbuf, MBUFSIZE - 1, fmt, argp);
940  va_end(argp);
941  mbuf[MBUFSIZE - 1] = '\0';
942  } else {
943  mbuf[0] = '\0';
944  }
945  if (current_logger.flags & GRN_LOG_LOCATION) {
946  snprintf(lbuf, LBUFSIZE - 1, "%d %s:%d %s()", getpid(), file, line, func);
947  lbuf[LBUFSIZE - 1] = '\0';
948  } else {
949  lbuf[0] = '\0';
950  }
951  current_logger.log(ctx, level, tbuf, "", mbuf, lbuf,
952  current_logger.user_data);
953  }
954 }
955 
956 static void
957 logger_init(void)
958 {
959  if (!default_logger_path) {
960  default_logger_path = strdup(GRN_LOG_PATH);
961  }
962  memcpy(&current_logger, &default_logger, sizeof(grn_logger));
963  CRITICAL_SECTION_INIT(default_logger_lock);
964 }
965 
966 static void
967 logger_fin(grn_ctx *ctx)
968 {
969  grn_logger_fin(ctx);
970  if (default_logger_path) {
971  free(default_logger_path);
972  default_logger_path = NULL;
973  }
974  CRITICAL_SECTION_FIN(default_logger_lock);
975 }
976 
977 
978 static char *default_query_logger_path = NULL;
979 static FILE *default_query_logger_file = NULL;
980 static grn_critical_section default_query_logger_lock;
981 
982 static void
983 default_query_logger_log(grn_ctx *ctx, unsigned int flag,
984  const char *timestamp, const char *info,
985  const char *message, void *user_data)
986 {
987  if (default_query_logger_path) {
988  CRITICAL_SECTION_ENTER(default_query_logger_lock);
989  if (!default_query_logger_file) {
990  default_query_logger_file = fopen(default_query_logger_path, "a");
991  }
992  if (default_query_logger_file) {
993  fprintf(default_query_logger_file, "%s|%s%s\n", timestamp, info, message);
994  fflush(default_query_logger_file);
995  }
996  CRITICAL_SECTION_LEAVE(default_query_logger_lock);
997  }
998 }
999 
1000 static void
1001 default_query_logger_close(grn_ctx *ctx, void *user_data)
1002 {
1004  "query log will be closed: <%s>", default_query_logger_path);
1005  CRITICAL_SECTION_ENTER(default_query_logger_lock);
1006  if (default_query_logger_file) {
1007  fclose(default_query_logger_file);
1008  default_query_logger_file = NULL;
1009  }
1010  CRITICAL_SECTION_LEAVE(default_query_logger_lock);
1011 }
1012 
1013 static void
1014 default_query_logger_reopen(grn_ctx *ctx, void *user_data)
1015 {
1016  default_query_logger_close(ctx, user_data);
1017  if (default_query_logger_path) {
1019  "query log is opened: <%s>", default_query_logger_path);
1020  }
1021 }
1022 
1023 static void
1024 default_query_logger_fin(grn_ctx *ctx, void *user_data)
1025 {
1026  if (default_query_logger_file) {
1027  default_query_logger_close(ctx, user_data);
1028  }
1029 }
1030 
1031 static grn_query_logger default_query_logger = {
1033  NULL,
1034  default_query_logger_log,
1035  default_query_logger_reopen,
1036  default_query_logger_fin
1037 };
1038 
1039 static grn_query_logger current_query_logger = {
1041  NULL,
1042  NULL,
1043  NULL,
1044  NULL
1045 };
1046 
1047 void
1049 {
1050  default_query_logger.flags = flags;
1051  if (current_query_logger.log == default_query_logger_log) {
1052  current_query_logger.flags = flags;
1053  }
1054 }
1055 
1056 unsigned int
1058 {
1059  return default_query_logger.flags;
1060 }
1061 
1062 void
1064 {
1065  if (default_query_logger_path) {
1066  free(default_query_logger_path);
1067  }
1068 
1069  if (path) {
1070  default_query_logger_path = strdup(path);
1071  } else {
1072  default_query_logger_path = NULL;
1073  }
1074 }
1075 
1076 const char *
1078 {
1079  return default_query_logger_path;
1080 }
1081 
1082 void
1084 {
1085  if (current_query_logger.reopen) {
1086  current_query_logger.reopen(ctx, current_query_logger.user_data);
1087  }
1088 }
1089 
1090 static void
1091 grn_query_logger_fin(grn_ctx *ctx)
1092 {
1093  if (current_query_logger.fin) {
1094  current_query_logger.fin(ctx, current_query_logger.user_data);
1095  }
1096 }
1097 
1098 grn_rc
1100 {
1101  grn_query_logger_fin(ctx);
1102  if (logger) {
1103  current_query_logger = *logger;
1104  } else {
1105  current_query_logger = default_query_logger;
1106  }
1107  return GRN_SUCCESS;
1108 }
1109 
1110 grn_bool
1111 grn_query_logger_pass(grn_ctx *ctx, unsigned int flag)
1112 {
1113  return current_query_logger.flags & flag;
1114 }
1115 
1116 #define TIMESTAMP_BUFFER_SIZE TBUFSIZE
1117 /* 8+a(%p) + 1(|) + 1(mark) + 15(elapsed time) = 25+a */
1118 #define INFO_BUFFER_SIZE 40
1119 #define MESSAGE_BUFFER_SIZE MBUFSIZE
1120 
1121 void
1122 grn_query_logger_put(grn_ctx *ctx, unsigned int flag, const char *mark,
1123  const char *format, ...)
1124 {
1125  char timestamp[TIMESTAMP_BUFFER_SIZE];
1126  char info[INFO_BUFFER_SIZE];
1127  char message[MESSAGE_BUFFER_SIZE];
1128 
1129  if (!current_query_logger.log) {
1130  return;
1131  }
1132 
1133  {
1134  grn_timeval tv;
1135  timestamp[0] = '\0';
1136  grn_timeval_now(ctx, &tv);
1137  grn_timeval2str(ctx, &tv, timestamp);
1138  }
1139 
1141  snprintf(info, INFO_BUFFER_SIZE - 1, "%p|%s", ctx, mark);
1142  info[INFO_BUFFER_SIZE - 1] = '\0';
1143  } else {
1144  grn_timeval tv;
1145  uint64_t elapsed_time;
1146  grn_timeval_now(ctx, &tv);
1147  elapsed_time =
1148  (uint64_t)(tv.tv_sec - ctx->impl->tv.tv_sec) * GRN_TIME_NSEC_PER_SEC +
1149  (tv.tv_nsec - ctx->impl->tv.tv_nsec);
1150 
1151  snprintf(info, INFO_BUFFER_SIZE - 1,
1152  "%p|%s%015" GRN_FMT_INT64U " ", ctx, mark, elapsed_time);
1153  info[INFO_BUFFER_SIZE - 1] = '\0';
1154  }
1155 
1156  {
1157  va_list args;
1158  va_start(args, format);
1159  vsnprintf(message, MESSAGE_BUFFER_SIZE - 1, format, args);
1160  va_end(args);
1161  message[MESSAGE_BUFFER_SIZE - 1] = '\0';
1162  }
1163 
1164  current_query_logger.log(ctx, flag, timestamp, info, message,
1165  current_query_logger.user_data);
1166 }
1167 
1168 static void
1169 query_logger_init(void)
1170 {
1171  memcpy(&current_query_logger, &default_query_logger, sizeof(grn_query_logger));
1172  CRITICAL_SECTION_INIT(default_query_logger_lock);
1173 }
1174 
1175 static void
1176 query_logger_fin(grn_ctx *ctx)
1177 {
1178  grn_query_logger_fin(ctx);
1179  if (default_query_logger_path) {
1180  free(default_query_logger_path);
1181  }
1182  CRITICAL_SECTION_FIN(default_query_logger_lock);
1183 }
1184 
1185 void
1187 {
1188  grn_logger_reopen(ctx);
1190 }
1191 
1192 
1193 static void
1194 check_overcommit_memory(grn_ctx *ctx)
1195 {
1196  FILE *file;
1197  int value;
1198  file = fopen("/proc/sys/vm/overcommit_memory", "r");
1199  if (!file) { return; }
1200  value = fgetc(file);
1201  if (value != '1') {
1202  GRN_LOG(ctx, GRN_LOG_NOTICE,
1203  "vm.overcommit_memory kernel parameter should be 1: <%c>: "
1204  "See INFO level log to resolve this",
1205  value);
1206  GRN_LOG(ctx, GRN_LOG_INFO,
1207  "Some processings with vm.overcommit_memory != 1 "
1208  "may break DB under low memory condition.");
1209  GRN_LOG(ctx, GRN_LOG_INFO,
1210  "To set vm.overcommit_memory to 1");
1211  GRN_LOG(ctx, GRN_LOG_INFO,
1212  "add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and "
1213  "restart your system or");
1214  GRN_LOG(ctx, GRN_LOG_INFO,
1215  "run 'sudo /sbin/sysctl vm.overcommit_memory=1' command.");
1216  }
1217  fclose(file);
1218 }
1219 
1220 static void
1221 check_grn_ja_skip_same_value_put(grn_ctx *ctx)
1222 {
1223  const char *grn_ja_skip_same_value_put_env;
1224 
1225  grn_ja_skip_same_value_put_env = getenv("GRN_JA_SKIP_SAME_VALUE_PUT");
1226  if (grn_ja_skip_same_value_put_env &&
1227  strcmp(grn_ja_skip_same_value_put_env, "yes") == 0) {
1229  }
1230 }
1231 
1232 grn_rc
1234 {
1235  grn_rc rc;
1236  grn_ctx *ctx = &grn_gctx;
1237  logger_init();
1238  query_logger_init();
1239  CRITICAL_SECTION_INIT(grn_glock);
1240  grn_gtick = 0;
1241  ctx->next = ctx;
1242  ctx->prev = ctx;
1243  grn_ctx_init(ctx, 0);
1245  grn_timeval_now(ctx, &grn_starttime);
1246 #ifdef WIN32
1247  {
1248  SYSTEM_INFO si;
1249  GetSystemInfo(&si);
1250  grn_pagesize = si.dwAllocationGranularity;
1251  }
1252 #else /* WIN32 */
1253  if ((grn_pagesize = sysconf(_SC_PAGESIZE)) == -1) {
1254  SERR("_SC_PAGESIZE");
1255  return ctx->rc;
1256  }
1257 #endif /* WIN32 */
1258  if (grn_pagesize & (grn_pagesize - 1)) {
1259  GRN_LOG(ctx, GRN_LOG_CRIT, "pagesize=%x", grn_pagesize);
1260  }
1261  // expand_stack();
1262 #ifdef USE_AIO
1263  if (getenv("GRN_DEBUG_PRINT")) {
1264  grn_debug_print = atoi(getenv("GRN_DEBUG_PRINT"));
1265  } else {
1266  grn_debug_print = 0;
1267  }
1268  if (getenv("GRN_AIO_ENABLED")) {
1269  grn_aio_enabled = atoi(getenv("GRN_AIO_ENABLED"));
1270  } else {
1271  grn_aio_enabled = 0;
1272  }
1273  if (grn_aio_enabled) {
1274  GRN_LOG(ctx, GRN_LOG_NOTICE, "AIO and DIO enabled");
1275  }
1276 #endif /* USE_AIO */
1277 #ifdef USE_FAIL_MALLOC
1278  if (getenv("GRN_FMALLOC_PROB")) {
1279  grn_fmalloc_prob = strtod(getenv("GRN_FMALLOC_PROB"), 0) * RAND_MAX;
1280  if (getenv("GRN_FMALLOC_SEED")) {
1281  srand((unsigned int)atoi(getenv("GRN_FMALLOC_SEED")));
1282  } else {
1283  srand((unsigned int)time(NULL));
1284  }
1285  }
1286  if (getenv("GRN_FMALLOC_FUNC")) {
1287  grn_fmalloc_func = getenv("GRN_FMALLOC_FUNC");
1288  }
1289  if (getenv("GRN_FMALLOC_FILE")) {
1290  grn_fmalloc_file = getenv("GRN_FMALLOC_FILE");
1291  }
1292  if (getenv("GRN_FMALLOC_LINE")) {
1293  grn_fmalloc_line = atoi(getenv("GRN_FMALLOC_LINE"));
1294  }
1295 #endif /* USE_FAIL_MALLOC */
1296  if ((rc = grn_com_init())) {
1297  GRN_LOG(ctx, GRN_LOG_ALERT, "grn_com_init failed (%d)", rc);
1298  return rc;
1299  }
1300  grn_ctx_impl_init(ctx);
1301  if ((rc = grn_io_init())) {
1302  GRN_LOG(ctx, GRN_LOG_ALERT, "io initialize failed (%d)", rc);
1303  return rc;
1304  }
1305  if ((rc = grn_plugins_init())) {
1306  GRN_LOG(ctx, GRN_LOG_ALERT, "plugins initialize failed (%d)", rc);
1307  return rc;
1308  }
1309  if ((rc = grn_normalizer_init())) {
1310  GRN_LOG(ctx, GRN_LOG_ALERT, "grn_normalizer_init failed (%d)", rc);
1311  return rc;
1312  }
1313  if ((rc = grn_token_init())) {
1314  GRN_LOG(ctx, GRN_LOG_ALERT, "grn_token_init failed (%d)", rc);
1315  return rc;
1316  }
1317  /*
1318  if ((rc = grn_index_init())) {
1319  GRN_LOG(ctx, GRN_LOG_ALERT, "index initialize failed (%d)", rc);
1320  return rc;
1321  }
1322  */
1323  grn_cache_init();
1324  GRN_LOG(ctx, GRN_LOG_NOTICE, "grn_init");
1325  check_overcommit_memory(ctx);
1326  check_grn_ja_skip_same_value_put(ctx);
1327  return rc;
1328 }
1329 
1332 {
1333  return grn_gctx.encoding;
1334 }
1335 
1336 grn_rc
1338 {
1339  switch (encoding) {
1340  case GRN_ENC_DEFAULT :
1342  return GRN_SUCCESS;
1343  case GRN_ENC_NONE :
1344  case GRN_ENC_EUC_JP :
1345  case GRN_ENC_UTF8 :
1346  case GRN_ENC_SJIS :
1347  case GRN_ENC_LATIN1 :
1348  case GRN_ENC_KOI8R :
1349  grn_gctx.encoding = encoding;
1350  return GRN_SUCCESS;
1351  default :
1352  return GRN_INVALID_ARGUMENT;
1353  }
1354 }
1355 
1358 {
1359  return grn_ctx_get_command_version(&grn_gctx);
1360 }
1361 
1362 grn_rc
1364 {
1365  return grn_ctx_set_command_version(&grn_gctx, version);
1366 }
1367 
1368 long long int
1370 {
1371  return grn_ctx_get_match_escalation_threshold(&grn_gctx);
1372 }
1373 
1374 grn_rc
1376 {
1377  return grn_ctx_set_match_escalation_threshold(&grn_gctx, threshold);
1378 }
1379 
1380 static int alloc_count = 0;
1381 
1382 grn_rc
1383 grn_fin(void)
1384 {
1385  grn_ctx *ctx, *ctx_;
1386  if (grn_gctx.stat == GRN_CTX_FIN) { return GRN_INVALID_ARGUMENT; }
1387  for (ctx = grn_gctx.next; ctx != &grn_gctx; ctx = ctx_) {
1388  ctx_ = ctx->next;
1389  if (ctx->stat != GRN_CTX_FIN) { grn_ctx_fin(ctx); }
1390  if (ctx->flags & GRN_CTX_ALLOCATED) {
1391  ctx->next->prev = ctx->prev;
1392  ctx->prev->next = ctx->next;
1393  GRN_GFREE(ctx);
1394  }
1395  }
1396  query_logger_fin(ctx);
1397  grn_cache_fin();
1398  grn_token_fin();
1400  grn_plugins_fin();
1401  grn_io_fin();
1402  grn_ctx_fin(ctx);
1403  grn_com_fin();
1404  GRN_LOG(ctx, GRN_LOG_NOTICE, "grn_fin (%d)", alloc_count);
1405  logger_fin(ctx);
1406  CRITICAL_SECTION_FIN(grn_glock);
1407  return GRN_SUCCESS;
1408 }
1409 
1410 grn_rc
1411 grn_ctx_connect(grn_ctx *ctx, const char *host, int port, int flags)
1412 {
1413  GRN_API_ENTER;
1414  if (!ctx->impl) { grn_ctx_impl_init(ctx); }
1415  if (!ctx->impl) { goto exit; }
1416  {
1417  grn_com *com = grn_com_copen(ctx, NULL, host, port);
1418  if (com) {
1419  ctx->impl->com = com;
1420  }
1421  }
1422 exit :
1423  GRN_API_RETURN(ctx->rc);
1424 }
1425 
1426 grn_rc
1428 {
1429  grn_rc rc = grn_ctx_fin(ctx);
1430  ctx->next->prev = ctx->prev;
1431  ctx->prev->next = ctx->next;
1432  GRN_GFREE(ctx);
1433  return rc;
1434 }
1435 
1438 {
1439  if (ctx->impl) {
1440  return ctx->impl->command_version;
1441  } else {
1443  }
1444 }
1445 
1446 const char *
1448 {
1449  if (ctx->impl) {
1450  return ctx->impl->mime_type;
1451  } else {
1452  return NULL;
1453  }
1454 }
1455 
1456 grn_rc
1458 {
1459  switch (version) {
1462  return GRN_SUCCESS;
1463  default :
1464  if (GRN_COMMAND_VERSION_MIN <= version &&
1465  version <= GRN_COMMAND_VERSION_MAX) {
1466  ctx->impl->command_version = version;
1467  return GRN_SUCCESS;
1468  } else {
1470  }
1471  }
1472 }
1473 
1474 long long int
1476 {
1477  if (ctx->impl) {
1478  return ctx->impl->match_escalation_threshold;
1479  } else {
1481  }
1482 }
1483 
1484 grn_rc
1485 grn_ctx_set_match_escalation_threshold(grn_ctx *ctx, long long int threshold)
1486 {
1487  ctx->impl->match_escalation_threshold = threshold;
1488  return GRN_SUCCESS;
1489 }
1490 
1493 {
1495  if (var->header.domain == GRN_DB_INT32) {
1496  ct = GRN_INT32_VALUE(var);
1497  } else if (GRN_TEXT_LEN(var)) {
1498  switch (*(GRN_TEXT_VALUE(var))) {
1499  case 't' :
1500  case 'T' :
1501  ct = GRN_CONTENT_TSV;
1502  break;
1503  case 'j' :
1504  case 'J' :
1505  ct = GRN_CONTENT_JSON;
1506  break;
1507  case 'x' :
1508  case 'X' :
1509  ct = GRN_CONTENT_XML;
1510  break;
1511  }
1512  }
1513  return ct;
1514 }
1515 
1516 static void
1517 get_content_mime_type(grn_ctx *ctx, const char *p, const char *pe)
1518 {
1520  ctx->impl->mime_type = "application/octet-stream";
1521 
1522  if (p + 2 <= pe) {
1523  switch (*p) {
1524  case 'c' :
1525  if (p + 3 == pe && !memcmp(p, "css", 3)) {
1527  ctx->impl->mime_type = "text/css";
1528  }
1529  break;
1530  case 'g' :
1531  if (p + 3 == pe && !memcmp(p, "gif", 3)) {
1533  ctx->impl->mime_type = "image/gif";
1534  }
1535  break;
1536  case 'h' :
1537  if (p + 4 == pe && !memcmp(p, "html", 4)) {
1539  ctx->impl->mime_type = "text/html";
1540  }
1541  break;
1542  case 'j' :
1543  if (!memcmp(p, "js", 2)) {
1544  if (p + 2 == pe) {
1546  ctx->impl->mime_type = "text/javascript";
1547  } else if (p + 4 == pe && !memcmp(p + 2, "on", 2)) {
1549  ctx->impl->mime_type = "application/json";
1550  }
1551  } else if (p + 3 == pe && !memcmp(p, "jpg", 3)) {
1553  ctx->impl->mime_type = "image/jpeg";
1554  }
1555  break;
1556 #ifdef GRN_WITH_MESSAGE_PACK
1557  case 'm' :
1558  if (p + 7 == pe && !memcmp(p, "msgpack", 7)) {
1560  ctx->impl->mime_type = "application/x-msgpack";
1561  }
1562  break;
1563 #endif
1564  case 'p' :
1565  if (p + 3 == pe && !memcmp(p, "png", 3)) {
1567  ctx->impl->mime_type = "image/png";
1568  }
1569  break;
1570  case 't' :
1571  if (p + 3 == pe && !memcmp(p, "txt", 3)) {
1573  ctx->impl->mime_type = "text/plain";
1574  } else if (p + 3 == pe && !memcmp(p, "tsv", 3)) {
1576  ctx->impl->mime_type = "text/plain";
1577  }
1578  break;
1579  case 'x':
1580  if (p + 3 == pe && !memcmp(p, "xml", 3)) {
1582  ctx->impl->mime_type = "text/xml";
1583  }
1584  break;
1585  }
1586  }
1587 }
1588 
1589 static void
1590 grn_str_get_mime_type(grn_ctx *ctx, const char *p, const char *pe,
1591  const char **key_end, const char **filename_end)
1592 {
1593  const char *pd = NULL;
1594  for (; p < pe && *p != '?' && *p != '#'; p++) {
1595  if (*p == '.') { pd = p; }
1596  }
1597  *filename_end = p;
1598  if (pd && pd < p) {
1599  get_content_mime_type(ctx, pd + 1, p);
1600  *key_end = pd;
1601  } else {
1602  *key_end = pe;
1603  }
1604 }
1605 
1606 static void
1607 get_command_version(grn_ctx *ctx, const char *p, const char *pe)
1608 {
1610  const char *rest;
1611 
1612  version = grn_atoui(p, pe, &rest);
1613  if (pe == rest) {
1614  grn_rc rc;
1615  rc = grn_ctx_set_command_version(ctx, version);
1616  if (rc == GRN_UNSUPPORTED_COMMAND_VERSION) {
1617  ERR(rc,
1618  "unsupported command version is specified: %d: "
1619  "stable command version: %d: "
1620  "available command versions: %d-%d",
1621  version,
1624  }
1625  }
1626 }
1627 
1628 #define INDEX_HTML "index.html"
1629 #define OUTPUT_TYPE "output_type"
1630 #define COMMAND_VERSION "command_version"
1631 #define EXPR_MISSING "expr_missing"
1632 #define OUTPUT_TYPE_LEN (sizeof(OUTPUT_TYPE) - 1)
1633 #define COMMAND_VERSION_LEN (sizeof(COMMAND_VERSION) - 1)
1634 
1635 #define HTTP_QUERY_PAIR_DELIMITER "="
1636 #define HTTP_QUERY_PAIRS_DELIMITERS "&;"
1637 
1638 static inline int
1639 command_proc_p(grn_obj *expr)
1640 {
1641  return (expr->header.type == GRN_PROC &&
1642  ((grn_proc *)expr)->type == GRN_PROC_COMMAND);
1643 }
1644 
1645 grn_obj *
1646 grn_ctx_qe_exec_uri(grn_ctx *ctx, const char *path, uint32_t path_len)
1647 {
1648  grn_obj buf, *expr, *val;
1649  const char *p = path, *e = path + path_len, *v, *key_end, *filename_end;
1650  GRN_TEXT_INIT(&buf, 0);
1651  p = grn_text_urldec(ctx, &buf, p, e, '?');
1652  if (!GRN_TEXT_LEN(&buf)) { GRN_TEXT_SETS(ctx, &buf, INDEX_HTML); }
1653  v = GRN_TEXT_VALUE(&buf);
1654  grn_str_get_mime_type(ctx, v, GRN_BULK_CURR(&buf), &key_end, &filename_end);
1655  if ((GRN_TEXT_LEN(&buf) >= 2 && v[0] == 'd' && v[1] == '/') &&
1656  (expr = grn_ctx_get(ctx, v + 2, key_end - (v + 2))) &&
1657  command_proc_p(expr)) {
1658  while (p < e) {
1659  int l;
1660  GRN_BULK_REWIND(&buf);
1661  p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIR_DELIMITER);
1662  v = GRN_TEXT_VALUE(&buf);
1663  l = GRN_TEXT_LEN(&buf);
1664  if (l == OUTPUT_TYPE_LEN && !memcmp(v, OUTPUT_TYPE, OUTPUT_TYPE_LEN)) {
1665  GRN_BULK_REWIND(&buf);
1666  p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIRS_DELIMITERS);
1667  v = GRN_TEXT_VALUE(&buf);
1668  get_content_mime_type(ctx, v, GRN_BULK_CURR(&buf));
1669  } else if (l == COMMAND_VERSION_LEN &&
1670  !memcmp(v, COMMAND_VERSION, COMMAND_VERSION_LEN)) {
1671  GRN_BULK_REWIND(&buf);
1672  p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIRS_DELIMITERS);
1673  get_command_version(ctx, GRN_TEXT_VALUE(&buf), GRN_BULK_CURR(&buf));
1674  if (ctx->rc) { goto exit; }
1675  } else {
1676  if (!(val = grn_expr_get_or_add_var(ctx, expr, v, l))) {
1677  val = &buf;
1678  }
1679  grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0);
1680  p = grn_text_cgidec(ctx, val, p, e, HTTP_QUERY_PAIRS_DELIMITERS);
1681  }
1682  }
1683  ctx->impl->curr_expr = expr;
1684  grn_expr_exec(ctx, expr, 0);
1685  } else if ((expr = grn_ctx_get(ctx, GRN_EXPR_MISSING_NAME,
1686  strlen(GRN_EXPR_MISSING_NAME)))) {
1687  if ((val = grn_expr_get_var_by_offset(ctx, expr, 0))) {
1688  grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0);
1689  GRN_TEXT_SET(ctx, val, v, filename_end - v);
1690  }
1691  ctx->impl->curr_expr = expr;
1692  grn_expr_exec(ctx, expr, 0);
1693  }
1694 exit :
1695  GRN_OBJ_FIN(ctx, &buf);
1696  return expr;
1697 }
1698 
1699 grn_obj *
1700 grn_ctx_qe_exec(grn_ctx *ctx, const char *str, uint32_t str_len)
1701 {
1702  char tok_type;
1703  int offset = 0;
1704  grn_obj buf, *expr = NULL, *val = NULL;
1705  const char *p = str, *e = str + str_len, *v;
1706  GRN_TEXT_INIT(&buf, 0);
1707  p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
1708  expr = grn_ctx_get(ctx, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
1709  while (p < e) {
1710  GRN_BULK_REWIND(&buf);
1711  p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
1712  v = GRN_TEXT_VALUE(&buf);
1713  switch (tok_type) {
1714  case GRN_TOK_VOID :
1715  p = e;
1716  break;
1717  case GRN_TOK_SYMBOL :
1718  if (GRN_TEXT_LEN(&buf) > 2 && v[0] == '-' && v[1] == '-') {
1719  int l = GRN_TEXT_LEN(&buf) - 2;
1720  v += 2;
1721  if (l == OUTPUT_TYPE_LEN && !memcmp(v, OUTPUT_TYPE, OUTPUT_TYPE_LEN)) {
1722  GRN_BULK_REWIND(&buf);
1723  p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
1724  v = GRN_TEXT_VALUE(&buf);
1725  get_content_mime_type(ctx, v, GRN_BULK_CURR(&buf));
1726  } else if (l == COMMAND_VERSION_LEN &&
1727  !memcmp(v, COMMAND_VERSION, COMMAND_VERSION_LEN)) {
1728  GRN_BULK_REWIND(&buf);
1729  p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
1730  get_command_version(ctx, GRN_TEXT_VALUE(&buf), GRN_BULK_CURR(&buf));
1731  if (ctx->rc) { goto exit; }
1732  } else if (expr && (val = grn_expr_get_or_add_var(ctx, expr, v, l))) {
1733  grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0);
1734  p = grn_text_unesc_tok(ctx, val, p, e, &tok_type);
1735  } else {
1736  p = e;
1737  }
1738  break;
1739  }
1740  // fallthru
1741  case GRN_TOK_STRING :
1742  case GRN_TOK_QUOTE :
1743  if (expr && (val = grn_expr_get_var_by_offset(ctx, expr, offset++))) {
1744  grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0);
1745  GRN_TEXT_PUT(ctx, val, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
1746  } else {
1747  p = e;
1748  }
1749  break;
1750  }
1751  }
1752  ctx->impl->curr_expr = expr;
1753  if (expr && command_proc_p(expr)) {
1754  grn_expr_exec(ctx, expr, 0);
1755  } else {
1756  GRN_BULK_REWIND(&buf);
1757  grn_text_unesc_tok(ctx, &buf, str, str + str_len, &tok_type);
1758  if (GRN_TEXT_LEN(&buf)) {
1759  ERR(GRN_INVALID_ARGUMENT, "invalid command name: %.*s",
1760  (int)GRN_TEXT_LEN(&buf), GRN_TEXT_VALUE(&buf));
1761  }
1762  }
1763 exit :
1764  GRN_OBJ_FIN(ctx, &buf);
1765  return expr;
1766 }
1767 
1768 grn_rc
1769 grn_ctx_sendv(grn_ctx *ctx, int argc, char **argv, int flags)
1770 {
1771  grn_obj buf;
1772  GRN_TEXT_INIT(&buf, 0);
1773  while (argc--) {
1774  // todo : encode into json like syntax
1775  GRN_TEXT_PUTS(ctx, &buf, *argv);
1776  argv++;
1777  if (argc) { GRN_TEXT_PUTC(ctx, &buf, ' '); }
1778  }
1779  grn_ctx_send(ctx, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf), flags);
1780  GRN_OBJ_FIN(ctx, &buf);
1781  return ctx->rc;
1782 }
1783 
1784 static int
1785 comment_command_p(const char *command, unsigned int length)
1786 {
1787  const char *p, *e;
1788 
1789  e = command + length;
1790  for (p = command; p < e; p++) {
1791  switch (*p) {
1792  case '#' :
1793  return GRN_TRUE;
1794  case ' ' :
1795  case '\t' :
1796  break;
1797  default :
1798  return GRN_FALSE;
1799  }
1800  }
1801  return GRN_FALSE;
1802 }
1803 
1804 unsigned int
1805 grn_ctx_send(grn_ctx *ctx, const char *str, unsigned int str_len, int flags)
1806 {
1807  if (!ctx) { return 0; }
1808  GRN_API_ENTER;
1809  if (ctx->impl) {
1810  if (ctx->impl->com) {
1811  grn_rc rc;
1812  grn_com_header sheader;
1813  grn_timeval_now(ctx, &ctx->impl->tv);
1814  if ((flags & GRN_CTX_MORE)) { flags |= GRN_CTX_QUIET; }
1815  if (ctx->stat == GRN_CTX_QUIT) { flags |= GRN_CTX_QUIT; }
1816  sheader.proto = GRN_COM_PROTO_GQTP;
1817  sheader.qtype = 0;
1818  sheader.keylen = 0;
1819  sheader.level = 0;
1820  sheader.flags = flags;
1821  sheader.status = 0;
1822  sheader.opaque = 0;
1823  sheader.cas = 0;
1824  if ((rc = grn_com_send(ctx, ctx->impl->com, &sheader, (char *)str, str_len, 0))) {
1825  ERR(rc, "grn_com_send failed");
1826  }
1827  goto exit;
1828  } else {
1829  grn_obj *expr = NULL;
1830  if (comment_command_p(str, str_len)) { goto output; };
1831  if (ctx->impl->qe_next) {
1832  grn_obj *val;
1833  expr = ctx->impl->qe_next;
1834  ctx->impl->qe_next = NULL;
1835  if ((val = grn_expr_get_var_by_offset(ctx, expr, 0))) {
1836  grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0);
1837  GRN_TEXT_PUT(ctx, val, str, str_len);
1838  }
1839  grn_expr_exec(ctx, expr, 0);
1840  } else {
1841  ctx->impl->mime_type = "application/json";
1843  grn_timeval_now(ctx, &ctx->impl->tv);
1845  ">", "%.*s", str_len, str);
1846  if (str_len && *str == '/') {
1847  expr = grn_ctx_qe_exec_uri(ctx, str + 1, str_len - 1);
1848  } else {
1849  expr = grn_ctx_qe_exec(ctx, str, str_len);
1850  }
1851  }
1852  if (ctx->stat == GRN_CTX_QUITTING) { ctx->stat = GRN_CTX_QUIT; }
1853  if (ctx->impl->qe_next) {
1854  ERRCLR(ctx);
1855  } else {
1857  "<", "rc=%d", ctx->rc);
1858  }
1859  output :
1860  if (!ERRP(ctx, GRN_CRIT)) {
1861  if (!(flags & GRN_CTX_QUIET) && ctx->impl->output) {
1862  ctx->impl->output(ctx, GRN_CTX_TAIL, ctx->impl->data.ptr);
1863  }
1864  }
1865  if (expr) { grn_expr_clear_vars(ctx, expr); }
1866  goto exit;
1867  }
1868  }
1869  ERR(GRN_INVALID_ARGUMENT, "invalid ctx assigned");
1870 exit :
1871  GRN_API_RETURN(0);
1872 }
1873 
1874 unsigned int
1875 grn_ctx_recv(grn_ctx *ctx, char **str, unsigned int *str_len, int *flags)
1876 {
1877  if (!ctx) { return GRN_INVALID_ARGUMENT; }
1878  if (ctx->stat == GRN_CTX_QUIT) {
1879  *str = NULL;
1880  *str_len = 0;
1881  *flags = GRN_CTX_QUIT;
1882  return 0;
1883  }
1884  GRN_API_ENTER;
1885  if (ctx->impl) {
1886  if (ctx->impl->com) {
1887  grn_com_header header;
1888  if (grn_com_recv(ctx, ctx->impl->com, &header, ctx->impl->outbuf)) {
1889  *str = NULL;
1890  *str_len = 0;
1891  *flags = 0;
1892  } else {
1893  *str = GRN_BULK_HEAD(ctx->impl->outbuf);
1894  *str_len = GRN_BULK_VSIZE(ctx->impl->outbuf);
1895  if (header.flags & GRN_CTX_QUIT) {
1896  ctx->stat = GRN_CTX_QUIT;
1897  *flags = GRN_CTX_QUIT;
1898  } else {
1899  *flags = (header.flags & GRN_CTX_TAIL) ? 0 : GRN_CTX_MORE;
1900  }
1901  ctx->impl->output_type = header.qtype;
1902  ctx->rc = (int16_t)ntohs(header.status);
1903  ctx->errbuf[0] = '\0';
1904  ctx->errline = 0;
1905  ctx->errfile = NULL;
1906  ctx->errfunc = NULL;
1907  }
1908  goto exit;
1909  } else {
1910  grn_obj *buf = ctx->impl->outbuf;
1911  unsigned int head = 0, tail = GRN_BULK_VSIZE(buf);
1912  /*
1913  unsigned int *offsets = (unsigned int *) GRN_BULK_HEAD(&ctx->impl->subbuf);
1914  int npackets = GRN_BULK_VSIZE(&ctx->impl->subbuf) / sizeof(unsigned int);
1915  if (npackets < ctx->impl->bufcur) {
1916  ERR(GRN_INVALID_ARGUMENT, "invalid argument");
1917  goto exit;
1918  }
1919  head = ctx->impl->bufcur ? offsets[ctx->impl->bufcur - 1] : 0;
1920  tail = ctx->impl->bufcur < npackets ? offsets[ctx->impl->bufcur] : GRN_BULK_VSIZE(buf);
1921  *flags = ctx->impl->bufcur++ < npackets ? GRN_CTX_MORE : 0;
1922  */
1923  *str = GRN_BULK_HEAD(buf) + head;
1924  *str_len = tail - head;
1925  GRN_BULK_REWIND(ctx->impl->outbuf);
1926  goto exit;
1927  }
1928  }
1929  ERR(GRN_INVALID_ARGUMENT, "invalid ctx assigned");
1930 exit :
1931  GRN_API_RETURN(0);
1932 }
1933 
1934 void
1935 grn_ctx_concat_func(grn_ctx *ctx, int flags, void *dummy)
1936 {
1937  if (ctx && ctx->impl && (flags & GRN_CTX_MORE)) {
1938  unsigned int size = GRN_BULK_VSIZE(ctx->impl->outbuf);
1939  grn_bulk_write(ctx, &ctx->impl->subbuf, (char *) &size, sizeof(unsigned int));
1940  }
1941 }
1942 
1943 void
1944 grn_ctx_stream_out_func(grn_ctx *ctx, int flags, void *stream)
1945 {
1946  if (ctx && ctx->impl) {
1947  grn_obj *buf = ctx->impl->outbuf;
1948  uint32_t size = GRN_BULK_VSIZE(buf);
1949  if (size) {
1950  if (fwrite(GRN_BULK_HEAD(buf), 1, size, (FILE *)stream)) {
1951  fputc('\n', (FILE *)stream);
1952  fflush((FILE *)stream);
1953  }
1954  GRN_BULK_REWIND(buf);
1955  }
1956  }
1957 }
1958 
1959 void
1960 grn_ctx_recv_handler_set(grn_ctx *ctx, void (*func)(grn_ctx *, int, void *), void *func_arg)
1961 {
1962  if (ctx && ctx->impl) {
1963  ctx->impl->output = func;
1964  ctx->impl->data.ptr = func_arg;
1965  }
1966 }
1967 
1968 grn_rc
1970 {
1971  if (!ctx || !ctx->impl) { return GRN_INVALID_ARGUMENT; }
1972  if (ctx->impl->com) {
1973  info->fd = ctx->impl->com->fd;
1974  info->com_status = ctx->impl->com_status;
1975  info->outbuf = ctx->impl->outbuf;
1976  info->stat = ctx->stat;
1977  } else {
1978  info->fd = -1;
1979  info->com_status = 0;
1980  info->outbuf = ctx->impl->outbuf;
1981  info->stat = ctx->stat;
1982  }
1983  return GRN_SUCCESS;
1984 }
1985 
1986 
1988 
1989 struct _grn_cache {
1993  grn_mutex mutex;
1994  uint32_t max_nentries;
1995  uint32_t nfetches;
1996  uint32_t nhits;
1997 };
1998 
2005  uint32_t nref;
2006 };
2007 
2008 static grn_cache *grn_cache_current = NULL;
2009 static grn_cache *grn_cache_default = NULL;
2010 
2011 grn_cache *
2013 {
2014  grn_cache *cache = NULL;
2015 
2016  GRN_API_ENTER;
2017  cache = GRN_MALLOC(sizeof(grn_cache));
2018  if (!cache) {
2019  ERR(GRN_NO_MEMORY_AVAILABLE, "[cache] failed to allocate grn_cache");
2020  goto exit;
2021  }
2022 
2023  cache->next = (grn_cache_entry*)cache;
2024  cache->prev = (grn_cache_entry *)cache;
2025  cache->hash = grn_hash_create(&grn_gctx, NULL, GRN_TABLE_MAX_KEY_SIZE,
2027  MUTEX_INIT(cache->mutex);
2029  cache->nfetches = 0;
2030  cache->nhits = 0;
2031 
2032 exit :
2033  GRN_API_RETURN(cache);
2034 }
2035 
2036 grn_rc
2038 {
2039  grn_ctx *ctx_original = ctx;
2040  grn_cache_entry *vp;
2041 
2042  GRN_API_ENTER;
2043 
2044  ctx = &grn_gctx;
2045  GRN_HASH_EACH(ctx, cache->hash, id, NULL, NULL, &vp, {
2046  grn_obj_close(ctx, vp->value);
2047  });
2048  grn_hash_close(ctx, cache->hash);
2049  MUTEX_FIN(cache->mutex);
2050  ctx = ctx_original;
2051  GRN_FREE(cache);
2052 
2053  GRN_API_RETURN(ctx->rc);
2054 }
2055 
2056 grn_rc
2058 {
2059  grn_cache_current = cache;
2060  return GRN_SUCCESS;
2061 }
2062 
2063 grn_cache *
2065 {
2066  return grn_cache_current;
2067 }
2068 
2069 void
2071 {
2072  grn_cache_default = grn_cache_open(&grn_gctx);
2073  grn_cache_current_set(&grn_gctx, grn_cache_default);
2074 }
2075 
2076 grn_rc
2077 grn_cache_set_max_n_entries(grn_ctx *ctx, grn_cache *cache, unsigned int n)
2078 {
2079  if (!cache) {
2080  return GRN_INVALID_ARGUMENT;
2081  }
2082  cache->max_nentries = n;
2083  return GRN_SUCCESS;
2084 }
2085 
2086 uint32_t
2088 {
2089  if (!cache) {
2090  return 0;
2091  }
2092  return cache->max_nentries;
2093 }
2094 
2095 void
2097  grn_cache_statistics *statistics)
2098 {
2099  MUTEX_LOCK(cache->mutex);
2100  statistics->nentries = GRN_HASH_SIZE(cache->hash);
2101  statistics->max_nentries = cache->max_nentries;
2102  statistics->nfetches = cache->nfetches;
2103  statistics->nhits = cache->nhits;
2104  MUTEX_UNLOCK(cache->mutex);
2105 }
2106 
2107 static void
2108 grn_cache_expire_entry(grn_cache *cache, grn_cache_entry *ce)
2109 {
2110  if (!ce->nref) {
2111  ce->prev->next = ce->next;
2112  ce->next->prev = ce->prev;
2113  grn_obj_close(&grn_gctx, ce->value);
2114  grn_hash_delete_by_id(&grn_gctx, cache->hash, ce->id, NULL);
2115  }
2116 }
2117 
2118 grn_obj *
2120  const char *str, uint32_t str_len)
2121 {
2122  grn_cache_entry *ce;
2123  grn_obj *obj = NULL;
2124  if (!ctx->impl || !ctx->impl->db) { return obj; }
2125  MUTEX_LOCK(cache->mutex);
2126  cache->nfetches++;
2127  if (grn_hash_get(&grn_gctx, cache->hash, str, str_len, (void **)&ce)) {
2128  if (ce->tv.tv_sec <= grn_db_lastmod(ctx->impl->db)) {
2129  grn_cache_expire_entry(cache, ce);
2130  goto exit;
2131  }
2132  ce->nref++;
2133  obj = ce->value;
2134  ce->prev->next = ce->next;
2135  ce->next->prev = ce->prev;
2136  {
2137  grn_cache_entry *ce0 = (grn_cache_entry *)cache;
2138  ce->next = ce0->next;
2139  ce->prev = ce0;
2140  ce0->next->prev = ce;
2141  ce0->next = ce;
2142  }
2143  cache->nhits++;
2144  }
2145 exit :
2146  MUTEX_UNLOCK(cache->mutex);
2147  return obj;
2148 }
2149 
2150 void
2152  const char *str, uint32_t str_len)
2153 {
2154  grn_cache_entry *ce;
2155  ctx = &grn_gctx;
2156  MUTEX_LOCK(cache->mutex);
2157  if (grn_hash_get(ctx, cache->hash, str, str_len, (void **)&ce)) {
2158  if (ce->nref) { ce->nref--; }
2159  }
2160  MUTEX_UNLOCK(cache->mutex);
2161 }
2162 
2163 void
2165  const char *str, uint32_t str_len, grn_obj *value)
2166 {
2167  grn_id id;
2168  int added = 0;
2169  grn_cache_entry *ce;
2170  grn_rc rc = GRN_SUCCESS;
2171  grn_obj *old = NULL, *obj;
2172  if (!ctx->impl || !cache->max_nentries) { return; }
2173  if (!(obj = grn_obj_open(&grn_gctx, GRN_BULK, 0, GRN_DB_TEXT))) { return; }
2174  GRN_TEXT_PUT(&grn_gctx, obj, GRN_TEXT_VALUE(value), GRN_TEXT_LEN(value));
2175  MUTEX_LOCK(cache->mutex);
2176  if ((id = grn_hash_add(&grn_gctx, cache->hash, str, str_len, (void **)&ce, &added))) {
2177  if (!added) {
2178  if (ce->nref) {
2179  rc = GRN_RESOURCE_BUSY;
2180  goto exit;
2181  }
2182  old = ce->value;
2183  ce->prev->next = ce->next;
2184  ce->next->prev = ce->prev;
2185  }
2186  ce->id = id;
2187  ce->value = obj;
2188  ce->tv = ctx->impl->tv;
2189  ce->nref = 0;
2190  {
2191  grn_cache_entry *ce0 = (grn_cache_entry *)cache;
2192  ce->next = ce0->next;
2193  ce->prev = ce0;
2194  ce0->next->prev = ce;
2195  ce0->next = ce;
2196  }
2197  if (GRN_HASH_SIZE(cache->hash) > cache->max_nentries) {
2198  grn_cache_expire_entry(cache, cache->prev);
2199  }
2200  } else {
2202  }
2203 exit :
2204  MUTEX_UNLOCK(cache->mutex);
2205  if (rc) { grn_obj_close(&grn_gctx, obj); }
2206  if (old) { grn_obj_close(&grn_gctx, old); }
2207 }
2208 
2209 void
2210 grn_cache_expire(grn_cache *cache, int32_t size)
2211 {
2212  grn_cache_entry *ce0 = (grn_cache_entry *)cache;
2213  MUTEX_LOCK(cache->mutex);
2214  while (ce0 != ce0->prev && size--) {
2215  grn_cache_expire_entry(cache, ce0->prev);
2216  }
2217  MUTEX_UNLOCK(cache->mutex);
2218 }
2219 
2220 void
2222 {
2223  grn_cache_current_set(&grn_gctx, NULL);
2224  grn_cache_close(&grn_gctx, grn_cache_default);
2225 }
2226 
2227 /**** memory allocation ****/
2228 
2229 #define ALIGN_SIZE (1<<3)
2230 #define ALIGN_MASK (ALIGN_SIZE-1)
2231 #define GRN_CTX_ALLOC_CLEAR 1
2232 
2233 void *
2234 grn_ctx_alloc(grn_ctx *ctx, size_t size, int flags,
2235  const char* file, int line, const char *func)
2236 {
2237  void *res = NULL;
2238  if (!ctx) { return res; }
2239  if (!ctx->impl) {
2240  grn_ctx_impl_init(ctx);
2241  if (ERRP(ctx, GRN_ERROR)) { return res; }
2242  }
2243  CRITICAL_SECTION_ENTER(ctx->impl->lock);
2244  {
2245  int32_t i;
2246  int32_t *header;
2247  grn_io_mapinfo *mi;
2248  size = ((size + ALIGN_MASK) & ~ALIGN_MASK) + ALIGN_SIZE;
2249  if (size > GRN_CTX_SEGMENT_SIZE) {
2250  uint64_t npages = (size + (grn_pagesize - 1)) / grn_pagesize;
2251  if (npages >= (1LL<<32)) {
2252  MERR("too long request size=%zu", size);
2253  goto exit;
2254  }
2255  for (i = 0, mi = ctx->impl->segs;; i++, mi++) {
2256  if (i >= GRN_CTX_N_SEGMENTS) {
2257  MERR("all segments are full");
2258  goto exit;
2259  }
2260  if (!mi->map) { break; }
2261  }
2262  if (!grn_io_anon_map(ctx, mi, npages * grn_pagesize)) { goto exit; }
2263  //GRN_LOG(ctx, GRN_LOG_NOTICE, "map i=%d (%d)", i, npages * grn_pagesize);
2264  mi->nref = (uint32_t) npages;
2266  ctx->impl->currseg = -1;
2267  header = mi->map;
2268  header[0] = i;
2269  header[1] = (int32_t) size;
2270  } else {
2271  i = ctx->impl->currseg;
2272  mi = &ctx->impl->segs[i];
2273  if (i < 0 || size + mi->nref > GRN_CTX_SEGMENT_SIZE) {
2274  for (i = 0, mi = ctx->impl->segs;; i++, mi++) {
2275  if (i >= GRN_CTX_N_SEGMENTS) {
2276  MERR("all segments are full");
2277  goto exit;
2278  }
2279  if (!mi->map) { break; }
2280  }
2281  if (!grn_io_anon_map(ctx, mi, GRN_CTX_SEGMENT_SIZE)) { goto exit; }
2282  //GRN_LOG(ctx, GRN_LOG_NOTICE, "map i=%d", i);
2283  mi->nref = 0;
2285  ctx->impl->currseg = i;
2286  }
2287  header = (int32_t *)((byte *)mi->map + mi->nref);
2288  mi->nref += size;
2289  mi->count++;
2290  header[0] = i;
2291  header[1] = (int32_t) size;
2292  if ((flags & GRN_CTX_ALLOC_CLEAR) &&
2293  (mi->count & GRN_CTX_SEGMENT_DIRTY) && (size > ALIGN_SIZE)) {
2294  memset(&header[2], 0, size - ALIGN_SIZE);
2295  }
2296  }
2297  /*
2298  {
2299  char g = (ctx == &grn_gctx) ? 'g' : ' ';
2300  GRN_LOG(ctx, GRN_LOG_NOTICE, "+%c(%p) %s:%d(%s) (%d:%d)%p mi(%d:%d)", g, ctx, file, line, func, header[0], header[1], &header[2], mi->nref, (mi->count & GRN_CTX_SEGMENT_MASK));
2301  }
2302  */
2303  res = &header[2];
2304  }
2305 exit :
2306  CRITICAL_SECTION_LEAVE(ctx->impl->lock);
2307  return res;
2308 }
2309 
2310 void *
2311 grn_ctx_malloc(grn_ctx *ctx, size_t size,
2312  const char* file, int line, const char *func)
2313 {
2314  return grn_ctx_alloc(ctx, size, 0, file, line, func);
2315 }
2316 
2317 void *
2318 grn_ctx_calloc(grn_ctx *ctx, size_t size,
2319  const char* file, int line, const char *func)
2320 {
2321  return grn_ctx_alloc(ctx, size, GRN_CTX_ALLOC_CLEAR, file, line, func);
2322 }
2323 
2324 void *
2325 grn_ctx_realloc(grn_ctx *ctx, void *ptr, size_t size,
2326  const char* file, int line, const char *func)
2327 {
2328  void *res = NULL;
2329  if (size) {
2330  /* todo : expand if possible */
2331  res = grn_ctx_alloc(ctx, size, 0, file, line, func);
2332  if (res && ptr) {
2333  int32_t *header = &((int32_t *)ptr)[-2];
2334  size_t size_ = header[1];
2335  memcpy(res, ptr, size_ > size ? size : size_);
2336  grn_ctx_free(ctx, ptr, file, line, func);
2337  }
2338  } else {
2339  grn_ctx_free(ctx, ptr, file, line, func);
2340  }
2341  return res;
2342 }
2343 
2344 char *
2345 grn_ctx_strdup(grn_ctx *ctx, const char *s, const char* file, int line, const char *func)
2346 {
2347  void *res = NULL;
2348  if (s) {
2349  size_t size = strlen(s) + 1;
2350  if ((res = grn_ctx_alloc(ctx, size, 0, file, line, func))) {
2351  memcpy(res, s, size);
2352  }
2353  }
2354  return res;
2355 }
2356 
2357 void
2358 grn_ctx_free(grn_ctx *ctx, void *ptr,
2359  const char* file, int line, const char *func)
2360 {
2361  if (!ctx) { return; }
2362  if (!ctx->impl) {
2363  ERR(GRN_INVALID_ARGUMENT,"ctx without impl passed.");
2364  return;
2365  }
2366  CRITICAL_SECTION_ENTER(ctx->impl->lock);
2367  if (ptr) {
2368  int32_t *header = &((int32_t *)ptr)[-2];
2369 
2370  if (header[0] >= GRN_CTX_N_SEGMENTS) {
2371  ERR(GRN_INVALID_ARGUMENT,"invalid ptr passed. ptr=%p seg=%d", ptr, *header);
2372  goto exit;
2373  }
2374  /*
2375  {
2376  int32_t i = header[0];
2377  char c = 'X', g = (ctx == &grn_gctx) ? 'g' : ' ';
2378  grn_io_mapinfo *mi = &ctx->impl->segs[i];
2379  if (!(mi->count & GRN_CTX_SEGMENT_VLEN) &&
2380  mi->map <= (void *)header && (char *)header < ((char *)mi->map + GRN_CTX_SEGMENT_SIZE)) { c = '-'; }
2381  GRN_LOG(ctx, GRN_LOG_NOTICE, "%c%c(%p) %s:%d(%s) (%d:%d)%p mi(%d:%d)", c, g, ctx, file, line, func, header[0], header[1], &header[2], mi->nref, (mi->count & GRN_CTX_SEGMENT_MASK));
2382  }
2383  */
2384  {
2385  int32_t i = header[0];
2386  grn_io_mapinfo *mi = &ctx->impl->segs[i];
2387  if (mi->count & GRN_CTX_SEGMENT_VLEN) {
2388  if (mi->map != header) {
2389  ERR(GRN_INVALID_ARGUMENT,"invalid ptr passed.. ptr=%p seg=%d", ptr, i);
2390  goto exit;
2391  }
2392  //GRN_LOG(ctx, GRN_LOG_NOTICE, "umap i=%d (%d)", i, mi->nref * grn_pagesize);
2393  grn_io_anon_unmap(ctx, mi, mi->nref * grn_pagesize);
2394  mi->map = NULL;
2395  } else {
2396  if (!mi->map) {
2397  ERR(GRN_INVALID_ARGUMENT,"invalid ptr passed... ptr=%p seg=%d", ptr, i);
2398  goto exit;
2399  }
2400  mi->count--;
2401  if (!(mi->count & GRN_CTX_SEGMENT_MASK)) {
2402  //GRN_LOG(ctx, GRN_LOG_NOTICE, "umap i=%d", i);
2403  if (i == ctx->impl->currseg) {
2405  mi->nref = 0;
2406  } else {
2408  mi->map = NULL;
2409  }
2410  }
2411  }
2412  }
2413  }
2414 exit :
2415  CRITICAL_SECTION_LEAVE(ctx->impl->lock);
2416 }
2417 
2418 #define DB_P(s) ((s) && (s)->header.type == GRN_DB)
2419 
2420 grn_rc
2422 {
2423  GRN_API_ENTER;
2424  if (db && !DB_P(db)) {
2425  ctx->rc = GRN_INVALID_ARGUMENT;
2426  } else {
2427  if (!ctx->impl) { grn_ctx_impl_init(ctx); }
2428  if (!ctx->rc) {
2429  ctx->impl->db = db;
2430  if (db) {
2431  grn_obj buf;
2432  GRN_TEXT_INIT(&buf, 0);
2433  grn_obj_get_info(ctx, db, GRN_INFO_ENCODING, &buf);
2434  ctx->encoding = *(grn_encoding *)GRN_BULK_HEAD(&buf);
2435  grn_obj_close(ctx, &buf);
2436  }
2437  }
2438  }
2439  GRN_API_RETURN(ctx->rc);
2440 }
2441 
2442 void *
2443 grn_ctx_alloc_lifo(grn_ctx *ctx, size_t size,
2444  const char* file, int line, const char *func)
2445 {
2446  if (!ctx) { return NULL; }
2447  if (!ctx->impl) {
2448  grn_ctx_impl_init(ctx);
2449  if (ERRP(ctx, GRN_ERROR)) { return NULL; }
2450  }
2451  {
2452  int32_t i = ctx->impl->lifoseg;
2453  grn_io_mapinfo *mi = &ctx->impl->segs[i];
2454  if (size > GRN_CTX_SEGMENT_SIZE) {
2455  uint64_t npages = (size + (grn_pagesize - 1)) / grn_pagesize;
2456  if (npages >= (1LL<<32)) {
2457  MERR("too long request size=%zu", size);
2458  return NULL;
2459  }
2460  for (;;) {
2461  if (++i >= GRN_CTX_N_SEGMENTS) {
2462  MERR("all segments are full");
2463  return NULL;
2464  }
2465  mi++;
2466  if (!mi->map) { break; }
2467  }
2468  if (!grn_io_anon_map(ctx, mi, npages * grn_pagesize)) { return NULL; }
2469  mi->nref = (uint32_t) npages;
2471  ctx->impl->lifoseg = i;
2472  return mi->map;
2473  } else {
2474  size = (size + ALIGN_MASK) & ~ALIGN_MASK;
2475  if (i < 0 || (mi->count & GRN_CTX_SEGMENT_VLEN) || size + mi->nref > GRN_CTX_SEGMENT_SIZE) {
2476  for (;;) {
2477  if (++i >= GRN_CTX_N_SEGMENTS) {
2478  MERR("all segments are full");
2479  return NULL;
2480  }
2481  if (!(++mi)->map) { break; }
2482  }
2483  if (!grn_io_anon_map(ctx, mi, GRN_CTX_SEGMENT_SIZE)) { return NULL; }
2484  mi->nref = 0;
2486  ctx->impl->lifoseg = i;
2487  }
2488  {
2489  uint32_t u = mi->nref;
2490  mi->nref += size;
2491  return (byte *)mi->map + u;
2492  }
2493  }
2494  }
2495 }
2496 
2497 void
2498 grn_ctx_free_lifo(grn_ctx *ctx, void *ptr,
2499  const char* file, int line, const char *func)
2500 {
2501  if (!ctx) { return; }
2502  if (!ctx->impl) {
2503  ERR(GRN_INVALID_ARGUMENT,"ctx without impl passed.");
2504  return;
2505  }
2506  {
2507  int32_t i = ctx->impl->lifoseg, done = 0;
2508  grn_io_mapinfo *mi = &ctx->impl->segs[i];
2509  if (i < 0) {
2510  ERR(GRN_INVALID_ARGUMENT, "lifo buffer is void");
2511  return;
2512  }
2513  for (; i >= 0; i--, mi--) {
2514  if (!(mi->count & GRN_CTX_SEGMENT_LIFO)) { continue; }
2515  if (done) { break; }
2516  if (mi->count & GRN_CTX_SEGMENT_VLEN) {
2517  if (mi->map == ptr) { done = 1; }
2518  grn_io_anon_unmap(ctx, mi, mi->nref * grn_pagesize);
2519  mi->map = NULL;
2520  } else {
2521  if (mi->map == ptr) {
2522  done = 1;
2523  } else {
2524  if (mi->map < ptr && ptr < (void *)((byte*)mi->map + mi->nref)) {
2525  mi->nref = (uint32_t) ((uintptr_t)ptr - (uintptr_t)mi->map);
2526  break;
2527  }
2528  }
2530  mi->map = NULL;
2531  }
2532  }
2533  ctx->impl->lifoseg = i;
2534  }
2535 }
2536 
2537 #if USE_DYNAMIC_MALLOC_CHANGE
2538 grn_malloc_func
2539 grn_ctx_get_malloc(grn_ctx *ctx)
2540 {
2541  if (!ctx || !ctx->impl) { return NULL; }
2542  return ctx->impl->malloc_func;
2543 }
2544 
2545 void
2546 grn_ctx_set_malloc(grn_ctx *ctx, grn_malloc_func malloc_func)
2547 {
2548  if (!ctx || !ctx->impl) { return; }
2549  ctx->impl->malloc_func = malloc_func;
2550 }
2551 
2552 grn_calloc_func
2553 grn_ctx_get_calloc(grn_ctx *ctx)
2554 {
2555  if (!ctx || !ctx->impl) { return NULL; }
2556  return ctx->impl->calloc_func;
2557 }
2558 
2559 void
2560 grn_ctx_set_calloc(grn_ctx *ctx, grn_calloc_func calloc_func)
2561 {
2562  if (!ctx || !ctx->impl) { return; }
2563  ctx->impl->calloc_func = calloc_func;
2564 }
2565 
2566 grn_realloc_func
2567 grn_ctx_get_realloc(grn_ctx *ctx)
2568 {
2569  if (!ctx || !ctx->impl) { return NULL; }
2570  return ctx->impl->realloc_func;
2571 }
2572 
2573 void
2574 grn_ctx_set_realloc(grn_ctx *ctx, grn_realloc_func realloc_func)
2575 {
2576  if (!ctx || !ctx->impl) { return; }
2577  ctx->impl->realloc_func = realloc_func;
2578 }
2579 
2580 grn_strdup_func
2581 grn_ctx_get_strdup(grn_ctx *ctx)
2582 {
2583  if (!ctx || !ctx->impl) { return NULL; }
2584  return ctx->impl->strdup_func;
2585 }
2586 
2587 void
2588 grn_ctx_set_strdup(grn_ctx *ctx, grn_strdup_func strdup_func)
2589 {
2590  if (!ctx || !ctx->impl) { return; }
2591  ctx->impl->strdup_func = strdup_func;
2592 }
2593 
2594 void *
2595 grn_malloc(grn_ctx *ctx, size_t size, const char* file, int line, const char *func)
2596 {
2597  if (ctx && ctx->impl && ctx->impl->malloc_func) {
2598  return ctx->impl->malloc_func(ctx, size, file, line, func);
2599  } else {
2600  return grn_malloc_default(ctx, size, file, line, func);
2601  }
2602 }
2603 
2604 void *
2605 grn_calloc(grn_ctx *ctx, size_t size, const char* file, int line, const char *func)
2606 {
2607  if (ctx && ctx->impl && ctx->impl->calloc_func) {
2608  return ctx->impl->calloc_func(ctx, size, file, line, func);
2609  } else {
2610  return grn_calloc_default(ctx, size, file, line, func);
2611  }
2612 }
2613 
2614 void *
2615 grn_realloc(grn_ctx *ctx, void *ptr, size_t size, const char* file, int line, const char *func)
2616 {
2617  if (ctx && ctx->impl && ctx->impl->realloc_func) {
2618  return ctx->impl->realloc_func(ctx, ptr, size, file, line, func);
2619  } else {
2620  return grn_realloc_default(ctx, ptr, size, file, line, func);
2621  }
2622 }
2623 
2624 char *
2625 grn_strdup(grn_ctx *ctx, const char *string, const char* file, int line, const char *func)
2626 {
2627  if (ctx && ctx->impl && ctx->impl->strdup_func) {
2628  return ctx->impl->strdup_func(ctx, string, file, line, func);
2629  } else {
2630  return grn_strdup_default(ctx, string, file, line, func);
2631  }
2632 }
2633 #endif
2634 
2635 void *
2636 grn_malloc_default(grn_ctx *ctx, size_t size, const char* file, int line, const char *func)
2637 {
2638  if (!ctx) { return NULL; }
2639  {
2640  void *res = malloc(size);
2641  if (res) {
2643  grn_alloc_info_add(res);
2644  } else {
2645  if (!(res = malloc(size))) {
2646  MERR("malloc fail (%zu)=%p (%s:%d) <%d>",
2647  size, res, file, line, alloc_count);
2648  } else {
2650  grn_alloc_info_add(res);
2651  }
2652  }
2653  return res;
2654  }
2655 }
2656 
2657 void *
2658 grn_calloc_default(grn_ctx *ctx, size_t size, const char* file, int line, const char *func)
2659 {
2660  if (!ctx) { return NULL; }
2661  {
2662  void *res = calloc(size, 1);
2663  if (res) {
2665  grn_alloc_info_add(res);
2666  } else {
2667  if (!(res = calloc(size, 1))) {
2668  MERR("calloc fail (%" GRN_FMT_LLU ")=%p (%s:%d) <%" GRN_FMT_LLU ">",
2669  (unsigned long long int)size, res, file, line,
2670  (unsigned long long int)alloc_count);
2671  } else {
2673  grn_alloc_info_add(res);
2674  }
2675  }
2676  return res;
2677  }
2678 }
2679 
2680 void
2681 grn_free_default(grn_ctx *ctx, void *ptr, const char* file, int line, const char *func)
2682 {
2683  if (!ctx) { return; }
2684  grn_alloc_info_check(ptr);
2685  {
2686  free(ptr);
2687  if (ptr) {
2688  GRN_ADD_ALLOC_COUNT(-1);
2689  } else {
2690  GRN_LOG(ctx, GRN_LOG_ALERT, "free fail (%p) (%s:%d) <%d>", ptr, file, line, alloc_count);
2691  }
2692  }
2693 }
2694 
2695 void *
2696 grn_realloc_default(grn_ctx *ctx, void *ptr, size_t size, const char* file, int line, const char *func)
2697 {
2698  void *res;
2699  if (!ctx) { return NULL; }
2700  if (size) {
2701  if (!(res = realloc(ptr, size))) {
2702  if (!(res = realloc(ptr, size))) {
2703  MERR("realloc fail (%p,%zu)=%p (%s:%d) <%d>", ptr, size, res, file, line, alloc_count);
2704  return NULL;
2705  }
2706  }
2707  if (ptr) {
2708  grn_alloc_info_change(ptr, res);
2709  } else {
2711  grn_alloc_info_add(res);
2712  }
2713  } else {
2714  if (!ptr) { return NULL; }
2715  grn_alloc_info_check(ptr);
2716  GRN_ADD_ALLOC_COUNT(-1);
2717  free(ptr);
2718  res = NULL;
2719  }
2720  return res;
2721 }
2722 
2723 int
2725 {
2726  return alloc_count;
2727 }
2728 
2729 char *
2730 grn_strdup_default(grn_ctx *ctx, const char *s, const char* file, int line, const char *func)
2731 {
2732  if (!ctx) { return NULL; }
2733  {
2734  char *res = strdup(s);
2735  if (res) {
2737  } else {
2738  if (!(res = strdup(s))) {
2739  MERR("strdup(%p)=%p (%s:%d) <%d>", s, res, file, line, alloc_count);
2740  }
2741  }
2742  return res;
2743  }
2744 }
2745 
2746 #ifdef USE_FAIL_MALLOC
2747 int
2748 grn_fail_malloc_check(size_t size, const char *file, int line, const char *func)
2749 {
2750  if ((grn_fmalloc_file && strcmp(file, grn_fmalloc_file)) ||
2751  (grn_fmalloc_line && line != grn_fmalloc_line) ||
2752  (grn_fmalloc_func && strcmp(func, grn_fmalloc_func))) {
2753  return 1;
2754  }
2755  if (grn_fmalloc_prob && grn_fmalloc_prob >= rand()) {
2756  return 0;
2757  }
2758  return 1;
2759 }
2760 
2761 void *
2762 grn_malloc_fail(grn_ctx *ctx, size_t size, const char* file, int line, const char *func)
2763 {
2764  if (grn_fail_malloc_check(size, file, line, func)) {
2765  return grn_malloc_default(ctx, size, file, line, func);
2766  } else {
2767  MERR("fail_malloc (%d) (%s:%d@%s) <%d>", size, file, line, func, alloc_count);
2768  return NULL;
2769  }
2770 }
2771 
2772 void *
2773 grn_calloc_fail(grn_ctx *ctx, size_t size, const char* file, int line, const char *func)
2774 {
2775  if (grn_fail_malloc_check(size, file, line, func)) {
2776  return grn_calloc_default(ctx, size, file, line, func);
2777  } else {
2778  MERR("fail_calloc (%d) (%s:%d@%s) <%d>", size, file, line, func, alloc_count);
2779  return NULL;
2780  }
2781 }
2782 
2783 void *
2784 grn_realloc_fail(grn_ctx *ctx, void *ptr, size_t size, const char* file, int line,
2785  const char *func)
2786 {
2787  if (grn_fail_malloc_check(size, file, line, func)) {
2788  return grn_realloc_default(ctx, ptr, size, file, line, func);
2789  } else {
2790  MERR("fail_realloc (%p,%zu) (%s:%d@%s) <%d>", ptr, size, file, line, func, alloc_count);
2791  return NULL;
2792  }
2793 }
2794 
2795 char *
2796 grn_strdup_fail(grn_ctx *ctx, const char *s, const char* file, int line, const char *func)
2797 {
2798  if (grn_fail_malloc_check(strlen(s), file, line, func)) {
2799  return grn_strdup_default(ctx, s, file, line, func);
2800  } else {
2801  MERR("fail_strdup(%p) (%s:%d@%s) <%d>", s, file, line, func, alloc_count);
2802  return NULL;
2803  }
2804 }
2805 #endif /* USE_FAIL_MALLOC */
2806 
2807 /* don't handle error inside logger functions */
2808 
2809 void
2810 grn_ctx_log(grn_ctx *ctx, const char *fmt, ...)
2811 {
2812  va_list argp;
2813  va_start(argp, fmt);
2814  vsnprintf(ctx->errbuf, GRN_CTX_MSGSIZE, fmt, argp);
2815  va_end(argp);
2816 }
2817 
2818 void
2819 grn_assert(grn_ctx *ctx, int cond, const char* file, int line, const char* func)
2820 {
2821  if (!cond) {
2822  GRN_LOG(ctx, GRN_LOG_WARNING, "ASSERT fail on %s %s:%d", func, file, line);
2823  }
2824 }
2825 
2826 const char *
2828 {
2829  return GRN_VERSION;
2830 }
2831 
2832 const char *
2834 {
2835  return PACKAGE;
2836 }
2837 
2838 #if defined(HAVE_SIGNAL_H) && !defined(WIN32)
2839 static int segv_received = 0;
2840 static void
2841 segv_handler(int signal_number, siginfo_t *info, void *context)
2842 {
2843  grn_ctx *ctx = &grn_gctx;
2844 
2845  if (segv_received) {
2846  GRN_LOG(ctx, GRN_LOG_CRIT, "SEGV received in SEGV handler.");
2847  exit(EXIT_FAILURE);
2848  }
2849  segv_received = 1;
2850 
2851  GRN_LOG(ctx, GRN_LOG_CRIT, "-- CRASHED!!! --");
2852 #ifdef HAVE_BACKTRACE
2853 # define N_TRACE_LEVEL 1024
2854  {
2855  static void *trace[N_TRACE_LEVEL];
2856  int n = backtrace(trace, N_TRACE_LEVEL);
2857  char **symbols = backtrace_symbols(trace, n);
2858  int i;
2859 
2860  if (symbols) {
2861  for (i = 0; i < n; i++) {
2862  GRN_LOG(ctx, GRN_LOG_CRIT, "%s", symbols[i]);
2863  }
2864  free(symbols);
2865  }
2866  }
2867 #else /* HAVE_BACKTRACE */
2868  GRN_LOG(ctx, GRN_LOG_CRIT, "backtrace() isn't available.");
2869 #endif /* HAVE_BACKTRACE */
2870  GRN_LOG(ctx, GRN_LOG_CRIT, "----------------");
2871  abort();
2872 }
2873 #endif /* defined(HAVE_SIGNAL_H) && !defined(WIN32) */
2874 
2875 grn_rc
2877 {
2878  grn_rc rc = GRN_SUCCESS;
2879 #if defined(HAVE_SIGNAL_H) && !defined(WIN32)
2880  grn_ctx *ctx = &grn_gctx;
2881  struct sigaction action;
2882 
2883  sigemptyset(&action.sa_mask);
2884  action.sa_sigaction = segv_handler;
2885  action.sa_flags = SA_SIGINFO | SA_ONSTACK;
2886 
2887  if (sigaction(SIGSEGV, &action, NULL)) {
2888  SERR("failed to set SIGSEGV action");
2889  rc = ctx->rc;
2890  };
2891 #endif
2892  return rc;
2893 }
2894 
2895 #if defined(HAVE_SIGNAL_H) && !defined(WIN32)
2896 static struct sigaction old_int_handler;
2897 static void
2898 int_handler(int signal_number, siginfo_t *info, void *context)
2899 {
2900  grn_gctx.stat = GRN_CTX_QUIT;
2901  sigaction(signal_number, &old_int_handler, NULL);
2902 }
2903 
2904 static struct sigaction old_term_handler;
2905 static void
2906 term_handler(int signal_number, siginfo_t *info, void *context)
2907 {
2908  grn_gctx.stat = GRN_CTX_QUIT;
2909  sigaction(signal_number, &old_term_handler, NULL);
2910 }
2911 #endif /* defined(HAVE_SIGNAL_H) && !defined(WIN32) */
2912 
2913 grn_rc
2915 {
2916  grn_rc rc = GRN_SUCCESS;
2917 #if defined(HAVE_SIGNAL_H) && !defined(WIN32)
2918  grn_ctx *ctx = &grn_gctx;
2919  struct sigaction action;
2920 
2921  sigemptyset(&action.sa_mask);
2922  action.sa_sigaction = int_handler;
2923  action.sa_flags = SA_SIGINFO;
2924 
2925  if (sigaction(SIGINT, &action, &old_int_handler)) {
2926  SERR("failed to set SIGINT action");
2927  rc = ctx->rc;
2928  }
2929 #endif
2930  return rc;
2931 }
2932 
2933 grn_rc
2935 {
2936  grn_rc rc = GRN_SUCCESS;
2937 #if defined(HAVE_SIGNAL_H) && !defined(WIN32)
2938  grn_ctx *ctx = &grn_gctx;
2939  struct sigaction action;
2940 
2941  sigemptyset(&action.sa_mask);
2942  action.sa_sigaction = term_handler;
2943  action.sa_flags = SA_SIGINFO;
2944 
2945  if (sigaction(SIGTERM, &action, &old_term_handler)) {
2946  SERR("failed to set SIGTERM action");
2947  rc = ctx->rc;
2948  }
2949 #endif
2950  return rc;
2951 }
2952 
2953 void
2954 grn_ctx_output_array_open(grn_ctx *ctx, const char *name, int nelements)
2955 {
2956  grn_output_array_open(ctx, ctx->impl->outbuf, ctx->impl->output_type,
2957  name, nelements);
2958 }
2959 
2960 void
2962 {
2963  grn_output_array_close(ctx, ctx->impl->outbuf, ctx->impl->output_type);
2964 }
2965 
2966 void
2967 grn_ctx_output_map_open(grn_ctx *ctx, const char *name, int nelements)
2968 {
2969  grn_output_map_open(ctx, ctx->impl->outbuf, ctx->impl->output_type,
2970  name, nelements);
2971 }
2972 
2973 void
2975 {
2976  grn_output_map_close(ctx, ctx->impl->outbuf, ctx->impl->output_type);
2977 }
2978 
2979 void
2981 {
2982  grn_output_int32(ctx, ctx->impl->outbuf, ctx->impl->output_type, value);
2983 }
2984 
2985 void
2986 grn_ctx_output_int64(grn_ctx *ctx, long long int value)
2987 {
2988  grn_output_int64(ctx, ctx->impl->outbuf, ctx->impl->output_type, value);
2989 }
2990 
2991 void
2992 grn_ctx_output_float(grn_ctx *ctx, double value)
2993 {
2994  grn_output_float(ctx, ctx->impl->outbuf, ctx->impl->output_type, value);
2995 }
2996 
2997 void
2998 grn_ctx_output_cstr(grn_ctx *ctx, const char *value)
2999 {
3000  grn_output_cstr(ctx, ctx->impl->outbuf, ctx->impl->output_type, value);
3001 }
3002 
3003 void
3004 grn_ctx_output_str(grn_ctx *ctx, const char *value, unsigned int value_len)
3005 {
3006  grn_output_str(ctx, ctx->impl->outbuf, ctx->impl->output_type,
3007  value, value_len);
3008 }
3009 
3010 void
3012 {
3013  grn_output_bool(ctx, ctx->impl->outbuf, ctx->impl->output_type, value);
3014 }
3015 
3016 void
3018 {
3019  grn_output_obj(ctx, ctx->impl->outbuf, ctx->impl->output_type,
3020  value, format);
3021 }