1 /* Copyright(C) 2004-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 #include "senna_in.h"
18 #include "str.h"
19 #include "inv.h"
20 #include "sym.h"
21 #include "store.h"
22 #include "ctx.h"
23 #include <stddef.h>
24 #include <string.h>
25 
26 /* rectangular arrays */
27 
28 #define SEN_RA_IDSTR "SENNA:RA:01.000"
29 #define SEN_RA_SEGMENT_SIZE (1 << 22)
30 
31 #define SEN_RA_MAX_CACHE (4294967295U)
32 
33 sen_ra *
sen_ra_create(const char * path,unsigned int element_size)34 sen_ra_create(const char *path, unsigned int element_size)
35 {
36   sen_io *io;
37   int max_segments, n_elm, w_elm;
38   sen_ra *ra = NULL;
39   struct sen_ra_header *header;
40   unsigned actual_size;
41   if (element_size > SEN_RA_SEGMENT_SIZE) {
42     SEN_LOG(sen_log_error, "element_size too large (%d)", element_size);
43     return NULL;
44   }
45   for (actual_size = 1; actual_size < element_size; actual_size *= 2) ;
46   max_segments = ((SEN_ID_MAX + 1) / SEN_RA_SEGMENT_SIZE) * actual_size;
47   io = sen_io_create(path, sizeof(struct sen_ra_header),
48                      SEN_RA_SEGMENT_SIZE, max_segments, sen_io_auto, SEN_RA_MAX_CACHE);
49   if (!io) { return NULL; }
50   header = sen_io_header(io);
51   memcpy(header->idstr, SEN_RA_IDSTR, 16);
52   header->element_size = actual_size;
53   header->curr_max = 0;
54   if (!(ra = SEN_GMALLOC(sizeof(sen_ra)))) {
55     sen_io_close(io);
56     return NULL;
57   }
58   n_elm = SEN_RA_SEGMENT_SIZE / header->element_size;
59   for (w_elm = 22; (1 << w_elm) > n_elm; w_elm--);
60   ra->io = io;
61   ra->header = header;
62   ra->element_mask =  n_elm - 1;
63   ra->element_width = w_elm;
64   return ra;
65 }
66 
67 sen_ra *
sen_ra_open(const char * path)68 sen_ra_open(const char *path)
69 {
70   sen_io *io;
71   int n_elm, w_elm;
72   sen_ra *ra = NULL;
73   struct sen_ra_header *header;
74   io = sen_io_open(path, sen_io_auto, SEN_RA_MAX_CACHE);
75   if (!io) { return NULL; }
76   header = sen_io_header(io);
77   if (memcmp(header->idstr, SEN_RA_IDSTR, 16)) {
78     SEN_LOG(sen_log_error, "ra_idstr (%s)", header->idstr);
79     sen_io_close(io);
80     return NULL;
81   }
82   if (!(ra = SEN_GMALLOC(sizeof(sen_ra)))) {
83     sen_io_close(io);
84     return NULL;
85   }
86   n_elm = SEN_RA_SEGMENT_SIZE / header->element_size;
87   for (w_elm = 22; (1 << w_elm) > n_elm; w_elm--);
88   ra->io = io;
89   ra->header = header;
90   ra->element_mask =  n_elm - 1;
91   ra->element_width = w_elm;
92   return ra;
93 }
94 
95 sen_rc
sen_ra_info(sen_ra * ra,unsigned int * element_size,sen_id * curr_max)96 sen_ra_info(sen_ra *ra, unsigned int *element_size, sen_id *curr_max)
97 {
98   if (!ra) { return sen_invalid_argument; }
99   if (element_size) { *element_size = ra->header->element_size; }
100   if (curr_max) { *curr_max = ra->header->curr_max; }
101   return sen_success;
102 }
103 
104 sen_rc
sen_ra_close(sen_ra * ra)105 sen_ra_close(sen_ra *ra)
106 {
107   sen_rc rc;
108   if (!ra) { return sen_invalid_argument; }
109   rc = sen_io_close(ra->io);
110   SEN_GFREE(ra);
111   return rc;
112 }
113 
114 sen_rc
sen_ra_remove(const char * path)115 sen_ra_remove(const char *path)
116 {
117   if (!path) { return sen_invalid_argument; }
118   return sen_io_remove(path);
119 }
120 
121 void *
sen_ra_get(sen_ra * ra,sen_id id)122 sen_ra_get(sen_ra *ra, sen_id id)
123 {
124   void *p;
125   uint16_t seg;
126   if (id > SEN_ID_MAX) { return NULL; }
127   seg = id >> ra->element_width;
128   SEN_IO_SEG_MAP(ra->io, seg, p);
129   if (!p) { return NULL; }
130   if (id > ra->header->curr_max) { ra->header->curr_max = id; }
131   return (void *)(((byte *)p) + ((id & ra->element_mask) * ra->header->element_size));
132 }
133 
134 void *
sen_ra_at(sen_ra * ra,sen_id id)135 sen_ra_at(sen_ra *ra, sen_id id)
136 {
137   void *p;
138   uint16_t seg;
139   static char buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
140   if (id > ra->header->curr_max) { return (void *) buf; }
141   seg = id >> ra->element_width;
142   SEN_IO_SEG_MAP(ra->io, seg, p);
143   if (!p) { return NULL; }
144   return (void *)(((byte *)p) + ((id & ra->element_mask) * ra->header->element_size));
145 }
146 
147 /**** jagged arrays ****/
148 
149 #define SEN_JA_MAX_CACHE (4294967295U)
150 #define SEG_NOT_ASSIGNED 0xffffffff
151 
152 #ifdef USE_JA01
153 
154 #define USE_SEG_MAP
155 
156 #define SEN_JA_IDSTR "SENNA:JA:01.000"
157 
158 #define W_OF_JA_MAX 38
159 #define W_OF_JA_SEGMENT 22
160 #define W_OF_JA_MAX_SEGMENTS (W_OF_JA_MAX - W_OF_JA_SEGMENT)
161 
162 #define W_OF_JA_EINFO 3
163 #define W_OF_JA_EINFO_IN_A_SEGMENT (W_OF_JA_SEGMENT - W_OF_JA_EINFO)
164 #define N_OF_JA_EINFO_IN_A_SEGMENT (1U << W_OF_JA_EINFO_IN_A_SEGMENT)
165 #define JA_EINFO_MASK (N_OF_JA_EINFO_IN_A_SEGMENT - 1)
166 
167 #define JA_SEGMENT_SIZE (1U << W_OF_JA_SEGMENT)
168 #define JA_MAX_SEGMENTS (1U << W_OF_JA_MAX_SEGMENTS)
169 
170 #define JA_BSA_SIZE (1U << (W_OF_JA_SEGMENT - 7))
171 #define JA_N_BSEGMENTS (1U << (W_OF_JA_MAX_SEGMENTS - 7))
172 
173 #define JA_N_ESEGMENTS (1U << 9)
174 
175 typedef struct _sen_ja_einfo sen_ja_einfo;
176 
177 struct _sen_ja_einfo {
178   union {
179     uint64_t ll;
180     struct {
181       uint16_t seg;
182       uint16_t pos;
183       uint16_t size;
184       uint8_t tail[2];
185     } s;
186   } u;
187 };
188 
189 #define EINFO_SET(e,_seg,_pos,_size) {\
190   (e)->u.s.seg = _seg;\
191   (e)->u.s.pos = (_pos) >> 4;\
192   (e)->u.s.size = _size;\
193   (e)->u.s.tail[0] = (((_pos) >> 14) & 0xc0) + ((_size) >> 16);\
194   (e)->u.s.tail[1] = 0;\
195 }
196 
197 #define EINFO_GET(e,_seg,_pos,_size) {\
198   _seg = (e)->u.s.seg;\
199   _pos = ((e)->u.s.pos + (((e)->u.s.tail[0] & 0xc0) << 10)) << 4;\
200   _size = (e)->u.s.size + (((e)->u.s.tail[0] & 0x3f) << 16);\
201 }
202 
203 typedef struct {
204   uint32_t seg;
205   uint32_t pos;
206 } ja_pos;
207 
208 struct _sen_ja {
209   sen_io *io;
210   struct sen_ja_header *header;
211 };
212 
213 struct sen_ja_header {
214   char idstr[16];
215   unsigned max_element_size;
216   unsigned max_segments;
217   ja_pos free_elements[24];
218   uint8_t segments[JA_MAX_SEGMENTS];
219   uint32_t esegs[JA_N_ESEGMENTS];
220   uint32_t bsegs[JA_N_BSEGMENTS];
221 };
222 
223 
224 #define JA_SEG_ESEG 1;
225 #define JA_SEG_BSEG 2;
226 
227 sen_ja *
sen_ja_create(const char * path,unsigned int max_element_size)228 sen_ja_create(const char *path, unsigned int max_element_size)
229 {
230   int i;
231   sen_io *io;
232   int max_segments;
233   sen_ja *ja = NULL;
234   struct sen_ja_header *header;
235   if (max_element_size > JA_SEGMENT_SIZE) {
236     SEN_LOG(sen_log_error, "max_element_size too large (%d)", max_element_size);
237     return NULL;
238   }
239   max_segments = max_element_size * 128;
240   if (max_segments > JA_MAX_SEGMENTS) { max_segments = JA_MAX_SEGMENTS; }
241   io = sen_io_create(path, sizeof(struct sen_ja_header),
242                      JA_SEGMENT_SIZE, max_segments, sen_io_auto, SEN_JA_MAX_CACHE);
243   if (!io) { return NULL; }
244   header = sen_io_header(io);
245   memcpy(header->idstr, SEN_JA_IDSTR, 16);
246   for (i = 0; i < JA_N_ESEGMENTS; i++) { header->esegs[i] = SEG_NOT_ASSIGNED; }
247   for (i = 0; i < JA_N_BSEGMENTS; i++) { header->bsegs[i] = SEG_NOT_ASSIGNED; }
248   header->max_element_size = max_element_size;
249   header->max_segments = max_segments;
250   header->segments[0] = JA_SEG_ESEG;
251   header->esegs[0] = 0;
252   if (!(ja = SEN_GMALLOC(sizeof(sen_ja)))) {
253     sen_io_close(io);
254     return NULL;
255   }
256   ja->io = io;
257   ja->header = header;
258   return ja;
259 }
260 
261 sen_ja *
sen_ja_open(const char * path)262 sen_ja_open(const char *path)
263 {
264   sen_io *io;
265   sen_ja *ja = NULL;
266   struct sen_ja_header *header;
267   io = sen_io_open(path, sen_io_auto, SEN_JA_MAX_CACHE);
268   if (!io) { return NULL; }
269   header = sen_io_header(io);
270   if (memcmp(header->idstr, SEN_JA_IDSTR, 16)) {
271     SEN_LOG(sen_log_error, "ja_idstr (%s)", header->idstr);
272     sen_io_close(io);
273     return NULL;
274   }
275   if (!(ja = SEN_GMALLOC(sizeof(sen_ja)))) {
276     sen_io_close(io);
277     return NULL;
278   }
279   ja->io = io;
280   ja->header = header;
281   return ja;
282 }
283 
284 sen_rc
sen_ja_info(sen_ja * ja,unsigned int * max_element_size)285 sen_ja_info(sen_ja *ja, unsigned int *max_element_size)
286 {
287   if (!ja) { return sen_invalid_argument; }
288   if (max_element_size) { *max_element_size = ja->header->max_element_size; }
289   return sen_success;
290 }
291 
292 sen_rc
sen_ja_close(sen_ja * ja)293 sen_ja_close(sen_ja *ja)
294 {
295   sen_rc rc;
296   if (!ja) { return sen_invalid_argument; }
297   rc = sen_io_close(ja->io);
298   SEN_GFREE(ja);
299   return rc;
300 }
301 
302 sen_rc
sen_ja_remove(const char * path)303 sen_ja_remove(const char *path)
304 {
305   if (!path) { return sen_invalid_argument; }
306   return sen_io_remove(path);
307 }
308 
309 void *
sen_ja_ref(sen_ja * ja,sen_id id,uint32_t * value_len)310 sen_ja_ref(sen_ja *ja, sen_id id, uint32_t *value_len)
311 {
312   sen_ja_einfo *einfo;
313   uint32_t lseg, *pseg, pos;
314   lseg = id >> W_OF_JA_EINFO_IN_A_SEGMENT;
315   pos = id & JA_EINFO_MASK;
316   pseg = &ja->header->esegs[lseg];
317   if (*pseg == SEG_NOT_ASSIGNED) { *value_len = 0; return NULL; }
318   SEN_IO_SEG_MAP(ja->io, *pseg, einfo);
319   if (!einfo) { *value_len = 0; return NULL; }
320   if (einfo[pos].u.s.tail[1] & 1) {
321     *value_len = einfo[pos].u.s.tail[1] >> 1;
322     return (void *) &einfo[pos];
323   }
324   {
325     void *value;
326     uint32_t jag, vpos, vsize;
327 #ifdef USE_SEG_MAP
328     EINFO_GET(&einfo[pos], jag, vpos, vsize);
329     SEN_IO_SEG_MAP(ja->io, jag, value);
330     // printf("at id=%d value=%p jag=%d vpos=%d ei=%p(%d:%d)\n", id, value, jag, vpos, &einfo[pos], einfo[pos].u.s.pos, einfo[pos].u.s.tail[0]);
331     if (!value) { *value_len = 0; return NULL; }
332     *value_len = vsize;
333     return (byte *)value + vpos;
334 #else /* USE_SEG_MAP */
335     sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
336     sen_io_win iw;
337     EINFO_GET(&einfo[pos], jag, vpos, vsize);
338     value = sen_io_win_map(ja->io, ctx, &iw, jag, vpos, vsize, sen_io_rdonly);
339     if (!value) { *value_len = 0; return NULL; }
340     *value_len = vsize;
341     return value;
342 #endif /* USE_SEG_MAP */
343   }
344 }
345 
346 sen_rc
sen_ja_unref(sen_ja * ja,sen_id id,void * value,uint32_t value_len)347 sen_ja_unref(sen_ja *ja, sen_id id, void *value, uint32_t value_len)
348 {
349   if (!value) { return sen_invalid_argument; }
350 #ifndef USE_SEG_MAP
351   {
352     sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
353     SEN_FREE(value);
354   }
355 #endif /* USE_SEG_MAP */
356   return sen_success;
357 }
358 
359 sen_rc sen_ja_alloc(sen_ja *ja, int element_size, sen_ja_einfo *einfo, sen_io_win *iw);
360 
361 sen_rc
sen_ja_put(sen_ja * ja,sen_id id,void * value,int value_len,int flags)362 sen_ja_put(sen_ja *ja, sen_id id, void *value, int value_len, int flags)
363 {
364   int rc;
365   sen_io_win iw;
366   sen_ja_einfo einfo;
367   if ((flags & SEN_ST_APPEND)) {
368     if (value_len) {
369       uint32_t old_len;
370       void *oldvalue = sen_ja_ref(ja, id, &old_len);
371       if (oldvalue) {
372 #ifdef USE_SEG_MAP
373         if ((rc = sen_ja_alloc(ja, value_len + old_len, &einfo, &iw))) { return rc; }
374         memcpy(iw.addr, oldvalue, old_len);
375         memcpy((byte *)iw.addr + old_len, value, value_len);
376 #else /* USE_SEG_MAP */
377         void *buf;
378         sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
379         if (!(buf = SEN_MALLOC(old_len + value_len))) { return sen_memory_exhausted; }
380         if ((rc = sen_ja_alloc(ja, old_len + value_len, &einfo, &iw))) {
381           SEN_FREE(buf);
382           return rc;
383         }
384         memcpy(buf, oldvalue, old_len);
385         memcpy((byte *)buf + old_len, value, value_len);
386         iw.addr = buf;
387         sen_io_win_unmap(&iw);
388 #endif /* USE_SEG_MAP */
389         sen_ja_unref(ja, id, oldvalue, old_len);
390       } else {
391 #ifdef USE_SEG_MAP
392         if ((rc = sen_ja_alloc(ja, value_len, &einfo, &iw))) { return rc; }
393         memcpy(iw.addr, value, value_len);
394 #else /* USE_SEG_MAP */
395         sen_io_win iw;
396         if ((rc = sen_ja_alloc(ja, value_len, &einfo, &iw))) { return rc; }
397         iw.addr = value;
398         sen_io_win_unmap(&iw);
399 #endif /* USE_SEG_MAP */
400       }
401     }
402   } else {
403     if (value_len) {
404 #ifdef USE_SEG_MAP
405       if ((rc = sen_ja_alloc(ja, value_len, &einfo, &iw))) { return rc; }
406       // printf("put id=%d, value_len=%d value=%p ei=%p(%d:%d)\n", id, value_len, buf, &einfo, einfo.u.s.pos, einfo.u.s.tail[0]);
407       memcpy(iw.addr, value, value_len);
408 #else /* USE_SEG_MAP */
409       sen_io_win iw;
410       if ((rc = sen_ja_alloc(ja, value_len, &einfo, &iw))) { return rc; }
411       iw.addr = value;
412       sen_io_win_unmap(&iw);
413 #endif /* USE_SEG_MAP */
414     } else {
415       memset(&einfo, 0, sizeof(sen_ja_einfo));
416     }
417   }
418   return sen_ja_replace(ja, id, &einfo);
419 }
420 
421 int
sen_ja_size(sen_ja * ja,sen_id id)422 sen_ja_size(sen_ja *ja, sen_id id)
423 {
424   sen_ja_einfo *einfo;
425   uint32_t lseg, *pseg, pos;
426   lseg = id >> W_OF_JA_EINFO_IN_A_SEGMENT;
427   pos = id & JA_EINFO_MASK;
428   pseg = &ja->header->esegs[lseg];
429   if (*pseg == SEG_NOT_ASSIGNED) { return -1; }
430   SEN_IO_SEG_MAP(ja->io, *pseg, einfo);
431   if (!einfo) { return -1; }
432   if (einfo[pos].u.s.tail[1] & 1) {
433     return einfo[pos].u.s.tail[1] >> 1;
434   } else {
435     return einfo[pos].u.s.size + ((einfo[pos].u.s.tail[0] & 0x3f) << 16);
436   }
437 }
438 
439 sen_rc
sen_ja_alloc(sen_ja * ja,int element_size,sen_ja_einfo * einfo,sen_io_win * iw)440 sen_ja_alloc(sen_ja *ja, int element_size, sen_ja_einfo *einfo, sen_io_win *iw)
441 {
442   int m, size;
443   ja_pos *vp;
444 #ifdef USE_SEG_MAP
445   void *addr;
446   if (element_size < 8) {
447     einfo->u.s.tail[1] = element_size * 2 + 1;
448     iw->addr = (void *)einfo;
449     return sen_success;
450   }
451 #endif /* USE_SEG_MAP */
452   if (element_size >= ja->header->max_element_size) {
453     return sen_invalid_argument;
454   }
455   for (m = 4, size = 16; size < element_size; m++, size *= 2);
456   vp = &ja->header->free_elements[m];
457   if (!vp->seg) {
458     int i = 0;
459     while (ja->header->segments[i]) {
460       if (++i >= ja->header->max_segments) { return sen_memory_exhausted; }
461     }
462     ja->header->segments[i] = m;
463     vp->seg = i;
464     vp->pos = 0;
465   }
466   EINFO_SET(einfo, vp->seg, vp->pos, element_size);
467 #ifdef USE_SEG_MAP
468   SEN_IO_SEG_MAP(ja->io, vp->seg, addr);
469   // printf("addr=%p seg=%d pos=%d\n", addr, vp->seg, vp->pos);
470   if (!addr) { return sen_memory_exhausted; }
471   iw->addr = (byte *)addr + vp->pos;
472 #else /* USE_SEG_MAP */
473   iw->io = ja->io;
474   iw->ctx = &sen_gctx;
475   iw->mode = sen_io_wronly;
476   iw->segment = vp->seg;
477   iw->offset = vp->pos;
478   iw->size = element_size;
479   iw->cached = 1;
480   {
481     int fno, base;
482     uint32_t nseg, bseg;
483     uint32_t segment_size = JA_SEGMENT_SIZE;
484     uint32_t segments_per_file = SEN_IO_FILE_SIZE / segment_size;
485     nseg = (iw->offset + element_size + segment_size - 1) / segment_size;
486     bseg = iw->segment + ja->io->base_seg;
487     fno = bseg / segments_per_file;
488     base = fno ? 0 : ja->io->base - ja->io->base_seg * segment_size;
489     iw->pos = (bseg % segments_per_file) * segment_size + iw->offset + base;
490     iw->nseg = nseg;
491   }
492 #endif /* USE_SEG_MAP */
493   if ((vp->pos += size) == JA_SEGMENT_SIZE) {
494     vp->seg = 0;
495     vp->pos = 0;
496   }
497   return sen_success;
498 }
499 
500 sen_rc
sen_ja_free(sen_ja * ja,sen_ja_einfo * einfo)501 sen_ja_free(sen_ja *ja, sen_ja_einfo *einfo)
502 {
503   uint32_t seg, pos, size;
504   if (einfo->u.s.tail[1] & 1) { return sen_success; }
505   EINFO_GET(einfo, seg, pos, size);
506   // free
507   return sen_success;
508 }
509 
510 sen_rc
sen_ja_replace(sen_ja * ja,sen_id id,sen_ja_einfo * ei)511 sen_ja_replace(sen_ja *ja, sen_id id, sen_ja_einfo *ei)
512 {
513   uint32_t lseg, *pseg, pos;
514   sen_ja_einfo *einfo, eback;
515   lseg = id >> W_OF_JA_EINFO_IN_A_SEGMENT;
516   pos = id & JA_EINFO_MASK;
517   pseg = &ja->header->esegs[lseg];
518   if (*pseg == SEG_NOT_ASSIGNED) {
519     int i = 0;
520     while (ja->header->segments[i]) {
521       if (++i >= ja->header->max_segments) { return sen_memory_exhausted; }
522     }
523     ja->header->segments[i] = 1;
524     *pseg = i;
525   }
526   SEN_IO_SEG_MAP(ja->io, *pseg, einfo);
527   if (!einfo) { return sen_memory_exhausted; }
528   eback = einfo[pos];
529   einfo[pos] = *ei;
530   SEN_SET_64BIT(&einfo[pos], *ei);
531   sen_ja_free(ja, &eback);
532   return sen_success;
533 }
534 
535 #else /* USE_JA01 */
536 
537 #define SEN_JA_IDSTR "SENNA:JA:02.000"
538 
539 struct _sen_ja {
540   sen_io *io;
541   struct sen_ja_header *header;
542   uint32_t *dsegs;
543   uint32_t *esegs;
544 };
545 
546 struct sen_ja_header {
547   char idstr[16];
548   uint32_t flags;
549   uint32_t align_width;
550   uint32_t segment_width;
551   uint32_t element_size;
552   uint32_t curr_pos;
553 };
554 
555 #define SEN_JA_DEFAULT_ALIGN_WIDTH    4
556 #define SEN_JA_DEFAULT_SEGMENT_WIDTH 20
557 
558 #define JA_SEGMENT_SIZE (1 << SEN_JA_DEFAULT_SEGMENT_WIDTH)
559 
560 #define JA_ALIGN_WIDTH (ja->header->align_width)
561 #define JA_ALIGN_MASK ((1U << JA_ALIGN_WIDTH) - 1)
562 
563 #define JA_DSEG_WIDTH (ja->header->segment_width)
564 #define JA_DSEG_MASK ((1U << JA_DSEG_WIDTH) - 1)
565 
566 #define JA_ESEG_WIDTH (JA_DSEG_WIDTH - 3)
567 #define JA_ESEG_MASK ((1U << JA_ESEG_WIDTH) - 1)
568 
569 #define JA_EPOS_WIDTH (JA_DSEG_WIDTH - JA_ALIGN_WIDTH)
570 #define JA_EPOS_MASK ((1U << JA_EPOS_WIDTH) - 1)
571 
572 // segment_width, align_width, flags
573 sen_ja *
sen_ja_create(const char * path,unsigned int max_element_size,uint32_t flags)574 sen_ja_create(const char *path, unsigned int max_element_size, uint32_t flags)
575 {
576   int i;
577   sen_io *io;
578   sen_ja *ja;
579   struct sen_ja_header *header;
580   uint32_t align_width = SEN_JA_DEFAULT_ALIGN_WIDTH;
581   uint32_t segment_width = SEN_JA_DEFAULT_SEGMENT_WIDTH;
582   uint32_t max_dsegs = 1 << (32 - (segment_width - align_width));
583   uint32_t max_esegs = 1 << (31 - segment_width);
584   if (align_width > segment_width || align_width + 32 < segment_width) {
585     SEN_LOG(sen_log_error, "invalid align_width, segment_width value");
586     return NULL;
587   }
588   io = sen_io_create(path,
589                      sizeof(struct sen_ja_header) +
590                      max_dsegs * sizeof(int32_t) +
591                      max_esegs * sizeof(int32_t),
592                      1 << segment_width, max_dsegs, sen_io_auto, SEN_JA_MAX_CACHE);
593   if (!io) { return NULL; }
594   header = sen_io_header(io);
595   memcpy(header->idstr, SEN_JA_IDSTR, 16);
596   header->flags = flags;
597   header->align_width = align_width;
598   header->segment_width = segment_width;
599   header->element_size = max_element_size;
600   header->curr_pos = 0;
601   if (!(ja = SEN_GMALLOC(sizeof(sen_ja)))) {
602     sen_io_close(io);
603     return NULL;
604   }
605   ja->io = io;
606   ja->header = header;
607   ja->dsegs = (uint32_t *)(((uintptr_t) header) + sizeof(struct sen_ja_header));
608   ja->esegs = &ja->dsegs[max_dsegs];
609   for (i = 0; i < max_esegs; i++) { ja->esegs[i] = SEG_NOT_ASSIGNED; }
610   return ja;
611 }
612 
613 sen_ja *
sen_ja_open(const char * path)614 sen_ja_open(const char *path)
615 {
616   sen_io *io;
617   sen_ja *ja = NULL;
618   struct sen_ja_header *header;
619   io = sen_io_open(path, sen_io_auto, SEN_JA_MAX_CACHE);
620   if (!io) { return NULL; }
621   header = sen_io_header(io);
622   if (memcmp(header->idstr, SEN_JA_IDSTR, 16)) {
623     SEN_LOG(sen_log_error, "ja_idstr (%s)", header->idstr);
624     sen_io_close(io);
625     return NULL;
626   }
627   if (!(ja = SEN_GMALLOC(sizeof(sen_ja)))) {
628     sen_io_close(io);
629     return NULL;
630   }
631   ja->io = io;
632   ja->header = header;
633   ja->dsegs = (uint32_t *)(((uintptr_t) header) + sizeof(struct sen_ja_header));
634   ja->esegs = &ja->dsegs[1 << (32 - JA_EPOS_WIDTH)];
635   return ja;
636 }
637 
638 sen_rc
sen_ja_info(sen_ja * ja,unsigned int * max_element_size)639 sen_ja_info(sen_ja *ja, unsigned int *max_element_size)
640 {
641   if (!ja) { return sen_invalid_argument; }
642   if (max_element_size) { *max_element_size = 4294967295U; }
643   return sen_success;
644 }
645 
646 sen_rc
sen_ja_close(sen_ja * ja)647 sen_ja_close(sen_ja *ja)
648 {
649   sen_rc rc;
650   if (!ja) { return sen_invalid_argument; }
651   rc = sen_io_close(ja->io);
652   SEN_GFREE(ja);
653   return rc;
654 }
655 
656 sen_rc
sen_ja_remove(const char * path)657 sen_ja_remove(const char *path)
658 {
659   if (!path) { return sen_invalid_argument; }
660   return sen_io_remove(path);
661 }
662 
663 inline static void *
sen_ja_ref_raw(sen_ja * ja,sen_id id,uint32_t * value_len)664 sen_ja_ref_raw(sen_ja *ja, sen_id id, uint32_t *value_len)
665 {
666   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
667   sen_io_ja_einfo *ep;
668   uint32_t lseg = id >> JA_ESEG_WIDTH;
669   uint32_t lpos = id & JA_ESEG_MASK;
670   uint32_t *pseg = &ja->esegs[lseg];
671   if (*pseg == SEG_NOT_ASSIGNED) { *value_len = 0; return NULL; }
672   SEN_IO_SEG_MAP(ja->io, *pseg, ep);
673   if (!ep) { *value_len = 0; return NULL; }
674   ep += lpos;
675   for (;;) {
676     void *value;
677     uint32_t epos = ep->pos;
678     uint32_t dseg = epos >> JA_EPOS_WIDTH;
679     uint32_t doff = (epos & JA_EPOS_MASK) << JA_ALIGN_WIDTH;
680     if (!(*value_len = ep->size)) { return NULL; }
681     if (sen_io_read_ja(ja->io, ctx, ep, epos, id, dseg, doff, &value, value_len)
682         != sen_internal_error) {
683       return value;
684     }
685   }
686 }
687 
688 #ifndef NO_ZLIB
689 #include <zlib.h>
690 
691 inline static void *
sen_ja_ref_zlib(sen_ja * ja,sen_id id,uint32_t * value_len)692 sen_ja_ref_zlib(sen_ja *ja, sen_id id, uint32_t *value_len)
693 {
694   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
695   z_stream zstream;
696   void *value, *zvalue;
697   uint32_t zvalue_len = *value_len + sizeof (uint64_t);
698   if (!(zvalue = sen_ja_ref_raw(ja, id, &zvalue_len))) { *value_len = 0; return NULL; }
699   zstream.next_in = (Bytef *)((uint64_t *)zvalue + 1);
700   zstream.avail_in = zvalue_len - sizeof (uint64_t);
701   zstream.zalloc = Z_NULL;
702   zstream.zfree = Z_NULL;
703   if (inflateInit2(&zstream, 15 /* windowBits */) != Z_OK) {
704     SEN_FREE((sen_io_ja_ehead *)zvalue - 1);
705     *value_len = 0;
706     return NULL;
707   }
708   if (!(value = SEN_MALLOC(*(uint64_t *)zvalue + sizeof (sen_io_ja_ehead)))) {
709     inflateEnd(&zstream);
710     SEN_FREE((sen_io_ja_ehead *)zvalue - 1);
711     *value_len = 0;
712     return NULL;
713   }
714   zstream.next_out = (Bytef *)((sen_io_ja_ehead *)value + 1);
715   zstream.avail_out = *(uint64_t *)zvalue;
716   if (inflate(&zstream, Z_FINISH) != Z_STREAM_END) {
717     inflateEnd(&zstream);
718     SEN_FREE(value);
719     SEN_FREE((sen_io_ja_ehead *)zvalue - 1);
720     *value_len = 0;
721     return NULL;
722   }
723   *value_len = zstream.total_out;
724   if (inflateEnd(&zstream) != Z_OK) {
725     SEN_FREE(value);
726     SEN_FREE((sen_io_ja_ehead *)zvalue - 1);
727     *value_len = 0;
728     return NULL;
729   }
730   *(sen_io_ja_ehead *)value = ((sen_io_ja_ehead *)zvalue)[-1];
731   SEN_FREE((sen_io_ja_ehead *)zvalue - 1);
732   return (sen_io_ja_ehead *)value + 1;
733 }
734 #endif /* NO_ZLIB */
735 
736 #ifndef NO_LZO
737 #include <lzo/lzo1x.h>
738 
739 inline static void *
sen_ja_ref_lzo(sen_ja * ja,sen_id id,uint32_t * value_len)740 sen_ja_ref_lzo(sen_ja *ja, sen_id id, uint32_t *value_len)
741 {
742   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
743   void *value, *lvalue;
744   uint32_t lvalue_len = *value_len + sizeof (uint64_t);
745   lzo_uint loutlen;
746   if (!(lvalue = sen_ja_ref_raw(ja, id, &lvalue_len))) { *value_len = 0; return NULL; }
747   if (!(value = SEN_MALLOC(*(uint64_t *)lvalue + sizeof (sen_io_ja_ehead)))) {
748     SEN_FREE((sen_io_ja_ehead *)lvalue - 1);
749     *value_len = 0;
750     return NULL;
751   }
752   loutlen = *(uint64_t *)lvalue;
753   switch (lzo1x_decompress((lzo_bytep)((uint64_t *)lvalue + 1), lvalue_len - sizeof (uint64_t),
754                            (lzo_bytep)((sen_io_ja_ehead *)value + 1), &loutlen, NULL)) {
755   case LZO_E_OK :
756   case LZO_E_INPUT_NOT_CONSUMED :
757     break;
758   default :
759     SEN_FREE(value);
760     SEN_FREE((sen_io_ja_ehead *)lvalue - 1);
761     *value_len = 0;
762     return NULL;
763   }
764   *value_len = loutlen;
765   *(sen_io_ja_ehead *)value = ((sen_io_ja_ehead *)lvalue)[-1];
766   SEN_FREE((sen_io_ja_ehead *)lvalue - 1);
767   return (sen_io_ja_ehead *)value + 1;
768 }
769 #endif /* NO_LZO */
770 
771 void *
sen_ja_ref(sen_ja * ja,sen_id id,uint32_t * value_len)772 sen_ja_ref(sen_ja *ja, sen_id id, uint32_t *value_len)
773 {
774 #ifndef NO_ZLIB
775   if (ja->header->flags & SEN_JA_ZLIB) {
776     return sen_ja_ref_zlib(ja, id, value_len);
777   }
778 #endif /* NO_ZLIB */
779 #ifndef NO_LZO
780   if (ja->header->flags & SEN_JA_LZO) {
781     return sen_ja_ref_lzo(ja, id, value_len);
782   }
783 #endif /* NO_LZO */
784   return sen_ja_ref_raw(ja, id, value_len);
785 }
786 
787 sen_rc
sen_ja_unref(sen_ja * ja,sen_id id,void * value,uint32_t value_len)788 sen_ja_unref(sen_ja *ja, sen_id id, void *value, uint32_t value_len)
789 {
790   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
791   SEN_FREE((void *)(((uintptr_t) value) - sizeof(sen_io_ja_ehead)));
792   return sen_success;
793 }
794 
795 #define SEG_ESEG 0xffffffff
796 
797 sen_rc
assign_eseg(sen_ja * ja,uint32_t lseg)798 assign_eseg(sen_ja *ja, uint32_t lseg)
799 {
800   int i;
801   uint32_t max_dsegs = 1 << (32 - JA_EPOS_WIDTH);
802   for (i = 0; i < max_dsegs; i++) {
803     if (ja->dsegs[i] == 0) {
804       if (ja->header->curr_pos && i == (ja->header->curr_pos >> JA_EPOS_WIDTH)) {
805         // todo : curr_pos must be moved.
806       }
807       ja->dsegs[i] = SEG_ESEG;
808       ja->esegs[lseg] = i;
809       return sen_success;
810     }
811   }
812   return sen_internal_error;
813 }
814 
815 static sen_rc
assign_rec(sen_ja * ja,int value_len)816 assign_rec(sen_ja *ja, int value_len)
817 {
818   if (ja->header->curr_pos) {
819     uint32_t doff = (ja->header->curr_pos & JA_EPOS_MASK) << JA_ALIGN_WIDTH;
820     if (doff + value_len + sizeof(sen_io_ja_ehead) <= (1 << JA_DSEG_WIDTH)) {
821       return sen_success;
822     }
823   }
824   {
825     uint32_t max_dsegs = 1 << (32 - JA_EPOS_WIDTH);
826     /* if (value_len <= JA_DSEG_MASK) { todo : } else */
827     {
828       uint32_t i, j;
829       uint32_t nseg = (value_len + sizeof(sen_io_ja_ehead) + JA_DSEG_MASK) >> JA_DSEG_WIDTH;
830       for (i = 0, j = 0; i < max_dsegs; i++) {
831         if (ja->dsegs[i] == 0) {
832           if (++j == nseg) {
833             ja->header->curr_pos = (i + 1 - j) << JA_EPOS_WIDTH;
834             return sen_success;
835           }
836         } else {
837           j = 0;
838         }
839       }
840     }
841     return sen_other_error;
842   }
843 }
844 
845 inline static sen_rc
sen_ja_put_raw(sen_ja * ja,sen_id id,void * value,int value_len,int flags)846 sen_ja_put_raw(sen_ja *ja, sen_id id, void *value, int value_len, int flags)
847 {
848   sen_rc rc = sen_success;
849   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
850   uint32_t newpos = 0;
851   sen_io_ja_einfo *ep;
852   {
853     uint32_t lseg = id >> JA_ESEG_WIDTH;
854     uint32_t lpos = id & JA_ESEG_MASK;
855     uint32_t *pseg = &ja->esegs[lseg];
856     if (*pseg == SEG_NOT_ASSIGNED && (rc = assign_eseg(ja, lseg))) { return rc; }
857     SEN_IO_SEG_MAP(ja->io, *pseg, ep);
858     if (!ep) { return sen_other_error; }
859     ep += lpos;
860   }
861   if (value_len) {
862     uint32_t dseg, doff, inc;
863     if ((rc = assign_rec(ja, value_len))) { return rc; }
864     newpos = ja->header->curr_pos;
865     dseg = newpos >> JA_EPOS_WIDTH;
866     doff = (newpos & JA_EPOS_MASK) << JA_ALIGN_WIDTH;
867     rc = sen_io_write_ja(ja->io, ctx, id, dseg, doff, value, value_len);
868     if (rc) { return rc; }
869     inc = ((value_len + sizeof(sen_io_ja_ehead) + JA_ALIGN_MASK) >> JA_ALIGN_WIDTH);
870     ja->header->curr_pos = ((newpos + inc) & JA_EPOS_MASK) ? (newpos + inc) : 0;
871     {
872       uint32_t max = 1U << JA_EPOS_WIDTH;
873       while (ja->dsegs[dseg] + inc > max) {
874         inc -= max - ja->dsegs[dseg];
875         ja->dsegs[dseg++] = max;
876       }
877       ja->dsegs[dseg] += inc;
878     }
879   }
880   {
881     sen_io_ja_einfo ne, oe;
882     oe = *ep;
883     ne.pos = newpos;
884     ne.size = value_len;
885     *ep = ne; // atomic_set64 maybe more suitable.
886     if (oe.size) {
887       uint32_t dseg, off, dec, max = 1U << JA_EPOS_WIDTH;
888       dseg = oe.pos >> JA_EPOS_WIDTH;
889       off = (oe.pos & JA_EPOS_MASK);
890       dec = ((oe.size + sizeof(sen_io_ja_ehead) + JA_ALIGN_MASK) >> JA_ALIGN_WIDTH);
891       if (off + dec > max) {
892         dec -= max - off;
893         ja->dsegs[dseg++] -= max - off;
894         while (dec > max) {
895           dec -= max;
896           ja->dsegs[dseg++] = 0;
897         }
898         {
899           uint32_t vsize = (dec << JA_ALIGN_WIDTH) - sizeof(sen_io_ja_ehead);
900           rc = sen_io_write_ja_ehead(ja->io, ctx, 0, dseg, 0, vsize);
901           // todo : handle rc..
902         }
903       }
904       ja->dsegs[dseg] -= dec;
905     }
906   }
907   return rc;
908 }
909 
910 #ifndef NO_ZLIB
911 inline static sen_rc
sen_ja_put_zlib(sen_ja * ja,sen_id id,void * value,int value_len,int flags)912 sen_ja_put_zlib(sen_ja *ja, sen_id id, void *value, int value_len, int flags)
913 {
914   sen_rc rc;
915   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
916   z_stream zstream;
917   void *zvalue;
918   int zvalue_len;
919   zstream.next_in = value;
920   zstream.avail_in = value_len;
921   zstream.zalloc = Z_NULL;
922   zstream.zfree = Z_NULL;
923   if (deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 /* windowBits */,
924                    8 /* memLevel */, Z_DEFAULT_STRATEGY) != Z_OK) { return sen_other_error; }
925   zvalue_len = deflateBound(&zstream, value_len);
926   if (!(zvalue = SEN_MALLOC(zvalue_len + sizeof (uint64_t)))) { deflateEnd(&zstream); return sen_memory_exhausted; }
927   zstream.next_out = (Bytef *)((uint64_t *)zvalue + 1);
928   zstream.avail_out = zvalue_len;
929   if (deflate(&zstream, Z_FINISH) != Z_STREAM_END) {
930     deflateEnd(&zstream);
931     SEN_FREE(zvalue);
932     return sen_other_error;
933   }
934   zvalue_len = zstream.total_out;
935   if (deflateEnd(&zstream) != Z_OK) { SEN_FREE(zvalue); return sen_other_error; }
936   *(uint64_t *)zvalue = value_len;
937   rc = sen_ja_put_raw(ja, id, zvalue, zvalue_len + sizeof (uint64_t), flags);
938   SEN_FREE(zvalue);
939   return rc;
940 }
941 #endif /* NO_ZLIB */
942 
943 #ifndef NO_LZO
944 inline static sen_rc
sen_ja_put_lzo(sen_ja * ja,sen_id id,void * value,int value_len,int flags)945 sen_ja_put_lzo(sen_ja *ja, sen_id id, void *value, int value_len, int flags)
946 {
947   sen_rc rc;
948   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
949   void *lvalue, *lwork;
950   lzo_uint lvalue_len = value_len + value_len / 16 + 64 + 3;
951   if (!(lvalue = SEN_MALLOC(lvalue_len + sizeof (uint64_t)))) { return sen_memory_exhausted; }
952   if (!(lwork = SEN_MALLOC(LZO1X_1_MEM_COMPRESS))) { SEN_FREE(lvalue); return sen_memory_exhausted; }
953   if (lzo1x_1_compress(value, value_len, (lzo_bytep)((uint64_t *)lvalue + 1), &lvalue_len, lwork) != LZO_E_OK) {
954     SEN_FREE(lwork);
955     SEN_FREE(lvalue);
956     return sen_other_error;
957   }
958   SEN_FREE(lwork);
959   *(uint64_t *)lvalue = value_len;
960   rc = sen_ja_put_raw(ja, id, lvalue, lvalue_len + sizeof (uint64_t), flags);
961   SEN_FREE(lvalue);
962   return rc;
963 }
964 #endif /* NO_LZO */
965 
966 sen_rc
sen_ja_put(sen_ja * ja,sen_id id,void * value,int value_len,int flags)967 sen_ja_put(sen_ja *ja, sen_id id, void *value, int value_len, int flags)
968 {
969 #ifndef NO_ZLIB
970   if (ja->header->flags & SEN_JA_ZLIB) {
971     return sen_ja_put_zlib(ja, id, value, value_len, flags);
972   }
973 #endif /* NO_ZLIB */
974 #ifndef NO_LZO
975   if (ja->header->flags & SEN_JA_LZO) {
976     return sen_ja_put_lzo(ja, id, value, value_len, flags);
977   }
978 #endif /* NO_LZO */
979   return sen_ja_put_raw(ja, id, value, value_len, flags);
980 }
981 
982 static sen_rc
sen_ja_defrag_seg(sen_ja * ja,uint32_t dseg)983 sen_ja_defrag_seg(sen_ja *ja, uint32_t dseg)
984 {
985   sen_rc rc = sen_success;
986   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
987   sen_io_win iw;
988   uint32_t epos = dseg << JA_EPOS_WIDTH;
989   uint32_t segsize = (1 << JA_DSEG_WIDTH);
990   byte *v = sen_io_win_map(ja->io, ctx, &iw, dseg, 0, segsize, sen_io_rdonly);
991   byte *ve = v + segsize;
992   uint32_t *segusage = &ja->dsegs[dseg];
993   if (!v) { return sen_internal_error; }
994   while (v < ve && *segusage) {
995     sen_io_ja_ehead *eh = (sen_io_ja_ehead *) v;
996     uint32_t inc = ((eh->size + sizeof(sen_io_ja_ehead) + JA_ALIGN_MASK) >> JA_ALIGN_WIDTH);
997     sen_io_ja_einfo *ep;
998     uint32_t lseg = eh->key >> JA_ESEG_WIDTH;
999     uint32_t lpos = eh->key & JA_ESEG_MASK;
1000     uint32_t *pseg = &ja->esegs[lseg];
1001     if (*pseg == SEG_NOT_ASSIGNED) {
1002       SEN_LOG(sen_log_error, "ep is not assigned (%x)", lseg);
1003       rc = sen_internal_error;
1004       goto exit;
1005     }
1006     SEN_IO_SEG_MAP(ja->io, *pseg, ep);
1007     if (!ep) {
1008       SEN_LOG(sen_log_error, "ep map failed (%x)", lseg);
1009       rc = sen_internal_error;
1010       goto exit;
1011     }
1012     ep += lpos;
1013     if (ep->pos == epos) {
1014       if (ep->size != eh->size) {
1015         SEN_LOG(sen_log_error, "ep->size(%d) != eh->size(%d)", ep->size, eh->size);
1016         rc = sen_internal_error;
1017         goto exit;
1018       }
1019       if ((rc = sen_ja_put(ja, eh->key, v + sizeof(sen_io_ja_ehead), eh->size, 0))) {
1020         goto exit;
1021       }
1022     }
1023     epos += inc;
1024     v += (inc << JA_ALIGN_WIDTH);
1025   }
1026   if (*segusage) {
1027     SEN_LOG(sen_log_error, "ja->dsegs[dseg] = %d after defrag", ja->dsegs[dseg]);
1028     rc = sen_internal_error;
1029   }
1030 exit :
1031   sen_io_win_unmap(&iw);
1032   return rc;
1033 }
1034 
1035 int
sen_ja_defrag(sen_ja * ja,int threshold)1036 sen_ja_defrag(sen_ja *ja, int threshold)
1037 {
1038   int nsegs = 0;
1039   uint32_t ts = 1U << (JA_EPOS_WIDTH - threshold);
1040   uint32_t dseg, max_dsegs = 1 << (32 - JA_EPOS_WIDTH);
1041   for (dseg = 0; dseg < max_dsegs; dseg++) {
1042     if (dseg == ja->header->curr_pos >> JA_EPOS_WIDTH) { continue; }
1043     if (ja->dsegs[dseg] && ja->dsegs[dseg] < ts) {
1044       if (!sen_ja_defrag_seg(ja, dseg)) { nsegs++; }
1045     }
1046   }
1047   return nsegs;
1048 }
1049 
1050 #endif /* USE_JA01 */
1051 
1052 /**** db ****/
1053 
1054 sen_rc
sen_db_lock(sen_db * s,int timeout)1055 sen_db_lock(sen_db *s, int timeout)
1056 {
1057   return sen_sym_lock(s->keys, timeout);
1058 }
1059 
1060 sen_rc
sen_db_unlock(sen_db * s)1061 sen_db_unlock(sen_db *s)
1062 {
1063   return sen_sym_unlock(s->keys);
1064 }
1065 
1066 sen_rc
sen_db_clear_lock(sen_db * s)1067 sen_db_clear_lock(sen_db *s)
1068 {
1069   return sen_sym_clear_lock(s->keys);
1070 }
1071 
1072 inline static void
gen_pathname(const char * path,char * buffer,int fno)1073 gen_pathname(const char *path, char *buffer, int fno)
1074 {
1075   size_t len = strlen(path);
1076   memcpy(buffer, path, len);
1077   if (fno >= 0) {
1078     buffer[len] = '.';
1079     sen_str_itoh(fno, buffer + len + 1, 7);
1080   } else {
1081     buffer[len] = '\0';
1082   }
1083 }
1084 
1085 sen_db_store *
sen_db_store_by_id(sen_db * s,sen_id id)1086 sen_db_store_by_id(sen_db *s, sen_id id)
1087 {
1088   const char *name;
1089   sen_db_store *slot;
1090   if (!id) { return NULL; }
1091   slot = sen_array_at(&s->stores, id);
1092   if (slot->type) { return slot; }
1093   if (!(name = _sen_sym_key(s->keys, id))) { return NULL; }
1094   return sen_db_store_open(s, name);
1095 }
1096 
1097 // todo : slot should has cache class id
1098 sen_db_store *
sen_db_slot_class(sen_db * s,const char * slot)1099 sen_db_slot_class(sen_db *s, const char *slot)
1100 {
1101   int i = SEN_SYM_MAX_KEY_SIZE;
1102   char buf[SEN_SYM_MAX_KEY_SIZE], *dst = buf;
1103   while (*slot != '.') {
1104     if (!*slot || !--i) { return NULL; }
1105     *dst++ = *slot++;
1106   }
1107   *dst = '\0';
1108   return sen_db_store_open(s, buf);
1109 }
1110 
1111 sen_rc
sen_db_idx_slot_build(sen_db * s,sen_db_store * store)1112 sen_db_idx_slot_build(sen_db *s, sen_db_store *store)
1113 {
1114   sen_inv *inv = store->u.i.inv;
1115   sen_db_store *k = sen_db_store_by_id(s, store->u.i.class); // todo: support surrogate class
1116   sen_id id = SEN_SYM_NIL; /* maxid = sen_sym_curr_id(index->keys); */
1117   sen_db_store *target = sen_db_store_by_id(s, store->triggers->target);
1118   if (!k || !target) { return sen_invalid_argument; }
1119   while ((id = sen_sym_next(k->u.c.keys, id))) {
1120     uint32_t vs;
1121     void *vp = (void *)sen_ja_ref(target->u.v.ja, id, &vs);
1122     if (vp) {
1123       if (vs && sen_inv_upd(inv, id, NULL, NULL, 0, vp, vs)) {
1124         SEN_LOG(sen_log_error, "sen_inv_upd failed. id=%d", id);
1125       }
1126       sen_ja_unref(target->u.v.ja, id, vp, vs);
1127     }
1128   }
1129   return sen_success;
1130 }
1131 
1132 sen_db_store *
sen_db_store_open(sen_db * s,const char * name)1133 sen_db_store_open(sen_db *s, const char *name)
1134 {
1135   sen_id id;
1136   uint32_t spec_len;
1137   sen_db_store *e, *k, *l, *r = NULL;
1138   char buffer[PATH_MAX];
1139   sen_db_store_spec *spec;
1140   if (!s || !(id = sen_sym_at(s->keys, name))) {
1141     return NULL;
1142   }
1143   if (!(e = sen_array_at(&s->stores, id))) { return NULL; }
1144   if (e->type) { return e; }
1145 
1146   if (!(spec = sen_ja_ref(s->values, id, &spec_len))) {
1147     return NULL;
1148   }
1149   if (spec->type == sen_db_idx_slot) {
1150     if (!(k = sen_db_store_by_id(s, spec->u.s.class)) ||
1151         !(l = sen_db_slot_class(s, name))) {
1152       sen_ja_unref(s->values, id, spec, spec_len);
1153       return NULL;
1154     }
1155   }
1156   MUTEX_LOCK(s->lock);
1157   e->db = s;
1158   e->id = id;
1159   e->triggers = NULL;
1160   gen_pathname(s->keys->io->path, buffer, id);
1161   switch (spec->type) {
1162   case sen_db_raw_class :
1163     e->u.bc.element_size = spec->u.c.size;
1164     break;
1165   case sen_db_class :
1166     if (!(e->u.c.keys = sen_sym_open(buffer))) { goto exit; }
1167     break;
1168   case sen_db_obj_slot :
1169     e->u.o.class = spec->u.s.class;
1170     if (!(e->u.o.ra = sen_ra_open(buffer))) { goto exit; }
1171     break;
1172   case sen_db_ra_slot :
1173     e->u.f.class = spec->u.s.class;
1174     if (!(e->u.f.ra = sen_ra_open(buffer))) { goto exit; }
1175     break;
1176   case sen_db_ja_slot :
1177     e->u.v.class = spec->u.s.class;
1178     if (!(e->u.v.ja = sen_ja_open(buffer))) { goto exit; }
1179     break;
1180   case sen_db_idx_slot :
1181     e->u.i.class = spec->u.s.class;
1182     if (!(e->u.i.inv = sen_inv_open(buffer, l->u.c.keys))) { goto exit; }
1183     break;
1184   case sen_db_rel1 :
1185     e->u.f.class = spec->u.s.class;
1186     if (!(e->u.f.ra = sen_ra_open(buffer))) { goto exit; }
1187     break;
1188   default :
1189     goto exit;
1190   }
1191   {
1192     int i;
1193     for (i = 0; i < spec->n_triggers; i++) {
1194       sen_id target = spec->triggers[i].target;
1195       if (target) {
1196         sen_db_trigger *r = SEN_GMALLOC(sizeof(sen_db_trigger));
1197         if (!r) { goto exit; }
1198         r->next = e->triggers;
1199         r->type = spec->triggers[i].type;
1200         r->target = target;
1201         e->triggers = r;
1202       }
1203     }
1204   }
1205   e->type = spec->type;
1206   r = e;
1207 exit :
1208   sen_ja_unref(s->values, id, spec, spec_len);
1209   MUTEX_UNLOCK(s->lock);
1210   return r;
1211 }
1212 
1213 sen_db_store *
sen_db_store_create(sen_db * s,const char * name,sen_db_store_spec * spec)1214 sen_db_store_create(sen_db *s, const char *name, sen_db_store_spec *spec)
1215 {
1216   sen_id id;
1217   sen_db_store *e, *k, *l, *r = NULL;
1218   char buffer[PATH_MAX];
1219   if (strlen(name) >= SEN_SYM_MAX_KEY_SIZE) {
1220     GERR(sen_invalid_argument, "too long store name (%s)", name);
1221     return NULL;
1222   }
1223   if (strchr(name, '.') &&
1224       ((spec->type == sen_db_raw_class) || (spec->type == sen_db_class))) {
1225     GERR(sen_invalid_argument, "class name must not include '.' (%s)", name);
1226     return NULL;
1227   }
1228   if (spec->type == sen_db_idx_slot) {
1229     if (!(k = sen_db_store_by_id(s, spec->u.s.class)) ||
1230         !(l = sen_db_slot_class(s, name))) {
1231       return NULL;
1232     }
1233   }
1234 
1235   if (sen_db_lock(s, -1)) {
1236     SEN_LOG(sen_log_crit, "sen_db_store_create: lock failed");
1237     return NULL;
1238   }
1239 
1240   if (sen_sym_at(s->keys, name)) {
1241     sen_db_unlock(s);
1242     GERR(sen_invalid_argument, "sen_db_store_create: existing name (%s)", name);
1243     return NULL;
1244   }
1245 
1246   if (!(id = sen_sym_nextid(s->keys, name))) {
1247     sen_db_unlock(s);
1248     return NULL;
1249   }
1250 
1251   MUTEX_LOCK(s->lock);
1252 
1253   if (!(e = sen_array_at(&s->stores, id))) { goto exit; }
1254   if (e->type) {
1255     SEN_LOG(sen_log_crit, "sen_db corrupt: %s", name);
1256     goto exit;
1257   }
1258 
1259   spec->n_triggers = 0;
1260   if (sen_ja_put(s->values, id, spec, SEN_DB_STORE_SPEC_SIZE(0), 0)) { goto exit; }
1261   e->db = s;
1262   e->id = id;
1263   e->triggers = NULL;
1264   gen_pathname(s->keys->io->path, buffer, id);
1265   switch (spec->type) {
1266   case sen_db_raw_class :
1267     e->u.bc.element_size = spec->u.c.size;
1268     break;
1269   case sen_db_class :
1270     if (!(e->u.c.keys = sen_sym_create(buffer,
1271                                        spec->u.c.size,
1272                                        spec->u.c.flags,
1273                                        spec->u.c.encoding))) { goto exit; }
1274     break;
1275   case sen_db_obj_slot :
1276     e->u.o.class = spec->u.s.class;
1277     if (!(e->u.o.ra = sen_ra_create(buffer, sizeof(sen_id)))) { goto exit; }
1278     break;
1279   case sen_db_ra_slot :
1280     e->u.f.class = spec->u.s.class;
1281     if (!(e->u.f.ra = sen_ra_create(buffer, spec->u.s.size))) { goto exit; }
1282     break;
1283   case sen_db_ja_slot :
1284     e->u.v.class = spec->u.s.class;
1285     if (!(e->u.v.ja = sen_ja_create(buffer, spec->u.s.size, spec->u.s.flags))) { goto exit; }
1286     break;
1287   case sen_db_idx_slot :
1288     e->u.i.class = spec->u.s.class;
1289     if (!(e->u.i.inv = sen_inv_create(buffer, l->u.c.keys, spec->u.s.size))) { goto exit; }
1290     break;
1291   case sen_db_rel1 :
1292     e->u.f.class = spec->u.s.class;
1293     if (!(e->u.f.ra = sen_ra_create(buffer, spec->u.s.size))) { goto exit; }
1294     break;
1295   default :
1296     goto exit;
1297   }
1298   if ((id != sen_sym_get(s->keys, name))) {
1299     SEN_LOG(sen_log_crit, "sen_db id unmatch: %d", id);
1300   }
1301   e->type = spec->type;
1302   r = e;
1303 exit :
1304   MUTEX_UNLOCK(s->lock);
1305   sen_db_unlock(s);
1306   // todo : sen_ja_put(s->values, id, NULL, 0, 0);
1307   return r;
1308 }
1309 
1310 sen_rc
sen_db_store_add_trigger(sen_db_store * e,sen_db_store_rel_spec * t)1311 sen_db_store_add_trigger(sen_db_store *e, sen_db_store_rel_spec *t)
1312 {
1313   sen_rc rc;
1314   sen_db *s = e->db;
1315   uint32_t spec_len, newspec_len;
1316   sen_db_store_spec *spec;
1317   sen_db_store_spec *newspec;
1318   sen_db_store *target = sen_db_store_by_id(s, t->target);
1319   if (!target) { return sen_invalid_argument; }
1320 
1321   if (sen_db_lock(s, -1)) {
1322     SEN_LOG(sen_log_crit, "sen_db_store_add_trigger: lock failed");
1323     return sen_abnormal_error;
1324   }
1325   if (!(spec = sen_ja_ref(s->values, e->id, &spec_len))) {
1326     sen_db_unlock(s);
1327     return sen_invalid_argument;
1328   }
1329   newspec_len = SEN_DB_STORE_SPEC_SIZE(spec->n_triggers + 1);
1330   if (!(newspec = SEN_GMALLOC(newspec_len))) {
1331     sen_db_unlock(s);
1332     return sen_memory_exhausted;
1333   }
1334   memcpy(newspec, spec, spec_len);
1335   memcpy(&newspec->triggers[spec->n_triggers], t, sizeof(sen_db_store_rel_spec));
1336   newspec->n_triggers++;
1337   sen_ja_unref(s->values, e->id, spec, spec_len);
1338   rc = sen_ja_put(s->values, e->id, newspec, newspec_len, 0);
1339   sen_db_unlock(s);
1340   SEN_GFREE(newspec);
1341   if (rc) { return rc; }
1342   {
1343     sen_db_trigger *r = SEN_GMALLOC(sizeof(sen_db_trigger));
1344     if (r) {
1345       MUTEX_LOCK(s->lock);
1346       r->next = e->triggers;
1347       r->type = t->type;
1348       r->target = t->target;
1349       e->triggers = r;
1350       MUTEX_UNLOCK(s->lock);
1351       if (t->type == sen_db_index_target) {
1352         sen_db_store_rel_spec invrs;
1353         invrs.type = sen_db_before_update_trigger;
1354         invrs.target = e->id;
1355         rc = sen_db_store_add_trigger(target, &invrs);
1356       }
1357     } else { rc = sen_memory_exhausted; }
1358   }
1359   return rc;
1360 }
1361 
1362 sen_rc
sen_db_store_del_trigger(sen_db_store * e,sen_db_store_rel_spec * t)1363 sen_db_store_del_trigger(sen_db_store *e, sen_db_store_rel_spec *t)
1364 {
1365   sen_rc rc;
1366   sen_db *s = e->db;
1367   uint32_t spec_len, newspec_len;
1368   uint32_t n_triggers = 0;
1369   sen_db_store_spec *spec;
1370   sen_db_store_spec *newspec;
1371   sen_db_trigger *r, **rp = &e->triggers;
1372   if (sen_db_lock(s, -1)) {
1373     SEN_LOG(sen_log_crit, "sen_db_del_trigger: lock failed");
1374     return sen_abnormal_error;
1375   }
1376   if (!(spec = sen_ja_ref(s->values, e->id, &spec_len))) {
1377     sen_db_unlock(s);
1378     return sen_invalid_argument;
1379   }
1380   MUTEX_LOCK(s->lock);
1381   while ((r = *rp)) {
1382     if (r->target == t->target) {
1383       *rp = r->next;
1384       SEN_GFREE(r);
1385     } else {
1386       n_triggers++;
1387       rp = &r->next;
1388     }
1389   }
1390   MUTEX_UNLOCK(s->lock);
1391   newspec_len = SEN_DB_STORE_SPEC_SIZE(n_triggers);
1392   if (!(newspec = SEN_GMALLOC(newspec_len))) {
1393     sen_db_unlock(s);
1394     sen_ja_unref(s->values, e->id, spec, spec_len);
1395     return sen_memory_exhausted;
1396   }
1397   memcpy(newspec, spec, newspec_len);
1398   newspec->n_triggers = n_triggers;
1399   sen_ja_unref(s->values, e->id, spec, spec_len);
1400   for (t = newspec->triggers, r = e->triggers; r; t++, r = r->next) {
1401     t->type = r->type;
1402     t->target = r->target;
1403   }
1404   rc = sen_ja_put(s->values, e->id, newspec, newspec_len, 0);
1405   sen_db_unlock(s);
1406   SEN_GFREE(newspec);
1407   return rc;
1408 }
1409 
1410 sen_db_store *
sen_db_slot_class_by_id(sen_db * s,sen_id slot)1411 sen_db_slot_class_by_id(sen_db *s, sen_id slot)
1412 {
1413   const char *slotname = _sen_sym_key(s->keys, slot);
1414   if (!slotname) { return NULL; }
1415   return sen_db_slot_class(s, slotname);
1416 }
1417 
1418 sen_rc
sen_db_class_slotpath(sen_db * s,sen_id class,const char * name,char * buf)1419 sen_db_class_slotpath(sen_db *s, sen_id class, const char *name, char *buf)
1420 {
1421   char *dst;
1422   const char *src = _sen_sym_key(s->keys, class);
1423   if (!src) { return sen_invalid_argument; }
1424   strcpy(buf, src);
1425   dst = buf + strlen(src);
1426   *dst++ = '.';
1427   strcpy(dst, name);
1428   return sen_success;
1429 }
1430 
1431 sen_db_store *
sen_db_class_slot(sen_db * s,sen_id class,const char * name)1432 sen_db_class_slot(sen_db *s, sen_id class, const char *name)
1433 {
1434   char buf[SEN_SYM_MAX_KEY_SIZE];
1435   if (sen_db_class_slotpath(s, class, name, buf)) { return NULL; }
1436   return sen_db_store_open(s, buf);
1437 }
1438 
1439 sen_db_store *
sen_db_class_add_slot(sen_db * s,sen_id class,const char * name,sen_db_store_spec * spec)1440 sen_db_class_add_slot(sen_db *s, sen_id class, const char *name, sen_db_store_spec *spec)
1441 {
1442   char buf[SEN_SYM_MAX_KEY_SIZE];
1443   if (sen_db_class_slotpath(s, class, name, buf)) { return NULL; }
1444   return sen_db_store_create(s, buf, spec);
1445 }
1446 
1447 sen_rc
sen_db_store_close(sen_db_store * slot)1448 sen_db_store_close(sen_db_store *slot)
1449 {
1450   sen_db_trigger *t, *t_;
1451   uint8_t type = slot->type;
1452   slot->type = 0;
1453   switch (type) {
1454   case sen_db_obj_slot :
1455     // sen_db_class_close(slot->u.o.class);
1456     sen_ra_close(slot->u.o.ra);
1457     break;
1458   case sen_db_ra_slot :
1459     sen_ra_close(slot->u.f.ra);
1460     break;
1461   case sen_db_ja_slot :
1462     sen_ja_close(slot->u.v.ja);
1463     break;
1464   case sen_db_idx_slot :
1465     sen_inv_close(slot->u.i.inv);
1466     break;
1467   case sen_db_class :
1468     sen_sym_close(slot->u.c.keys);
1469     break;
1470   case sen_db_rel1 :
1471     sen_ra_close(slot->u.f.ra);
1472     break;
1473   default :
1474     return sen_invalid_argument;
1475   }
1476   for (t = slot->triggers; t; t = t_) {
1477     t_ = t->next;
1478     SEN_GFREE(t);
1479   }
1480   return sen_success;
1481 }
1482 
1483 sen_rc
sen_db_store_remove(sen_db * s,const char * name)1484 sen_db_store_remove(sen_db *s, const char *name)
1485 {
1486   sen_rc rc;
1487   sen_id id;
1488   sen_db_store *e;
1489   uint32_t spec_len;
1490   char buffer[PATH_MAX];
1491   sen_db_store_spec *spec;
1492   if (!s || !(id = sen_sym_at(s->keys, name))) { return sen_invalid_argument; }
1493   if ((e = sen_array_at(&s->stores, id)) && (e->type)) { sen_db_store_close(e); }
1494   if (!(spec = sen_ja_ref(s->values, id, &spec_len))) {
1495     return sen_invalid_format;
1496   }
1497   {
1498     int i;
1499     sen_db_store *target;
1500     const sen_db_store_rel_spec *t;
1501     sen_db_store_rel_spec invrs;
1502     invrs.target = id;
1503     for (t = spec->triggers, i = spec->n_triggers; i; t++, i--) {
1504       if (t->target && (target = sen_db_store_by_id(s, t->target))) {
1505         if ((rc = sen_db_store_del_trigger(target, &invrs))) {
1506           SEN_LOG(sen_log_notice, "sen_db_store_del_trigger failed(%d)", t->target);
1507         }
1508       }
1509     }
1510   }
1511   if (sen_db_lock(s, -1)) {
1512     SEN_LOG(sen_log_crit, "sen_db_store_remove: lock failed");
1513     sen_ja_unref(s->values, id, spec, spec_len);
1514     return sen_abnormal_error;
1515   }
1516   MUTEX_LOCK(s->lock);
1517   gen_pathname(s->keys->io->path, buffer, id);
1518   switch (spec->type) {
1519   case sen_db_raw_class :
1520     /* todo */
1521     break;
1522   case sen_db_class :
1523     rc = sen_sym_remove(buffer);
1524     break;
1525   case sen_db_obj_slot :
1526     rc = sen_ra_remove(buffer);
1527     break;
1528   case sen_db_ra_slot :
1529     rc = sen_ra_remove(buffer);
1530     break;
1531   case sen_db_ja_slot :
1532     rc = sen_ja_remove(buffer);
1533     break;
1534   case sen_db_idx_slot :
1535     rc = sen_inv_remove(buffer);
1536     break;
1537   case sen_db_rel1 :
1538     rc = sen_ra_remove(buffer);
1539     break;
1540   default :
1541     break;
1542   }
1543   sen_ja_unref(s->values, id, spec, spec_len);
1544   rc = sen_ja_put(s->values, id, NULL, 0, 0);
1545   rc = sen_sym_del(s->keys, name);
1546   MUTEX_UNLOCK(s->lock);
1547   sen_db_unlock(s);
1548   return rc;
1549 }
1550 
1551 sen_rc
sen_db_class_del_slot(sen_db * s,sen_id class,const char * name)1552 sen_db_class_del_slot(sen_db *s, sen_id class, const char *name)
1553 {
1554   char buf[SEN_SYM_MAX_KEY_SIZE];
1555   if (sen_db_class_slotpath(s, class, name, buf)) { return sen_invalid_argument; }
1556   return sen_db_store_remove(s, buf);
1557 }
1558 
1559 sen_rc
sen_db_prepare_builtin_class(sen_db * db)1560 sen_db_prepare_builtin_class(sen_db *db)
1561 {
1562   sen_db_store_spec spec;
1563   spec.type = sen_db_raw_class;
1564   spec.n_triggers = 0;
1565   spec.u.c.flags = 0;
1566   spec.u.c.encoding = db->keys->encoding;
1567   /* 1 */
1568   spec.u.c.size = sizeof(int32_t);
1569   if (!sen_db_store_create(db, "<int>", &spec)) { return sen_memory_exhausted; }
1570   /* 2 */
1571   spec.u.c.size = sizeof(uint32_t);
1572   if (!sen_db_store_create(db, "<uint>", &spec)) { return sen_memory_exhausted; }
1573   /* 3 */
1574   spec.u.c.size = sizeof(int64_t);
1575   if (!sen_db_store_create(db, "<int64>", &spec)) { return sen_memory_exhausted; }
1576   /* 4 */
1577   spec.u.c.size = sizeof(double);
1578   if (!sen_db_store_create(db, "<float>", &spec)) { return sen_memory_exhausted; }
1579   /* 5 */
1580   spec.u.c.size = SEN_SYM_MAX_KEY_SIZE;
1581   if (!sen_db_store_create(db, "<shorttext>", &spec)) { return sen_memory_exhausted; }
1582   /* 6 */
1583   spec.u.c.size = 1 << 16;
1584   if (!sen_db_store_create(db, "<text>", &spec)) { return sen_memory_exhausted; }
1585   /* 7 */
1586   spec.u.c.size = JA_SEGMENT_SIZE;
1587   if (!sen_db_store_create(db, "<longtext>", &spec)) { return sen_memory_exhausted; }
1588   /* 8 */
1589   spec.u.c.size = sizeof(sen_timeval);
1590   if (!sen_db_store_create(db, "<time>", &spec)) { return sen_memory_exhausted; }
1591   return sen_success;
1592 }
1593 
1594 sen_db *
sen_db_create(const char * path,int flags,sen_encoding encoding)1595 sen_db_create(const char *path, int flags, sen_encoding encoding)
1596 {
1597   sen_db *s;
1598   ERRCLR(NULL);
1599   if (strlen(path) <= PATH_MAX - 14) {
1600     if ((s = SEN_GMALLOC(sizeof(sen_db)))) {
1601       sen_array_init(&s->stores, &sen_gctx, sizeof(sen_db_store),
1602                      SEN_ARRAY_CLEAR|SEN_ARRAY_THREADSAFE);
1603       if ((s->keys = sen_sym_create(path, 0, flags, encoding))) {
1604         char buffer[PATH_MAX];
1605         gen_pathname(path, buffer, 0);
1606         if ((s->values = sen_ja_create(buffer, JA_SEGMENT_SIZE, 0))) {
1607           MUTEX_INIT(s->lock);
1608           sen_db_prepare_builtin_class(s);
1609           if (!ERRP(&sen_gctx, SEN_ERROR)) {
1610             SEN_LOG(sen_log_notice, "db created (%s) flags=%x", path, s->keys->flags);
1611             sen_gctx.db = s;
1612             sen_gctx.encoding = encoding;
1613             return s;
1614           }
1615         } else {
1616           GERR(sen_memory_exhausted, "ja create failed");
1617         }
1618         sen_sym_close(s->keys);
1619       } else {
1620         GERR(sen_memory_exhausted, "s->keys create failed");
1621       }
1622       sen_array_fin(&s->stores);
1623       SEN_GFREE(s);
1624     } else {
1625       GERR(sen_memory_exhausted, "sen_db alloc failed");
1626     }
1627   } else {
1628     GERR(sen_invalid_argument, "too long path");
1629   }
1630   return NULL;
1631 }
1632 
1633 sen_db *
sen_db_open(const char * path)1634 sen_db_open(const char *path)
1635 {
1636   sen_db *s;
1637   ERRCLR(NULL);
1638   if (strlen(path) <= PATH_MAX - 14) {
1639     if ((s = SEN_GMALLOC(sizeof(sen_db)))) {
1640       sen_array_init(&s->stores, &sen_gctx, sizeof(sen_db_store),
1641                      SEN_ARRAY_CLEAR|SEN_ARRAY_THREADSAFE);
1642       if ((s->keys = sen_sym_open(path))) {
1643         char buffer[PATH_MAX];
1644         gen_pathname(path, buffer, 0);
1645         if ((s->values = sen_ja_open(buffer))) {
1646           SEN_LOG(sen_log_notice, "db opened (%s) flags=%x", path, s->keys->flags);
1647           sen_gctx.db = s;
1648           sen_gctx.encoding = s->keys->encoding;
1649           MUTEX_INIT(s->lock);
1650           return s;
1651         } else {
1652           GERR(sen_memory_exhausted, "ja open failed");
1653         }
1654         sen_sym_close(s->keys);
1655       } else {
1656         GERR(sen_memory_exhausted, "s->keys open failed");
1657       }
1658       sen_array_fin(&s->stores);
1659       SEN_GFREE(s);
1660     } else {
1661       GERR(sen_memory_exhausted, "sen_db alloc failed");
1662     }
1663   } else {
1664     GERR(sen_invalid_argument, "too long path");
1665   }
1666   return NULL;
1667 }
1668 
1669 sen_rc
sen_db_close(sen_db * s)1670 sen_db_close(sen_db *s)
1671 {
1672   if (!s) { return sen_invalid_argument; }
1673   {
1674     sen_id id;
1675     sen_db_store *sp;
1676     SEN_ARRAY_EACH(&s->stores, 1, sen_sym_curr_id(s->keys), id, sp, {
1677       if (sp->type) { sen_db_store_close(sp); }
1678     });
1679   }
1680   sen_array_fin(&s->stores);
1681   sen_sym_close(s->keys);
1682   sen_ja_close(s->values);
1683   SEN_GFREE(s);
1684   return sen_success;
1685 }
1686 
1687 /**** vgram ****/
1688 
1689 static int len_sum = 0;
1690 static int img_sum = 0;
1691 static int simple_sum = 0;
1692 static int skip_sum = 0;
1693 
1694 sen_vgram *
sen_vgram_create(const char * path)1695 sen_vgram_create(const char *path)
1696 {
1697   sen_vgram *s;
1698   if (!(s = SEN_GMALLOC(sizeof(sen_vgram)))) { return NULL; }
1699   s->vgram = sen_sym_create(path, sizeof(sen_id) * 2, 0, sen_enc_none);
1700   if (!s->vgram) {
1701     SEN_GFREE(s);
1702     return NULL;
1703   }
1704   return s;
1705 }
1706 
1707 sen_vgram *
sen_vgram_open(const char * path)1708 sen_vgram_open(const char *path)
1709 {
1710   sen_vgram *s;
1711   if (!(s = SEN_GMALLOC(sizeof(sen_vgram)))) { return NULL; }
1712   s->vgram = sen_sym_open(path);
1713   if (!s->vgram) {
1714     SEN_GFREE(s);
1715     return NULL;
1716   }
1717   return s;
1718 }
1719 
1720 sen_vgram_buf *
sen_vgram_buf_open(size_t len)1721 sen_vgram_buf_open(size_t len)
1722 {
1723   sen_vgram_buf *b;
1724   if (!(b = SEN_GMALLOC(sizeof(sen_vgram_buf)))) { return NULL; }
1725   b->len = len;
1726   b->tvs = b->tvp = SEN_GMALLOC(sizeof(sen_id) * len);
1727   if (!b->tvp) { SEN_GFREE(b); return NULL; }
1728   b->tve = b->tvs + len;
1729   b->vps = b->vpp = SEN_GMALLOC(sizeof(sen_vgram_vnode) * len * 2);
1730   if (!b->vpp) { SEN_GFREE(b->tvp); SEN_GFREE(b); return NULL; }
1731   b->vpe = b->vps + len;
1732   return b;
1733 }
1734 
1735 sen_rc
sen_vgram_buf_add(sen_vgram_buf * b,sen_id tid)1736 sen_vgram_buf_add(sen_vgram_buf *b, sen_id tid)
1737 {
1738   uint8_t dummybuf[8], *dummyp;
1739   ptrdiff_t pd;
1740   if (b->tvp < b->tve) { *b->tvp++ = tid; }
1741   dummyp = dummybuf;
1742   SEN_B_ENC(tid, dummyp);
1743   pd = dummyp - dummybuf;
1744   simple_sum += (int)pd;
1745   return sen_success;
1746 }
1747 
1748 typedef struct {
1749   sen_id vid;
1750   sen_id tid;
1751 } vgram_key;
1752 
1753 sen_rc
sen_vgram_update(sen_vgram * vgram,sen_id rid,sen_vgram_buf * b,sen_set * terms)1754 sen_vgram_update(sen_vgram *vgram, sen_id rid, sen_vgram_buf *b, sen_set *terms)
1755 {
1756   sen_inv_updspec **u;
1757   if (b && b->tvs < b->tvp) {
1758     sen_id *t0, *tn;
1759     for (t0 = b->tvs; t0 < b->tvp - 1; t0++) {
1760       sen_vgram_vnode *v, **vp;
1761       if (sen_set_at(terms, t0, (void **) &u)) {
1762         vp = &(*u)->vnodes;
1763         for (tn = t0 + 1; tn < b->tvp; tn++) {
1764           for (v = *vp; v && v->tid != *tn; v = v->cdr) ;
1765           if (!v) {
1766             if (b->vpp < b->vpe) {
1767               v = b->vpp++;
1768             } else {
1769               // todo;
1770               break;
1771             }
1772             v->car = NULL;
1773             v->cdr = *vp;
1774             *vp = v;
1775             v->tid = *tn;
1776             v->vid = 0;
1777             v->freq = 0;
1778             v->len = tn - t0;
1779           }
1780           v->freq++;
1781           if (v->vid) {
1782             vp = &v->car;
1783           } else {
1784             break;
1785           }
1786         }
1787       }
1788     }
1789     {
1790       sen_set *th = sen_set_open(sizeof(sen_id), sizeof(int), 0);
1791       if (!th) { return sen_memory_exhausted; }
1792       if (t0 == b->tvp) { SEN_LOG(sen_log_debug, "t0 == tvp"); }
1793       for (t0 = b->tvs; t0 < b->tvp; t0++) {
1794         sen_id vid, vid0 = *t0, vid1 = 0;
1795         sen_vgram_vnode *v, *v2 = NULL, **vp;
1796         if (sen_set_at(terms, t0, (void **) &u)) {
1797           vp = &(*u)->vnodes;
1798           for (tn = t0 + 1; tn < b->tvp; tn++) {
1799             for (v = *vp; v; v = v->cdr) {
1800               if (!v->vid && (v->freq < 2 || v->freq * v->len < 4)) {
1801                 *vp = v->cdr;
1802                 v->freq = 0;
1803               }
1804               if (v->tid == *tn) { break; }
1805               vp = &v->cdr;
1806             }
1807             if (v) {
1808               if (v->freq) {
1809                 v2 = v;
1810                 vid1 = vid0;
1811                 vid0 = v->vid;
1812               }
1813               if (v->vid) {
1814                 vp = &v->car;
1815                 continue;
1816               }
1817             }
1818             break;
1819           }
1820         }
1821         if (v2) {
1822           if (!v2->vid) {
1823             vgram_key key;
1824             key.vid = vid1;
1825             key.tid = v2->tid;
1826             if (!(v2->vid = sen_sym_get(vgram->vgram, (char *)&key))) {
1827               sen_set_close(th);
1828               return sen_memory_exhausted;
1829             }
1830           }
1831           vid = *t0 = v2->vid * 2 + 1;
1832           memset(t0 + 1, 0, sizeof(sen_id) * v2->len);
1833           t0 += v2->len;
1834         } else {
1835           vid = *t0 *= 2;
1836         }
1837         {
1838           int *tf;
1839           if (!sen_set_get(th, &vid, (void **) &tf)) {
1840             sen_set_close(th);
1841             return sen_memory_exhausted;
1842           }
1843           (*tf)++;
1844         }
1845       }
1846       if (!th->n_entries) { SEN_LOG(sen_log_debug, "th->n_entries == 0"); }
1847       {
1848         int j = 0;
1849         int skip = 0;
1850         sen_set_eh *ehs, *ehp, *ehe;
1851         sen_set_sort_optarg arg;
1852         uint8_t *ps = SEN_GMALLOC(b->len * 2), *pp, *pe;
1853         if (!ps) {
1854           sen_set_close(th);
1855           return sen_memory_exhausted;
1856         }
1857         pp = ps;
1858         pe = ps + b->len * 2;
1859         arg.mode = sen_sort_descending;
1860         arg.compar = NULL;
1861         arg.compar_arg = (void *)(intptr_t)sizeof(sen_id);
1862         ehs = sen_set_sort(th, 0, &arg);
1863         if (!ehs) {
1864           SEN_GFREE(ps);
1865           sen_set_close(th);
1866           return sen_memory_exhausted;
1867         }
1868         SEN_B_ENC(th->n_entries, pp);
1869         for (ehp = ehs, ehe = ehs + th->n_entries; ehp < ehe; ehp++, j++) {
1870           int *id = (int *)SEN_SET_INTVAL(*ehp);
1871           SEN_B_ENC(*SEN_SET_INTKEY(*ehp), pp);
1872           *id = j;
1873         }
1874         for (t0 = b->tvs; t0 < b->tvp; t0++) {
1875           if (*t0) {
1876             int *id;
1877             if (!sen_set_at(th, t0, (void **) &id)) {
1878               SEN_LOG(sen_log_error, "lookup error (%d)", *t0);
1879             }
1880             SEN_B_ENC(*id, pp);
1881           } else {
1882             skip++;
1883           }
1884         }
1885         len_sum += b->len;
1886         img_sum += pp - ps;
1887         skip_sum += skip;
1888         SEN_GFREE(ehs);
1889         SEN_GFREE(ps);
1890       }
1891       sen_set_close(th);
1892     }
1893   }
1894   return sen_success;
1895 }
1896 
1897 sen_rc
sen_vgram_buf_close(sen_vgram_buf * b)1898 sen_vgram_buf_close(sen_vgram_buf *b)
1899 {
1900   if (!b) { return sen_invalid_argument; }
1901   if (b->tvs) { SEN_GFREE(b->tvs); }
1902   if (b->vps) { SEN_GFREE(b->vps); }
1903   SEN_GFREE(b);
1904   return sen_success;
1905 }
1906 
1907 sen_rc
sen_vgram_close(sen_vgram * vgram)1908 sen_vgram_close(sen_vgram *vgram)
1909 {
1910   if (!vgram) { return sen_invalid_argument; }
1911   SEN_LOG(sen_log_debug, "len=%d img=%d skip=%d simple=%d", len_sum, img_sum, skip_sum, simple_sum);
1912   sen_sym_close(vgram->vgram);
1913   SEN_GFREE(vgram);
1914   return sen_success;
1915 }
1916