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