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