1 /* Copyright(C) 2007 Brazil
2
3 This library is free software; you can redistribute it and/or
4 modify it under the terms of the GNU Lesser General Public
5 License as published by the Free Software Foundation; either
6 version 2.1 of the License, or (at your option) any later version.
7
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Lesser General Public License for more details.
12
13 You should have received a copy of the GNU Lesser General Public
14 License along with this library; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 #include "senna_in.h"
19 #include <string.h>
20 #include "lex.h"
21 #include "ql.h"
22 #include "sym.h"
23 #include "snip.h"
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <time.h>
27
28 sen_ctx sen_gctx;
29
30 /* simple array */
31
32 void
sen_array_init(sen_array * a,sen_ctx * ctx,uint16_t element_size,uint16_t flags)33 sen_array_init(sen_array *a, sen_ctx *ctx, uint16_t element_size, uint16_t flags)
34 {
35 a->ctx = ctx;
36 a->element_size = element_size;
37 a->flags = flags;
38 a->max = 0;
39 if (flags & SEN_ARRAY_THREADSAFE) { MUTEX_INIT(a->lock); }
40 memset(a->elements, 0, sizeof(a->elements));
41 }
42
43 void
sen_array_fin(sen_array * a)44 sen_array_fin(sen_array *a)
45 {
46 int i;
47 sen_ctx *ctx = a->ctx;
48 for (i = 0; i < SEN_ARRAY_N; i++) {
49 void **e = &a->elements[i];
50 if (*e) {
51 SEN_FREE(*e);
52 *e = NULL;
53 }
54 }
55 }
56
57 void *
sen_array_at(sen_array * a,sen_id id)58 sen_array_at(sen_array *a, sen_id id)
59 {
60 void *e;
61 SEN_ARRAY_AT(a, id, e);
62 return e;
63 }
64
65 sen_id
sen_array_id(sen_array * a,void * p)66 sen_array_id(sen_array *a, void *p)
67 {
68 uint32_t i, s, n;
69 uintptr_t o, p_ = (uintptr_t) p;
70 for (i = 0, s = 0; i < SEN_ARRAY_N; i++, s += n) {
71 n = SEN_ARRAY_S * SEN_ARRAY_R(i);
72 o = (uintptr_t) a->elements[i];
73 if (o <= p_ && p_ < o + n * a->element_size) {
74 return s + ((p_ - o) / a->element_size);
75 }
76 }
77 return SEN_SYM_NIL;
78 }
79
80 /* fixme by 2038 */
81
82 sen_rc
sen_timeval_now(sen_timeval * tv)83 sen_timeval_now(sen_timeval *tv)
84 {
85 #ifdef WIN32
86 time_t t;
87 struct _timeb tb;
88 time(&t);
89 _ftime(&tb);
90 tv->tv_sec = (int32_t) t;
91 tv->tv_usec = tb.millitm * 1000;
92 return sen_success;
93 #else /* WIN32 */
94 struct timeval t;
95 sen_rc rc = gettimeofday(&t, NULL) ? sen_external_error : sen_success;
96 if (!rc) {
97 tv->tv_sec = (int32_t) t.tv_sec;
98 tv->tv_usec = t.tv_usec;
99 }
100 return rc;
101 #endif /* WIN32 */
102 }
103
104 sen_rc
sen_timeval2str(sen_timeval * tv,char * buf)105 sen_timeval2str(sen_timeval *tv, char *buf)
106 {
107 struct tm *ltm;
108 #ifdef WIN32
109 time_t tvsec = (time_t) tv->tv_sec;
110 ltm = localtime(&tvsec);
111 #else /* WIN32 */
112 struct tm tm;
113 time_t t = tv->tv_sec;
114 ltm = localtime_r(&t, &tm);
115 #endif /* WIN32 */
116 if (!ltm) { return sen_external_error; }
117 snprintf(buf, SEN_TIMEVAL_STR_SIZE - 1, SEN_TIMEVAL_STR_FORMAT,
118 ltm->tm_year + 1900, ltm->tm_mon + 1, ltm->tm_mday,
119 ltm->tm_hour, ltm->tm_min, ltm->tm_sec, (int) tv->tv_usec);
120 buf[SEN_TIMEVAL_STR_SIZE - 1] = '\0';
121 return sen_success;
122 }
123
124 sen_rc
sen_str2timeval(const char * str,uint32_t str_len,sen_timeval * tv)125 sen_str2timeval(const char *str, uint32_t str_len, sen_timeval *tv)
126 {
127 struct tm tm;
128 const char *r1, *r2, *rend = str + str_len;
129 uint32_t uv;
130 memset(&tm, 0, sizeof(struct tm));
131
132 tm.tm_year = (int)sen_atoui(str, rend, &r1) - 1900;
133 if ((r1 + 1) >= rend || (*r1 != '/' && *r1 != '-') ||
134 tm.tm_year < 0) { return sen_invalid_argument; }
135 r1++;
136 tm.tm_mon = (int)sen_atoui(r1, rend, &r1) - 1;
137 if ((r1 + 1) >= rend || (*r1 != '/' && *r1 != '-') ||
138 tm.tm_mon < 0 || tm.tm_mon >= 12) { return sen_invalid_argument; }
139 r1++;
140 tm.tm_mday = (int)sen_atoui(r1, rend, &r1);
141 if ((r1 + 1) >= rend || *r1 != ' ' ||
142 tm.tm_mday < 1 || tm.tm_mday > 31) { return sen_invalid_argument; }
143
144 tm.tm_hour = (int)sen_atoui(++r1, rend, &r2);
145 if ((r2 + 1) >= rend || r1 == r2 || *r2 != ':' ||
146 tm.tm_hour < 0 || tm.tm_hour >= 24) {
147 return sen_invalid_argument;
148 }
149 r1 = r2 + 1;
150 tm.tm_min = (int)sen_atoui(r1, rend, &r2);
151 if ((r2 + 1) >= rend || r1 == r2 || *r2 != ':' ||
152 tm.tm_min < 0 || tm.tm_min >= 60) {
153 return sen_invalid_argument;
154 }
155 r1 = r2 + 1;
156 tm.tm_sec = (int)sen_atoui(r1, rend, &r2);
157 if (r1 == r2 ||
158 tm.tm_sec < 0 || tm.tm_sec > 61 /* leap 2sec */) {
159 return sen_invalid_argument;
160 }
161 r1 = r2;
162
163 if ((tv->tv_sec = (int32_t) mktime(&tm)) == -1) { return sen_invalid_argument; }
164 if ((r1 + 1) < rend && *r1 == '.') { r1++; }
165 uv = sen_atoi(r1, rend, &r2);
166 while (r2 < r1 + 6) {
167 uv *= 10;
168 r2++;
169 }
170 if (uv >= 1000000) { return sen_invalid_argument; }
171 tv->tv_usec = uv;
172 return sen_success;
173 }
174
175 #ifdef USE_FAIL_MALLOC
176 int sen_fmalloc_prob = 0;
177 char *sen_fmalloc_func = NULL;
178 char *sen_fmalloc_file = NULL;
179 int sen_fmalloc_line = 0;
180 #endif /* USE_FAIL_MALLOC */
181
182 void
sen_ctx_init(sen_ctx * ctx)183 sen_ctx_init(sen_ctx *ctx)
184 {
185 ERRCLR(ctx);
186 ctx->db = NULL;
187 ctx->phs = NIL;
188 ctx->code = NIL;
189 ctx->dump = NIL;
190 ctx->op = SEN_OP_T0LVL;
191 ctx->args = NIL;
192 ctx->envir = NIL;
193 ctx->value = NIL;
194 ctx->ncells = 0;
195 ctx->seqno = 0;
196 ctx->lseqno = 0;
197 ctx->nbinds = 0;
198 ctx->nunbinds = 0;
199 ctx->feed_mode = sen_ql_atonce;
200 ctx->stat = SEN_QL_WAIT_EXPR;
201 ctx->cur = NULL;
202 ctx->str_end = NULL;
203 ctx->batchmode = 0;
204 ctx->gc_verbose = 0;
205 ctx->inbuf = NULL;
206 ctx->co.mode = 0;
207 ctx->co.func = NULL;
208 #ifdef USE_SET_AS_OBJECTS
209 ctx->objects = NULL;
210 #else /* USE_SET_AS_OBJECTS */
211 sen_array_init(&ctx->objects, ctx, sizeof(sen_obj), 0);
212 ctx->freelist = NIL;
213 #endif /* USE_SET_AS_OBJECTS */
214 ctx->symbols = NULL;
215 ctx->com = NULL;
216 sen_rbuf_init(&ctx->outbuf, 0);
217 sen_rbuf_init(&ctx->subbuf, 0);
218 }
219
220 sen_rc
sen_ctx_fin(sen_ctx * ctx)221 sen_ctx_fin(sen_ctx *ctx)
222 {
223 sen_rc rc = sen_success;
224 #ifdef USE_SET_AS_OBJECTS
225 if (ctx->objects) {
226 sen_obj *o;
227 sen_set_cursor *sc;
228 if ((sc = sen_set_cursor_open(ctx->objects))) {
229 while (sen_set_cursor_next(sc, NULL, (void **) &o)) { sen_obj_clear(ctx, o); }
230 sen_set_cursor_close(sc);
231 } else {
232 return sen_memory_exhausted;
233 }
234 sen_set_close(ctx->objects);
235 }
236 #else /* USE_SET_AS_OBJECTS */
237 {
238 sen_id id;
239 sen_obj *o;
240 SEN_ARRAY_EACH(&ctx->objects, 1, ctx->seqno, id, o, {
241 if (!(o->flags & SEN_OBJ_FREE)) { sen_obj_clear(ctx, o); }
242 });
243 }
244 sen_array_fin(&ctx->objects);
245 #endif /* USE_SET_AS_OBJECTS */
246 if (ctx->symbols) {
247 sen_set_close(ctx->symbols);
248 }
249 if (ctx->com) {
250 if (ctx->stat != SEN_CTX_QUIT) {
251 int flags;
252 char *str;
253 unsigned int str_len;
254 sen_ctx_send(ctx, "(quit)", 6, SEN_CTX_HEAD);
255 sen_ctx_recv(ctx, &str, &str_len, &flags);
256 }
257 sen_ctx_send(ctx, "ACK", 3, SEN_CTX_HEAD);
258 rc = sen_com_sqtp_close(NULL, ctx->com);
259 }
260 rc = sen_rbuf_fin(&ctx->outbuf);
261 rc = sen_rbuf_fin(&ctx->subbuf);
262 return rc;
263 }
264
265 void
sen_ctx_initql(sen_ctx * ctx)266 sen_ctx_initql(sen_ctx *ctx)
267 {
268 if (!ctx->symbols) {
269 #ifdef USE_SET_AS_OBJECTS
270 if ((ctx->objects = sen_set_open(sizeof(int), sizeof(sen_obj), 0))) {
271 #endif /* USE_SET_AS_OBJECTS */
272 if ((ctx->symbols = sen_set_open(0, sizeof(sen_obj), 0))) {
273 if (ctx->db) { sen_ql_def_db_funcs(ctx); }
274 if (!ERRP(ctx, SEN_ERROR)) {
275 sen_ql_init_globals(ctx);
276 if (!ERRP(ctx, SEN_ERROR)) {
277 return;
278 }
279 }
280 sen_set_close(ctx->symbols);
281 ctx->symbols = NULL;
282 } else {
283 MERR("ctx->symbols init failed");
284 }
285 #ifdef USE_SET_AS_OBJECTS
286 sen_set_close(ctx->objects);
287 ctx->objects = NULL;
288 } else {
289 MERR("ctx->objects init failed");
290 }
291 #endif /* USE_SET_AS_OBJECTS */
292 } else {
293 MERR("invalid ctx assigned");
294 }
295 }
296
297 static void
expand_stack(void)298 expand_stack(void)
299 {
300 #ifndef WIN32
301 struct rlimit rlim;
302 if (!getrlimit(RLIMIT_STACK, &rlim)) {
303 SEN_LOG(sen_log_notice, "RLIMIT_STACK is %d (%d)", rlim.rlim_cur, getpid());
304 if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < SEN_STACK_SIZE) {
305 rlim.rlim_cur = SEN_STACK_SIZE;
306 if (!setrlimit(RLIMIT_STACK, &rlim)) {
307 SEN_LOG(sen_log_notice, "expanded RLIMIT_STACK to %d", rlim.rlim_cur);
308 }
309 }
310 }
311 #endif /* WIN32 */
312 }
313
314 sen_rc
sen_init(void)315 sen_init(void)
316 {
317 sen_rc rc;
318 sen_ql_init_const();
319 sen_ctx_init(&sen_gctx);
320 sen_gctx.encoding = sen_strtoenc(SENNA_DEFAULT_ENCODING);
321 expand_stack();
322 #ifdef USE_AIO
323 if (getenv("SEN_DEBUG_PRINT")) {
324 sen_debug_print = atoi(getenv("SEN_DEBUG_PRINT"));
325 } else {
326 sen_debug_print = 0;
327 }
328 if (getenv("SEN_AIO_ENABLED")) {
329 sen_aio_enabled = atoi(getenv("SEN_AIO_ENABLED"));
330 } else {
331 sen_aio_enabled = 0;
332 }
333 if (sen_aio_enabled) {
334 SEN_LOG(sen_log_notice, "AIO and DIO enabled");
335 sen_cache_open();
336 }
337 #endif /* USE_AIO */
338 #ifdef USE_FAIL_MALLOC
339 if (getenv("SEN_FMALLOC_PROB")) {
340 sen_fmalloc_prob = strtod(getenv("SEN_FMALLOC_PROB"), 0) * RAND_MAX;
341 if (getenv("SEN_FMALLOC_SEED")) {
342 srand((unsigned int)atoi(getenv("SEN_FMALLOC_SEED")));
343 } else {
344 srand((unsigned int)time(NULL));
345 }
346 }
347 if (getenv("SEN_FMALLOC_FUNC")) {
348 sen_fmalloc_func = getenv("SEN_FMALLOC_FUNC");
349 }
350 if (getenv("SEN_FMALLOC_FILE")) {
351 sen_fmalloc_file = getenv("SEN_FMALLOC_FILE");
352 }
353 if (getenv("SEN_FMALLOC_LINE")) {
354 sen_fmalloc_line = atoi(getenv("SEN_FMALLOC_LINE"));
355 }
356 #endif /* USE_FAIL_MALLOC */
357 if ((rc = sen_lex_init())) {
358 SEN_LOG(sen_log_alert, "sen_lex_init failed (%d)", rc);
359 return rc;
360 }
361 if ((rc = sen_com_init())) {
362 SEN_LOG(sen_log_alert, "sen_com_init failed (%d)", rc);
363 return rc;
364 }
365 sen_ctx_initql(&sen_gctx);
366 if ((rc = sen_gctx.rc)) {
367 SEN_LOG(sen_log_alert, "gctx initialize failed (%d)", rc);
368 return rc;
369 }
370 SEN_LOG(sen_log_notice, "sen_init");
371 return rc;
372 }
373
374 static int alloc_count = 0;
375
376 sen_rc
sen_fin(void)377 sen_fin(void)
378 {
379 sen_ctx_fin(&sen_gctx);
380 sen_lex_fin();
381 sen_str_fin();
382 sen_com_fin();
383 SEN_LOG(sen_log_notice, "sen_fin (%d)", alloc_count);
384 sen_logger_fin();
385 return sen_success;
386 }
387
388 sen_ctx *
sen_ctx_open(sen_db * db,int flags)389 sen_ctx_open(sen_db *db, int flags)
390 {
391 sen_ctx *ctx = SEN_GMALLOCN(sen_ctx, 1);
392 if (ctx) {
393 sen_ctx_init(ctx);
394 if ((ctx->db = db)) { ctx->encoding = db->keys->encoding; }
395 if (flags & SEN_CTX_USEQL) {
396 sen_ctx_initql(ctx);
397 if (ERRP(ctx, SEN_ERROR)) {
398 sen_ctx_close(ctx);
399 return NULL;
400 }
401 }
402 if (flags & SEN_CTX_BATCHMODE) { ctx->batchmode = 1; }
403 }
404 return ctx;
405 }
406
407 sen_ctx *
sen_ctx_connect(const char * host,int port,int flags)408 sen_ctx_connect(const char *host, int port, int flags)
409 {
410 sen_ctx *ctx;
411 sen_com_sqtp *com = sen_com_sqtp_copen(NULL, host, port);
412 if (!com) { return NULL; }
413 if ((ctx = SEN_GMALLOCN(sen_ctx, 1))) {
414 sen_ctx_init(ctx);
415 ctx->com = com;
416 } else {
417 sen_com_sqtp_close(NULL, com);
418 }
419 return ctx;
420 }
421
422 sen_rc
sen_ctx_close(sen_ctx * ctx)423 sen_ctx_close(sen_ctx *ctx)
424 {
425 sen_rc rc = sen_ctx_fin(ctx);
426 SEN_GFREE(ctx);
427 return rc;
428 }
429
430 sen_rc
sen_ctx_send(sen_ctx * ctx,char * str,unsigned int str_len,int flags)431 sen_ctx_send(sen_ctx *ctx, char *str, unsigned int str_len, int flags)
432 {
433 ERRCLR(ctx);
434 if (ctx->com) {
435 sen_rc rc;
436 static uint32_t info = 0;
437 sen_com_sqtp_header sheader;
438 if ((flags & SEN_CTX_MORE)) { flags |= SEN_CTX_QUIET; }
439 sheader.flags = flags;
440 sheader.size = str_len;
441 sheader.qtype = 0;
442 sheader.level = 0;
443 sheader.status = 0;
444 sheader.info = info++; /* for debug */
445 if ((rc = sen_com_sqtp_send(ctx->com, &sheader, (char *)str))) {
446 ERR(rc, "sen_com_sqtp_send failed");
447 }
448 goto exit;
449 } else {
450 if (ctx->symbols) {
451 sen_ql_feed(ctx, str, str_len, flags);
452 if (ctx->stat == SEN_QL_QUITTING) { ctx->stat = SEN_CTX_QUIT; }
453 if (!ERRP(ctx, SEN_CRIT)) {
454 if (!(flags & SEN_CTX_QUIET) && ctx->output) {
455 ctx->output(ctx, 0, ctx->data.ptr);
456 }
457 }
458 goto exit;
459 }
460 }
461 ERR(sen_invalid_argument, "invalid ctx assigned");
462 exit :
463 return ctx->rc;
464 }
465
466 sen_rc
sen_ctx_recv(sen_ctx * ctx,char ** str,unsigned int * str_len,int * flags)467 sen_ctx_recv(sen_ctx *ctx, char **str, unsigned int *str_len, int *flags)
468 {
469 ERRCLR(ctx);
470 if (ctx->stat == SEN_CTX_QUIT) {
471 *flags = SEN_CTX_QUIT;
472 return ctx->rc;
473 }
474 if (ctx->com) {
475 if (sen_com_sqtp_recv(ctx->com, &ctx->com->msg, &ctx->com_status, &ctx->com_info)) {
476 *str = NULL;
477 *str_len = 0;
478 *flags = 0;
479 } else {
480 sen_com_sqtp_header *rheader = SEN_COM_SQTP_MSG_HEADER(&ctx->com->msg);
481 *str = SEN_COM_SQTP_MSG_BODY(&ctx->com->msg);
482 *str_len = rheader->size;
483 if (rheader->flags & SEN_CTX_QUIT) {
484 ctx->stat = SEN_CTX_QUIT;
485 *flags = SEN_CTX_QUIT;
486 } else {
487 *flags = (rheader->flags & SEN_CTX_TAIL) ? 0 : SEN_CTX_MORE;
488 }
489 }
490 if (ctx->com->rc) {
491 ERR(ctx->com->rc, "sen_com_sqtp_recv failed!");
492 }
493 goto exit;
494 } else {
495 if (ctx->symbols) {
496 sen_rbuf *buf = &ctx->outbuf;
497 unsigned int head, tail;
498 unsigned int *offsets = (unsigned int *) ctx->subbuf.head;
499 int npackets = SEN_RBUF_VSIZE(&ctx->subbuf) / sizeof(unsigned int);
500 if (npackets < ctx->bufcur) { return sen_invalid_argument; }
501 head = ctx->bufcur ? offsets[ctx->bufcur - 1] : 0;
502 tail = ctx->bufcur < npackets ? offsets[ctx->bufcur] : SEN_RBUF_VSIZE(buf);
503 *str = buf->head + head;
504 *str_len = tail - head;
505 *flags = ctx->bufcur++ < npackets ? SEN_CTX_MORE : 0;
506 goto exit;
507 }
508 }
509 ERR(sen_invalid_argument, "invalid ctx assigned");
510 exit :
511 return ctx->rc;
512 }
513
514 void
sen_ctx_concat_func(sen_ctx * ctx,int flags,void * dummy)515 sen_ctx_concat_func(sen_ctx *ctx, int flags, void *dummy)
516 {
517 if (flags & SEN_CTX_MORE) {
518 unsigned int size = SEN_RBUF_VSIZE(&ctx->outbuf);
519 sen_rbuf_write(&ctx->subbuf, (char *) &size, sizeof(unsigned int));
520 }
521 }
522
523 void
sen_ctx_stream_out_func(sen_ctx * ctx,int flags,void * stream)524 sen_ctx_stream_out_func(sen_ctx *ctx, int flags, void *stream)
525 {
526 sen_rbuf *buf = &ctx->outbuf;
527 uint32_t size = SEN_RBUF_VSIZE(buf);
528 if (size) {
529 fwrite(buf->head, 1, size, (FILE *)stream);
530 fputc('\n', (FILE *)stream);
531 fflush((FILE *)stream);
532 SEN_RBUF_REWIND(buf);
533 }
534 }
535
536 void
sen_ctx_recv_handler_set(sen_ctx * ctx,void (* func)(sen_ctx *,int,void *),void * func_arg)537 sen_ctx_recv_handler_set(sen_ctx *ctx, void (*func)(sen_ctx *, int, void *), void *func_arg)
538 {
539 ctx->output = func;
540 ctx->data.ptr = func_arg;
541 }
542
543 sen_rc
sen_ctx_info_get(sen_ctx * ctx,sen_ctx_info * info)544 sen_ctx_info_get(sen_ctx *ctx, sen_ctx_info *info)
545 {
546 if (!ctx) { return sen_invalid_argument; }
547 if (ctx->com) {
548 info->fd = ctx->com->com.fd;
549 info->com_status = ctx->com_status;
550 info->com_info = ctx->com_info;
551 info->outbuf = &ctx->com->msg;
552 info->stat = ctx->stat;
553 } else {
554 info->fd = -1;
555 info->com_status = 0;
556 info->com_info = 0;
557 info->outbuf = &ctx->outbuf;
558 info->stat = ctx->stat;
559 }
560 return sen_success;
561 }
562
563
564 sen_obj *
sen_get(const char * key)565 sen_get(const char *key)
566 {
567 sen_obj *obj;
568 if (!sen_set_get(sen_gctx.symbols, key, (void **) &obj)) {
569 SEN_LOG(sen_log_warning, "sen_get(%s) failed", key);
570 return F;
571 }
572 if (!obj->flags) {
573 obj->flags |= SEN_OBJ_SYMBOL;
574 obj->type = sen_ql_void;
575 }
576 return obj;
577 }
578
579 sen_obj *
sen_at(const char * key)580 sen_at(const char *key)
581 {
582 sen_obj *obj;
583 if (!sen_set_at(sen_gctx.symbols, key, (void **) &obj)) { return F; }
584 return obj;
585 }
586
587 sen_rc
sen_del(const char * key)588 sen_del(const char *key)
589 {
590 sen_obj *obj;
591 sen_set_eh *eh;
592 if (!(eh = sen_set_get(sen_gctx.symbols, key, (void **) &obj))) {
593 SEN_LOG(sen_log_warning, "sen_del(%s) failed", key);
594 return sen_invalid_argument;
595 }
596 /* todo : do something */
597 return sen_set_del(sen_gctx.symbols, eh);
598 }
599
600 /**** memory allocation ****/
601
602 void *
sen_malloc(sen_ctx * ctx,size_t size,const char * file,int line)603 sen_malloc(sen_ctx *ctx, size_t size, const char* file, int line)
604 {
605 void *res = malloc(size);
606 if (res) {
607 alloc_count++;
608 } else {
609 sen_index_expire();
610 if (!(res = malloc(size))) {
611 MERR("malloc fail (%d)=%p (%s:%d) <%d>", size, res, file, line, alloc_count);
612 }
613 }
614 return res;
615 }
616
617 void *
sen_calloc(sen_ctx * ctx,size_t size,const char * file,int line)618 sen_calloc(sen_ctx *ctx, size_t size, const char* file, int line)
619 {
620 void *res = calloc(size, 1);
621 if (res) {
622 alloc_count++;
623 } else {
624 sen_index_expire();
625 if (!(res = calloc(size, 1))) {
626 MERR("calloc fail (%d)=%p (%s:%d) <%d>", size, res, file, line, alloc_count);
627 }
628 }
629 return res;
630 }
631
632 void
sen_free(sen_ctx * ctx,void * ptr,const char * file,int line)633 sen_free(sen_ctx *ctx, void *ptr, const char* file, int line)
634 {
635 free(ptr);
636 if (ptr) {
637 alloc_count--;
638 } else {
639 SEN_LOG(sen_log_alert, "free fail (%p) (%s:%d) <%d>", ptr, file, line, alloc_count);
640 }
641 }
642
643 void *
sen_realloc(sen_ctx * ctx,void * ptr,size_t size,const char * file,int line)644 sen_realloc(sen_ctx *ctx, void *ptr, size_t size, const char* file, int line)
645 {
646 void *res;
647 if (!size) {
648 alloc_count--;
649 #if defined __FreeBSD__
650 free(ptr);
651 return NULL;
652 #endif /* __FreeBSD__ */
653 }
654 res = realloc(ptr, size);
655 if (!ptr && res) { alloc_count++; }
656 if (size && !res) {
657 sen_index_expire();
658 if (!(res = realloc(ptr, size))) {
659 MERR("realloc fail (%p,%zu)=%p (%s:%d) <%d>", ptr, size, res, file, line, alloc_count);
660 }
661 }
662 if (!size && res) {
663 SEN_LOG(sen_log_alert, "realloc(%p,%zu)=%p (%s:%d) <%d>", ptr, size, res, file, line, alloc_count);
664 // sen_free(ctx, res, file, line);
665 }
666 return res;
667 }
668
669 char *
sen_strdup(sen_ctx * ctx,const char * s,const char * file,int line)670 sen_strdup(sen_ctx *ctx, const char *s, const char* file, int line)
671 {
672 char *res = strdup(s);
673 if (res) {
674 alloc_count++;
675 } else {
676 sen_index_expire();
677 if (!(res = strdup(s))) {
678 MERR("strdup(%p)=%p (%s:%d) <%d>", s, res, file, line, alloc_count);
679 }
680 }
681 return res;
682 }
683
684 #ifdef USE_FAIL_MALLOC
685 int
fail_malloc_check(size_t size,const char * file,int line,const char * func)686 fail_malloc_check(size_t size, const char *file, int line, const char *func)
687 {
688 if ((sen_fmalloc_file && strcmp(file, sen_fmalloc_file)) ||
689 (sen_fmalloc_line && line != sen_fmalloc_line) ||
690 (sen_fmalloc_func && strcmp(func, sen_fmalloc_func))) {
691 return 1;
692 }
693 if (sen_fmalloc_prob && sen_fmalloc_prob >= rand()) {
694 return 0;
695 }
696 return 1;
697 }
698
699 void *
sen_fail_malloc(sen_ctx * ctx,size_t size,const char * file,int line,const char * func)700 sen_fail_malloc(sen_ctx *ctx, size_t size, const char* file, int line, const char *func)
701 {
702 if (fail_malloc_check(size, file, line, func)) {
703 return sen_malloc(ctx, size, file, line);
704 } else {
705 sen_index_expire();
706 MERR("fail_malloc (%d) (%s:%d@%s) <%d>", size, file, line, func, alloc_count);
707 return NULL;
708 }
709 }
710
711 void *
sen_fail_calloc(sen_ctx * ctx,size_t size,const char * file,int line,const char * func)712 sen_fail_calloc(sen_ctx *ctx, size_t size, const char* file, int line, const char *func)
713 {
714 if (fail_malloc_check(size, file, line, func)) {
715 return sen_calloc(ctx, size, file, line);
716 } else {
717 sen_index_expire();
718 MERR("fail_calloc (%d) (%s:%d@%s) <%d>", size, file, line, func, alloc_count);
719 return NULL;
720 }
721 }
722
723 void *
sen_fail_realloc(sen_ctx * ctx,void * ptr,size_t size,const char * file,int line,const char * func)724 sen_fail_realloc(sen_ctx *ctx, void *ptr, size_t size, const char* file, int line,
725 const char *func)
726 {
727 if (fail_malloc_check(size, file, line, func)) {
728 return sen_realloc(ctx, ptr, size, file, line);
729 } else {
730 sen_index_expire();
731 MERR("fail_realloc (%p,%zu) (%s:%d@%s) <%d>", ptr, size
732 , file, line, func, alloc_count);
733 return NULL;
734 }
735 }
736
737 char *
sen_fail_strdup(sen_ctx * ctx,const char * s,const char * file,int line,const char * func)738 sen_fail_strdup(sen_ctx *ctx, const char *s, const char* file, int line, const char *func)
739 {
740 if (fail_malloc_check(strlen(s), file, line, func)) {
741 return sen_strdup(ctx, s, file, line);
742 } else {
743 sen_index_expire();
744 MERR("fail_strdup(%p) (%s:%d@%s) <%d>", s, file, line, func, alloc_count);
745 return NULL;
746 }
747 }
748 #endif /* USE_FAIL_MALLOC */
749
750 sen_obj *
sen_obj_new(sen_ctx * ctx)751 sen_obj_new(sen_ctx *ctx)
752 {
753 sen_obj *o;
754 #ifdef USE_SET_AS_OBJECTS
755 do {
756 if (!sen_set_get(ctx->objects, &ctx->seqno, (void **) &o)) {
757 MERR("sen_set_get failed");
758 return NULL;
759 }
760 // SEN_SET_INT_ADD(ctx->objects, &ctx->seqno, o);
761 ctx->seqno++;
762 } while (o->type);
763 #else /* USE_SET_AS_OBJECTS */
764 if (ctx->freelist == NIL) {
765 if (!(o = sen_array_at(&ctx->objects, ctx->seqno + 1))) {
766 MERR("sen_set_get failed");
767 return NULL;
768 }
769 ctx->seqno++;
770 } else {
771 o = ctx->freelist;
772 ctx->freelist = CDR(ctx->freelist);
773 }
774 #endif /* USE_SET_AS_OBJECTS */
775 o->flags = 0;
776 o->nrefs = 0;
777 ctx->n_entries++;
778 return o;
779 }
780
781 sen_obj *
sen_obj_cons(sen_ctx * ctx,sen_obj * a,sen_obj * b)782 sen_obj_cons(sen_ctx *ctx, sen_obj *a, sen_obj *b)
783 {
784 sen_obj *o;
785 SEN_OBJ_NEW(ctx, o);
786 o->type = sen_ql_list;
787 o->flags = SEN_OBJ_REFERER;
788 o->u.l.car = a;
789 o->u.l.cdr = b;
790 return o;
791 }
792
793 sen_obj *
sen_obj_alloc(sen_ctx * ctx,uint32_t size)794 sen_obj_alloc(sen_ctx *ctx, uint32_t size)
795 {
796 void *value = SEN_MALLOC(size + 1);
797 if (value) {
798 sen_obj *o = sen_obj_new(ctx);
799 if (!ERRP(ctx, SEN_ERROR)) {
800 o->flags = SEN_OBJ_ALLOCATED;
801 o->type = sen_ql_bulk;
802 o->u.b.size = size;
803 o->u.b.value = value;
804 return o;
805 }
806 SEN_FREE(value);
807 } else {
808 MERR("malloc(%d) failed", size + 1);
809 }
810 return NULL;
811 }
812
813 char *
sen_obj_copy_bulk_value(sen_ctx * ctx,sen_obj * o)814 sen_obj_copy_bulk_value(sen_ctx *ctx, sen_obj *o)
815 {
816 if (o->type != sen_ql_bulk) { return NULL; }
817 if (o->flags & SEN_OBJ_ALLOCATED) {
818 o->flags &= ~SEN_OBJ_ALLOCATED;
819 return o->u.b.value;
820 } else {
821 char *v = SEN_MALLOC(o->u.b.size + 1);
822 if (!v) {
823 MERR("malloc(%d) failed", o->u.b.size + 1);
824 return NULL;
825 }
826 memcpy(v, o->u.b.value, o->u.b.size);
827 v[o->u.b.size] = '\0';
828 return v;
829 }
830 }
831
832 void
sen_obj_clear(sen_ctx * ctx,sen_obj * o)833 sen_obj_clear(sen_ctx *ctx, sen_obj *o)
834 {
835 if (o->flags & SEN_OBJ_ALLOCATED) {
836 switch (o->type) {
837 case sen_ql_snip :
838 if (o->u.p.value) { sen_snip_close(o->u.p.value); }
839 break;
840 case sen_ql_records :
841 if (o->u.p.value) { sen_records_close(o->u.p.value); }
842 break;
843 case sen_ql_bulk :
844 if (o->u.b.value) {
845 if (o->flags & SEN_OBJ_FROMJA) {
846 sen_ja_unref(ctx->db->values, 0, o->u.b.value, o->u.b.size);
847 } else {
848 SEN_FREE(o->u.b.value);
849 }
850 }
851 break;
852 case sen_ql_query :
853 if (o->u.p.value) { sen_query_close(o->u.p.value); }
854 break;
855 case sen_ql_symsnip :
856 sen_ql_symsnip_spec_close(ctx, (symsnip_spec *)o->u.p.value);
857 break;
858 default :
859 SEN_LOG(sen_log_warning, "obj_clear: invalid type(%x)", o->type);
860 break;
861 }
862 }
863 o->flags = 0;
864 }
865
866 /* don't handle error inside logger functions */
867
868 void
sen_ctx_log(sen_ctx * ctx,char * fmt,...)869 sen_ctx_log(sen_ctx *ctx, char *fmt, ...)
870 {
871 va_list argp;
872 va_start(argp, fmt);
873 vsnprintf(ctx->errbuf, SEN_CTX_MSGSIZE - 1, fmt, argp);
874 va_end(argp);
875 ctx->errbuf[SEN_CTX_MSGSIZE - 1] = '\0';
876 }
877
878 static FILE *default_logger_fp = NULL;
879
880 static void
default_logger_func(int level,const char * time,const char * title,const char * msg,const char * location,void * func_arg)881 default_logger_func(int level, const char *time, const char *title,
882 const char *msg, const char *location, void *func_arg)
883 {
884 const char slev[] = " EACewnid-";
885 if (!default_logger_fp) {
886 // mutex_lock
887 default_logger_fp = fopen(SENNA_LOG_PATH, "a");
888 // mutex_unlock
889 }
890 if (default_logger_fp) {
891 fprintf(default_logger_fp, "%s|%c|%s %s %s\n",
892 time, *(slev + level), title, msg, location);
893 fflush(default_logger_fp);
894 }
895 }
896
897 void
sen_logger_fin(void)898 sen_logger_fin(void)
899 {
900 if (default_logger_fp) {
901 fclose(default_logger_fp);
902 default_logger_fp = NULL;
903 }
904 }
905
906 static sen_logger_info default_logger = {
907 SEN_LOG_DEFAULT_LEVEL,
908 SEN_LOG_TIME|SEN_LOG_MESSAGE,
909 default_logger_func
910 };
911
912 static const sen_logger_info *sen_logger = &default_logger;
913
914 sen_rc
sen_logger_info_set(const sen_logger_info * info)915 sen_logger_info_set(const sen_logger_info *info)
916 {
917 if (info) {
918 sen_logger = info;
919 } else {
920 sen_logger = &default_logger;
921 }
922 return sen_success;
923 }
924
925 int
sen_logger_pass(sen_log_level level)926 sen_logger_pass(sen_log_level level)
927 {
928 return level <= sen_logger->max_level;
929 }
930
931 #define TBUFSIZE SEN_TIMEVAL_STR_SIZE
932 #define MBUFSIZE 0x1000
933 #define LBUFSIZE 0x400
934
935 void
sen_logger_put(sen_log_level level,const char * file,int line,const char * func,char * fmt,...)936 sen_logger_put(sen_log_level level,
937 const char *file, int line, const char *func, char *fmt, ...)
938 {
939 if (level <= sen_logger->max_level) {
940 char tbuf[TBUFSIZE];
941 char mbuf[MBUFSIZE];
942 char lbuf[LBUFSIZE];
943 if (sen_logger->flags & SEN_LOG_TIME) {
944 sen_timeval tv;
945 if (sen_timeval_now(&tv) || sen_timeval2str(&tv, tbuf)) { tbuf[0] = '\0'; }
946 } else {
947 tbuf[0] = '\0';
948 }
949 if (sen_logger->flags & SEN_LOG_MESSAGE) {
950 va_list argp;
951 va_start(argp, fmt);
952 vsnprintf(mbuf, MBUFSIZE - 1, fmt, argp);
953 va_end(argp);
954 mbuf[MBUFSIZE - 1] = '\0';
955 } else {
956 mbuf[0] = '\0';
957 }
958 if (sen_logger->flags & SEN_LOG_LOCATION) {
959 snprintf(lbuf, LBUFSIZE - 1, "%04x %s:%d %s()",
960 getpid(), file, line, func);
961 lbuf[LBUFSIZE - 1] = '\0';
962 } else {
963 lbuf[0] = '\0';
964 }
965 if (sen_logger->func) {
966 sen_logger->func(level, tbuf, "", mbuf, lbuf, sen_logger->func_arg);
967 } else {
968 default_logger_func(level, tbuf, "", mbuf, lbuf, sen_logger->func_arg);
969 }
970 }
971 }
972
973 void
sen_assert(int cond,const char * file,int line,const char * func)974 sen_assert(int cond, const char* file, int line, const char* func)
975 {
976 if (!cond) {
977 SEN_LOG(sen_log_warning, "ASSERT fail on %s %s:%d", func, file, line);
978 }
979 }
980