1 /* -*- c-basic-offset: 2 -*- */
2 /*
3   Copyright(C) 2009-2017 Brazil
4 
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License version 2.1 as published by the Free Software Foundation.
8 
9   This library is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Lesser General Public License for more details.
13 
14   You should have received a copy of the GNU Lesser General Public
15   License along with this library; if not, write to the Free Software
16   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA
17 */
18 #include "grn.h"
19 #include "grn_str.h"
20 #include "grn_store.h"
21 #include "grn_ctx_impl.h"
22 #include "grn_output.h"
23 #include <string.h>
24 
25 /* rectangular arrays */
26 
27 #define GRN_RA_W_SEGMENT    22
28 #define GRN_RA_SEGMENT_SIZE (1 << GRN_RA_W_SEGMENT)
29 
30 static grn_ra *
_grn_ra_create(grn_ctx * ctx,grn_ra * ra,const char * path,unsigned int element_size)31 _grn_ra_create(grn_ctx *ctx, grn_ra *ra, const char *path, unsigned int element_size)
32 {
33   grn_io *io;
34   int max_segments, n_elm, w_elm;
35   struct grn_ra_header *header;
36   unsigned int actual_size;
37   if (element_size > GRN_RA_SEGMENT_SIZE) {
38     GRN_LOG(ctx, GRN_LOG_ERROR, "element_size too large (%d)", element_size);
39     return NULL;
40   }
41   for (actual_size = 1; actual_size < element_size; actual_size *= 2) ;
42   max_segments = ((GRN_ID_MAX + 1) / GRN_RA_SEGMENT_SIZE) * actual_size;
43   io = grn_io_create(ctx, path, sizeof(struct grn_ra_header),
44                      GRN_RA_SEGMENT_SIZE, max_segments, grn_io_auto,
45                      GRN_IO_EXPIRE_SEGMENT);
46   if (!io) { return NULL; }
47   header = grn_io_header(io);
48   grn_io_set_type(io, GRN_COLUMN_FIX_SIZE);
49   header->element_size = actual_size;
50   n_elm = GRN_RA_SEGMENT_SIZE / header->element_size;
51   for (w_elm = GRN_RA_W_SEGMENT; (1 << w_elm) > n_elm; w_elm--);
52   ra->io = io;
53   ra->header = header;
54   ra->element_mask =  n_elm - 1;
55   ra->element_width = w_elm;
56   return ra;
57 }
58 
59 grn_ra *
grn_ra_create(grn_ctx * ctx,const char * path,unsigned int element_size)60 grn_ra_create(grn_ctx *ctx, const char *path, unsigned int element_size)
61 {
62   grn_ra *ra = (grn_ra *)GRN_CALLOC(sizeof(grn_ra));
63   if (!ra) {
64     return NULL;
65   }
66   GRN_DB_OBJ_SET_TYPE(ra, GRN_COLUMN_FIX_SIZE);
67   if (!_grn_ra_create(ctx, ra, path, element_size)) {
68     GRN_FREE(ra);
69     return NULL;
70   }
71   return ra;
72 }
73 
74 grn_ra *
grn_ra_open(grn_ctx * ctx,const char * path)75 grn_ra_open(grn_ctx *ctx, const char *path)
76 {
77   grn_io *io;
78   int n_elm, w_elm;
79   grn_ra *ra = NULL;
80   struct grn_ra_header *header;
81   uint32_t io_type;
82   io = grn_io_open(ctx, path, grn_io_auto);
83   if (!io) { return NULL; }
84   header = grn_io_header(io);
85   io_type = grn_io_get_type(io);
86   if (io_type != GRN_COLUMN_FIX_SIZE) {
87     ERR(GRN_INVALID_FORMAT,
88         "[column][fix-size] file type must be %#04x: <%#04x>",
89         GRN_COLUMN_FIX_SIZE, io_type);
90     grn_io_close(ctx, io);
91     return NULL;
92   }
93   ra = GRN_MALLOCN(grn_ra, 1);
94   if (!ra) {
95     grn_io_close(ctx, io);
96     return NULL;
97   }
98   n_elm = GRN_RA_SEGMENT_SIZE / header->element_size;
99   for (w_elm = GRN_RA_W_SEGMENT; (1 << w_elm) > n_elm; w_elm--);
100   GRN_DB_OBJ_SET_TYPE(ra, GRN_COLUMN_FIX_SIZE);
101   ra->io = io;
102   ra->header = header;
103   ra->element_mask =  n_elm - 1;
104   ra->element_width = w_elm;
105   return ra;
106 }
107 
108 grn_rc
grn_ra_info(grn_ctx * ctx,grn_ra * ra,unsigned int * element_size)109 grn_ra_info(grn_ctx *ctx, grn_ra *ra, unsigned int *element_size)
110 {
111   if (!ra) { return GRN_INVALID_ARGUMENT; }
112   if (element_size) { *element_size = ra->header->element_size; }
113   return GRN_SUCCESS;
114 }
115 
116 grn_rc
grn_ra_close(grn_ctx * ctx,grn_ra * ra)117 grn_ra_close(grn_ctx *ctx, grn_ra *ra)
118 {
119   grn_rc rc;
120   if (!ra) { return GRN_INVALID_ARGUMENT; }
121   rc = grn_io_close(ctx, ra->io);
122   GRN_FREE(ra);
123   return rc;
124 }
125 
126 grn_rc
grn_ra_remove(grn_ctx * ctx,const char * path)127 grn_ra_remove(grn_ctx *ctx, const char *path)
128 {
129   if (!path) { return GRN_INVALID_ARGUMENT; }
130   return grn_io_remove(ctx, path);
131 }
132 
133 grn_rc
grn_ra_truncate(grn_ctx * ctx,grn_ra * ra)134 grn_ra_truncate(grn_ctx *ctx, grn_ra *ra)
135 {
136   grn_rc rc;
137   const char *io_path;
138   char *path;
139   unsigned int element_size;
140   if ((io_path = grn_io_path(ra->io)) && *io_path != '\0') {
141     if (!(path = GRN_STRDUP(io_path))) {
142       ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_path);
143       return GRN_NO_MEMORY_AVAILABLE;
144     }
145   } else {
146     path = NULL;
147   }
148   element_size = ra->header->element_size;
149   if ((rc = grn_io_close(ctx, ra->io))) { goto exit; }
150   ra->io = NULL;
151   if (path && (rc = grn_io_remove(ctx, path))) { goto exit; }
152   if (!_grn_ra_create(ctx, ra, path, element_size)) {
153     rc = GRN_UNKNOWN_ERROR;
154   }
155 exit:
156   if (path) { GRN_FREE(path); }
157   return rc;
158 }
159 
160 void *
grn_ra_ref(grn_ctx * ctx,grn_ra * ra,grn_id id)161 grn_ra_ref(grn_ctx *ctx, grn_ra *ra, grn_id id)
162 {
163   void *p = NULL;
164   uint16_t seg;
165   if (id > GRN_ID_MAX) { return NULL; }
166   seg = id >> ra->element_width;
167   GRN_IO_SEG_REF(ra->io, seg, p);
168   if (!p) { return NULL; }
169   return (void *)(((byte *)p) + ((id & ra->element_mask) * ra->header->element_size));
170 }
171 
172 grn_rc
grn_ra_unref(grn_ctx * ctx,grn_ra * ra,grn_id id)173 grn_ra_unref(grn_ctx *ctx, grn_ra *ra, grn_id id)
174 {
175   uint16_t seg;
176   if (id > GRN_ID_MAX) { return GRN_INVALID_ARGUMENT; }
177   seg = id >> ra->element_width;
178   GRN_IO_SEG_UNREF(ra->io, seg);
179   return GRN_SUCCESS;
180 }
181 
182 void *
grn_ra_ref_cache(grn_ctx * ctx,grn_ra * ra,grn_id id,grn_ra_cache * cache)183 grn_ra_ref_cache(grn_ctx *ctx, grn_ra *ra, grn_id id, grn_ra_cache *cache)
184 {
185   void *p = NULL;
186   uint16_t seg;
187   if (id > GRN_ID_MAX) { return NULL; }
188   seg = id >> ra->element_width;
189   if (seg == cache->seg) {
190     p = cache->p;
191   } else {
192     if (cache->seg != -1) { GRN_IO_SEG_UNREF(ra->io, cache->seg); }
193     GRN_IO_SEG_REF(ra->io, seg, p);
194     cache->seg = seg;
195     cache->p = p;
196   }
197   if (!p) { return NULL; }
198   return (void *)(((byte *)p) + ((id & ra->element_mask) * ra->header->element_size));
199 }
200 
201 grn_rc
grn_ra_cache_fin(grn_ctx * ctx,grn_ra * ra,grn_id id)202 grn_ra_cache_fin(grn_ctx *ctx, grn_ra *ra, grn_id id)
203 {
204   uint16_t seg;
205   if (id > GRN_ID_MAX) { return GRN_INVALID_ARGUMENT; }
206   seg = id >> ra->element_width;
207   GRN_IO_SEG_UNREF(ra->io, seg);
208   return GRN_SUCCESS;
209 }
210 
211 /**** jagged arrays ****/
212 
213 #define GRN_JA_W_SEGREGATE_THRESH_V1   7
214 #define GRN_JA_W_SEGREGATE_THRESH_V2   16
215 #define GRN_JA_W_CAPACITY              38
216 #define GRN_JA_W_SEGMENT               22
217 
218 #define JA_ESEG_VOID                   (0xffffffffU)
219 #define JA_SEGMENT_SIZE                (1U << GRN_JA_W_SEGMENT)
220 #define JA_W_EINFO                     3
221 #define JA_W_SEGMENTS_MAX              (GRN_JA_W_CAPACITY - GRN_JA_W_SEGMENT)
222 #define JA_W_EINFO_IN_A_SEGMENT        (GRN_JA_W_SEGMENT - JA_W_EINFO)
223 #define JA_N_EINFO_IN_A_SEGMENT        (1U << JA_W_EINFO_IN_A_SEGMENT)
224 #define JA_M_EINFO_IN_A_SEGMENT        (JA_N_EINFO_IN_A_SEGMENT - 1)
225 #define JA_N_GARBAGES_IN_A_SEGMENT     ((1U << (GRN_JA_W_SEGMENT - 3)) - 2)
226 #define JA_N_ELEMENT_VARIATION_V1      (GRN_JA_W_SEGREGATE_THRESH_V1 - JA_W_EINFO + 1)
227 #define JA_N_ELEMENT_VARIATION_V2      (GRN_JA_W_SEGREGATE_THRESH_V2 - JA_W_EINFO + 1)
228 #define JA_N_DSEGMENTS                 (1U << JA_W_SEGMENTS_MAX)
229 #define JA_N_ESEGMENTS                 (1U << (GRN_ID_WIDTH - JA_W_EINFO_IN_A_SEGMENT))
230 
231 typedef struct _grn_ja_einfo grn_ja_einfo;
232 
233 struct _grn_ja_einfo {
234   union {
235     struct {
236       uint16_t seg;
237       uint16_t pos;
238       uint16_t size;
239       uint8_t c1;
240       uint8_t c2;
241     } n;
242     struct {
243       uint32_t size;
244       uint16_t seg;
245       uint8_t c1;
246       uint8_t c2;
247     } h;
248     uint8_t c[8];
249   } u;
250 };
251 
252 #define ETINY (0x80)
253 #define EHUGE (0x40)
254 #define ETINY_P(e) ((e)->u.c[7] & ETINY)
255 #define ETINY_ENC(e,_size) ((e)->u.c[7] = (_size) + ETINY)
256 #define ETINY_DEC(e,_size) ((_size) = (e)->u.c[7] & ~(ETINY|EHUGE))
257 #define EHUGE_P(e) ((e)->u.c[7] & EHUGE)
258 #define EHUGE_ENC(e,_seg,_size) do {\
259   (e)->u.h.c1 = 0;\
260   (e)->u.h.c2 = EHUGE;\
261   (e)->u.h.seg = (_seg);\
262   (e)->u.h.size = (_size);\
263 } while (0)
264 #define EHUGE_DEC(e,_seg,_size) do {\
265   (_seg) = (e)->u.h.seg;\
266   (_size) = (e)->u.h.size;\
267 } while (0)
268 #define EINFO_ENC(e,_seg,_pos,_size) do {\
269   (e)->u.n.c1 = (_pos) >> 16;\
270   (e)->u.n.c2 = ((_size) >> 16);\
271   (e)->u.n.seg = (_seg);\
272   (e)->u.n.pos = (_pos);\
273   (e)->u.n.size = (_size);\
274 } while (0)
275 #define EINFO_DEC(e,_seg,_pos,_size) do {\
276   (_seg) = (e)->u.n.seg;\
277   (_pos) = ((e)->u.n.c1 << 16) + (e)->u.n.pos;\
278   (_size) = ((e)->u.n.c2 << 16) + (e)->u.n.size;\
279 } while (0)
280 
281 typedef struct {
282   uint32_t seg;
283   uint32_t pos;
284 } ja_pos;
285 
286 typedef struct {
287   uint32_t head;
288   uint32_t tail;
289   uint32_t nrecs;
290   uint32_t next;
291   ja_pos recs[JA_N_GARBAGES_IN_A_SEGMENT];
292 } grn_ja_ginfo;
293 
294 struct grn_ja_header_v1 {
295   uint32_t flags;
296   uint32_t curr_seg;
297   uint32_t curr_pos;
298   uint32_t max_element_size;
299   ja_pos free_elements[JA_N_ELEMENT_VARIATION_V1];
300   uint32_t garbages[JA_N_ELEMENT_VARIATION_V1];
301   uint32_t ngarbages[JA_N_ELEMENT_VARIATION_V1];
302   uint32_t dsegs[JA_N_DSEGMENTS];
303   uint32_t esegs[JA_N_ESEGMENTS];
304 };
305 
306 struct grn_ja_header_v2 {
307   uint32_t flags;
308   uint32_t curr_seg;
309   uint32_t curr_pos;
310   uint32_t max_element_size;
311   ja_pos free_elements[JA_N_ELEMENT_VARIATION_V2];
312   uint32_t garbages[JA_N_ELEMENT_VARIATION_V2];
313   uint32_t ngarbages[JA_N_ELEMENT_VARIATION_V2];
314   uint32_t dsegs[JA_N_DSEGMENTS];
315   uint32_t esegs[JA_N_ESEGMENTS];
316   uint8_t segregate_threshold;
317   uint8_t n_element_variation;
318 };
319 
320 struct grn_ja_header {
321   uint32_t flags;
322   uint32_t *curr_seg;
323   uint32_t *curr_pos;
324   uint32_t max_element_size;
325   ja_pos *free_elements;
326   uint32_t *garbages;
327   uint32_t *ngarbages;
328   uint32_t *dsegs;
329   uint32_t *esegs;
330   uint8_t segregate_threshold;
331   uint8_t n_element_variation;
332 };
333 
334 #define SEG_SEQ        (0x10000000U)
335 #define SEG_HUGE       (0x20000000U)
336 #define SEG_EINFO      (0x30000000U)
337 #define SEG_GINFO      (0x40000000U)
338 #define SEG_MASK       (0xf0000000U)
339 
340 #define SEGMENTS_AT(ja,seg) ((ja)->header->dsegs[seg])
341 #define SEGMENTS_SEGRE_ON(ja,seg,width) (SEGMENTS_AT(ja,seg) = width)
342 #define SEGMENTS_SEQ_ON(ja,seg) (SEGMENTS_AT(ja,seg) = SEG_SEQ)
343 #define SEGMENTS_HUGE_ON(ja,seg) (SEGMENTS_AT(ja,seg) = SEG_HUGE)
344 #define SEGMENTS_EINFO_ON(ja,seg,lseg) (SEGMENTS_AT(ja,seg) = SEG_EINFO|(lseg))
345 #define SEGMENTS_GINFO_ON(ja,seg,width) (SEGMENTS_AT(ja,seg) = SEG_GINFO|(width))
346 #define SEGMENTS_OFF(ja,seg) (SEGMENTS_AT(ja,seg) = 0)
347 
348 static grn_ja *
_grn_ja_create(grn_ctx * ctx,grn_ja * ja,const char * path,unsigned int max_element_size,uint32_t flags)349 _grn_ja_create(grn_ctx *ctx, grn_ja *ja, const char *path,
350                unsigned int max_element_size, uint32_t flags)
351 {
352   int i;
353   grn_io *io;
354   struct grn_ja_header *header;
355   struct grn_ja_header_v2 *header_v2;
356   io = grn_io_create(ctx, path, sizeof(struct grn_ja_header_v2),
357                      JA_SEGMENT_SIZE, JA_N_DSEGMENTS, grn_io_auto,
358                      GRN_IO_EXPIRE_SEGMENT);
359   if (!io) { return NULL; }
360   grn_io_set_type(io, GRN_COLUMN_VAR_SIZE);
361 
362   header_v2 = grn_io_header(io);
363   header_v2->flags = flags;
364   header_v2->curr_seg = 0;
365   header_v2->curr_pos = JA_SEGMENT_SIZE;
366   header_v2->max_element_size = max_element_size;
367   for (i = 0; i < JA_N_ESEGMENTS; i++) { header_v2->esegs[i] = JA_ESEG_VOID; }
368   header_v2->segregate_threshold = GRN_JA_W_SEGREGATE_THRESH_V2;
369   header_v2->n_element_variation = JA_N_ELEMENT_VARIATION_V2;
370 
371   header = GRN_MALLOCN(struct grn_ja_header, 1);
372   if (!header) {
373     grn_io_close(ctx, io);
374     return NULL;
375   }
376   header->flags               = header_v2->flags;
377   header->curr_seg            = &(header_v2->curr_seg);
378   header->curr_pos            = &(header_v2->curr_pos);
379   header->max_element_size    = header_v2->max_element_size;
380   header->free_elements       = header_v2->free_elements;
381   header->garbages            = header_v2->garbages;
382   header->ngarbages           = header_v2->ngarbages;
383   header->dsegs               = header_v2->dsegs;
384   header->esegs               = header_v2->esegs;
385   header->segregate_threshold = header_v2->segregate_threshold;
386   header->n_element_variation = header_v2->n_element_variation;
387 
388   ja->io = io;
389   ja->header = header;
390   SEGMENTS_EINFO_ON(ja, 0, 0);
391   header->esegs[0] = 0;
392   return ja;
393 }
394 
395 grn_ja *
grn_ja_create(grn_ctx * ctx,const char * path,unsigned int max_element_size,uint32_t flags)396 grn_ja_create(grn_ctx *ctx, const char *path, unsigned int max_element_size, uint32_t flags)
397 {
398   grn_ja *ja = NULL;
399   ja = (grn_ja *)GRN_CALLOC(sizeof(grn_ja));
400   if (!ja) {
401     return NULL;
402   }
403   GRN_DB_OBJ_SET_TYPE(ja, GRN_COLUMN_VAR_SIZE);
404   if (!_grn_ja_create(ctx, ja, path, max_element_size, flags)) {
405     GRN_FREE(ja);
406     return NULL;
407   }
408   return ja;
409 }
410 
411 grn_ja *
grn_ja_open(grn_ctx * ctx,const char * path)412 grn_ja_open(grn_ctx *ctx, const char *path)
413 {
414   grn_io *io;
415   grn_ja *ja = NULL;
416   struct grn_ja_header *header;
417   struct grn_ja_header_v2 *header_v2;
418   uint32_t io_type;
419   io = grn_io_open(ctx, path, grn_io_auto);
420   if (!io) { return NULL; }
421   header_v2 = grn_io_header(io);
422   io_type = grn_io_get_type(io);
423   if (io_type != GRN_COLUMN_VAR_SIZE) {
424     ERR(GRN_INVALID_FORMAT,
425         "[column][var-size] file type must be %#04x: <%#04x>",
426         GRN_COLUMN_VAR_SIZE, io_type);
427     grn_io_close(ctx, io);
428     return NULL;
429   }
430   if (header_v2->segregate_threshold == 0) {
431     header_v2->segregate_threshold = GRN_JA_W_SEGREGATE_THRESH_V1;
432   }
433   if (header_v2->n_element_variation == 0) {
434     header_v2->n_element_variation = JA_N_ELEMENT_VARIATION_V1;
435   }
436   ja = GRN_MALLOCN(grn_ja, 1);
437   if (!ja) {
438     grn_io_close(ctx, io);
439     return NULL;
440   }
441   GRN_DB_OBJ_SET_TYPE(ja, GRN_COLUMN_VAR_SIZE);
442   header = GRN_MALLOCN(struct grn_ja_header, 1);
443   if (!header) {
444     grn_io_close(ctx, io);
445     GRN_FREE(ja);
446     return NULL;
447   }
448 
449   header->flags               = header_v2->flags;
450   header->curr_seg            = &(header_v2->curr_seg);
451   header->curr_pos            = &(header_v2->curr_pos);
452   header->max_element_size    = header_v2->max_element_size;
453   header->segregate_threshold = header_v2->segregate_threshold;
454   header->n_element_variation = header_v2->n_element_variation;
455   if (header->segregate_threshold == GRN_JA_W_SEGREGATE_THRESH_V1) {
456     struct grn_ja_header_v1 *header_v1 = (struct grn_ja_header_v1 *)header_v2;
457     header->free_elements = header_v1->free_elements;
458     header->garbages      = header_v1->garbages;
459     header->ngarbages     = header_v1->ngarbages;
460     header->dsegs         = header_v1->dsegs;
461     header->esegs         = header_v1->esegs;
462   } else {
463     header->free_elements = header_v2->free_elements;
464     header->garbages      = header_v2->garbages;
465     header->ngarbages     = header_v2->ngarbages;
466     header->dsegs         = header_v2->dsegs;
467     header->esegs         = header_v2->esegs;
468   }
469 
470   ja->io = io;
471   ja->header = header;
472 
473   return ja;
474 }
475 
476 grn_rc
grn_ja_info(grn_ctx * ctx,grn_ja * ja,unsigned int * max_element_size)477 grn_ja_info(grn_ctx *ctx, grn_ja *ja, unsigned int *max_element_size)
478 {
479   if (!ja) { return GRN_INVALID_ARGUMENT; }
480   if (max_element_size) { *max_element_size = ja->header->max_element_size; }
481   return GRN_SUCCESS;
482 }
483 
484 grn_column_flags
grn_ja_get_flags(grn_ctx * ctx,grn_ja * ja)485 grn_ja_get_flags(grn_ctx *ctx, grn_ja *ja)
486 {
487   if (!ja) {
488     return 0;
489   }
490 
491   return ja->header->flags;
492 }
493 
494 grn_rc
grn_ja_close(grn_ctx * ctx,grn_ja * ja)495 grn_ja_close(grn_ctx *ctx, grn_ja *ja)
496 {
497   grn_rc rc;
498   if (!ja) { return GRN_INVALID_ARGUMENT; }
499   rc = grn_io_close(ctx, ja->io);
500   GRN_FREE(ja->header);
501   GRN_FREE(ja);
502   return rc;
503 }
504 
505 grn_rc
grn_ja_remove(grn_ctx * ctx,const char * path)506 grn_ja_remove(grn_ctx *ctx, const char *path)
507 {
508   if (!path) { return GRN_INVALID_ARGUMENT; }
509   return grn_io_remove(ctx, path);
510 }
511 
512 grn_rc
grn_ja_truncate(grn_ctx * ctx,grn_ja * ja)513 grn_ja_truncate(grn_ctx *ctx, grn_ja *ja)
514 {
515   grn_rc rc;
516   const char *io_path;
517   char *path;
518   unsigned int max_element_size;
519   uint32_t flags;
520   if ((io_path = grn_io_path(ja->io)) && *io_path != '\0') {
521     if (!(path = GRN_STRDUP(io_path))) {
522       ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_path);
523       return GRN_NO_MEMORY_AVAILABLE;
524     }
525   } else {
526     path = NULL;
527   }
528   max_element_size = ja->header->max_element_size;
529   flags = ja->header->flags;
530   if ((rc = grn_io_close(ctx, ja->io))) { goto exit; }
531   ja->io = NULL;
532   if (path && (rc = grn_io_remove(ctx, path))) { goto exit; }
533   GRN_FREE(ja->header);
534   if (!_grn_ja_create(ctx, ja, path, max_element_size, flags)) {
535     rc = GRN_UNKNOWN_ERROR;
536   }
537 exit:
538   if (path) { GRN_FREE(path); }
539   return rc;
540 }
541 
542 static void *
grn_ja_ref_raw(grn_ctx * ctx,grn_ja * ja,grn_id id,grn_io_win * iw,uint32_t * value_len)543 grn_ja_ref_raw(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_io_win *iw, uint32_t *value_len)
544 {
545   uint32_t pseg = ja->header->esegs[id >> JA_W_EINFO_IN_A_SEGMENT];
546   iw->size = 0;
547   iw->addr = NULL;
548   iw->pseg = pseg;
549   iw->uncompressed_value = NULL;
550   if (pseg != JA_ESEG_VOID) {
551     grn_ja_einfo *einfo = NULL;
552     GRN_IO_SEG_REF(ja->io, pseg, einfo);
553     if (einfo) {
554       grn_ja_einfo *ei = &einfo[id & JA_M_EINFO_IN_A_SEGMENT];
555       if (ETINY_P(ei)) {
556         iw->tiny_p = 1;
557         ETINY_DEC(ei, iw->size);
558         iw->io = ja->io;
559         iw->ctx = ctx;
560         iw->addr = (void *)ei;
561       } else {
562         uint32_t jag, vpos, vsize;
563         iw->tiny_p = 0;
564         if (EHUGE_P(ei)) {
565           EHUGE_DEC(ei, jag, vsize);
566           vpos = 0;
567         } else {
568           EINFO_DEC(ei, jag, vpos, vsize);
569         }
570         grn_io_win_map(ja->io, ctx, iw, jag, vpos, vsize, grn_io_rdonly);
571       }
572       if (!iw->addr) { GRN_IO_SEG_UNREF(ja->io, pseg); }
573     }
574   }
575   *value_len = iw->size;
576   return iw->addr;
577 }
578 
579 grn_rc
grn_ja_unref(grn_ctx * ctx,grn_io_win * iw)580 grn_ja_unref(grn_ctx *ctx, grn_io_win *iw)
581 {
582   if (iw->uncompressed_value) {
583     GRN_FREE(iw->uncompressed_value);
584     iw->uncompressed_value = NULL;
585   }
586   if (!iw->addr) { return GRN_INVALID_ARGUMENT; }
587   GRN_IO_SEG_UNREF(iw->io, iw->pseg);
588   if (!iw->tiny_p) { grn_io_win_unmap(iw); }
589   return GRN_SUCCESS;
590 }
591 
592 #define DELETED 0x80000000
593 
594 static grn_rc
grn_ja_free(grn_ctx * ctx,grn_ja * ja,grn_ja_einfo * einfo)595 grn_ja_free(grn_ctx *ctx, grn_ja *ja, grn_ja_einfo *einfo)
596 {
597   grn_ja_ginfo *ginfo = NULL;
598   uint32_t seg, pos, element_size, aligned_size, m, *gseg;
599   if (ETINY_P(einfo)) { return GRN_SUCCESS; }
600   if (EHUGE_P(einfo)) {
601     uint32_t n;
602     EHUGE_DEC(einfo, seg, element_size);
603     n = ((element_size + JA_SEGMENT_SIZE - 1) >> GRN_JA_W_SEGMENT);
604     for (; n--; seg++) { SEGMENTS_OFF(ja, seg); }
605     return GRN_SUCCESS;
606   }
607   EINFO_DEC(einfo, seg, pos, element_size);
608   if (!element_size) { return GRN_SUCCESS; }
609   {
610     int es = element_size - 1;
611     GRN_BIT_SCAN_REV(es, m);
612     m++;
613   }
614   if (m > ja->header->segregate_threshold) {
615     byte *addr = NULL;
616     GRN_IO_SEG_REF(ja->io, seg, addr);
617     if (!addr) { return GRN_NO_MEMORY_AVAILABLE; }
618     aligned_size = (element_size + sizeof(grn_id) - 1) & ~(sizeof(grn_id) - 1);
619     *(uint32_t *)(addr + pos - sizeof(grn_id)) = DELETED|aligned_size;
620     if (SEGMENTS_AT(ja, seg) < (aligned_size + sizeof(grn_id)) + SEG_SEQ) {
621       GRN_LOG(ctx, GRN_WARN, "inconsistent ja entry detected (%d > %d)",
622               element_size, SEGMENTS_AT(ja, seg) - SEG_SEQ);
623     }
624     SEGMENTS_AT(ja, seg) -= (aligned_size + sizeof(grn_id));
625     if (SEGMENTS_AT(ja, seg) == SEG_SEQ) {
626       /* reuse the segment */
627       SEGMENTS_OFF(ja, seg);
628       if (seg == *(ja->header->curr_seg)) {
629         *(ja->header->curr_pos) = JA_SEGMENT_SIZE;
630       }
631     }
632     GRN_IO_SEG_UNREF(ja->io, seg);
633   } else {
634     uint32_t lseg = 0, lseg_;
635     gseg = &ja->header->garbages[m - JA_W_EINFO];
636     while ((lseg_ = *gseg)) {
637       if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
638       GRN_IO_SEG_REF(ja->io, lseg_, ginfo);
639       if (!ginfo) {
640         return GRN_NO_MEMORY_AVAILABLE;
641       }
642       lseg = lseg_;
643       if (ginfo->nrecs < JA_N_GARBAGES_IN_A_SEGMENT) { break; }
644       gseg = &ginfo->next;
645     }
646     if (!lseg_) {
647       uint32_t i = 0;
648       while (SEGMENTS_AT(ja, i)) {
649         if (++i >= JA_N_DSEGMENTS) {
650           if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
651           return GRN_NO_MEMORY_AVAILABLE;
652         }
653       }
654       SEGMENTS_GINFO_ON(ja, i, m - JA_W_EINFO);
655       *gseg = i;
656       lseg_ = *gseg;
657       if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
658       GRN_IO_SEG_REF(ja->io, lseg_, ginfo);
659       lseg = lseg_;
660       if (!ginfo) {
661         return GRN_NO_MEMORY_AVAILABLE;
662       }
663       ginfo->head = 0;
664       ginfo->tail = 0;
665       ginfo->nrecs = 0;
666       ginfo->next = 0;
667     }
668     ginfo->recs[ginfo->head].seg = seg;
669     ginfo->recs[ginfo->head].pos = pos;
670     if (++ginfo->head == JA_N_GARBAGES_IN_A_SEGMENT) { ginfo->head = 0; }
671     ginfo->nrecs++;
672     ja->header->ngarbages[m - JA_W_EINFO]++;
673     if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
674   }
675   return GRN_SUCCESS;
676 }
677 
678 grn_rc
grn_ja_replace(grn_ctx * ctx,grn_ja * ja,grn_id id,grn_ja_einfo * ei,uint64_t * cas)679 grn_ja_replace(grn_ctx *ctx, grn_ja *ja, grn_id id,
680                grn_ja_einfo *ei, uint64_t *cas)
681 {
682   grn_rc rc = GRN_SUCCESS;
683   uint32_t lseg, *pseg, pos;
684   grn_ja_einfo *einfo = NULL, eback;
685   lseg = id >> JA_W_EINFO_IN_A_SEGMENT;
686   pos = id & JA_M_EINFO_IN_A_SEGMENT;
687   pseg = &ja->header->esegs[lseg];
688   if (grn_io_lock(ctx, ja->io, grn_lock_timeout)) {
689     return ctx->rc;
690   }
691   if (*pseg == JA_ESEG_VOID) {
692     int i = 0;
693     while (SEGMENTS_AT(ja, i)) {
694       if (++i >= JA_N_DSEGMENTS) {
695         ERR(GRN_NOT_ENOUGH_SPACE, "grn_ja file (%s) is full", ja->io->path);
696         rc = GRN_NOT_ENOUGH_SPACE;
697         goto exit;
698       }
699     }
700     SEGMENTS_EINFO_ON(ja, i, lseg);
701     GRN_IO_SEG_REF(ja->io, i, einfo);
702     if (einfo) {
703       *pseg = i;
704       memset(einfo, 0, JA_SEGMENT_SIZE);
705     }
706   } else {
707     GRN_IO_SEG_REF(ja->io, *pseg, einfo);
708   }
709   if (!einfo) {
710     rc = GRN_NO_MEMORY_AVAILABLE;
711     goto exit;
712   }
713   eback = einfo[pos];
714   if (cas && *cas != *((uint64_t *)&eback)) {
715     ERR(GRN_CAS_ERROR, "cas failed (%d)", id);
716     GRN_IO_SEG_UNREF(ja->io, *pseg);
717     rc = GRN_CAS_ERROR;
718     goto exit;
719   }
720   // smb_wmb();
721   {
722     uint64_t *location = (uint64_t *)(einfo + pos);
723     uint64_t value = *((uint64_t *)ei);
724     GRN_SET_64BIT(location, value);
725   }
726   GRN_IO_SEG_UNREF(ja->io, *pseg);
727   grn_ja_free(ctx, ja, &eback);
728 exit :
729   grn_io_unlock(ja->io);
730   return rc;
731 }
732 
733 #define JA_N_GARBAGES_TH 10
734 
735 // todo : grn_io_win_map cause verbose copy when nseg > 1, it should be copied directly.
736 static grn_rc
grn_ja_alloc(grn_ctx * ctx,grn_ja * ja,grn_id id,uint32_t element_size,grn_ja_einfo * einfo,grn_io_win * iw)737 grn_ja_alloc(grn_ctx *ctx, grn_ja *ja, grn_id id,
738              uint32_t element_size, grn_ja_einfo *einfo, grn_io_win *iw)
739 {
740   byte *addr = NULL;
741   iw->io = ja->io;
742   iw->ctx = ctx;
743   iw->cached = 1;
744   if (element_size < 8) {
745     ETINY_ENC(einfo, element_size);
746     iw->tiny_p = 1;
747     iw->addr = (void *)einfo;
748     return GRN_SUCCESS;
749   }
750   iw->tiny_p = 0;
751   if (grn_io_lock(ctx, ja->io, grn_lock_timeout)) { return ctx->rc; }
752   if (element_size + sizeof(grn_id) > JA_SEGMENT_SIZE) {
753     int i, j, n = (element_size + JA_SEGMENT_SIZE - 1) >> GRN_JA_W_SEGMENT;
754     for (i = 0, j = -1; i < JA_N_DSEGMENTS; i++) {
755       if (SEGMENTS_AT(ja, i)) {
756         j = i;
757       } else {
758         if (i == j + n) {
759           j++;
760           addr = grn_io_win_map(ja->io, ctx, iw, j, 0, element_size, grn_io_wronly);
761           if (!addr) {
762             grn_io_unlock(ja->io);
763             return GRN_NO_MEMORY_AVAILABLE;
764           }
765           EHUGE_ENC(einfo, j, element_size);
766           for (; j <= i; j++) { SEGMENTS_HUGE_ON(ja, j); }
767           grn_io_unlock(ja->io);
768           return GRN_SUCCESS;
769         }
770       }
771     }
772     GRN_LOG(ctx, GRN_LOG_CRIT, "ja full. requested element_size=%d.", element_size);
773     grn_io_unlock(ja->io);
774     return GRN_NO_MEMORY_AVAILABLE;
775   } else {
776     ja_pos *vp;
777     int m, aligned_size, es = element_size - 1;
778     GRN_BIT_SCAN_REV(es, m);
779     m++;
780     if (m > ja->header->segregate_threshold) {
781       uint32_t seg = *(ja->header->curr_seg);
782       uint32_t pos = *(ja->header->curr_pos);
783       if (pos + element_size + sizeof(grn_id) > JA_SEGMENT_SIZE) {
784         seg = 0;
785         while (SEGMENTS_AT(ja, seg)) {
786           if (++seg >= JA_N_DSEGMENTS) {
787             grn_io_unlock(ja->io);
788             GRN_LOG(ctx, GRN_LOG_CRIT, "ja full. seg=%d.", seg);
789             return GRN_NOT_ENOUGH_SPACE;
790           }
791         }
792         SEGMENTS_SEQ_ON(ja, seg);
793         *(ja->header->curr_seg) = seg;
794         pos = 0;
795       }
796       GRN_IO_SEG_REF(ja->io, seg, addr);
797       if (!addr) {
798         grn_io_unlock(ja->io);
799         return GRN_NO_MEMORY_AVAILABLE;
800       }
801       *(grn_id *)(addr + pos) = id;
802       aligned_size = (element_size + sizeof(grn_id) - 1) & ~(sizeof(grn_id) - 1);
803       if (pos + aligned_size < JA_SEGMENT_SIZE) {
804         *(grn_id *)(addr + pos + aligned_size) = GRN_ID_NIL;
805       }
806       SEGMENTS_AT(ja, seg) += aligned_size + sizeof(grn_id);
807       pos += sizeof(grn_id);
808       EINFO_ENC(einfo, seg, pos, element_size);
809       iw->segment = seg;
810       iw->addr = addr + pos;
811       *(ja->header->curr_pos) = pos + aligned_size;
812       grn_io_unlock(ja->io);
813       return GRN_SUCCESS;
814     } else {
815       uint32_t lseg = 0, lseg_;
816       aligned_size = 1 << m;
817       if (ja->header->ngarbages[m - JA_W_EINFO] > JA_N_GARBAGES_TH) {
818         grn_ja_ginfo *ginfo = NULL;
819         uint32_t seg, pos, *gseg;
820         gseg = &ja->header->garbages[m - JA_W_EINFO];
821         while ((lseg_ = *gseg)) {
822           GRN_IO_SEG_REF(ja->io, lseg_, ginfo);
823           if (!ginfo) {
824             if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
825             grn_io_unlock(ja->io);
826             return GRN_NO_MEMORY_AVAILABLE;
827           }
828           if (ginfo->next || ginfo->nrecs > JA_N_GARBAGES_TH) {
829             seg = ginfo->recs[ginfo->tail].seg;
830             pos = ginfo->recs[ginfo->tail].pos;
831             GRN_IO_SEG_REF(ja->io, seg, addr);
832             if (!addr) {
833               if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
834               GRN_IO_SEG_UNREF(ja->io, lseg_);
835               grn_io_unlock(ja->io);
836               return GRN_NO_MEMORY_AVAILABLE;
837             }
838             EINFO_ENC(einfo, seg, pos, element_size);
839             iw->segment = seg;
840             iw->addr = addr + pos;
841             if (++ginfo->tail == JA_N_GARBAGES_IN_A_SEGMENT) { ginfo->tail = 0; }
842             ginfo->nrecs--;
843             ja->header->ngarbages[m - JA_W_EINFO]--;
844             if (!ginfo->nrecs) {
845               SEGMENTS_OFF(ja, *gseg);
846               *gseg = ginfo->next;
847             }
848             if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
849             GRN_IO_SEG_UNREF(ja->io, lseg_);
850             grn_io_unlock(ja->io);
851             return GRN_SUCCESS;
852           }
853           if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
854           if (!ginfo->next) {
855             GRN_IO_SEG_UNREF(ja->io, lseg_);
856             break;
857           }
858           lseg = lseg_;
859           gseg = &ginfo->next;
860         }
861       }
862       vp = &ja->header->free_elements[m - JA_W_EINFO];
863       if (!vp->seg) {
864         int i = 0;
865         while (SEGMENTS_AT(ja, i)) {
866           if (++i >= JA_N_DSEGMENTS) {
867             grn_io_unlock(ja->io);
868             return GRN_NO_MEMORY_AVAILABLE;
869           }
870         }
871         SEGMENTS_SEGRE_ON(ja, i, m);
872         vp->seg = i;
873         vp->pos = 0;
874       }
875     }
876     EINFO_ENC(einfo, vp->seg, vp->pos, element_size);
877     GRN_IO_SEG_REF(ja->io, vp->seg, addr);
878     if (!addr) {
879       grn_io_unlock(ja->io);
880       return GRN_NO_MEMORY_AVAILABLE;
881     }
882     iw->segment = vp->seg;
883     iw->addr = addr + vp->pos;
884     if ((vp->pos += aligned_size) == JA_SEGMENT_SIZE) {
885       vp->seg = 0;
886       vp->pos = 0;
887     }
888     iw->uncompressed_value = NULL;
889     grn_io_unlock(ja->io);
890     return GRN_SUCCESS;
891   }
892 }
893 
894 static grn_rc
set_value(grn_ctx * ctx,grn_ja * ja,grn_id id,void * value,uint32_t value_len,grn_ja_einfo * einfo)895 set_value(grn_ctx *ctx, grn_ja *ja, grn_id id, void *value, uint32_t value_len,
896           grn_ja_einfo *einfo)
897 {
898   grn_rc rc = GRN_SUCCESS;
899   grn_io_win iw;
900   if ((ja->header->flags & GRN_OBJ_RING_BUFFER) &&
901       value_len >= ja->header->max_element_size) {
902     if ((rc = grn_ja_alloc(ctx, ja, id, value_len + sizeof(uint32_t), einfo, &iw))) {
903       return rc;
904     }
905     grn_memcpy(iw.addr, value, value_len);
906     memset((byte *)iw.addr + value_len, 0, sizeof(uint32_t));
907     grn_io_win_unmap(&iw);
908   } else {
909     if ((rc = grn_ja_alloc(ctx, ja, id, value_len, einfo, &iw))) { return rc; }
910     grn_memcpy(iw.addr, value, value_len);
911     grn_io_win_unmap(&iw);
912   }
913   return rc;
914 }
915 
916 static grn_rc
grn_ja_put_raw(grn_ctx * ctx,grn_ja * ja,grn_id id,void * value,uint32_t value_len,int flags,uint64_t * cas)917 grn_ja_put_raw(grn_ctx *ctx, grn_ja *ja, grn_id id,
918                void *value, uint32_t value_len, int flags, uint64_t *cas)
919 {
920   int rc;
921   int64_t buf;
922   grn_io_win iw;
923   grn_ja_einfo einfo;
924 
925   if ((flags & GRN_OBJ_SET_MASK) == GRN_OBJ_SET &&
926       value_len > 0) {
927     grn_io_win jw;
928     uint32_t old_len;
929     void *old_value;
930     grn_bool same_value = GRN_FALSE;
931 
932     old_value = grn_ja_ref(ctx, ja, id, &jw, &old_len);
933     if (value_len == old_len && memcmp(value, old_value, value_len) == 0) {
934       same_value = GRN_TRUE;
935     }
936     grn_ja_unref(ctx, &jw);
937     if (same_value) {
938       return GRN_SUCCESS;
939     }
940   }
941 
942   switch (flags & GRN_OBJ_SET_MASK) {
943   case GRN_OBJ_APPEND :
944     if (value_len) {
945       grn_io_win jw;
946       uint32_t old_len;
947       void *oldvalue = grn_ja_ref(ctx, ja, id, &jw, &old_len);
948       if (oldvalue) {
949         if ((ja->header->flags & GRN_OBJ_RING_BUFFER) &&
950             old_len + value_len >= ja->header->max_element_size) {
951           if (old_len >= ja->header->max_element_size) {
952             byte *b = oldvalue;
953             uint32_t el = old_len - sizeof(uint32_t);
954             uint32_t pos = *((uint32_t *)(b + el));
955             GRN_ASSERT(pos < el);
956             if (el <= pos + value_len) {
957               uint32_t rest = el - pos;
958               grn_memcpy(b + pos, value, rest);
959               grn_memcpy(b, (byte *)value + rest, value_len - rest);
960               *((uint32_t *)(b + el)) = value_len - rest;
961             } else {
962               grn_memcpy(b + pos, value, value_len);
963               *((uint32_t *)(b + el)) = pos + value_len;
964             }
965             return GRN_SUCCESS;
966           } else {
967             if ((rc = grn_ja_alloc(ctx, ja, id,
968                                    value_len + old_len + sizeof(uint32_t),
969                                    &einfo, &iw))) {
970               grn_ja_unref(ctx, &jw);
971               return rc;
972             }
973             grn_memcpy(iw.addr, oldvalue, old_len);
974             grn_memcpy((byte *)iw.addr + old_len, value, value_len);
975             memset((byte *)iw.addr + old_len + value_len, 0, sizeof(uint32_t));
976             grn_io_win_unmap(&iw);
977           }
978         } else {
979           if ((rc = grn_ja_alloc(ctx, ja, id, value_len + old_len, &einfo, &iw))) {
980             grn_ja_unref(ctx, &jw);
981             return rc;
982           }
983           grn_memcpy(iw.addr, oldvalue, old_len);
984           grn_memcpy((byte *)iw.addr + old_len, value, value_len);
985           grn_io_win_unmap(&iw);
986         }
987         grn_ja_unref(ctx, &jw);
988       } else {
989         set_value(ctx, ja, id, value, value_len, &einfo);
990       }
991     }
992     break;
993   case GRN_OBJ_PREPEND :
994     if (value_len) {
995       grn_io_win jw;
996       uint32_t old_len;
997       void *oldvalue = grn_ja_ref(ctx, ja, id, &jw, &old_len);
998       if (oldvalue) {
999         if ((ja->header->flags & GRN_OBJ_RING_BUFFER) &&
1000             old_len + value_len >= ja->header->max_element_size) {
1001           if (old_len >= ja->header->max_element_size) {
1002             byte *b = oldvalue;
1003             uint32_t el = old_len - sizeof(uint32_t);
1004             uint32_t pos = *((uint32_t *)(b + el));
1005             GRN_ASSERT(pos < el);
1006             if (pos < value_len) {
1007               uint32_t rest = value_len - pos;
1008               grn_memcpy(b, (byte *)value + rest, pos);
1009               grn_memcpy(b + el - rest, value, rest);
1010               *((uint32_t *)(b + el)) = el - rest;
1011             } else {
1012               grn_memcpy(b + pos - value_len, value, value_len);
1013               *((uint32_t *)(b + el)) = pos - value_len;
1014             }
1015             return GRN_SUCCESS;
1016           } else {
1017             if ((rc = grn_ja_alloc(ctx, ja, id,
1018                                    value_len + old_len + sizeof(uint32_t),
1019                                    &einfo, &iw))) {
1020               grn_ja_unref(ctx, &jw);
1021               return rc;
1022             }
1023             grn_memcpy(iw.addr, value, value_len);
1024             grn_memcpy((byte *)iw.addr + value_len, oldvalue, old_len);
1025             memset((byte *)iw.addr + value_len + old_len, 0, sizeof(uint32_t));
1026             grn_io_win_unmap(&iw);
1027           }
1028         } else {
1029           if ((rc = grn_ja_alloc(ctx, ja, id, value_len + old_len, &einfo, &iw))) {
1030             grn_ja_unref(ctx, &jw);
1031             return rc;
1032           }
1033           grn_memcpy(iw.addr, value, value_len);
1034           grn_memcpy((byte *)iw.addr + value_len, oldvalue, old_len);
1035           grn_io_win_unmap(&iw);
1036         }
1037         grn_ja_unref(ctx, &jw);
1038       } else {
1039         set_value(ctx, ja, id, value, value_len, &einfo);
1040       }
1041     }
1042     break;
1043   case GRN_OBJ_DECR :
1044     if (value_len == sizeof(int64_t)) {
1045       int64_t *v = (int64_t *)&buf;
1046       *v = -(*(int64_t *)value);
1047       value = v;
1048     } else if (value_len == sizeof(int32_t)) {
1049       int32_t *v = (int32_t *)&buf;
1050       *v = -(*(int32_t *)value);
1051       value = v;
1052     } else {
1053       return GRN_INVALID_ARGUMENT;
1054     }
1055     /* fallthru */
1056   case GRN_OBJ_INCR :
1057     {
1058       grn_io_win jw;
1059       uint32_t old_len;
1060       void *oldvalue = grn_ja_ref(ctx, ja, id, &jw, &old_len);
1061       if (oldvalue && old_len) {
1062         grn_rc rc = GRN_INVALID_ARGUMENT;
1063         if (old_len == sizeof(int64_t) && value_len == sizeof(int64_t)) {
1064           (*(int64_t *)oldvalue) += (*(int64_t *)value);
1065           rc = GRN_SUCCESS;
1066         } else if (old_len == sizeof(int32_t) && value_len == sizeof(int32_t)) {
1067           (*(int32_t *)oldvalue) += (*(int32_t *)value);
1068           rc = GRN_SUCCESS;
1069         }
1070         grn_ja_unref(ctx, &jw);
1071         return rc;
1072       }
1073     }
1074     /* fallthru */
1075   case GRN_OBJ_SET :
1076     if (value_len) {
1077       set_value(ctx, ja, id, value, value_len, &einfo);
1078     } else {
1079       memset(&einfo, 0, sizeof(grn_ja_einfo));
1080     }
1081     break;
1082   default :
1083     ERR(GRN_INVALID_ARGUMENT, "grn_ja_put_raw called with illegal flags value");
1084     return GRN_INVALID_ARGUMENT;
1085   }
1086   if ((rc = grn_ja_replace(ctx, ja, id, &einfo, cas))) {
1087     if (!grn_io_lock(ctx, ja->io, grn_lock_timeout)) {
1088       grn_ja_free(ctx, ja, &einfo);
1089       grn_io_unlock(ja->io);
1090     }
1091   }
1092   return rc;
1093 }
1094 
1095 grn_rc
grn_ja_putv(grn_ctx * ctx,grn_ja * ja,grn_id id,grn_obj * vector,int flags)1096 grn_ja_putv(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_obj *vector, int flags)
1097 {
1098   grn_obj header, footer;
1099   grn_rc rc = GRN_SUCCESS;
1100   grn_section *vp;
1101   int i, f = 0, n = grn_vector_size(ctx, vector);
1102   GRN_TEXT_INIT(&header, 0);
1103   GRN_TEXT_INIT(&footer, 0);
1104   grn_text_benc(ctx, &header, n);
1105   for (i = 0, vp = vector->u.v.sections; i < n; i++, vp++) {
1106     grn_text_benc(ctx, &header, vp->length);
1107     if (vp->weight || vp->domain) { f = 1; }
1108   }
1109   if (f) {
1110     for (i = 0, vp = vector->u.v.sections; i < n; i++, vp++) {
1111       grn_text_benc(ctx, &footer, vp->weight);
1112       grn_text_benc(ctx, &footer, vp->domain);
1113     }
1114   }
1115   {
1116     grn_io_win iw;
1117     grn_ja_einfo einfo;
1118     grn_obj *body = vector->u.v.body;
1119     size_t sizeh = GRN_BULK_VSIZE(&header);
1120     size_t sizev = body ? GRN_BULK_VSIZE(body) : 0;
1121     size_t sizef = GRN_BULK_VSIZE(&footer);
1122     if ((rc = grn_ja_alloc(ctx, ja, id, sizeh + sizev + sizef, &einfo, &iw))) { goto exit; }
1123     grn_memcpy(iw.addr, GRN_BULK_HEAD(&header), sizeh);
1124     if (body) {
1125       grn_memcpy((char *)iw.addr + sizeh, GRN_BULK_HEAD(body), sizev);
1126     }
1127     if (f) {
1128       grn_memcpy((char *)iw.addr + sizeh + sizev, GRN_BULK_HEAD(&footer), sizef);
1129     }
1130     grn_io_win_unmap(&iw);
1131     rc = grn_ja_replace(ctx, ja, id, &einfo, NULL);
1132   }
1133 exit :
1134   GRN_OBJ_FIN(ctx, &footer);
1135   GRN_OBJ_FIN(ctx, &header);
1136   return rc;
1137 }
1138 
1139 uint32_t
grn_ja_size(grn_ctx * ctx,grn_ja * ja,grn_id id)1140 grn_ja_size(grn_ctx *ctx, grn_ja *ja, grn_id id)
1141 {
1142   grn_ja_einfo *einfo = NULL, *ei;
1143   uint32_t lseg, *pseg, pos, size;
1144   lseg = id >> JA_W_EINFO_IN_A_SEGMENT;
1145   pos = id & JA_M_EINFO_IN_A_SEGMENT;
1146   pseg = &ja->header->esegs[lseg];
1147   if (*pseg == JA_ESEG_VOID) {
1148     ctx->rc = GRN_INVALID_ARGUMENT;
1149     return 0;
1150   }
1151   GRN_IO_SEG_REF(ja->io, *pseg, einfo);
1152   if (!einfo) {
1153     ctx->rc = GRN_NO_MEMORY_AVAILABLE;
1154     return 0;
1155   }
1156   ei = &einfo[pos];
1157   if (ETINY_P(ei)) {
1158     ETINY_DEC(ei, size);
1159   } else {
1160     if (EHUGE_P(ei)) {
1161       size = ei->u.h.size;
1162     } else {
1163       size = (ei->u.n.c2 << 16) + ei->u.n.size;
1164     }
1165   }
1166   GRN_IO_SEG_UNREF(ja->io, *pseg);
1167   return size;
1168 }
1169 
1170 grn_rc
grn_ja_element_info(grn_ctx * ctx,grn_ja * ja,grn_id id,uint64_t * cas,uint32_t * pos,uint32_t * size)1171 grn_ja_element_info(grn_ctx *ctx, grn_ja *ja, grn_id id,
1172                     uint64_t *cas, uint32_t *pos, uint32_t *size)
1173 {
1174   uint32_t pseg = ja->header->esegs[id >> JA_W_EINFO_IN_A_SEGMENT];
1175   if (pseg == JA_ESEG_VOID) {
1176     return GRN_INVALID_ARGUMENT;
1177   } else {
1178     grn_ja_einfo *einfo = NULL;
1179     GRN_IO_SEG_REF(ja->io, pseg, einfo);
1180     if (einfo) {
1181       grn_ja_einfo *ei;
1182       *cas = *((uint64_t *)&einfo[id & JA_M_EINFO_IN_A_SEGMENT]);
1183       ei = (grn_ja_einfo *)cas;
1184       if (ETINY_P(ei)) {
1185         ETINY_DEC(ei, *size);
1186         *pos = 0;
1187       } else {
1188         uint32_t jag;
1189         if (EHUGE_P(ei)) {
1190           EHUGE_DEC(ei, jag, *size);
1191           *pos = 0;
1192         } else {
1193           EINFO_DEC(ei, jag, *pos, *size);
1194         }
1195       }
1196       GRN_IO_SEG_UNREF(ja->io, pseg);
1197     } else {
1198       return GRN_INVALID_ARGUMENT;
1199     }
1200   }
1201   return GRN_SUCCESS;
1202 }
1203 
1204 #define COMPRESSED_VALUE_META_FLAG(meta) ((meta) & 0xf000000000000000)
1205 #define COMPRESSED_VALUE_META_FLAG_RAW             0x1000000000000000
1206 #define COMPRESSED_VALUE_META_UNCOMPRESSED_LEN(meta) \
1207                                          ((meta) & 0x0fffffffffffffff)
1208 
1209 #define COMPRESS_THRESHOLD_BYTE 256
1210 #define COMPRESS_PACKED_VALUE_SIZE_MAX 257
1211         /* COMPRESS_THRESHOLD_BYTE - 1 + sizeof(uint64_t) = 257 */
1212 
1213 #if defined(GRN_WITH_ZLIB) || defined(GRN_WITH_LZ4) || defined(GRN_WITH_ZSTD)
1214 #  define GRN_WITH_COMPRESSED
1215 #endif
1216 
1217 #ifdef GRN_WITH_COMPRESSED
1218 static void *
grn_ja_ref_packed(grn_ctx * ctx,grn_io_win * iw,uint32_t * value_len,void * raw_value,uint32_t raw_value_len,void ** compressed_value,uint32_t * compressed_value_len,uint32_t * uncompressed_value_len)1219 grn_ja_ref_packed(grn_ctx *ctx,
1220                   grn_io_win *iw,
1221                   uint32_t *value_len,
1222                   void *raw_value,
1223                   uint32_t raw_value_len,
1224                   void **compressed_value,
1225                   uint32_t *compressed_value_len,
1226                   uint32_t *uncompressed_value_len)
1227 {
1228   uint64_t compressed_value_meta;
1229 
1230   compressed_value_meta = *((uint64_t *)raw_value);
1231   *compressed_value = (void *)(((uint64_t *)raw_value) + 1);
1232   *compressed_value_len = raw_value_len - sizeof(uint64_t);
1233 
1234   *uncompressed_value_len =
1235     COMPRESSED_VALUE_META_UNCOMPRESSED_LEN(compressed_value_meta);
1236   switch (COMPRESSED_VALUE_META_FLAG(compressed_value_meta)) {
1237   case COMPRESSED_VALUE_META_FLAG_RAW :
1238     iw->uncompressed_value = NULL;
1239     *value_len = *uncompressed_value_len;
1240     return *compressed_value;
1241   default :
1242     return NULL;
1243   }
1244 }
1245 
1246 static grn_rc
grn_ja_put_packed(grn_ctx * ctx,grn_ja * ja,grn_id id,void * value,uint32_t value_len,int flags,uint64_t * cas)1247 grn_ja_put_packed(grn_ctx *ctx,
1248                   grn_ja *ja,
1249                   grn_id id,
1250                   void *value,
1251                   uint32_t value_len,
1252                   int flags,
1253                   uint64_t *cas)
1254 {
1255   char *packed_value[COMPRESS_PACKED_VALUE_SIZE_MAX];
1256   uint32_t packed_value_len;
1257   uint64_t packed_value_meta;
1258 
1259   packed_value_len = value_len + sizeof(uint64_t);
1260   packed_value_meta = value_len | COMPRESSED_VALUE_META_FLAG_RAW;
1261   *((uint64_t *)packed_value) = packed_value_meta;
1262   memcpy(((uint64_t *)packed_value) + 1,
1263          value,
1264          value_len);
1265   return grn_ja_put_raw(ctx,
1266                         ja,
1267                         id,
1268                         packed_value,
1269                         packed_value_len,
1270                         flags,
1271                         cas);
1272 }
1273 
1274 static void
grn_ja_compress_error(grn_ctx * ctx,grn_ja * ja,grn_id id,grn_rc rc,const char * message,const char * detail)1275 grn_ja_compress_error(grn_ctx *ctx,
1276                       grn_ja *ja,
1277                       grn_id id,
1278                       grn_rc rc,
1279                       const char *message,
1280                       const char *detail)
1281 {
1282   char name[GRN_TABLE_MAX_KEY_SIZE];
1283   int name_len;
1284 
1285   if (ja->obj.id == GRN_ID_NIL) {
1286     name[0] = '\0';
1287     name_len = 0;
1288   } else {
1289     name_len = grn_obj_name(ctx, (grn_obj *)ja, name, GRN_TABLE_MAX_KEY_SIZE);
1290   }
1291   ERR(GRN_ZSTD_ERROR,
1292       "[ja]%s: %s%.*s%s<%u>%s%s%s",
1293       message,
1294       name_len == 0 ? "" : "<",
1295       name_len,
1296       name,
1297       name_len == 0 ? "" : ">: ",
1298       id,
1299       detail ? " :<" : "",
1300       detail ? detail : "",
1301       detail ? ">" : "");
1302 }
1303 #endif /* GRN_WITH_COMPRESSED */
1304 
1305 #ifdef GRN_WITH_ZLIB
1306 #include <zlib.h>
1307 
1308 static const char *
grn_zrc_to_string(int zrc)1309 grn_zrc_to_string(int zrc)
1310 {
1311   switch (zrc) {
1312   case Z_OK :
1313     return "OK";
1314   case Z_STREAM_END :
1315     return "Stream is end";
1316   case Z_NEED_DICT :
1317     return "Need dictionary";
1318   case Z_ERRNO :
1319     return "See errno";
1320   case Z_STREAM_ERROR :
1321     return "Stream error";
1322   case Z_DATA_ERROR :
1323     return "Data error";
1324   case Z_MEM_ERROR :
1325     return "Memory error";
1326   case Z_BUF_ERROR :
1327     return "Buffer error";
1328   case Z_VERSION_ERROR :
1329     return "Version error";
1330   default :
1331     return "Unknown";
1332   }
1333 }
1334 
1335 static void *
grn_ja_ref_zlib(grn_ctx * ctx,grn_ja * ja,grn_id id,grn_io_win * iw,uint32_t * value_len)1336 grn_ja_ref_zlib(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_io_win *iw, uint32_t *value_len)
1337 {
1338   z_stream zstream;
1339   void *raw_value;
1340   uint32_t raw_value_len;
1341   void *zvalue;
1342   uint32_t zvalue_len;
1343   void *unpacked_value;
1344   uint32_t uncompressed_value_len;
1345   int zrc;
1346 
1347   if (!(raw_value = grn_ja_ref_raw(ctx, ja, id, iw, &raw_value_len))) {
1348     iw->uncompressed_value = NULL;
1349     *value_len = 0;
1350     return NULL;
1351   }
1352 
1353   unpacked_value = grn_ja_ref_packed(ctx,
1354                                      iw, value_len,
1355                                      raw_value, raw_value_len,
1356                                      &zvalue, &zvalue_len,
1357                                      &uncompressed_value_len);
1358   if (unpacked_value) {
1359     return unpacked_value;
1360   }
1361 
1362   zstream.next_in = (Bytef *)zvalue;
1363   zstream.avail_in = zvalue_len;
1364   zstream.zalloc = Z_NULL;
1365   zstream.zfree = Z_NULL;
1366   zrc = inflateInit2(&zstream, 15 /* windowBits */);
1367   if (zrc != Z_OK) {
1368     iw->uncompressed_value = NULL;
1369     *value_len = 0;
1370     grn_ja_compress_error(ctx,
1371                           ja,
1372                           id,
1373                           GRN_ZLIB_ERROR,
1374                           "[zlib] failed to decompress: initialize",
1375                           grn_zrc_to_string(zrc));
1376     return NULL;
1377   }
1378   if (!(iw->uncompressed_value = GRN_MALLOC(uncompressed_value_len))) {
1379     inflateEnd(&zstream);
1380     iw->uncompressed_value = NULL;
1381     *value_len = 0;
1382     grn_ja_compress_error(ctx,
1383                           ja,
1384                           id,
1385                           GRN_ZLIB_ERROR,
1386                           "[zlib] failed to decompress: allocate buffer",
1387                           NULL);
1388     return NULL;
1389   }
1390   zstream.next_out = (Bytef *)iw->uncompressed_value;
1391   zstream.avail_out = uncompressed_value_len;
1392   zrc = inflate(&zstream, Z_FINISH);
1393   if (zrc != Z_STREAM_END) {
1394     inflateEnd(&zstream);
1395     GRN_FREE(iw->uncompressed_value);
1396     iw->uncompressed_value = NULL;
1397     *value_len = 0;
1398     grn_ja_compress_error(ctx,
1399                           ja,
1400                           id,
1401                           GRN_ZLIB_ERROR,
1402                           "[zlib] failed to decompress: finish",
1403                           grn_zrc_to_string(zrc));
1404     return NULL;
1405   }
1406   *value_len = zstream.total_out;
1407   zrc = inflateEnd(&zstream);
1408   if (zrc != Z_OK) {
1409     GRN_FREE(iw->uncompressed_value);
1410     iw->uncompressed_value = NULL;
1411     *value_len = 0;
1412     grn_ja_compress_error(ctx,
1413                           ja,
1414                           id,
1415                           GRN_ZLIB_ERROR,
1416                           "[zlib] failed to decompress: end",
1417                           grn_zrc_to_string(zrc));
1418     return NULL;
1419   }
1420   return iw->uncompressed_value;
1421 }
1422 #endif /* GRN_WITH_ZLIB */
1423 
1424 #ifdef GRN_WITH_LZ4
1425 #include <lz4.h>
1426 
1427 # if (LZ4_VERSION_MAJOR == 1 && LZ4_VERSION_MINOR < 6)
1428 #  define LZ4_compress_default(source, dest, source_size, max_dest_size) \
1429   LZ4_compress((source), (dest), (source_size))
1430 # endif
1431 
1432 static void *
grn_ja_ref_lz4(grn_ctx * ctx,grn_ja * ja,grn_id id,grn_io_win * iw,uint32_t * value_len)1433 grn_ja_ref_lz4(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_io_win *iw, uint32_t *value_len)
1434 {
1435   void *raw_value;
1436   uint32_t raw_value_len;
1437   void *lz4_value;
1438   uint32_t lz4_value_len;
1439   void *unpacked_value;
1440   uint32_t uncompressed_value_len;
1441 
1442   if (!(raw_value = grn_ja_ref_raw(ctx, ja, id, iw, &raw_value_len))) {
1443     iw->uncompressed_value = NULL;
1444     *value_len = 0;
1445     return NULL;
1446   }
1447 
1448   unpacked_value = grn_ja_ref_packed(ctx,
1449                                      iw, value_len,
1450                                      raw_value, raw_value_len,
1451                                      &lz4_value, &lz4_value_len,
1452                                      &uncompressed_value_len);
1453   if (unpacked_value) {
1454     return unpacked_value;
1455   }
1456 
1457   if (!(iw->uncompressed_value = GRN_MALLOC(uncompressed_value_len))) {
1458     iw->uncompressed_value = NULL;
1459     *value_len = 0;
1460     return NULL;
1461   }
1462   if (LZ4_decompress_safe((const char *)(lz4_value),
1463                           (char *)(iw->uncompressed_value),
1464                           lz4_value_len,
1465                           uncompressed_value_len) < 0) {
1466     GRN_FREE(iw->uncompressed_value);
1467     iw->uncompressed_value = NULL;
1468     *value_len = 0;
1469     grn_ja_compress_error(ctx,
1470                           ja,
1471                           id,
1472                           GRN_LZ4_ERROR,
1473                           "[lz4] failed to decompress",
1474                           NULL);
1475     return NULL;
1476   }
1477   *value_len = uncompressed_value_len;
1478   return iw->uncompressed_value;
1479 }
1480 #endif /* GRN_WITH_LZ4 */
1481 
1482 #ifdef GRN_WITH_ZSTD
1483 #include <zstd.h>
1484 
1485 static void *
grn_ja_ref_zstd(grn_ctx * ctx,grn_ja * ja,grn_id id,grn_io_win * iw,uint32_t * value_len)1486 grn_ja_ref_zstd(grn_ctx *ctx,
1487                 grn_ja *ja,
1488                 grn_id id,
1489                 grn_io_win *iw,
1490                 uint32_t *value_len)
1491 {
1492   void *raw_value;
1493   uint32_t raw_value_len;
1494   void *zstd_value;
1495   uint32_t zstd_value_len;
1496   void *unpacked_value;
1497   uint32_t uncompressed_value_len;
1498   size_t written_len;
1499 
1500   if (!(raw_value = grn_ja_ref_raw(ctx, ja, id, iw, &raw_value_len))) {
1501     iw->uncompressed_value = NULL;
1502     *value_len = 0;
1503     return NULL;
1504   }
1505 
1506   unpacked_value = grn_ja_ref_packed(ctx,
1507                                      iw, value_len,
1508                                      raw_value, raw_value_len,
1509                                      &zstd_value, &zstd_value_len,
1510                                      &uncompressed_value_len);
1511   if (unpacked_value) {
1512     return unpacked_value;
1513   }
1514 
1515   if (!(iw->uncompressed_value = GRN_MALLOC(uncompressed_value_len))) {
1516     iw->uncompressed_value = NULL;
1517     *value_len = 0;
1518     return NULL;
1519   }
1520 
1521   written_len = ZSTD_decompress((char *)(iw->uncompressed_value),
1522                                 uncompressed_value_len,
1523                                 zstd_value,
1524                                 zstd_value_len);
1525   if (ZSTD_isError(written_len)) {
1526     GRN_FREE(iw->uncompressed_value);
1527     iw->uncompressed_value = NULL;
1528     *value_len = 0;
1529     grn_ja_compress_error(ctx,
1530                           ja,
1531                           id,
1532                           GRN_ZSTD_ERROR,
1533                           "[zstd] failed to decompress",
1534                           ZSTD_getErrorName(written_len));
1535     return NULL;
1536   }
1537   *value_len = uncompressed_value_len;
1538   return iw->uncompressed_value;
1539 }
1540 #endif /* GRN_WITH_ZSTD */
1541 
1542 void *
grn_ja_ref(grn_ctx * ctx,grn_ja * ja,grn_id id,grn_io_win * iw,uint32_t * value_len)1543 grn_ja_ref(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_io_win *iw, uint32_t *value_len)
1544 {
1545   switch (ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
1546 #ifdef GRN_WITH_ZLIB
1547   case GRN_OBJ_COMPRESS_ZLIB :
1548     return grn_ja_ref_zlib(ctx, ja, id, iw, value_len);
1549 #endif /* GRN_WITH_ZLIB */
1550 #ifdef GRN_WITH_LZ4
1551   case GRN_OBJ_COMPRESS_LZ4 :
1552     return grn_ja_ref_lz4(ctx, ja, id, iw, value_len);
1553 #endif /* GRN_WITH_LZ4 */
1554 #ifdef GRN_WITH_ZSTD
1555   case GRN_OBJ_COMPRESS_ZSTD :
1556     return grn_ja_ref_zstd(ctx, ja, id, iw, value_len);
1557 #endif /* GRN_WITH_ZSTD */
1558   default :
1559     return grn_ja_ref_raw(ctx, ja, id, iw, value_len);
1560   }
1561 }
1562 
1563 grn_obj *
grn_ja_get_value(grn_ctx * ctx,grn_ja * ja,grn_id id,grn_obj * value)1564 grn_ja_get_value(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_obj *value)
1565 {
1566   void *v;
1567   uint32_t len;
1568   grn_io_win iw;
1569   if (!value) {
1570     if (!(value = grn_obj_open(ctx, GRN_BULK, 0, 0))) {
1571       ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_value failed");
1572       goto exit;
1573     }
1574   }
1575   if ((v = grn_ja_ref(ctx, ja, id, &iw, &len))) {
1576     if ((ja->header->flags & GRN_OBJ_RING_BUFFER) &&
1577         len > ja->header->max_element_size) {
1578       byte *b = v;
1579       uint32_t el = len - sizeof(uint32_t);
1580       uint32_t pos = *((uint32_t *)(b + el));
1581       GRN_ASSERT(pos < el);
1582       grn_bulk_write(ctx, value, (char *)(b + pos), el - pos);
1583       grn_bulk_write(ctx, value, (char *)(b), pos);
1584     } else {
1585       grn_bulk_write(ctx, value, v, len);
1586     }
1587     grn_ja_unref(ctx, &iw);
1588   }
1589 exit :
1590   return value;
1591 }
1592 
1593 #ifdef GRN_WITH_ZLIB
1594 inline static grn_rc
grn_ja_put_zlib(grn_ctx * ctx,grn_ja * ja,grn_id id,void * value,uint32_t value_len,int flags,uint64_t * cas)1595 grn_ja_put_zlib(grn_ctx *ctx, grn_ja *ja, grn_id id,
1596                 void *value, uint32_t value_len, int flags, uint64_t *cas)
1597 {
1598   grn_rc rc;
1599   z_stream zstream;
1600   void *zvalue;
1601   int zvalue_len;
1602   int zrc;
1603 
1604   if (value_len == 0) {
1605     return grn_ja_put_raw(ctx, ja, id, value, value_len, flags, cas);
1606   }
1607 
1608   if (value_len < COMPRESS_THRESHOLD_BYTE) {
1609     return grn_ja_put_packed(ctx, ja, id, value, value_len, flags, cas);
1610   }
1611 
1612   zstream.next_in = value;
1613   zstream.avail_in = value_len;
1614   zstream.zalloc = Z_NULL;
1615   zstream.zfree = Z_NULL;
1616   zrc = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
1617                      15 /* windowBits */,
1618                      8 /* memLevel */,
1619                      Z_DEFAULT_STRATEGY);
1620   if (zrc != Z_OK) {
1621     grn_ja_compress_error(ctx,
1622                           ja,
1623                           id,
1624                           GRN_ZLIB_ERROR,
1625                           "[zlib] failed to compress: initialize",
1626                           grn_zrc_to_string(zrc));
1627     return ctx->rc;
1628   }
1629   zvalue_len = deflateBound(&zstream, value_len);
1630   if (!(zvalue = GRN_MALLOC(zvalue_len + sizeof(uint64_t)))) {
1631     deflateEnd(&zstream);
1632     grn_ja_compress_error(ctx,
1633                           ja,
1634                           id,
1635                           GRN_ZLIB_ERROR,
1636                           "[zlib] failed to allocate compress buffer",
1637                           NULL);
1638     return ctx->rc;
1639   }
1640   zstream.next_out = (Bytef *)(((uint64_t *)zvalue) + 1);
1641   zstream.avail_out = zvalue_len;
1642   zrc = deflate(&zstream, Z_FINISH);
1643   if (zrc != Z_STREAM_END) {
1644     deflateEnd(&zstream);
1645     GRN_FREE(zvalue);
1646     grn_ja_compress_error(ctx,
1647                           ja,
1648                           id,
1649                           GRN_ZLIB_ERROR,
1650                           "[zlib] failed to compress: finish",
1651                           grn_zrc_to_string(zrc));
1652     return ctx->rc;
1653   }
1654   zvalue_len = zstream.total_out;
1655   zrc = deflateEnd(&zstream);
1656   if (zrc != Z_OK) {
1657     GRN_FREE(zvalue);
1658     grn_ja_compress_error(ctx,
1659                           ja,
1660                           id,
1661                           GRN_ZLIB_ERROR,
1662                           "[zlib] failed to compress: end",
1663                           grn_zrc_to_string(zrc));
1664     return ctx->rc;
1665   }
1666   *(uint64_t *)zvalue = value_len;
1667   rc = grn_ja_put_raw(ctx, ja, id, zvalue, zvalue_len + sizeof(uint64_t), flags, cas);
1668   GRN_FREE(zvalue);
1669   return rc;
1670 }
1671 #endif /* GRN_WITH_ZLIB */
1672 
1673 #ifdef GRN_WITH_LZ4
1674 inline static grn_rc
grn_ja_put_lz4(grn_ctx * ctx,grn_ja * ja,grn_id id,void * value,uint32_t value_len,int flags,uint64_t * cas)1675 grn_ja_put_lz4(grn_ctx *ctx, grn_ja *ja, grn_id id,
1676                void *value, uint32_t value_len, int flags, uint64_t *cas)
1677 {
1678   grn_rc rc;
1679   void *packed_value;
1680   int packed_value_len_max;
1681   int packed_value_len_real;
1682   char *lz4_value;
1683   int lz4_value_len_max;
1684   int lz4_value_len_real;
1685 
1686   if (value_len == 0) {
1687     return grn_ja_put_raw(ctx, ja, id, value, value_len, flags, cas);
1688   }
1689 
1690   if (value_len < COMPRESS_THRESHOLD_BYTE) {
1691     return grn_ja_put_packed(ctx, ja, id, value, value_len, flags, cas);
1692   }
1693 
1694   if (value_len > (uint32_t)LZ4_MAX_INPUT_SIZE) {
1695     uint64_t packed_value_meta;
1696 
1697     packed_value_len_real = value_len + sizeof(uint64_t);
1698     packed_value = GRN_MALLOC(packed_value_len_real);
1699     if (!packed_value) {
1700       grn_ja_compress_error(ctx,
1701                             ja,
1702                             id,
1703                             GRN_LZ4_ERROR,
1704                             "[lz4] failed to allocate packed buffer",
1705                             NULL);
1706       return ctx->rc;
1707     }
1708     packed_value_meta = value_len | COMPRESSED_VALUE_META_FLAG_RAW;
1709     *((uint64_t *)packed_value) = packed_value_meta;
1710     memcpy(((uint64_t *)packed_value) + 1,
1711            value,
1712            value_len);
1713     rc = grn_ja_put_raw(ctx,
1714                         ja,
1715                         id,
1716                         packed_value,
1717                         packed_value_len_real,
1718                         flags,
1719                         cas);
1720     GRN_FREE(packed_value);
1721     return rc;
1722   }
1723 
1724   lz4_value_len_max = LZ4_compressBound(value_len);
1725   packed_value_len_max = lz4_value_len_max + sizeof(uint64_t);
1726   if (!(packed_value = GRN_MALLOC(packed_value_len_max))) {
1727     grn_ja_compress_error(ctx,
1728                           ja,
1729                           id,
1730                           GRN_LZ4_ERROR,
1731                           "[lz4] failed to allocate compress buffer",
1732                           NULL);
1733     return ctx->rc;
1734   }
1735   lz4_value = (char *)((uint64_t *)packed_value + 1);
1736   lz4_value_len_real = LZ4_compress_default((const char *)value,
1737                                             lz4_value,
1738                                             value_len,
1739                                             lz4_value_len_max);
1740   if (lz4_value_len_real <= 0) {
1741     GRN_FREE(packed_value);
1742     grn_ja_compress_error(ctx,
1743                           ja,
1744                           id,
1745                           GRN_LZ4_ERROR,
1746                           "[lz4] failed to compress",
1747                           NULL);
1748     return ctx->rc;
1749   }
1750   *(uint64_t *)packed_value = value_len;
1751   packed_value_len_real = lz4_value_len_real + sizeof(uint64_t);
1752   rc = grn_ja_put_raw(ctx,
1753                       ja,
1754                       id,
1755                       packed_value,
1756                       packed_value_len_real,
1757                       flags,
1758                       cas);
1759   GRN_FREE(packed_value);
1760   return rc;
1761 }
1762 #endif /* GRN_WITH_LZ4 */
1763 
1764 #ifdef GRN_WITH_ZSTD
1765 inline static grn_rc
grn_ja_put_zstd(grn_ctx * ctx,grn_ja * ja,grn_id id,void * value,uint32_t value_len,int flags,uint64_t * cas)1766 grn_ja_put_zstd(grn_ctx *ctx,
1767                 grn_ja *ja,
1768                 grn_id id,
1769                 void *value,
1770                 uint32_t value_len,
1771                 int flags,
1772                 uint64_t *cas)
1773 {
1774   grn_rc rc;
1775   void *packed_value;
1776   int packed_value_len_max;
1777   int packed_value_len_real;
1778   void *zstd_value;
1779   int zstd_value_len_max;
1780   int zstd_value_len_real;
1781   int zstd_compression_level = 3;
1782 
1783   if (value_len == 0) {
1784     return grn_ja_put_raw(ctx, ja, id, value, value_len, flags, cas);
1785   }
1786 
1787   if (value_len < COMPRESS_THRESHOLD_BYTE) {
1788     return grn_ja_put_packed(ctx, ja, id, value, value_len, flags, cas);
1789   }
1790 
1791   zstd_value_len_max = ZSTD_compressBound(value_len);
1792   packed_value_len_max = zstd_value_len_max + sizeof(uint64_t);
1793   if (!(packed_value = GRN_MALLOC(packed_value_len_max))) {
1794     grn_ja_compress_error(ctx,
1795                           ja,
1796                           id,
1797                           GRN_ZSTD_ERROR,
1798                           "[zstd] failed to allocate compress buffer",
1799                           NULL);
1800     return ctx->rc;
1801   }
1802   zstd_value = ((uint64_t *)packed_value) + 1;
1803   zstd_value_len_real = ZSTD_compress(zstd_value, zstd_value_len_max,
1804                                       value, value_len,
1805                                       zstd_compression_level);
1806   if (ZSTD_isError(zstd_value_len_real)) {
1807     grn_ja_compress_error(ctx,
1808                           ja,
1809                           id,
1810                           GRN_ZSTD_ERROR,
1811                           "[zstd] failed to compress",
1812                           ZSTD_getErrorName(zstd_value_len_real));
1813     return ctx->rc;
1814   }
1815   *(uint64_t *)packed_value = value_len;
1816   packed_value_len_real = zstd_value_len_real + sizeof(uint64_t);
1817   rc = grn_ja_put_raw(ctx,
1818                       ja,
1819                       id,
1820                       packed_value,
1821                       packed_value_len_real,
1822                       flags,
1823                       cas);
1824   GRN_FREE(packed_value);
1825   return rc;
1826 }
1827 #endif /* GRN_WITH_ZSTD */
1828 
1829 grn_rc
grn_ja_put(grn_ctx * ctx,grn_ja * ja,grn_id id,void * value,uint32_t value_len,int flags,uint64_t * cas)1830 grn_ja_put(grn_ctx *ctx, grn_ja *ja, grn_id id, void *value, uint32_t value_len,
1831            int flags, uint64_t *cas)
1832 {
1833   switch (ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
1834 #ifdef GRN_WITH_ZLIB
1835   case GRN_OBJ_COMPRESS_ZLIB :
1836     return grn_ja_put_zlib(ctx, ja, id, value, value_len, flags, cas);
1837 #endif /* GRN_WITH_ZLIB */
1838 #ifdef GRN_WITH_LZ4
1839   case GRN_OBJ_COMPRESS_LZ4 :
1840     return grn_ja_put_lz4(ctx, ja, id, value, value_len, flags, cas);
1841 #endif /* GRN_WITH_LZ4 */
1842 #ifdef GRN_WITH_ZSTD
1843   case GRN_OBJ_COMPRESS_ZSTD :
1844     return grn_ja_put_zstd(ctx, ja, id, value, value_len, flags, cas);
1845 #endif /* GRN_WITH_ZSTD */
1846   default :
1847     return grn_ja_put_raw(ctx, ja, id, value, value_len, flags, cas);
1848   }
1849 }
1850 
1851 static grn_rc
grn_ja_defrag_seg(grn_ctx * ctx,grn_ja * ja,uint32_t seg)1852 grn_ja_defrag_seg(grn_ctx *ctx, grn_ja *ja, uint32_t seg)
1853 {
1854   byte *v = NULL, *ve;
1855   uint32_t element_size, cum = 0, *seginfo = &SEGMENTS_AT(ja,seg), sum;
1856   sum = (*seginfo & ~SEG_MASK);
1857   GRN_IO_SEG_REF(ja->io, seg, v);
1858   if (!v) { return GRN_NO_MEMORY_AVAILABLE; }
1859   ve = v + JA_SEGMENT_SIZE;
1860   while (v < ve && cum < sum) {
1861     grn_id id = *((grn_id *)v);
1862     if (!id) { break; }
1863     if (id & DELETED) {
1864       element_size = (id & ~DELETED);
1865     } else {
1866       uint64_t cas;
1867       uint32_t pos;
1868       if (grn_ja_element_info(ctx, ja, id, &cas, &pos, &element_size)) { break; }
1869       if (v + sizeof(uint32_t) != ve - JA_SEGMENT_SIZE + pos) {
1870         GRN_LOG(ctx, GRN_LOG_WARNING,
1871                 "dseges[%d] = pos unmatch (%d != %" GRN_FMT_LLD ")",
1872                 seg, pos, (long long int)(v + sizeof(uint32_t) + JA_SEGMENT_SIZE - ve));
1873         break;
1874       }
1875       if (grn_ja_put(ctx, ja, id, v + sizeof(uint32_t), element_size, GRN_OBJ_SET, &cas)) {
1876         GRN_LOG(ctx, GRN_LOG_WARNING,
1877                 "dseges[%d] = put failed (%d)", seg, id);
1878         break;
1879       }
1880       element_size = (element_size + sizeof(grn_id) - 1) & ~(sizeof(grn_id) - 1);
1881       cum += sizeof(uint32_t) + element_size;
1882     }
1883     v += sizeof(uint32_t) + element_size;
1884   }
1885   if (*seginfo) {
1886     GRN_LOG(ctx, GRN_LOG_WARNING, "dseges[%d] = %d after defrag", seg, (*seginfo & ~SEG_MASK));
1887   }
1888   GRN_IO_SEG_UNREF(ja->io, seg);
1889   return GRN_SUCCESS;
1890 }
1891 
1892 int
grn_ja_defrag(grn_ctx * ctx,grn_ja * ja,int threshold)1893 grn_ja_defrag(grn_ctx *ctx, grn_ja *ja, int threshold)
1894 {
1895   int nsegs = 0;
1896   uint32_t seg, ts = 1U << (GRN_JA_W_SEGMENT - threshold);
1897   for (seg = 0; seg < JA_N_DSEGMENTS; seg++) {
1898     if (seg == *(ja->header->curr_seg)) { continue; }
1899     if (((SEGMENTS_AT(ja, seg) & SEG_MASK) == SEG_SEQ) &&
1900         ((SEGMENTS_AT(ja, seg) & ~SEG_MASK) < ts)) {
1901       if (!grn_ja_defrag_seg(ctx, ja, seg)) { nsegs++; }
1902     }
1903   }
1904   return nsegs;
1905 }
1906 
1907 void
grn_ja_check(grn_ctx * ctx,grn_ja * ja)1908 grn_ja_check(grn_ctx *ctx, grn_ja *ja)
1909 {
1910   char buf[8];
1911   uint32_t seg;
1912   struct grn_ja_header *h = ja->header;
1913   GRN_OUTPUT_ARRAY_OPEN("RESULT", 8);
1914   GRN_OUTPUT_MAP_OPEN("SUMMARY", 8);
1915   GRN_OUTPUT_CSTR("flags");
1916   grn_itoh(h->flags, buf, 8);
1917   GRN_OUTPUT_STR(buf, 8);
1918   GRN_OUTPUT_CSTR("curr seg");
1919   GRN_OUTPUT_INT64(*(h->curr_seg));
1920   GRN_OUTPUT_CSTR("curr pos");
1921   GRN_OUTPUT_INT64(*(h->curr_pos));
1922   GRN_OUTPUT_CSTR("max_element_size");
1923   GRN_OUTPUT_INT64(h->max_element_size);
1924   GRN_OUTPUT_CSTR("segregate_threshold");
1925   GRN_OUTPUT_INT64(h->segregate_threshold);
1926   GRN_OUTPUT_CSTR("n_element_variation");
1927   GRN_OUTPUT_INT64(h->n_element_variation);
1928   GRN_OUTPUT_MAP_CLOSE();
1929   GRN_OUTPUT_ARRAY_OPEN("DETAIL", -1);
1930   for (seg = 0; seg < JA_N_DSEGMENTS; seg++) {
1931     int dseg = SEGMENTS_AT(ja, seg);
1932     if (dseg) {
1933       GRN_OUTPUT_MAP_OPEN("SEG", -1);
1934       GRN_OUTPUT_CSTR("seg id");
1935       GRN_OUTPUT_INT64(seg);
1936       GRN_OUTPUT_CSTR("seg type");
1937       GRN_OUTPUT_INT64((dseg & SEG_MASK)>>28);
1938       GRN_OUTPUT_CSTR("seg value");
1939       GRN_OUTPUT_INT64(dseg & ~SEG_MASK);
1940       if ((dseg & SEG_MASK) == SEG_SEQ) {
1941         byte *v = NULL, *ve;
1942         uint32_t element_size, cum = 0, sum = dseg & ~SEG_MASK;
1943         uint32_t n_del_elements = 0, n_elements = 0, s_del_elements = 0, s_elements = 0;
1944         GRN_IO_SEG_REF(ja->io, seg, v);
1945         if (v) {
1946           /*
1947           GRN_OUTPUT_CSTR("seg seq");
1948           GRN_OUTPUT_ARRAY_OPEN("SEQ", -1);
1949           */
1950           ve = v + JA_SEGMENT_SIZE;
1951           while (v < ve && cum < sum) {
1952             grn_id id = *((grn_id *)v);
1953             /*
1954             GRN_OUTPUT_MAP_OPEN("ENTRY", -1);
1955             GRN_OUTPUT_CSTR("id");
1956             GRN_OUTPUT_INT64(id);
1957             */
1958             if (!id) { break; }
1959             if (id & DELETED) {
1960               element_size = (id & ~DELETED);
1961               n_del_elements++;
1962               s_del_elements += element_size;
1963             } else {
1964               element_size = grn_ja_size(ctx, ja, id);
1965               element_size = (element_size + sizeof(grn_id) - 1) & ~(sizeof(grn_id) - 1);
1966               cum += sizeof(uint32_t) + element_size;
1967               n_elements++;
1968               s_elements += sizeof(uint32_t) + element_size;
1969             }
1970             v += sizeof(uint32_t) + element_size;
1971             /*
1972             GRN_OUTPUT_CSTR("size");
1973             GRN_OUTPUT_INT64(element_size);
1974             GRN_OUTPUT_CSTR("cum");
1975             GRN_OUTPUT_INT64(cum);
1976             GRN_OUTPUT_MAP_CLOSE();
1977             */
1978           }
1979           GRN_IO_SEG_UNREF(ja->io, seg);
1980           /*
1981           GRN_OUTPUT_ARRAY_CLOSE();
1982           */
1983           GRN_OUTPUT_CSTR("n_elements");
1984           GRN_OUTPUT_INT64(n_elements);
1985           GRN_OUTPUT_CSTR("s_elements");
1986           GRN_OUTPUT_INT64(s_elements);
1987           GRN_OUTPUT_CSTR("n_del_elements");
1988           GRN_OUTPUT_INT64(n_del_elements);
1989           GRN_OUTPUT_CSTR("s_del_elements");
1990           GRN_OUTPUT_INT64(s_del_elements);
1991           if (cum != sum) {
1992             GRN_OUTPUT_CSTR("cum gap");
1993             GRN_OUTPUT_INT64(cum - sum);
1994           }
1995         }
1996       }
1997       GRN_OUTPUT_MAP_CLOSE();
1998     }
1999   }
2000   GRN_OUTPUT_ARRAY_CLOSE();
2001   GRN_OUTPUT_ARRAY_CLOSE();
2002 }
2003 
2004 /* grn_ja_reader */
2005 
2006 grn_rc
grn_ja_reader_init(grn_ctx * ctx,grn_ja_reader * reader,grn_ja * ja)2007 grn_ja_reader_init(grn_ctx *ctx, grn_ja_reader *reader, grn_ja *ja)
2008 {
2009   reader->ja = ja;
2010   reader->einfo_seg_id = JA_ESEG_VOID;
2011   reader->ref_avail = GRN_FALSE;
2012   reader->ref_seg_id = JA_ESEG_VOID;
2013   reader->ref_seg_ids = NULL;
2014   reader->nref_seg_ids = 0;
2015   reader->ref_seg_ids_size = 0;
2016   reader->body_seg_id = JA_ESEG_VOID;
2017   reader->body_seg_addr = NULL;
2018   reader->packed_buf = NULL;
2019   reader->packed_buf_size = 0;
2020 #ifdef GRN_WITH_ZLIB
2021   if (reader->ja->header->flags & GRN_OBJ_COMPRESS_ZLIB) {
2022     z_stream *new_stream = GRN_MALLOCN(z_stream, 1);
2023     if (!new_stream) {
2024       return GRN_NO_MEMORY_AVAILABLE;
2025     }
2026     new_stream->zalloc = NULL;
2027     new_stream->zfree = NULL;
2028     new_stream->opaque = NULL;
2029     if (inflateInit2(new_stream, 15) != Z_OK) {
2030       GRN_FREE(new_stream);
2031       return GRN_ZLIB_ERROR;
2032     }
2033     reader->stream = new_stream;
2034   }
2035 #endif /* GRN_WITH_ZLIB */
2036   return GRN_SUCCESS;
2037 }
2038 
2039 grn_rc
grn_ja_reader_fin(grn_ctx * ctx,grn_ja_reader * reader)2040 grn_ja_reader_fin(grn_ctx *ctx, grn_ja_reader *reader)
2041 {
2042   grn_rc rc = GRN_SUCCESS;
2043   if (reader->einfo_seg_id != JA_ESEG_VOID) {
2044     GRN_IO_SEG_UNREF(reader->ja->io, reader->einfo_seg_id);
2045   }
2046   if (reader->ref_seg_ids) {
2047     grn_ja_reader_unref(ctx, reader);
2048     GRN_FREE(reader->ref_seg_ids);
2049   }
2050   if (reader->body_seg_addr) {
2051     GRN_IO_SEG_UNREF(reader->ja->io, reader->body_seg_id);
2052   }
2053   if (reader->packed_buf) {
2054     GRN_FREE(reader->packed_buf);
2055   }
2056 #ifdef GRN_WITH_ZLIB
2057   if (reader->ja->header->flags & GRN_OBJ_COMPRESS_ZLIB) {
2058     if (reader->stream) {
2059       if (inflateEnd((z_stream *)reader->stream) != Z_OK) {
2060         rc = GRN_UNKNOWN_ERROR;
2061       }
2062       GRN_FREE(reader->stream);
2063     }
2064   }
2065 #endif /* GRN_WITH_ZLIB */
2066   return rc;
2067 }
2068 
2069 grn_rc
grn_ja_reader_open(grn_ctx * ctx,grn_ja * ja,grn_ja_reader ** reader)2070 grn_ja_reader_open(grn_ctx *ctx, grn_ja *ja, grn_ja_reader **reader)
2071 {
2072   grn_rc rc;
2073   grn_ja_reader *new_reader = GRN_MALLOCN(grn_ja_reader, 1);
2074   if (!new_reader) {
2075     return GRN_NO_MEMORY_AVAILABLE;
2076   }
2077   rc = grn_ja_reader_init(ctx, new_reader, ja);
2078   if (rc != GRN_SUCCESS) {
2079     GRN_FREE(new_reader);
2080     return rc;
2081   }
2082   *reader = new_reader;
2083   return GRN_SUCCESS;
2084 }
2085 
2086 grn_rc
grn_ja_reader_close(grn_ctx * ctx,grn_ja_reader * reader)2087 grn_ja_reader_close(grn_ctx *ctx, grn_ja_reader *reader)
2088 {
2089   grn_rc rc = grn_ja_reader_fin(ctx, reader);
2090   GRN_FREE(reader);
2091   return rc;
2092 }
2093 
2094 #ifdef GRN_WITH_COMPRESSED
2095 /* grn_ja_reader_seek_compressed() prepares to access a compressed value. */
2096 static grn_rc
grn_ja_reader_seek_compressed(grn_ctx * ctx,grn_ja_reader * reader,grn_id id)2097 grn_ja_reader_seek_compressed(grn_ctx *ctx, grn_ja_reader *reader, grn_id id)
2098 {
2099   grn_ja_einfo *einfo;
2100   void *seg_addr;
2101   uint32_t seg_id = reader->ja->header->esegs[id >> JA_W_EINFO_IN_A_SEGMENT];
2102   if (seg_id == JA_ESEG_VOID) {
2103     return GRN_INVALID_ARGUMENT;
2104   }
2105   if (seg_id != reader->einfo_seg_id) {
2106     GRN_IO_SEG_REF(reader->ja->io, seg_id, seg_addr);
2107     if (!seg_addr) {
2108       return GRN_UNKNOWN_ERROR;
2109     }
2110     if (reader->einfo_seg_id != JA_ESEG_VOID) {
2111       GRN_IO_SEG_UNREF(reader->ja->io, reader->einfo_seg_id);
2112     }
2113     reader->einfo_seg_id = seg_id;
2114     reader->einfo_seg_addr = seg_addr;
2115   }
2116   einfo = (grn_ja_einfo *)reader->einfo_seg_addr;
2117   einfo += id & JA_M_EINFO_IN_A_SEGMENT;
2118   reader->einfo = einfo;
2119   /* ETINY_P(einfo) is always false because the original size needs 8 bytes. */
2120   if (EHUGE_P(einfo)) {
2121     EHUGE_DEC(einfo, seg_id, reader->packed_size);
2122     reader->body_seg_offset = 0;
2123   } else {
2124     EINFO_DEC(einfo, seg_id, reader->body_seg_offset, reader->packed_size);
2125   }
2126   if (seg_id != reader->body_seg_id) {
2127     GRN_IO_SEG_REF(reader->ja->io, seg_id, seg_addr);
2128     if (!seg_addr) {
2129       return GRN_UNKNOWN_ERROR;
2130     }
2131     if (reader->body_seg_addr) {
2132       GRN_IO_SEG_UNREF(reader->ja->io, reader->body_seg_id);
2133     }
2134     reader->body_seg_id = seg_id;
2135     reader->body_seg_addr = seg_addr;
2136   }
2137   seg_addr = (char *)reader->body_seg_addr + reader->body_seg_offset;
2138   reader->value_size = (uint32_t)*(uint64_t *)seg_addr;
2139   return GRN_SUCCESS;
2140 }
2141 #endif /* GRN_WITH_COMPRESSED */
2142 
2143 /* grn_ja_reader_seek_raw() prepares to access a value. */
2144 static grn_rc
grn_ja_reader_seek_raw(grn_ctx * ctx,grn_ja_reader * reader,grn_id id)2145 grn_ja_reader_seek_raw(grn_ctx *ctx, grn_ja_reader *reader, grn_id id)
2146 {
2147   grn_ja_einfo *einfo;
2148   void *seg_addr;
2149   uint32_t seg_id = reader->ja->header->esegs[id >> JA_W_EINFO_IN_A_SEGMENT];
2150   if (seg_id == JA_ESEG_VOID) {
2151     return GRN_INVALID_ARGUMENT;
2152   }
2153   if (seg_id != reader->einfo_seg_id) {
2154     GRN_IO_SEG_REF(reader->ja->io, seg_id, seg_addr);
2155     if (!seg_addr) {
2156       return GRN_UNKNOWN_ERROR;
2157     }
2158     if (reader->einfo_seg_id != JA_ESEG_VOID) {
2159       GRN_IO_SEG_UNREF(reader->ja->io, reader->einfo_seg_id);
2160     }
2161     reader->einfo_seg_id = seg_id;
2162     reader->einfo_seg_addr = seg_addr;
2163   }
2164   einfo = (grn_ja_einfo *)reader->einfo_seg_addr;
2165   einfo += id & JA_M_EINFO_IN_A_SEGMENT;
2166   reader->einfo = einfo;
2167   if (ETINY_P(einfo)) {
2168     ETINY_DEC(einfo, reader->value_size);
2169     reader->ref_avail = GRN_FALSE;
2170   } else {
2171     if (EHUGE_P(einfo)) {
2172       EHUGE_DEC(einfo, seg_id, reader->value_size);
2173       reader->ref_avail = GRN_FALSE;
2174     } else {
2175       EINFO_DEC(einfo, seg_id, reader->body_seg_offset, reader->value_size);
2176       reader->ref_avail = GRN_TRUE;
2177     }
2178     if (reader->body_seg_addr) {
2179       if (seg_id != reader->body_seg_id) {
2180         GRN_IO_SEG_UNREF(reader->ja->io, reader->body_seg_id);
2181         reader->body_seg_addr = NULL;
2182       }
2183     }
2184     reader->body_seg_id = seg_id;
2185   }
2186   return GRN_SUCCESS;
2187 }
2188 
2189 grn_rc
grn_ja_reader_seek(grn_ctx * ctx,grn_ja_reader * reader,grn_id id)2190 grn_ja_reader_seek(grn_ctx *ctx, grn_ja_reader *reader, grn_id id)
2191 {
2192   switch (reader->ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
2193 #ifdef GRN_WITH_ZLIB
2194   case GRN_OBJ_COMPRESS_ZLIB :
2195     return grn_ja_reader_seek_compressed(ctx, reader, id);
2196 #endif /* GRN_WITH_ZLIB */
2197 #ifdef GRN_WITH_LZ4
2198   case GRN_OBJ_COMPRESS_LZ4 :
2199     return grn_ja_reader_seek_compressed(ctx, reader, id);
2200 #endif /* GRN_WITH_LZ4 */
2201 #ifdef GRN_WITH_ZSTD
2202   case GRN_OBJ_COMPRESS_ZSTD :
2203     return grn_ja_reader_seek_compressed(ctx, reader, id);
2204 #endif /* GRN_WITH_ZSTD */
2205   default :
2206     return grn_ja_reader_seek_raw(ctx, reader, id);
2207   }
2208 }
2209 
2210 grn_rc
grn_ja_reader_ref(grn_ctx * ctx,grn_ja_reader * reader,void ** addr)2211 grn_ja_reader_ref(grn_ctx *ctx, grn_ja_reader *reader, void **addr)
2212 {
2213   if (!reader->ref_avail) {
2214     return GRN_INVALID_ARGUMENT;
2215   }
2216   if (reader->body_seg_id != reader->ref_seg_id) {
2217     void *seg_addr;
2218     if (reader->nref_seg_ids == reader->ref_seg_ids_size) {
2219       size_t n_bytes;
2220       uint32_t new_size, *new_seg_ids;
2221       if (reader->ref_seg_ids_size == 0) {
2222         new_size = GRN_JA_READER_INITIAL_REF_SEG_IDS_SIZE;
2223       } else {
2224         new_size = reader->ref_seg_ids_size * 2;
2225       }
2226       n_bytes = sizeof(uint32_t) * new_size;
2227       new_seg_ids = (uint32_t *)GRN_REALLOC(reader->ref_seg_ids, n_bytes);
2228       if (!new_seg_ids) {
2229         return GRN_NO_MEMORY_AVAILABLE;
2230       }
2231       reader->ref_seg_ids = new_seg_ids;
2232       reader->ref_seg_ids_size = new_size;
2233     }
2234     GRN_IO_SEG_REF(reader->ja->io, reader->body_seg_id, seg_addr);
2235     if (!seg_addr) {
2236       return GRN_UNKNOWN_ERROR;
2237     }
2238     reader->ref_seg_id = reader->body_seg_id;
2239     reader->ref_seg_addr = seg_addr;
2240     reader->ref_seg_ids[reader->nref_seg_ids++] = reader->body_seg_id;
2241   }
2242   *addr = (char *)reader->ref_seg_addr + reader->body_seg_offset;
2243   return GRN_SUCCESS;
2244 }
2245 
2246 grn_rc
grn_ja_reader_unref(grn_ctx * ctx,grn_ja_reader * reader)2247 grn_ja_reader_unref(grn_ctx *ctx, grn_ja_reader *reader)
2248 {
2249   uint32_t i;
2250   for (i = 0; i < reader->nref_seg_ids; i++) {
2251     GRN_IO_SEG_UNREF(reader->ja->io, reader->ref_seg_ids[i]);
2252   }
2253   reader->ref_seg_id = JA_ESEG_VOID;
2254   reader->nref_seg_ids = 0;
2255   return GRN_FUNCTION_NOT_IMPLEMENTED;
2256 }
2257 
2258 #ifdef GRN_WITH_ZLIB
2259 /* grn_ja_reader_read_zlib() reads a value compressed with zlib. */
2260 static grn_rc
grn_ja_reader_read_zlib(grn_ctx * ctx,grn_ja_reader * reader,void * buf)2261 grn_ja_reader_read_zlib(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
2262 {
2263   uLong dest_size = reader->value_size;
2264   z_stream *stream = (z_stream *)reader->stream;
2265   grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
2266   if (EHUGE_P(einfo)) {
2267     /* TODO: Use z_stream to avoid copy. */
2268     grn_io *io = reader->ja->io;
2269     void *seg_addr;
2270     char *packed_ptr;
2271     uint32_t size, seg_id;
2272     if (reader->packed_size > reader->packed_buf_size) {
2273       void *new_buf = GRN_REALLOC(reader->packed_buf, reader->packed_size);
2274       if (!new_buf) {
2275         return GRN_NO_MEMORY_AVAILABLE;
2276       }
2277       reader->packed_buf = new_buf;
2278       reader->packed_buf_size = reader->packed_size;
2279     }
2280     packed_ptr = (char *)reader->packed_buf;
2281     grn_memcpy(packed_ptr, (char *)reader->body_seg_addr + sizeof(uint64_t),
2282                io->header->segment_size - sizeof(uint64_t));
2283     packed_ptr += io->header->segment_size - sizeof(uint64_t);
2284     size = reader->packed_size - (io->header->segment_size - sizeof(uint64_t));
2285     seg_id = reader->body_seg_id + 1;
2286     while (size > io->header->segment_size) {
2287       GRN_IO_SEG_REF(io, seg_id, seg_addr);
2288       if (!seg_addr) {
2289         return GRN_UNKNOWN_ERROR;
2290       }
2291       grn_memcpy(packed_ptr, seg_addr, io->header->segment_size);
2292       GRN_IO_SEG_UNREF(io, seg_id);
2293       seg_id++;
2294       size -= io->header->segment_size;
2295       packed_ptr += io->header->segment_size;
2296     }
2297     GRN_IO_SEG_REF(io, seg_id, seg_addr);
2298     if (!seg_addr) {
2299       return GRN_UNKNOWN_ERROR;
2300     }
2301     grn_memcpy(packed_ptr, seg_addr, size);
2302     GRN_IO_SEG_UNREF(io, seg_id);
2303     seg_id++;
2304     if (uncompress((Bytef *)buf, &dest_size, (Bytef *)reader->packed_buf,
2305                    reader->packed_size - sizeof(uint64_t)) != Z_OK) {
2306       return GRN_ZLIB_ERROR;
2307     }
2308     if (dest_size != reader->value_size) {
2309       return GRN_ZLIB_ERROR;
2310     }
2311   } else {
2312     char *packed_addr = (char *)reader->body_seg_addr;
2313     packed_addr += reader->body_seg_offset + sizeof(uint64_t);
2314     if (inflateReset(stream) != Z_OK) {
2315       return GRN_ZLIB_ERROR;
2316     }
2317     stream->next_in = (Bytef *)packed_addr;
2318     stream->avail_in = reader->packed_size - sizeof(uint64_t);
2319     stream->next_out = (Bytef *)buf;
2320     stream->avail_out = dest_size;
2321     if ((inflate(stream, Z_FINISH) != Z_STREAM_END) || stream->avail_out) {
2322       return GRN_ZLIB_ERROR;
2323     }
2324   }
2325   return GRN_SUCCESS;
2326 }
2327 #endif /* GRN_WITH_ZLIB */
2328 
2329 #ifdef GRN_WITH_LZ4
2330 /* grn_ja_reader_read_lz4() reads a value compressed with LZ4. */
2331 static grn_rc
grn_ja_reader_read_lz4(grn_ctx * ctx,grn_ja_reader * reader,void * buf)2332 grn_ja_reader_read_lz4(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
2333 {
2334   int src_size, dest_size;
2335   grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
2336   if (EHUGE_P(einfo)) {
2337     grn_io *io = reader->ja->io;
2338     void *seg_addr;
2339     char *packed_ptr;
2340     uint32_t size, seg_id;
2341     if (reader->packed_size > reader->packed_buf_size) {
2342       void *new_buf = GRN_REALLOC(reader->packed_buf, reader->packed_size);
2343       if (!new_buf) {
2344         return GRN_NO_MEMORY_AVAILABLE;
2345       }
2346       reader->packed_buf = new_buf;
2347       reader->packed_buf_size = reader->packed_size;
2348     }
2349     packed_ptr = (char *)reader->packed_buf;
2350     grn_memcpy(packed_ptr, (char *)reader->body_seg_addr + sizeof(uint64_t),
2351                io->header->segment_size - sizeof(uint64_t));
2352     packed_ptr += io->header->segment_size - sizeof(uint64_t);
2353     size = reader->packed_size - (io->header->segment_size - sizeof(uint64_t));
2354     seg_id = reader->body_seg_id + 1;
2355     while (size > io->header->segment_size) {
2356       GRN_IO_SEG_REF(io, seg_id, seg_addr);
2357       if (!seg_addr) {
2358         return GRN_UNKNOWN_ERROR;
2359       }
2360       grn_memcpy(packed_ptr, seg_addr, io->header->segment_size);
2361       GRN_IO_SEG_UNREF(io, seg_id);
2362       seg_id++;
2363       size -= io->header->segment_size;
2364       packed_ptr += io->header->segment_size;
2365     }
2366     GRN_IO_SEG_REF(io, seg_id, seg_addr);
2367     if (!seg_addr) {
2368       return GRN_UNKNOWN_ERROR;
2369     }
2370     grn_memcpy(packed_ptr, seg_addr, size);
2371     GRN_IO_SEG_UNREF(io, seg_id);
2372     seg_id++;
2373     src_size = (int)(reader->packed_size - sizeof(uint64_t));
2374     dest_size = LZ4_decompress_safe(reader->packed_buf, buf, src_size,
2375                                     (int)reader->value_size);
2376   } else {
2377     char *packed_addr = (char *)reader->body_seg_addr;
2378     packed_addr += reader->body_seg_offset + sizeof(uint64_t);
2379     src_size = (int)(reader->packed_size - sizeof(uint64_t));
2380     dest_size = LZ4_decompress_safe(packed_addr, buf, src_size,
2381                                     (int)reader->value_size);
2382   }
2383   if ((uint32_t)dest_size != reader->value_size) {
2384     return GRN_LZ4_ERROR;
2385   }
2386   return GRN_SUCCESS;
2387 }
2388 #endif /* GRN_WITH_LZ4 */
2389 
2390 #ifdef GRN_WITH_ZSTD
2391 /* grn_ja_reader_read_zstd() reads a value compressed with Zstandard. */
2392 static grn_rc
grn_ja_reader_read_zstd(grn_ctx * ctx,grn_ja_reader * reader,void * buf)2393 grn_ja_reader_read_zstd(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
2394 {
2395   int src_size, dest_size;
2396   grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
2397   if (EHUGE_P(einfo)) {
2398     grn_io *io = reader->ja->io;
2399     void *seg_addr;
2400     char *packed_ptr;
2401     uint32_t size, seg_id;
2402     if (reader->packed_size > reader->packed_buf_size) {
2403       void *new_buf = GRN_REALLOC(reader->packed_buf, reader->packed_size);
2404       if (!new_buf) {
2405         return GRN_NO_MEMORY_AVAILABLE;
2406       }
2407       reader->packed_buf = new_buf;
2408       reader->packed_buf_size = reader->packed_size;
2409     }
2410     packed_ptr = (char *)reader->packed_buf;
2411     grn_memcpy(packed_ptr, (char *)reader->body_seg_addr + sizeof(uint64_t),
2412                io->header->segment_size - sizeof(uint64_t));
2413     packed_ptr += io->header->segment_size - sizeof(uint64_t);
2414     size = reader->packed_size - (io->header->segment_size - sizeof(uint64_t));
2415     seg_id = reader->body_seg_id + 1;
2416     while (size > io->header->segment_size) {
2417       GRN_IO_SEG_REF(io, seg_id, seg_addr);
2418       if (!seg_addr) {
2419         return GRN_UNKNOWN_ERROR;
2420       }
2421       grn_memcpy(packed_ptr, seg_addr, io->header->segment_size);
2422       GRN_IO_SEG_UNREF(io, seg_id);
2423       seg_id++;
2424       size -= io->header->segment_size;
2425       packed_ptr += io->header->segment_size;
2426     }
2427     GRN_IO_SEG_REF(io, seg_id, seg_addr);
2428     if (!seg_addr) {
2429       return GRN_UNKNOWN_ERROR;
2430     }
2431     grn_memcpy(packed_ptr, seg_addr, size);
2432     GRN_IO_SEG_UNREF(io, seg_id);
2433     seg_id++;
2434     src_size = (int)(reader->packed_size - sizeof(uint64_t));
2435     dest_size = ZSTD_decompress(reader->packed_buf, reader->value_size,
2436                                 buf, src_size);
2437   } else {
2438     char *packed_addr = (char *)reader->body_seg_addr;
2439     packed_addr += reader->body_seg_offset + sizeof(uint64_t);
2440     src_size = (int)(reader->packed_size - sizeof(uint64_t));
2441     dest_size = ZSTD_decompress(packed_addr, reader->value_size,
2442                                 buf, src_size);
2443   }
2444   if ((uint32_t)dest_size != reader->value_size) {
2445     return GRN_ZSTD_ERROR;
2446   }
2447   return GRN_SUCCESS;
2448 }
2449 #endif /* GRN_WITH_ZSTD */
2450 
2451 /* grn_ja_reader_read_raw() reads a value. */
2452 static grn_rc
grn_ja_reader_read_raw(grn_ctx * ctx,grn_ja_reader * reader,void * buf)2453 grn_ja_reader_read_raw(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
2454 {
2455   grn_io *io = reader->ja->io;
2456   grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
2457   if (ETINY_P(einfo)) {
2458     grn_memcpy(buf, einfo, reader->value_size);
2459   } else if (EHUGE_P(einfo)) {
2460     char *buf_ptr = (char *)buf;
2461     void *seg_addr;
2462     uint32_t seg_id = reader->body_seg_id;
2463     uint32_t size = reader->value_size;
2464     while (size > io->header->segment_size) {
2465       GRN_IO_SEG_REF(io, seg_id, seg_addr);
2466       if (!seg_addr) {
2467         return GRN_UNKNOWN_ERROR;
2468       }
2469       grn_memcpy(buf_ptr, seg_addr, io->header->segment_size);
2470       GRN_IO_SEG_UNREF(io, seg_id);
2471       seg_id++;
2472       size -= io->header->segment_size;
2473       buf_ptr += io->header->segment_size;
2474     }
2475     GRN_IO_SEG_REF(io, seg_id, seg_addr);
2476     if (!seg_addr) {
2477       return GRN_UNKNOWN_ERROR;
2478     }
2479     grn_memcpy(buf_ptr, seg_addr, size);
2480     GRN_IO_SEG_UNREF(io, seg_id);
2481     seg_id++;
2482   } else {
2483     if (!reader->body_seg_addr) {
2484       GRN_IO_SEG_REF(io, reader->body_seg_id, reader->body_seg_addr);
2485       if (!reader->body_seg_addr) {
2486         return GRN_UNKNOWN_ERROR;
2487       }
2488     }
2489     grn_memcpy(buf, (char *)reader->body_seg_addr + reader->body_seg_offset,
2490                reader->value_size);
2491   }
2492   return GRN_SUCCESS;
2493 }
2494 
2495 grn_rc
grn_ja_reader_read(grn_ctx * ctx,grn_ja_reader * reader,void * buf)2496 grn_ja_reader_read(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
2497 {
2498   switch (reader->ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
2499 #ifdef GRN_WITH_ZLIB
2500   case GRN_OBJ_COMPRESS_ZLIB :
2501     return grn_ja_reader_read_zlib(ctx, reader, buf);
2502 #endif /* GRN_WITH_ZLIB */
2503 #ifdef GRN_WITH_LZ4
2504   case GRN_OBJ_COMPRESS_LZ4 :
2505     return grn_ja_reader_read_lz4(ctx, reader, buf);
2506 #endif /* GRN_WITH_LZ4 */
2507 #ifdef GRN_WITH_ZSTD
2508   case GRN_OBJ_COMPRESS_ZSTD :
2509     return grn_ja_reader_read_zstd(ctx, reader, buf);
2510 #endif /* GRN_WITH_ZSTD */
2511   default :
2512     return grn_ja_reader_read_raw(ctx, reader, buf);
2513   }
2514 }
2515 
2516 #ifdef GRN_WITH_ZLIB
2517 /* grn_ja_reader_pread_zlib() reads a part of a value compressed with zlib. */
2518 static grn_rc
grn_ja_reader_pread_zlib(grn_ctx * ctx,grn_ja_reader * reader,size_t offset,size_t size,void * buf)2519 grn_ja_reader_pread_zlib(grn_ctx *ctx, grn_ja_reader *reader,
2520                          size_t offset, size_t size, void *buf)
2521 {
2522   /* TODO: To be supported? */
2523   return GRN_FUNCTION_NOT_IMPLEMENTED;
2524 }
2525 #endif /* GRN_WITH_ZLIB */
2526 
2527 #ifdef GRN_WITH_LZ4
2528 /* grn_ja_reader_pread_lz4() reads a part of a value compressed with LZ4. */
2529 static grn_rc
grn_ja_reader_pread_lz4(grn_ctx * ctx,grn_ja_reader * reader,size_t offset,size_t size,void * buf)2530 grn_ja_reader_pread_lz4(grn_ctx *ctx, grn_ja_reader *reader,
2531                         size_t offset, size_t size, void *buf)
2532 {
2533   /* TODO: To be supported? */
2534   return GRN_FUNCTION_NOT_IMPLEMENTED;
2535 }
2536 #endif /* GRN_WITH_LZ4 */
2537 
2538 #ifdef GRN_WITH_ZSTD
2539 /* grn_ja_reader_pread_zstd() reads a part of a value compressed with ZSTD. */
2540 static grn_rc
grn_ja_reader_pread_zstd(grn_ctx * ctx,grn_ja_reader * reader,size_t offset,size_t size,void * buf)2541 grn_ja_reader_pread_zstd(grn_ctx *ctx, grn_ja_reader *reader,
2542                          size_t offset, size_t size, void *buf)
2543 {
2544   /* TODO: To be supported? */
2545   return GRN_FUNCTION_NOT_IMPLEMENTED;
2546 }
2547 #endif /* GRN_WITH_ZSTD */
2548 
2549 /* grn_ja_reader_pread_raw() reads a part of a value. */
2550 static grn_rc
grn_ja_reader_pread_raw(grn_ctx * ctx,grn_ja_reader * reader,size_t offset,size_t size,void * buf)2551 grn_ja_reader_pread_raw(grn_ctx *ctx, grn_ja_reader *reader,
2552                         size_t offset, size_t size, void *buf)
2553 {
2554   grn_io *io = reader->ja->io;
2555   grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
2556   if ((offset >= reader->value_size) || !size) {
2557     return GRN_SUCCESS;
2558   }
2559   if (size > (reader->value_size - offset)) {
2560     size = reader->value_size - offset;
2561   }
2562   if (ETINY_P(einfo)) {
2563     grn_memcpy(buf, (char *)einfo + offset, size);
2564   } else if (EHUGE_P(einfo)) {
2565     char *buf_ptr = (char *)buf;
2566     void *seg_addr;
2567     uint32_t seg_id = reader->body_seg_id;
2568     if (offset >= io->header->segment_size) {
2569       seg_id += offset / io->header->segment_size;
2570       offset %= io->header->segment_size;
2571     }
2572     GRN_IO_SEG_REF(io, seg_id, seg_addr);
2573     if (!seg_addr) {
2574       return GRN_UNKNOWN_ERROR;
2575     }
2576     grn_memcpy(buf_ptr, (char *)seg_addr + offset,
2577                io->header->segment_size - offset);
2578     GRN_IO_SEG_UNREF(io, seg_id);
2579     seg_id++;
2580     size -= io->header->segment_size - offset;
2581     buf_ptr += io->header->segment_size - offset;
2582     while (size > io->header->segment_size) {
2583       GRN_IO_SEG_REF(io, seg_id, seg_addr);
2584       if (!seg_addr) {
2585         return GRN_UNKNOWN_ERROR;
2586       }
2587       grn_memcpy(buf_ptr, (char *)seg_addr, io->header->segment_size);
2588       GRN_IO_SEG_UNREF(io, seg_id);
2589       seg_id++;
2590       size -= io->header->segment_size;
2591       buf_ptr += io->header->segment_size;
2592     }
2593     GRN_IO_SEG_REF(io, seg_id, seg_addr);
2594     if (!seg_addr) {
2595       return GRN_UNKNOWN_ERROR;
2596     }
2597     grn_memcpy(buf_ptr, seg_addr, size);
2598     GRN_IO_SEG_UNREF(io, seg_id);
2599   } else {
2600     if (!reader->body_seg_addr) {
2601       GRN_IO_SEG_REF(io, reader->body_seg_id, reader->body_seg_addr);
2602       if (!reader->body_seg_addr) {
2603         return GRN_UNKNOWN_ERROR;
2604       }
2605     }
2606     offset += reader->body_seg_offset;
2607     grn_memcpy(buf, (char *)reader->body_seg_addr + offset, size);
2608   }
2609   return GRN_SUCCESS;
2610 }
2611 
2612 grn_rc
grn_ja_reader_pread(grn_ctx * ctx,grn_ja_reader * reader,size_t offset,size_t size,void * buf)2613 grn_ja_reader_pread(grn_ctx *ctx, grn_ja_reader *reader,
2614                     size_t offset, size_t size, void *buf)
2615 {
2616   switch (reader->ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
2617 #ifdef GRN_WITH_ZLIB
2618   case GRN_OBJ_COMPRESS_ZLIB :
2619     return grn_ja_reader_pread_zlib(ctx, reader, offset, size, buf);
2620 #endif /* GRN_WITH_ZLIB */
2621 #ifdef GRN_WITH_LZ4
2622   case GRN_OBJ_COMPRESS_LZ4 :
2623     return grn_ja_reader_pread_lz4(ctx, reader, offset, size, buf);
2624 #endif /* GRN_WITH_LZ4 */
2625 #ifdef GRN_WITH_ZSTD
2626   case GRN_OBJ_COMPRESS_ZSTD :
2627     return grn_ja_reader_pread_zstd(ctx, reader, offset, size, buf);
2628 #endif /* GRN_WITH_ZSTD */
2629   default :
2630     return grn_ja_reader_pread_raw(ctx, reader, offset, size, buf);
2631   }
2632 }
2633 
2634 /**** vgram ****/
2635 
2636 /*
2637 
2638 static int len_sum = 0;
2639 static int img_sum = 0;
2640 static int simple_sum = 0;
2641 static int skip_sum = 0;
2642 
2643 grn_vgram *
2644 grn_vgram_create(const char *path)
2645 {
2646   grn_vgram *s;
2647   if (!(s = GRN_MALLOCN(grn_vgram, 1))) { return NULL; }
2648   s->vgram = grn_sym_create(path, sizeof(grn_id) * 2, 0, GRN_ENC_NONE);
2649   if (!s->vgram) {
2650     GRN_FREE(s);
2651     return NULL;
2652   }
2653   return s;
2654 }
2655 
2656 grn_vgram *
2657 grn_vgram_open(const char *path)
2658 {
2659   grn_vgram *s;
2660   if (!(s = GRN_MALLOCN(grn_vgram, 1))) { return NULL; }
2661   s->vgram = grn_sym_open(path);
2662   if (!s->vgram) {
2663     GRN_FREE(s);
2664     return NULL;
2665   }
2666   return s;
2667 }
2668 
2669 grn_vgram_buf *
2670 grn_vgram_buf_open(size_t len)
2671 {
2672   grn_vgram_buf *b;
2673   if (!(b = GRN_MALLOCN(grn_vgram_buf, 1))) { return NULL; }
2674   b->len = len;
2675   b->tvs = b->tvp = GRN_MALLOCN(grn_id, len);
2676   if (!b->tvp) { GRN_FREE(b); return NULL; }
2677   b->tve = b->tvs + len;
2678   b->vps = b->vpp = GRN_MALLOCN(grn_vgram_vnode, len * 2);
2679   if (!b->vpp) { GRN_FREE(b->tvp); GRN_FREE(b); return NULL; }
2680   b->vpe = b->vps + len;
2681   return b;
2682 }
2683 
2684 grn_rc
2685 grn_vgram_buf_add(grn_vgram_buf *b, grn_id tid)
2686 {
2687   uint8_t dummybuf[8], *dummyp;
2688   if (b->tvp < b->tve) { *b->tvp++ = tid; }
2689   dummyp = dummybuf;
2690   GRN_B_ENC(tid, dummyp);
2691   simple_sum += dummyp - dummybuf;
2692   return GRN_SUCCESS;
2693 }
2694 
2695 typedef struct {
2696   grn_id vid;
2697   grn_id tid;
2698 } vgram_key;
2699 
2700 grn_rc
2701 grn_vgram_update(grn_vgram *vgram, grn_id rid, grn_vgram_buf *b, grn_hash *terms)
2702 {
2703   grn_inv_updspec **u;
2704   if (b && b->tvs < b->tvp) {
2705     grn_id *t0, *tn;
2706     for (t0 = b->tvs; t0 < b->tvp - 1; t0++) {
2707       grn_vgram_vnode *v, **vp;
2708       if (grn_set_at(terms, t0, (void **) &u)) {
2709         vp = &(*u)->vnodes;
2710         for (tn = t0 + 1; tn < b->tvp; tn++) {
2711           for (v = *vp; v && v->tid != *tn; v = v->cdr) ;
2712           if (!v) {
2713             if (b->vpp < b->vpe) {
2714               v = b->vpp++;
2715             } else {
2716               // todo;
2717               break;
2718             }
2719             v->car = NULL;
2720             v->cdr = *vp;
2721             *vp = v;
2722             v->tid = *tn;
2723             v->vid = 0;
2724             v->freq = 0;
2725             v->len = tn - t0;
2726           }
2727           v->freq++;
2728           if (v->vid) {
2729             vp = &v->car;
2730           } else {
2731             break;
2732           }
2733         }
2734       }
2735     }
2736     {
2737       grn_set *th = grn_set_open(sizeof(grn_id), sizeof(int), 0);
2738       if (!th) { return GRN_NO_MEMORY_AVAILABLE; }
2739       if (t0 == b->tvp) { GRN_LOG(ctx, GRN_LOG_DEBUG, "t0 == tvp"); }
2740       for (t0 = b->tvs; t0 < b->tvp; t0++) {
2741         grn_id vid, vid0 = *t0, vid1 = 0;
2742         grn_vgram_vnode *v, *v2 = NULL, **vp;
2743         if (grn_set_at(terms, t0, (void **) &u)) {
2744           vp = &(*u)->vnodes;
2745           for (tn = t0 + 1; tn < b->tvp; tn++) {
2746             for (v = *vp; v; v = v->cdr) {
2747               if (!v->vid && (v->freq < 2 || v->freq * v->len < 4)) {
2748                 *vp = v->cdr;
2749                 v->freq = 0;
2750               }
2751               if (v->tid == *tn) { break; }
2752               vp = &v->cdr;
2753             }
2754             if (v) {
2755               if (v->freq) {
2756                 v2 = v;
2757                 vid1 = vid0;
2758                 vid0 = v->vid;
2759               }
2760               if (v->vid) {
2761                 vp = &v->car;
2762                 continue;
2763               }
2764             }
2765             break;
2766           }
2767         }
2768         if (v2) {
2769           if (!v2->vid) {
2770             vgram_key key;
2771             key.vid = vid1;
2772             key.tid = v2->tid;
2773             if (!(v2->vid = grn_sym_get(vgram->vgram, (char *)&key))) {
2774               grn_set_close(th);
2775               return GRN_NO_MEMORY_AVAILABLE;
2776             }
2777           }
2778           vid = *t0 = v2->vid * 2 + 1;
2779           memset(t0 + 1, 0, sizeof(grn_id) * v2->len);
2780           t0 += v2->len;
2781         } else {
2782           vid = *t0 *= 2;
2783         }
2784         {
2785           int *tf;
2786           if (!grn_set_get(th, &vid, (void **) &tf)) {
2787             grn_set_close(th);
2788             return GRN_NO_MEMORY_AVAILABLE;
2789           }
2790           (*tf)++;
2791         }
2792       }
2793       if (!th->n_entries) { GRN_LOG(ctx, GRN_LOG_DEBUG, "th->n_entries == 0"); }
2794       {
2795         int j = 0;
2796         int skip = 0;
2797         grn_set_eh *ehs, *ehp, *ehe;
2798         grn_set_sort_optarg arg;
2799         uint8_t *ps = GRN_MALLOC(b->len * 2), *pp, *pe;
2800         if (!ps) {
2801           grn_set_close(th);
2802           return GRN_NO_MEMORY_AVAILABLE;
2803         }
2804         pp = ps;
2805         pe = ps + b->len * 2;
2806         arg.mode = grn_sort_descending;
2807         arg.compar = NULL;
2808         arg.compar_arg = (void *)(intptr_t)sizeof(grn_id);
2809         ehs = grn_set_sort(th, 0, &arg);
2810         if (!ehs) {
2811           GRN_FREE(ps);
2812           grn_set_close(th);
2813           return GRN_NO_MEMORY_AVAILABLE;
2814         }
2815         GRN_B_ENC(th->n_entries, pp);
2816         for (ehp = ehs, ehe = ehs + th->n_entries; ehp < ehe; ehp++, j++) {
2817           int *id = (int *)GRN_SET_INTVAL(*ehp);
2818           GRN_B_ENC(*GRN_SET_INTKEY(*ehp), pp);
2819           *id = j;
2820         }
2821         for (t0 = b->tvs; t0 < b->tvp; t0++) {
2822           if (*t0) {
2823             int *id;
2824             if (!grn_set_at(th, t0, (void **) &id)) {
2825               GRN_LOG(ctx, GRN_LOG_ERROR, "lookup error (%d)", *t0);
2826             }
2827             GRN_B_ENC(*id, pp);
2828           } else {
2829             skip++;
2830           }
2831         }
2832         len_sum += b->len;
2833         img_sum += pp - ps;
2834         skip_sum += skip;
2835         GRN_FREE(ehs);
2836         GRN_FREE(ps);
2837       }
2838       grn_set_close(th);
2839     }
2840   }
2841   return GRN_SUCCESS;
2842 }
2843 
2844 grn_rc
2845 grn_vgram_buf_close(grn_vgram_buf *b)
2846 {
2847   if (!b) { return GRN_INVALID_ARGUMENT; }
2848   if (b->tvs) { GRN_FREE(b->tvs); }
2849   if (b->vps) { GRN_FREE(b->vps); }
2850   GRN_FREE(b);
2851   return GRN_SUCCESS;
2852 }
2853 
2854 grn_rc
2855 grn_vgram_close(grn_vgram *vgram)
2856 {
2857   if (!vgram) { return GRN_INVALID_ARGUMENT; }
2858   GRN_LOG(ctx, GRN_LOG_DEBUG, "len=%d img=%d skip=%d simple=%d", len_sum, img_sum, skip_sum, simple_sum);
2859   grn_sym_close(vgram->vgram);
2860   GRN_FREE(vgram);
2861   return GRN_SUCCESS;
2862 }
2863 */
2864