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   unsigned 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     unsigned 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     uint i;
754     int j, n = (element_size + JA_SEGMENT_SIZE - 1) >> GRN_JA_W_SEGMENT;
755     for (i = 0, j = -1;  i < JA_N_DSEGMENTS; i++) {
756       if (SEGMENTS_AT(ja, i)) {
757         j = i;
758       } else {
759         if (i == j + n) {
760           j++;
761           addr = grn_io_win_map(ja->io, ctx, iw, j, 0, element_size, grn_io_wronly);
762           if (!addr) {
763             grn_io_unlock(ja->io);
764             return GRN_NO_MEMORY_AVAILABLE;
765           }
766           EHUGE_ENC(einfo, j, element_size);
767           for (; j <= i; j++) { SEGMENTS_HUGE_ON(ja, j); }
768           grn_io_unlock(ja->io);
769           return GRN_SUCCESS;
770         }
771       }
772     }
773     GRN_LOG(ctx, GRN_LOG_CRIT, "ja full. requested element_size=%d.", element_size);
774     grn_io_unlock(ja->io);
775     return GRN_NO_MEMORY_AVAILABLE;
776   } else {
777     ja_pos *vp;
778     int m, aligned_size, es = element_size - 1;
779     GRN_BIT_SCAN_REV(es, m);
780     m++;
781     if (m > ja->header->segregate_threshold) {
782       uint32_t seg = *(ja->header->curr_seg);
783       uint32_t pos = *(ja->header->curr_pos);
784       if (pos + element_size + sizeof(grn_id) > JA_SEGMENT_SIZE) {
785         seg = 0;
786         while (SEGMENTS_AT(ja, seg)) {
787           if (++seg >= JA_N_DSEGMENTS) {
788             grn_io_unlock(ja->io);
789             GRN_LOG(ctx, GRN_LOG_CRIT, "ja full. seg=%d.", seg);
790             return GRN_NOT_ENOUGH_SPACE;
791           }
792         }
793         SEGMENTS_SEQ_ON(ja, seg);
794         *(ja->header->curr_seg) = seg;
795         pos = 0;
796       }
797       GRN_IO_SEG_REF(ja->io, seg, addr);
798       if (!addr) {
799         grn_io_unlock(ja->io);
800         return GRN_NO_MEMORY_AVAILABLE;
801       }
802       *(grn_id *)(addr + pos) = id;
803       aligned_size = (element_size + sizeof(grn_id) - 1) & ~(sizeof(grn_id) - 1);
804       if (pos + aligned_size < JA_SEGMENT_SIZE) {
805         *(grn_id *)(addr + pos + aligned_size) = GRN_ID_NIL;
806       }
807       SEGMENTS_AT(ja, seg) += aligned_size + sizeof(grn_id);
808       pos += sizeof(grn_id);
809       EINFO_ENC(einfo, seg, pos, element_size);
810       iw->segment = seg;
811       iw->addr = addr + pos;
812       *(ja->header->curr_pos) = pos + aligned_size;
813       grn_io_unlock(ja->io);
814       return GRN_SUCCESS;
815     } else {
816       uint32_t lseg = 0, lseg_;
817       aligned_size = 1 << m;
818       if (ja->header->ngarbages[m - JA_W_EINFO] > JA_N_GARBAGES_TH) {
819         grn_ja_ginfo *ginfo = NULL;
820         uint32_t seg, pos, *gseg;
821         gseg = &ja->header->garbages[m - JA_W_EINFO];
822         while ((lseg_ = *gseg)) {
823           GRN_IO_SEG_REF(ja->io, lseg_, ginfo);
824           if (!ginfo) {
825             if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
826             grn_io_unlock(ja->io);
827             return GRN_NO_MEMORY_AVAILABLE;
828           }
829           if (ginfo->next || ginfo->nrecs > JA_N_GARBAGES_TH) {
830             seg = ginfo->recs[ginfo->tail].seg;
831             pos = ginfo->recs[ginfo->tail].pos;
832             GRN_IO_SEG_REF(ja->io, seg, addr);
833             if (!addr) {
834               if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
835               GRN_IO_SEG_UNREF(ja->io, lseg_);
836               grn_io_unlock(ja->io);
837               return GRN_NO_MEMORY_AVAILABLE;
838             }
839             EINFO_ENC(einfo, seg, pos, element_size);
840             iw->segment = seg;
841             iw->addr = addr + pos;
842             if (++ginfo->tail == JA_N_GARBAGES_IN_A_SEGMENT) { ginfo->tail = 0; }
843             ginfo->nrecs--;
844             ja->header->ngarbages[m - JA_W_EINFO]--;
845             if (!ginfo->nrecs) {
846               SEGMENTS_OFF(ja, *gseg);
847               *gseg = ginfo->next;
848             }
849             if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
850             GRN_IO_SEG_UNREF(ja->io, lseg_);
851             grn_io_unlock(ja->io);
852             return GRN_SUCCESS;
853           }
854           if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
855           if (!ginfo->next) {
856             GRN_IO_SEG_UNREF(ja->io, lseg_);
857             break;
858           }
859           lseg = lseg_;
860           gseg = &ginfo->next;
861         }
862       }
863       vp = &ja->header->free_elements[m - JA_W_EINFO];
864       if (!vp->seg) {
865         int i = 0;
866         while (SEGMENTS_AT(ja, i)) {
867           if (++i >= JA_N_DSEGMENTS) {
868             grn_io_unlock(ja->io);
869             return GRN_NO_MEMORY_AVAILABLE;
870           }
871         }
872         SEGMENTS_SEGRE_ON(ja, i, m);
873         vp->seg = i;
874         vp->pos = 0;
875       }
876     }
877     EINFO_ENC(einfo, vp->seg, vp->pos, element_size);
878     GRN_IO_SEG_REF(ja->io, vp->seg, addr);
879     if (!addr) {
880       grn_io_unlock(ja->io);
881       return GRN_NO_MEMORY_AVAILABLE;
882     }
883     iw->segment = vp->seg;
884     iw->addr = addr + vp->pos;
885     if ((vp->pos += aligned_size) == JA_SEGMENT_SIZE) {
886       vp->seg = 0;
887       vp->pos = 0;
888     }
889     iw->uncompressed_value = NULL;
890     grn_io_unlock(ja->io);
891     return GRN_SUCCESS;
892   }
893 }
894 
895 static grn_rc
set_value(grn_ctx * ctx,grn_ja * ja,grn_id id,void * value,uint32_t value_len,grn_ja_einfo * einfo)896 set_value(grn_ctx *ctx, grn_ja *ja, grn_id id, void *value, uint32_t value_len,
897           grn_ja_einfo *einfo)
898 {
899   grn_rc rc = GRN_SUCCESS;
900   grn_io_win iw;
901   if ((ja->header->flags & GRN_OBJ_RING_BUFFER) &&
902       value_len >= ja->header->max_element_size) {
903     if ((rc = grn_ja_alloc(ctx, ja, id, value_len + sizeof(uint32_t), einfo, &iw))) {
904       return rc;
905     }
906     grn_memcpy(iw.addr, value, value_len);
907     memset((byte *)iw.addr + value_len, 0, sizeof(uint32_t));
908     grn_io_win_unmap(&iw);
909   } else {
910     if ((rc = grn_ja_alloc(ctx, ja, id, value_len, einfo, &iw))) { return rc; }
911     grn_memcpy(iw.addr, value, value_len);
912     grn_io_win_unmap(&iw);
913   }
914   return rc;
915 }
916 
917 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)918 grn_ja_put_raw(grn_ctx *ctx, grn_ja *ja, grn_id id,
919                void *value, uint32_t value_len, int flags, uint64_t *cas)
920 {
921   int rc;
922   int64_t buf;
923   grn_io_win iw;
924   grn_ja_einfo einfo;
925 
926   if ((flags & GRN_OBJ_SET_MASK) == GRN_OBJ_SET &&
927       value_len > 0) {
928     grn_io_win jw;
929     uint32_t old_len;
930     void *old_value;
931     grn_bool same_value = GRN_FALSE;
932 
933     old_value = grn_ja_ref(ctx, ja, id, &jw, &old_len);
934     if (value_len == old_len && memcmp(value, old_value, value_len) == 0) {
935       same_value = GRN_TRUE;
936     }
937     grn_ja_unref(ctx, &jw);
938     if (same_value) {
939       return GRN_SUCCESS;
940     }
941   }
942 
943   switch (flags & GRN_OBJ_SET_MASK) {
944   case GRN_OBJ_APPEND :
945     if (value_len) {
946       grn_io_win jw;
947       uint32_t old_len;
948       void *oldvalue = grn_ja_ref(ctx, ja, id, &jw, &old_len);
949       if (oldvalue) {
950         if ((ja->header->flags & GRN_OBJ_RING_BUFFER) &&
951             old_len + value_len >= ja->header->max_element_size) {
952           if (old_len >= ja->header->max_element_size) {
953             byte *b = oldvalue;
954             uint32_t el = old_len - sizeof(uint32_t);
955             uint32_t pos = *((uint32_t *)(b + el));
956             GRN_ASSERT(pos < el);
957             if (el <= pos + value_len) {
958               uint32_t rest = el - pos;
959               grn_memcpy(b + pos, value, rest);
960               grn_memcpy(b, (byte *)value + rest, value_len - rest);
961               *((uint32_t *)(b + el)) = value_len - rest;
962             } else {
963               grn_memcpy(b + pos, value, value_len);
964               *((uint32_t *)(b + el)) = pos + value_len;
965             }
966             return GRN_SUCCESS;
967           } else {
968             if ((rc = grn_ja_alloc(ctx, ja, id,
969                                    value_len + old_len + sizeof(uint32_t),
970                                    &einfo, &iw))) {
971               grn_ja_unref(ctx, &jw);
972               return rc;
973             }
974             grn_memcpy(iw.addr, oldvalue, old_len);
975             grn_memcpy((byte *)iw.addr + old_len, value, value_len);
976             memset((byte *)iw.addr + old_len + value_len, 0, sizeof(uint32_t));
977             grn_io_win_unmap(&iw);
978           }
979         } else {
980           if ((rc = grn_ja_alloc(ctx, ja, id, value_len + old_len, &einfo, &iw))) {
981             grn_ja_unref(ctx, &jw);
982             return rc;
983           }
984           grn_memcpy(iw.addr, oldvalue, old_len);
985           grn_memcpy((byte *)iw.addr + old_len, value, value_len);
986           grn_io_win_unmap(&iw);
987         }
988         grn_ja_unref(ctx, &jw);
989       } else {
990         set_value(ctx, ja, id, value, value_len, &einfo);
991       }
992     }
993     break;
994   case GRN_OBJ_PREPEND :
995     if (value_len) {
996       grn_io_win jw;
997       uint32_t old_len;
998       void *oldvalue = grn_ja_ref(ctx, ja, id, &jw, &old_len);
999       if (oldvalue) {
1000         if ((ja->header->flags & GRN_OBJ_RING_BUFFER) &&
1001             old_len + value_len >= ja->header->max_element_size) {
1002           if (old_len >= ja->header->max_element_size) {
1003             byte *b = oldvalue;
1004             uint32_t el = old_len - sizeof(uint32_t);
1005             uint32_t pos = *((uint32_t *)(b + el));
1006             GRN_ASSERT(pos < el);
1007             if (pos < value_len) {
1008               uint32_t rest = value_len - pos;
1009               grn_memcpy(b, (byte *)value + rest, pos);
1010               grn_memcpy(b + el - rest, value, rest);
1011               *((uint32_t *)(b + el)) = el - rest;
1012             } else {
1013               grn_memcpy(b + pos - value_len, value, value_len);
1014               *((uint32_t *)(b + el)) = pos - value_len;
1015             }
1016             return GRN_SUCCESS;
1017           } else {
1018             if ((rc = grn_ja_alloc(ctx, ja, id,
1019                                    value_len + old_len + sizeof(uint32_t),
1020                                    &einfo, &iw))) {
1021               grn_ja_unref(ctx, &jw);
1022               return rc;
1023             }
1024             grn_memcpy(iw.addr, value, value_len);
1025             grn_memcpy((byte *)iw.addr + value_len, oldvalue, old_len);
1026             memset((byte *)iw.addr + value_len + old_len, 0, sizeof(uint32_t));
1027             grn_io_win_unmap(&iw);
1028           }
1029         } else {
1030           if ((rc = grn_ja_alloc(ctx, ja, id, value_len + old_len, &einfo, &iw))) {
1031             grn_ja_unref(ctx, &jw);
1032             return rc;
1033           }
1034           grn_memcpy(iw.addr, value, value_len);
1035           grn_memcpy((byte *)iw.addr + value_len, oldvalue, old_len);
1036           grn_io_win_unmap(&iw);
1037         }
1038         grn_ja_unref(ctx, &jw);
1039       } else {
1040         set_value(ctx, ja, id, value, value_len, &einfo);
1041       }
1042     }
1043     break;
1044   case GRN_OBJ_DECR :
1045     if (value_len == sizeof(int64_t)) {
1046       int64_t *v = (int64_t *)&buf;
1047       *v = -(*(int64_t *)value);
1048       value = v;
1049     } else if (value_len == sizeof(int32_t)) {
1050       int32_t *v = (int32_t *)&buf;
1051       *v = -(*(int32_t *)value);
1052       value = v;
1053     } else {
1054       return GRN_INVALID_ARGUMENT;
1055     }
1056     /* fallthru */
1057   case GRN_OBJ_INCR :
1058     {
1059       grn_io_win jw;
1060       uint32_t old_len;
1061       void *oldvalue = grn_ja_ref(ctx, ja, id, &jw, &old_len);
1062       if (oldvalue && old_len) {
1063         grn_rc rc = GRN_INVALID_ARGUMENT;
1064         if (old_len == sizeof(int64_t) && value_len == sizeof(int64_t)) {
1065           (*(int64_t *)oldvalue) += (*(int64_t *)value);
1066           rc = GRN_SUCCESS;
1067         } else if (old_len == sizeof(int32_t) && value_len == sizeof(int32_t)) {
1068           (*(int32_t *)oldvalue) += (*(int32_t *)value);
1069           rc = GRN_SUCCESS;
1070         }
1071         grn_ja_unref(ctx, &jw);
1072         return rc;
1073       }
1074     }
1075     /* fallthru */
1076   case GRN_OBJ_SET :
1077     if (value_len) {
1078       set_value(ctx, ja, id, value, value_len, &einfo);
1079     } else {
1080       memset(&einfo, 0, sizeof(grn_ja_einfo));
1081     }
1082     break;
1083   default :
1084     ERR(GRN_INVALID_ARGUMENT, "grn_ja_put_raw called with illegal flags value");
1085     return GRN_INVALID_ARGUMENT;
1086   }
1087   if ((rc = grn_ja_replace(ctx, ja, id, &einfo, cas))) {
1088     if (!grn_io_lock(ctx, ja->io, grn_lock_timeout)) {
1089       grn_ja_free(ctx, ja, &einfo);
1090       grn_io_unlock(ja->io);
1091     }
1092   }
1093   return rc;
1094 }
1095 
1096 grn_rc
grn_ja_putv(grn_ctx * ctx,grn_ja * ja,grn_id id,grn_obj * vector,int flags)1097 grn_ja_putv(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_obj *vector, int flags)
1098 {
1099   grn_obj header, footer;
1100   grn_rc rc = GRN_SUCCESS;
1101   grn_section *vp;
1102   int i, f = 0, n = grn_vector_size(ctx, vector);
1103   GRN_TEXT_INIT(&header, 0);
1104   GRN_TEXT_INIT(&footer, 0);
1105   grn_text_benc(ctx, &header, n);
1106   for (i = 0, vp = vector->u.v.sections; i < n; i++, vp++) {
1107     grn_text_benc(ctx, &header, vp->length);
1108     if (vp->weight || vp->domain) { f = 1; }
1109   }
1110   if (f) {
1111     for (i = 0, vp = vector->u.v.sections; i < n; i++, vp++) {
1112       grn_text_benc(ctx, &footer, vp->weight);
1113       grn_text_benc(ctx, &footer, vp->domain);
1114     }
1115   }
1116   {
1117     grn_io_win iw;
1118     grn_ja_einfo einfo;
1119     grn_obj *body = vector->u.v.body;
1120     size_t sizeh = GRN_BULK_VSIZE(&header);
1121     size_t sizev = body ? GRN_BULK_VSIZE(body) : 0;
1122     size_t sizef = GRN_BULK_VSIZE(&footer);
1123     if ((rc = grn_ja_alloc(ctx, ja, id, sizeh + sizev + sizef, &einfo, &iw))) { goto exit; }
1124     grn_memcpy(iw.addr, GRN_BULK_HEAD(&header), sizeh);
1125     if (body) {
1126       grn_memcpy((char *)iw.addr + sizeh, GRN_BULK_HEAD(body), sizev);
1127     }
1128     if (f) {
1129       grn_memcpy((char *)iw.addr + sizeh + sizev, GRN_BULK_HEAD(&footer), sizef);
1130     }
1131     grn_io_win_unmap(&iw);
1132     rc = grn_ja_replace(ctx, ja, id, &einfo, NULL);
1133   }
1134 exit :
1135   GRN_OBJ_FIN(ctx, &footer);
1136   GRN_OBJ_FIN(ctx, &header);
1137   return rc;
1138 }
1139 
1140 uint32_t
grn_ja_size(grn_ctx * ctx,grn_ja * ja,grn_id id)1141 grn_ja_size(grn_ctx *ctx, grn_ja *ja, grn_id id)
1142 {
1143   grn_ja_einfo *einfo = NULL, *ei;
1144   uint32_t lseg, *pseg, pos, size;
1145   lseg = id >> JA_W_EINFO_IN_A_SEGMENT;
1146   pos = id & JA_M_EINFO_IN_A_SEGMENT;
1147   pseg = &ja->header->esegs[lseg];
1148   if (*pseg == JA_ESEG_VOID) {
1149     ctx->rc = GRN_INVALID_ARGUMENT;
1150     return 0;
1151   }
1152   GRN_IO_SEG_REF(ja->io, *pseg, einfo);
1153   if (!einfo) {
1154     ctx->rc = GRN_NO_MEMORY_AVAILABLE;
1155     return 0;
1156   }
1157   ei = &einfo[pos];
1158   if (ETINY_P(ei)) {
1159     ETINY_DEC(ei, size);
1160   } else {
1161     if (EHUGE_P(ei)) {
1162       size = ei->u.h.size;
1163     } else {
1164       size = (ei->u.n.c2 << 16) + ei->u.n.size;
1165     }
1166   }
1167   GRN_IO_SEG_UNREF(ja->io, *pseg);
1168   return size;
1169 }
1170 
1171 grn_rc
grn_ja_element_info(grn_ctx * ctx,grn_ja * ja,grn_id id,uint64_t * cas,uint32_t * pos,uint32_t * size)1172 grn_ja_element_info(grn_ctx *ctx, grn_ja *ja, grn_id id,
1173                     uint64_t *cas, uint32_t *pos, uint32_t *size)
1174 {
1175   uint32_t pseg = ja->header->esegs[id >> JA_W_EINFO_IN_A_SEGMENT];
1176   if (pseg == JA_ESEG_VOID) {
1177     return GRN_INVALID_ARGUMENT;
1178   } else {
1179     grn_ja_einfo *einfo = NULL;
1180     GRN_IO_SEG_REF(ja->io, pseg, einfo);
1181     if (einfo) {
1182       grn_ja_einfo *ei;
1183       *cas = *((uint64_t *)&einfo[id & JA_M_EINFO_IN_A_SEGMENT]);
1184       ei = (grn_ja_einfo *)cas;
1185       if (ETINY_P(ei)) {
1186         ETINY_DEC(ei, *size);
1187         *pos = 0;
1188       } else {
1189         uint32_t jag;
1190         if (EHUGE_P(ei)) {
1191           EHUGE_DEC(ei, jag, *size);
1192           *pos = 0;
1193         } else {
1194           EINFO_DEC(ei, jag, *pos, *size);
1195         }
1196       }
1197       GRN_IO_SEG_UNREF(ja->io, pseg);
1198     } else {
1199       return GRN_INVALID_ARGUMENT;
1200     }
1201   }
1202   return GRN_SUCCESS;
1203 }
1204 
1205 #define COMPRESSED_VALUE_META_FLAG(meta) ((meta) & 0xf000000000000000)
1206 #define COMPRESSED_VALUE_META_FLAG_RAW             0x1000000000000000
1207 #define COMPRESSED_VALUE_META_UNCOMPRESSED_LEN(meta) \
1208                                          ((meta) & 0x0fffffffffffffff)
1209 
1210 #define COMPRESS_THRESHOLD_BYTE 256
1211 #define COMPRESS_PACKED_VALUE_SIZE_MAX 257
1212         /* COMPRESS_THRESHOLD_BYTE - 1 + sizeof(uint64_t) = 257 */
1213 
1214 #if defined(GRN_WITH_ZLIB) || defined(GRN_WITH_LZ4) || defined(GRN_WITH_ZSTD)
1215 #  define GRN_WITH_COMPRESSED
1216 #endif
1217 
1218 #ifdef GRN_WITH_COMPRESSED
1219 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)1220 grn_ja_ref_packed(grn_ctx *ctx,
1221                   grn_io_win *iw,
1222                   uint32_t *value_len,
1223                   void *raw_value,
1224                   uint32_t raw_value_len,
1225                   void **compressed_value,
1226                   uint32_t *compressed_value_len,
1227                   uint32_t *uncompressed_value_len)
1228 {
1229   uint64_t compressed_value_meta;
1230 
1231   compressed_value_meta = *((uint64_t *)raw_value);
1232   *compressed_value = (void *)(((uint64_t *)raw_value) + 1);
1233   *compressed_value_len = raw_value_len - sizeof(uint64_t);
1234 
1235   *uncompressed_value_len =
1236     COMPRESSED_VALUE_META_UNCOMPRESSED_LEN(compressed_value_meta);
1237   switch (COMPRESSED_VALUE_META_FLAG(compressed_value_meta)) {
1238   case COMPRESSED_VALUE_META_FLAG_RAW :
1239     iw->uncompressed_value = NULL;
1240     *value_len = *uncompressed_value_len;
1241     return *compressed_value;
1242   default :
1243     return NULL;
1244   }
1245 }
1246 
1247 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)1248 grn_ja_put_packed(grn_ctx *ctx,
1249                   grn_ja *ja,
1250                   grn_id id,
1251                   void *value,
1252                   uint32_t value_len,
1253                   int flags,
1254                   uint64_t *cas)
1255 {
1256   char *packed_value[COMPRESS_PACKED_VALUE_SIZE_MAX];
1257   uint32_t packed_value_len;
1258   uint64_t packed_value_meta;
1259 
1260   packed_value_len = value_len + sizeof(uint64_t);
1261   packed_value_meta = value_len | COMPRESSED_VALUE_META_FLAG_RAW;
1262   *((uint64_t *)packed_value) = packed_value_meta;
1263   memcpy(((uint64_t *)packed_value) + 1,
1264          value,
1265          value_len);
1266   return grn_ja_put_raw(ctx,
1267                         ja,
1268                         id,
1269                         packed_value,
1270                         packed_value_len,
1271                         flags,
1272                         cas);
1273 }
1274 
1275 static void
grn_ja_compress_error(grn_ctx * ctx,grn_ja * ja,grn_id id,grn_rc rc,const char * message,const char * detail)1276 grn_ja_compress_error(grn_ctx *ctx,
1277                       grn_ja *ja,
1278                       grn_id id,
1279                       grn_rc rc,
1280                       const char *message,
1281                       const char *detail)
1282 {
1283   char name[GRN_TABLE_MAX_KEY_SIZE];
1284   int name_len;
1285 
1286   if (ja->obj.id == GRN_ID_NIL) {
1287     name[0] = '\0';
1288     name_len = 0;
1289   } else {
1290     name_len = grn_obj_name(ctx, (grn_obj *)ja, name, GRN_TABLE_MAX_KEY_SIZE);
1291   }
1292   ERR(GRN_ZSTD_ERROR,
1293       "[ja]%s: %s%.*s%s<%u>%s%s%s",
1294       message,
1295       name_len == 0 ? "" : "<",
1296       name_len,
1297       name,
1298       name_len == 0 ? "" : ">: ",
1299       id,
1300       detail ? " :<" : "",
1301       detail ? detail : "",
1302       detail ? ">" : "");
1303 }
1304 #endif /* GRN_WITH_COMPRESSED */
1305 
1306 #ifdef GRN_WITH_ZLIB
1307 #include <zlib.h>
1308 
1309 static const char *
grn_zrc_to_string(int zrc)1310 grn_zrc_to_string(int zrc)
1311 {
1312   switch (zrc) {
1313   case Z_OK :
1314     return "OK";
1315   case Z_STREAM_END :
1316     return "Stream is end";
1317   case Z_NEED_DICT :
1318     return "Need dictionary";
1319   case Z_ERRNO :
1320     return "See errno";
1321   case Z_STREAM_ERROR :
1322     return "Stream error";
1323   case Z_DATA_ERROR :
1324     return "Data error";
1325   case Z_MEM_ERROR :
1326     return "Memory error";
1327   case Z_BUF_ERROR :
1328     return "Buffer error";
1329   case Z_VERSION_ERROR :
1330     return "Version error";
1331   default :
1332     return "Unknown";
1333   }
1334 }
1335 
1336 static void *
grn_ja_ref_zlib(grn_ctx * ctx,grn_ja * ja,grn_id id,grn_io_win * iw,uint32_t * value_len)1337 grn_ja_ref_zlib(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_io_win *iw, uint32_t *value_len)
1338 {
1339   z_stream zstream;
1340   void *raw_value;
1341   uint32_t raw_value_len;
1342   void *zvalue;
1343   uint32_t zvalue_len;
1344   void *unpacked_value;
1345   uint32_t uncompressed_value_len;
1346   int zrc;
1347 
1348   if (!(raw_value = grn_ja_ref_raw(ctx, ja, id, iw, &raw_value_len))) {
1349     iw->uncompressed_value = NULL;
1350     *value_len = 0;
1351     return NULL;
1352   }
1353 
1354   unpacked_value = grn_ja_ref_packed(ctx,
1355                                      iw, value_len,
1356                                      raw_value, raw_value_len,
1357                                      &zvalue, &zvalue_len,
1358                                      &uncompressed_value_len);
1359   if (unpacked_value) {
1360     return unpacked_value;
1361   }
1362 
1363   zstream.next_in = (Bytef *)zvalue;
1364   zstream.avail_in = zvalue_len;
1365   zstream.zalloc = Z_NULL;
1366   zstream.zfree = Z_NULL;
1367   zrc = inflateInit2(&zstream, 15 /* windowBits */);
1368   if (zrc != Z_OK) {
1369     iw->uncompressed_value = NULL;
1370     *value_len = 0;
1371     grn_ja_compress_error(ctx,
1372                           ja,
1373                           id,
1374                           GRN_ZLIB_ERROR,
1375                           "[zlib] failed to decompress: initialize",
1376                           grn_zrc_to_string(zrc));
1377     return NULL;
1378   }
1379   if (!(iw->uncompressed_value = GRN_MALLOC(uncompressed_value_len))) {
1380     inflateEnd(&zstream);
1381     iw->uncompressed_value = NULL;
1382     *value_len = 0;
1383     grn_ja_compress_error(ctx,
1384                           ja,
1385                           id,
1386                           GRN_ZLIB_ERROR,
1387                           "[zlib] failed to decompress: allocate buffer",
1388                           NULL);
1389     return NULL;
1390   }
1391   zstream.next_out = (Bytef *)iw->uncompressed_value;
1392   zstream.avail_out = uncompressed_value_len;
1393   zrc = inflate(&zstream, Z_FINISH);
1394   if (zrc != Z_STREAM_END) {
1395     inflateEnd(&zstream);
1396     GRN_FREE(iw->uncompressed_value);
1397     iw->uncompressed_value = NULL;
1398     *value_len = 0;
1399     grn_ja_compress_error(ctx,
1400                           ja,
1401                           id,
1402                           GRN_ZLIB_ERROR,
1403                           "[zlib] failed to decompress: finish",
1404                           grn_zrc_to_string(zrc));
1405     return NULL;
1406   }
1407   *value_len = zstream.total_out;
1408   zrc = inflateEnd(&zstream);
1409   if (zrc != Z_OK) {
1410     GRN_FREE(iw->uncompressed_value);
1411     iw->uncompressed_value = NULL;
1412     *value_len = 0;
1413     grn_ja_compress_error(ctx,
1414                           ja,
1415                           id,
1416                           GRN_ZLIB_ERROR,
1417                           "[zlib] failed to decompress: end",
1418                           grn_zrc_to_string(zrc));
1419     return NULL;
1420   }
1421   return iw->uncompressed_value;
1422 }
1423 #endif /* GRN_WITH_ZLIB */
1424 
1425 #ifdef GRN_WITH_LZ4
1426 #include <lz4.h>
1427 
1428 # if (LZ4_VERSION_MAJOR == 1 && LZ4_VERSION_MINOR < 6)
1429 #  define LZ4_compress_default(source, dest, source_size, max_dest_size) \
1430   LZ4_compress((source), (dest), (source_size))
1431 # endif
1432 
1433 static void *
grn_ja_ref_lz4(grn_ctx * ctx,grn_ja * ja,grn_id id,grn_io_win * iw,uint32_t * value_len)1434 grn_ja_ref_lz4(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_io_win *iw, uint32_t *value_len)
1435 {
1436   void *raw_value;
1437   uint32_t raw_value_len;
1438   void *lz4_value;
1439   uint32_t lz4_value_len;
1440   void *unpacked_value;
1441   uint32_t uncompressed_value_len;
1442 
1443   if (!(raw_value = grn_ja_ref_raw(ctx, ja, id, iw, &raw_value_len))) {
1444     iw->uncompressed_value = NULL;
1445     *value_len = 0;
1446     return NULL;
1447   }
1448 
1449   unpacked_value = grn_ja_ref_packed(ctx,
1450                                      iw, value_len,
1451                                      raw_value, raw_value_len,
1452                                      &lz4_value, &lz4_value_len,
1453                                      &uncompressed_value_len);
1454   if (unpacked_value) {
1455     return unpacked_value;
1456   }
1457 
1458   if (!(iw->uncompressed_value = GRN_MALLOC(uncompressed_value_len))) {
1459     iw->uncompressed_value = NULL;
1460     *value_len = 0;
1461     return NULL;
1462   }
1463   if (LZ4_decompress_safe((const char *)(lz4_value),
1464                           (char *)(iw->uncompressed_value),
1465                           lz4_value_len,
1466                           uncompressed_value_len) < 0) {
1467     GRN_FREE(iw->uncompressed_value);
1468     iw->uncompressed_value = NULL;
1469     *value_len = 0;
1470     grn_ja_compress_error(ctx,
1471                           ja,
1472                           id,
1473                           GRN_LZ4_ERROR,
1474                           "[lz4] failed to decompress",
1475                           NULL);
1476     return NULL;
1477   }
1478   *value_len = uncompressed_value_len;
1479   return iw->uncompressed_value;
1480 }
1481 #endif /* GRN_WITH_LZ4 */
1482 
1483 #ifdef GRN_WITH_ZSTD
1484 #include <zstd.h>
1485 
1486 static void *
grn_ja_ref_zstd(grn_ctx * ctx,grn_ja * ja,grn_id id,grn_io_win * iw,uint32_t * value_len)1487 grn_ja_ref_zstd(grn_ctx *ctx,
1488                 grn_ja *ja,
1489                 grn_id id,
1490                 grn_io_win *iw,
1491                 uint32_t *value_len)
1492 {
1493   void *raw_value;
1494   uint32_t raw_value_len;
1495   void *zstd_value;
1496   uint32_t zstd_value_len;
1497   void *unpacked_value;
1498   uint32_t uncompressed_value_len;
1499   size_t written_len;
1500 
1501   if (!(raw_value = grn_ja_ref_raw(ctx, ja, id, iw, &raw_value_len))) {
1502     iw->uncompressed_value = NULL;
1503     *value_len = 0;
1504     return NULL;
1505   }
1506 
1507   unpacked_value = grn_ja_ref_packed(ctx,
1508                                      iw, value_len,
1509                                      raw_value, raw_value_len,
1510                                      &zstd_value, &zstd_value_len,
1511                                      &uncompressed_value_len);
1512   if (unpacked_value) {
1513     return unpacked_value;
1514   }
1515 
1516   if (!(iw->uncompressed_value = GRN_MALLOC(uncompressed_value_len))) {
1517     iw->uncompressed_value = NULL;
1518     *value_len = 0;
1519     return NULL;
1520   }
1521 
1522   written_len = ZSTD_decompress((char *)(iw->uncompressed_value),
1523                                 uncompressed_value_len,
1524                                 zstd_value,
1525                                 zstd_value_len);
1526   if (ZSTD_isError(written_len)) {
1527     GRN_FREE(iw->uncompressed_value);
1528     iw->uncompressed_value = NULL;
1529     *value_len = 0;
1530     grn_ja_compress_error(ctx,
1531                           ja,
1532                           id,
1533                           GRN_ZSTD_ERROR,
1534                           "[zstd] failed to decompress",
1535                           ZSTD_getErrorName(written_len));
1536     return NULL;
1537   }
1538   *value_len = uncompressed_value_len;
1539   return iw->uncompressed_value;
1540 }
1541 #endif /* GRN_WITH_ZSTD */
1542 
1543 void *
grn_ja_ref(grn_ctx * ctx,grn_ja * ja,grn_id id,grn_io_win * iw,uint32_t * value_len)1544 grn_ja_ref(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_io_win *iw, uint32_t *value_len)
1545 {
1546   switch (ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
1547 #ifdef GRN_WITH_ZLIB
1548   case GRN_OBJ_COMPRESS_ZLIB :
1549     return grn_ja_ref_zlib(ctx, ja, id, iw, value_len);
1550 #endif /* GRN_WITH_ZLIB */
1551 #ifdef GRN_WITH_LZ4
1552   case GRN_OBJ_COMPRESS_LZ4 :
1553     return grn_ja_ref_lz4(ctx, ja, id, iw, value_len);
1554 #endif /* GRN_WITH_LZ4 */
1555 #ifdef GRN_WITH_ZSTD
1556   case GRN_OBJ_COMPRESS_ZSTD :
1557     return grn_ja_ref_zstd(ctx, ja, id, iw, value_len);
1558 #endif /* GRN_WITH_ZSTD */
1559   default :
1560     return grn_ja_ref_raw(ctx, ja, id, iw, value_len);
1561   }
1562 }
1563 
1564 grn_obj *
grn_ja_get_value(grn_ctx * ctx,grn_ja * ja,grn_id id,grn_obj * value)1565 grn_ja_get_value(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_obj *value)
1566 {
1567   void *v;
1568   uint32_t len;
1569   grn_io_win iw;
1570   if (!value) {
1571     if (!(value = grn_obj_open(ctx, GRN_BULK, 0, 0))) {
1572       ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_value failed");
1573       goto exit;
1574     }
1575   }
1576   if ((v = grn_ja_ref(ctx, ja, id, &iw, &len))) {
1577     if ((ja->header->flags & GRN_OBJ_RING_BUFFER) &&
1578         len > ja->header->max_element_size) {
1579       byte *b = v;
1580       uint32_t el = len - sizeof(uint32_t);
1581       uint32_t pos = *((uint32_t *)(b + el));
1582       GRN_ASSERT(pos < el);
1583       grn_bulk_write(ctx, value, (char *)(b + pos), el - pos);
1584       grn_bulk_write(ctx, value, (char *)(b), pos);
1585     } else {
1586       grn_bulk_write(ctx, value, v, len);
1587     }
1588     grn_ja_unref(ctx, &iw);
1589   }
1590 exit :
1591   return value;
1592 }
1593 
1594 #ifdef GRN_WITH_ZLIB
1595 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)1596 grn_ja_put_zlib(grn_ctx *ctx, grn_ja *ja, grn_id id,
1597                 void *value, uint32_t value_len, int flags, uint64_t *cas)
1598 {
1599   grn_rc rc;
1600   z_stream zstream;
1601   void *zvalue;
1602   int zvalue_len;
1603   int zrc;
1604 
1605   if (value_len == 0) {
1606     return grn_ja_put_raw(ctx, ja, id, value, value_len, flags, cas);
1607   }
1608 
1609   if (value_len < COMPRESS_THRESHOLD_BYTE) {
1610     return grn_ja_put_packed(ctx, ja, id, value, value_len, flags, cas);
1611   }
1612 
1613   zstream.next_in = value;
1614   zstream.avail_in = value_len;
1615   zstream.zalloc = Z_NULL;
1616   zstream.zfree = Z_NULL;
1617   zrc = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
1618                      15 /* windowBits */,
1619                      8 /* memLevel */,
1620                      Z_DEFAULT_STRATEGY);
1621   if (zrc != Z_OK) {
1622     grn_ja_compress_error(ctx,
1623                           ja,
1624                           id,
1625                           GRN_ZLIB_ERROR,
1626                           "[zlib] failed to compress: initialize",
1627                           grn_zrc_to_string(zrc));
1628     return ctx->rc;
1629   }
1630   zvalue_len = deflateBound(&zstream, value_len);
1631   if (!(zvalue = GRN_MALLOC(zvalue_len + sizeof(uint64_t)))) {
1632     deflateEnd(&zstream);
1633     grn_ja_compress_error(ctx,
1634                           ja,
1635                           id,
1636                           GRN_ZLIB_ERROR,
1637                           "[zlib] failed to allocate compress buffer",
1638                           NULL);
1639     return ctx->rc;
1640   }
1641   zstream.next_out = (Bytef *)(((uint64_t *)zvalue) + 1);
1642   zstream.avail_out = zvalue_len;
1643   zrc = deflate(&zstream, Z_FINISH);
1644   if (zrc != Z_STREAM_END) {
1645     deflateEnd(&zstream);
1646     GRN_FREE(zvalue);
1647     grn_ja_compress_error(ctx,
1648                           ja,
1649                           id,
1650                           GRN_ZLIB_ERROR,
1651                           "[zlib] failed to compress: finish",
1652                           grn_zrc_to_string(zrc));
1653     return ctx->rc;
1654   }
1655   zvalue_len = zstream.total_out;
1656   zrc = deflateEnd(&zstream);
1657   if (zrc != Z_OK) {
1658     GRN_FREE(zvalue);
1659     grn_ja_compress_error(ctx,
1660                           ja,
1661                           id,
1662                           GRN_ZLIB_ERROR,
1663                           "[zlib] failed to compress: end",
1664                           grn_zrc_to_string(zrc));
1665     return ctx->rc;
1666   }
1667   *(uint64_t *)zvalue = value_len;
1668   rc = grn_ja_put_raw(ctx, ja, id, zvalue, zvalue_len + sizeof(uint64_t), flags, cas);
1669   GRN_FREE(zvalue);
1670   return rc;
1671 }
1672 #endif /* GRN_WITH_ZLIB */
1673 
1674 #ifdef GRN_WITH_LZ4
1675 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)1676 grn_ja_put_lz4(grn_ctx *ctx, grn_ja *ja, grn_id id,
1677                void *value, uint32_t value_len, int flags, uint64_t *cas)
1678 {
1679   grn_rc rc;
1680   void *packed_value;
1681   int packed_value_len_max;
1682   int packed_value_len_real;
1683   char *lz4_value;
1684   int lz4_value_len_max;
1685   int lz4_value_len_real;
1686 
1687   if (value_len == 0) {
1688     return grn_ja_put_raw(ctx, ja, id, value, value_len, flags, cas);
1689   }
1690 
1691   if (value_len < COMPRESS_THRESHOLD_BYTE) {
1692     return grn_ja_put_packed(ctx, ja, id, value, value_len, flags, cas);
1693   }
1694 
1695   if (value_len > (uint32_t)LZ4_MAX_INPUT_SIZE) {
1696     uint64_t packed_value_meta;
1697 
1698     packed_value_len_real = value_len + sizeof(uint64_t);
1699     packed_value = GRN_MALLOC(packed_value_len_real);
1700     if (!packed_value) {
1701       grn_ja_compress_error(ctx,
1702                             ja,
1703                             id,
1704                             GRN_LZ4_ERROR,
1705                             "[lz4] failed to allocate packed buffer",
1706                             NULL);
1707       return ctx->rc;
1708     }
1709     packed_value_meta = value_len | COMPRESSED_VALUE_META_FLAG_RAW;
1710     *((uint64_t *)packed_value) = packed_value_meta;
1711     memcpy(((uint64_t *)packed_value) + 1,
1712            value,
1713            value_len);
1714     rc = grn_ja_put_raw(ctx,
1715                         ja,
1716                         id,
1717                         packed_value,
1718                         packed_value_len_real,
1719                         flags,
1720                         cas);
1721     GRN_FREE(packed_value);
1722     return rc;
1723   }
1724 
1725   lz4_value_len_max = LZ4_compressBound(value_len);
1726   packed_value_len_max = lz4_value_len_max + sizeof(uint64_t);
1727   if (!(packed_value = GRN_MALLOC(packed_value_len_max))) {
1728     grn_ja_compress_error(ctx,
1729                           ja,
1730                           id,
1731                           GRN_LZ4_ERROR,
1732                           "[lz4] failed to allocate compress buffer",
1733                           NULL);
1734     return ctx->rc;
1735   }
1736   lz4_value = (char *)((uint64_t *)packed_value + 1);
1737   lz4_value_len_real = LZ4_compress_default((const char *)value,
1738                                             lz4_value,
1739                                             value_len,
1740                                             lz4_value_len_max);
1741   if (lz4_value_len_real <= 0) {
1742     GRN_FREE(packed_value);
1743     grn_ja_compress_error(ctx,
1744                           ja,
1745                           id,
1746                           GRN_LZ4_ERROR,
1747                           "[lz4] failed to compress",
1748                           NULL);
1749     return ctx->rc;
1750   }
1751   *(uint64_t *)packed_value = value_len;
1752   packed_value_len_real = lz4_value_len_real + sizeof(uint64_t);
1753   rc = grn_ja_put_raw(ctx,
1754                       ja,
1755                       id,
1756                       packed_value,
1757                       packed_value_len_real,
1758                       flags,
1759                       cas);
1760   GRN_FREE(packed_value);
1761   return rc;
1762 }
1763 #endif /* GRN_WITH_LZ4 */
1764 
1765 #ifdef GRN_WITH_ZSTD
1766 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)1767 grn_ja_put_zstd(grn_ctx *ctx,
1768                 grn_ja *ja,
1769                 grn_id id,
1770                 void *value,
1771                 uint32_t value_len,
1772                 int flags,
1773                 uint64_t *cas)
1774 {
1775   grn_rc rc;
1776   void *packed_value;
1777   int packed_value_len_max;
1778   int packed_value_len_real;
1779   void *zstd_value;
1780   int zstd_value_len_max;
1781   int zstd_value_len_real;
1782   int zstd_compression_level = 3;
1783 
1784   if (value_len == 0) {
1785     return grn_ja_put_raw(ctx, ja, id, value, value_len, flags, cas);
1786   }
1787 
1788   if (value_len < COMPRESS_THRESHOLD_BYTE) {
1789     return grn_ja_put_packed(ctx, ja, id, value, value_len, flags, cas);
1790   }
1791 
1792   zstd_value_len_max = ZSTD_compressBound(value_len);
1793   packed_value_len_max = zstd_value_len_max + sizeof(uint64_t);
1794   if (!(packed_value = GRN_MALLOC(packed_value_len_max))) {
1795     grn_ja_compress_error(ctx,
1796                           ja,
1797                           id,
1798                           GRN_ZSTD_ERROR,
1799                           "[zstd] failed to allocate compress buffer",
1800                           NULL);
1801     return ctx->rc;
1802   }
1803   zstd_value = ((uint64_t *)packed_value) + 1;
1804   zstd_value_len_real = ZSTD_compress(zstd_value, zstd_value_len_max,
1805                                       value, value_len,
1806                                       zstd_compression_level);
1807   if (ZSTD_isError(zstd_value_len_real)) {
1808     grn_ja_compress_error(ctx,
1809                           ja,
1810                           id,
1811                           GRN_ZSTD_ERROR,
1812                           "[zstd] failed to compress",
1813                           ZSTD_getErrorName(zstd_value_len_real));
1814     return ctx->rc;
1815   }
1816   *(uint64_t *)packed_value = value_len;
1817   packed_value_len_real = zstd_value_len_real + sizeof(uint64_t);
1818   rc = grn_ja_put_raw(ctx,
1819                       ja,
1820                       id,
1821                       packed_value,
1822                       packed_value_len_real,
1823                       flags,
1824                       cas);
1825   GRN_FREE(packed_value);
1826   return rc;
1827 }
1828 #endif /* GRN_WITH_ZSTD */
1829 
1830 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)1831 grn_ja_put(grn_ctx *ctx, grn_ja *ja, grn_id id, void *value, uint32_t value_len,
1832            int flags, uint64_t *cas)
1833 {
1834   switch (ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
1835 #ifdef GRN_WITH_ZLIB
1836   case GRN_OBJ_COMPRESS_ZLIB :
1837     return grn_ja_put_zlib(ctx, ja, id, value, value_len, flags, cas);
1838 #endif /* GRN_WITH_ZLIB */
1839 #ifdef GRN_WITH_LZ4
1840   case GRN_OBJ_COMPRESS_LZ4 :
1841     return grn_ja_put_lz4(ctx, ja, id, value, value_len, flags, cas);
1842 #endif /* GRN_WITH_LZ4 */
1843 #ifdef GRN_WITH_ZSTD
1844   case GRN_OBJ_COMPRESS_ZSTD :
1845     return grn_ja_put_zstd(ctx, ja, id, value, value_len, flags, cas);
1846 #endif /* GRN_WITH_ZSTD */
1847   default :
1848     return grn_ja_put_raw(ctx, ja, id, value, value_len, flags, cas);
1849   }
1850 }
1851 
1852 static grn_rc
grn_ja_defrag_seg(grn_ctx * ctx,grn_ja * ja,uint32_t seg)1853 grn_ja_defrag_seg(grn_ctx *ctx, grn_ja *ja, uint32_t seg)
1854 {
1855   byte *v = NULL, *ve;
1856   uint32_t element_size, cum = 0, *seginfo = &SEGMENTS_AT(ja,seg), sum;
1857   sum = (*seginfo & ~SEG_MASK);
1858   GRN_IO_SEG_REF(ja->io, seg, v);
1859   if (!v) { return GRN_NO_MEMORY_AVAILABLE; }
1860   ve = v + JA_SEGMENT_SIZE;
1861   while (v < ve && cum < sum) {
1862     grn_id id = *((grn_id *)v);
1863     if (!id) { break; }
1864     if (id & DELETED) {
1865       element_size = (id & ~DELETED);
1866     } else {
1867       uint64_t cas;
1868       uint32_t pos;
1869       if (grn_ja_element_info(ctx, ja, id, &cas, &pos, &element_size)) { break; }
1870       if (v + sizeof(uint32_t) != ve - JA_SEGMENT_SIZE + pos) {
1871         GRN_LOG(ctx, GRN_LOG_WARNING,
1872                 "dseges[%d] = pos unmatch (%d != %" GRN_FMT_LLD ")",
1873                 seg, pos, (long long int)(v + sizeof(uint32_t) + JA_SEGMENT_SIZE - ve));
1874         break;
1875       }
1876       if (grn_ja_put(ctx, ja, id, v + sizeof(uint32_t), element_size, GRN_OBJ_SET, &cas)) {
1877         GRN_LOG(ctx, GRN_LOG_WARNING,
1878                 "dseges[%d] = put failed (%d)", seg, id);
1879         break;
1880       }
1881       element_size = (element_size + sizeof(grn_id) - 1) & ~(sizeof(grn_id) - 1);
1882       cum += sizeof(uint32_t) + element_size;
1883     }
1884     v += sizeof(uint32_t) + element_size;
1885   }
1886   if (*seginfo) {
1887     GRN_LOG(ctx, GRN_LOG_WARNING, "dseges[%d] = %d after defrag", seg, (*seginfo & ~SEG_MASK));
1888   }
1889   GRN_IO_SEG_UNREF(ja->io, seg);
1890   return GRN_SUCCESS;
1891 }
1892 
1893 int
grn_ja_defrag(grn_ctx * ctx,grn_ja * ja,int threshold)1894 grn_ja_defrag(grn_ctx *ctx, grn_ja *ja, int threshold)
1895 {
1896   int nsegs = 0;
1897   uint32_t seg, ts = 1U << (GRN_JA_W_SEGMENT - threshold);
1898   for (seg = 0; seg < JA_N_DSEGMENTS; seg++) {
1899     if (seg == *(ja->header->curr_seg)) { continue; }
1900     if (((SEGMENTS_AT(ja, seg) & SEG_MASK) == SEG_SEQ) &&
1901         ((SEGMENTS_AT(ja, seg) & ~SEG_MASK) < ts)) {
1902       if (!grn_ja_defrag_seg(ctx, ja, seg)) { nsegs++; }
1903     }
1904   }
1905   return nsegs;
1906 }
1907 
1908 void
grn_ja_check(grn_ctx * ctx,grn_ja * ja)1909 grn_ja_check(grn_ctx *ctx, grn_ja *ja)
1910 {
1911   char buf[8];
1912   uint32_t seg;
1913   struct grn_ja_header *h = ja->header;
1914   GRN_OUTPUT_ARRAY_OPEN("RESULT", 8);
1915   GRN_OUTPUT_MAP_OPEN("SUMMARY", 8);
1916   GRN_OUTPUT_CSTR("flags");
1917   grn_itoh(h->flags, buf, 8);
1918   GRN_OUTPUT_STR(buf, 8);
1919   GRN_OUTPUT_CSTR("curr seg");
1920   GRN_OUTPUT_INT64(*(h->curr_seg));
1921   GRN_OUTPUT_CSTR("curr pos");
1922   GRN_OUTPUT_INT64(*(h->curr_pos));
1923   GRN_OUTPUT_CSTR("max_element_size");
1924   GRN_OUTPUT_INT64(h->max_element_size);
1925   GRN_OUTPUT_CSTR("segregate_threshold");
1926   GRN_OUTPUT_INT64(h->segregate_threshold);
1927   GRN_OUTPUT_CSTR("n_element_variation");
1928   GRN_OUTPUT_INT64(h->n_element_variation);
1929   GRN_OUTPUT_MAP_CLOSE();
1930   GRN_OUTPUT_ARRAY_OPEN("DETAIL", -1);
1931   for (seg = 0; seg < JA_N_DSEGMENTS; seg++) {
1932     int dseg = SEGMENTS_AT(ja, seg);
1933     if (dseg) {
1934       GRN_OUTPUT_MAP_OPEN("SEG", -1);
1935       GRN_OUTPUT_CSTR("seg id");
1936       GRN_OUTPUT_INT64(seg);
1937       GRN_OUTPUT_CSTR("seg type");
1938       GRN_OUTPUT_INT64((dseg & SEG_MASK)>>28);
1939       GRN_OUTPUT_CSTR("seg value");
1940       GRN_OUTPUT_INT64(dseg & ~SEG_MASK);
1941       if ((dseg & SEG_MASK) == SEG_SEQ) {
1942         byte *v = NULL, *ve;
1943         uint32_t element_size, cum = 0, sum = dseg & ~SEG_MASK;
1944         uint32_t n_del_elements = 0, n_elements = 0, s_del_elements = 0, s_elements = 0;
1945         GRN_IO_SEG_REF(ja->io, seg, v);
1946         if (v) {
1947           /*
1948           GRN_OUTPUT_CSTR("seg seq");
1949           GRN_OUTPUT_ARRAY_OPEN("SEQ", -1);
1950           */
1951           ve = v + JA_SEGMENT_SIZE;
1952           while (v < ve && cum < sum) {
1953             grn_id id = *((grn_id *)v);
1954             /*
1955             GRN_OUTPUT_MAP_OPEN("ENTRY", -1);
1956             GRN_OUTPUT_CSTR("id");
1957             GRN_OUTPUT_INT64(id);
1958             */
1959             if (!id) { break; }
1960             if (id & DELETED) {
1961               element_size = (id & ~DELETED);
1962               n_del_elements++;
1963               s_del_elements += element_size;
1964             } else {
1965               element_size = grn_ja_size(ctx, ja, id);
1966               element_size = (element_size + sizeof(grn_id) - 1) & ~(sizeof(grn_id) - 1);
1967               cum += sizeof(uint32_t) + element_size;
1968               n_elements++;
1969               s_elements += sizeof(uint32_t) + element_size;
1970             }
1971             v += sizeof(uint32_t) + element_size;
1972             /*
1973             GRN_OUTPUT_CSTR("size");
1974             GRN_OUTPUT_INT64(element_size);
1975             GRN_OUTPUT_CSTR("cum");
1976             GRN_OUTPUT_INT64(cum);
1977             GRN_OUTPUT_MAP_CLOSE();
1978             */
1979           }
1980           GRN_IO_SEG_UNREF(ja->io, seg);
1981           /*
1982           GRN_OUTPUT_ARRAY_CLOSE();
1983           */
1984           GRN_OUTPUT_CSTR("n_elements");
1985           GRN_OUTPUT_INT64(n_elements);
1986           GRN_OUTPUT_CSTR("s_elements");
1987           GRN_OUTPUT_INT64(s_elements);
1988           GRN_OUTPUT_CSTR("n_del_elements");
1989           GRN_OUTPUT_INT64(n_del_elements);
1990           GRN_OUTPUT_CSTR("s_del_elements");
1991           GRN_OUTPUT_INT64(s_del_elements);
1992           if (cum != sum) {
1993             GRN_OUTPUT_CSTR("cum gap");
1994             GRN_OUTPUT_INT64(cum - sum);
1995           }
1996         }
1997       }
1998       GRN_OUTPUT_MAP_CLOSE();
1999     }
2000   }
2001   GRN_OUTPUT_ARRAY_CLOSE();
2002   GRN_OUTPUT_ARRAY_CLOSE();
2003 }
2004 
2005 /* grn_ja_reader */
2006 
2007 grn_rc
grn_ja_reader_init(grn_ctx * ctx,grn_ja_reader * reader,grn_ja * ja)2008 grn_ja_reader_init(grn_ctx *ctx, grn_ja_reader *reader, grn_ja *ja)
2009 {
2010   reader->ja = ja;
2011   reader->einfo_seg_id = JA_ESEG_VOID;
2012   reader->ref_avail = GRN_FALSE;
2013   reader->ref_seg_id = JA_ESEG_VOID;
2014   reader->ref_seg_ids = NULL;
2015   reader->nref_seg_ids = 0;
2016   reader->ref_seg_ids_size = 0;
2017   reader->body_seg_id = JA_ESEG_VOID;
2018   reader->body_seg_addr = NULL;
2019   reader->packed_buf = NULL;
2020   reader->packed_buf_size = 0;
2021 #ifdef GRN_WITH_ZLIB
2022   if (reader->ja->header->flags & GRN_OBJ_COMPRESS_ZLIB) {
2023     z_stream *new_stream = GRN_MALLOCN(z_stream, 1);
2024     if (!new_stream) {
2025       return GRN_NO_MEMORY_AVAILABLE;
2026     }
2027     new_stream->zalloc = NULL;
2028     new_stream->zfree = NULL;
2029     new_stream->opaque = NULL;
2030     if (inflateInit2(new_stream, 15) != Z_OK) {
2031       GRN_FREE(new_stream);
2032       return GRN_ZLIB_ERROR;
2033     }
2034     reader->stream = new_stream;
2035   }
2036 #endif /* GRN_WITH_ZLIB */
2037   return GRN_SUCCESS;
2038 }
2039 
2040 grn_rc
grn_ja_reader_fin(grn_ctx * ctx,grn_ja_reader * reader)2041 grn_ja_reader_fin(grn_ctx *ctx, grn_ja_reader *reader)
2042 {
2043   grn_rc rc = GRN_SUCCESS;
2044   if (reader->einfo_seg_id != JA_ESEG_VOID) {
2045     GRN_IO_SEG_UNREF(reader->ja->io, reader->einfo_seg_id);
2046   }
2047   if (reader->ref_seg_ids) {
2048     grn_ja_reader_unref(ctx, reader);
2049     GRN_FREE(reader->ref_seg_ids);
2050   }
2051   if (reader->body_seg_addr) {
2052     GRN_IO_SEG_UNREF(reader->ja->io, reader->body_seg_id);
2053   }
2054   if (reader->packed_buf) {
2055     GRN_FREE(reader->packed_buf);
2056   }
2057 #ifdef GRN_WITH_ZLIB
2058   if (reader->ja->header->flags & GRN_OBJ_COMPRESS_ZLIB) {
2059     if (reader->stream) {
2060       if (inflateEnd((z_stream *)reader->stream) != Z_OK) {
2061         rc = GRN_UNKNOWN_ERROR;
2062       }
2063       GRN_FREE(reader->stream);
2064     }
2065   }
2066 #endif /* GRN_WITH_ZLIB */
2067   return rc;
2068 }
2069 
2070 grn_rc
grn_ja_reader_open(grn_ctx * ctx,grn_ja * ja,grn_ja_reader ** reader)2071 grn_ja_reader_open(grn_ctx *ctx, grn_ja *ja, grn_ja_reader **reader)
2072 {
2073   grn_rc rc;
2074   grn_ja_reader *new_reader = GRN_MALLOCN(grn_ja_reader, 1);
2075   if (!new_reader) {
2076     return GRN_NO_MEMORY_AVAILABLE;
2077   }
2078   rc = grn_ja_reader_init(ctx, new_reader, ja);
2079   if (rc != GRN_SUCCESS) {
2080     GRN_FREE(new_reader);
2081     return rc;
2082   }
2083   *reader = new_reader;
2084   return GRN_SUCCESS;
2085 }
2086 
2087 grn_rc
grn_ja_reader_close(grn_ctx * ctx,grn_ja_reader * reader)2088 grn_ja_reader_close(grn_ctx *ctx, grn_ja_reader *reader)
2089 {
2090   grn_rc rc = grn_ja_reader_fin(ctx, reader);
2091   GRN_FREE(reader);
2092   return rc;
2093 }
2094 
2095 #ifdef GRN_WITH_COMPRESSED
2096 /* grn_ja_reader_seek_compressed() prepares to access a compressed value. */
2097 static grn_rc
grn_ja_reader_seek_compressed(grn_ctx * ctx,grn_ja_reader * reader,grn_id id)2098 grn_ja_reader_seek_compressed(grn_ctx *ctx, grn_ja_reader *reader, grn_id id)
2099 {
2100   grn_ja_einfo *einfo;
2101   void *seg_addr;
2102   uint32_t seg_id = reader->ja->header->esegs[id >> JA_W_EINFO_IN_A_SEGMENT];
2103   if (seg_id == JA_ESEG_VOID) {
2104     return GRN_INVALID_ARGUMENT;
2105   }
2106   if (seg_id != reader->einfo_seg_id) {
2107     GRN_IO_SEG_REF(reader->ja->io, seg_id, seg_addr);
2108     if (!seg_addr) {
2109       return GRN_UNKNOWN_ERROR;
2110     }
2111     if (reader->einfo_seg_id != JA_ESEG_VOID) {
2112       GRN_IO_SEG_UNREF(reader->ja->io, reader->einfo_seg_id);
2113     }
2114     reader->einfo_seg_id = seg_id;
2115     reader->einfo_seg_addr = seg_addr;
2116   }
2117   einfo = (grn_ja_einfo *)reader->einfo_seg_addr;
2118   einfo += id & JA_M_EINFO_IN_A_SEGMENT;
2119   reader->einfo = einfo;
2120   /* ETINY_P(einfo) is always false because the original size needs 8 bytes. */
2121   if (EHUGE_P(einfo)) {
2122     EHUGE_DEC(einfo, seg_id, reader->packed_size);
2123     reader->body_seg_offset = 0;
2124   } else {
2125     EINFO_DEC(einfo, seg_id, reader->body_seg_offset, reader->packed_size);
2126   }
2127   if (seg_id != reader->body_seg_id) {
2128     GRN_IO_SEG_REF(reader->ja->io, seg_id, seg_addr);
2129     if (!seg_addr) {
2130       return GRN_UNKNOWN_ERROR;
2131     }
2132     if (reader->body_seg_addr) {
2133       GRN_IO_SEG_UNREF(reader->ja->io, reader->body_seg_id);
2134     }
2135     reader->body_seg_id = seg_id;
2136     reader->body_seg_addr = seg_addr;
2137   }
2138   seg_addr = (char *)reader->body_seg_addr + reader->body_seg_offset;
2139   reader->value_size = (uint32_t)*(uint64_t *)seg_addr;
2140   return GRN_SUCCESS;
2141 }
2142 #endif /* GRN_WITH_COMPRESSED */
2143 
2144 /* grn_ja_reader_seek_raw() prepares to access a value. */
2145 static grn_rc
grn_ja_reader_seek_raw(grn_ctx * ctx,grn_ja_reader * reader,grn_id id)2146 grn_ja_reader_seek_raw(grn_ctx *ctx, grn_ja_reader *reader, grn_id id)
2147 {
2148   grn_ja_einfo *einfo;
2149   void *seg_addr;
2150   uint32_t seg_id = reader->ja->header->esegs[id >> JA_W_EINFO_IN_A_SEGMENT];
2151   if (seg_id == JA_ESEG_VOID) {
2152     return GRN_INVALID_ARGUMENT;
2153   }
2154   if (seg_id != reader->einfo_seg_id) {
2155     GRN_IO_SEG_REF(reader->ja->io, seg_id, seg_addr);
2156     if (!seg_addr) {
2157       return GRN_UNKNOWN_ERROR;
2158     }
2159     if (reader->einfo_seg_id != JA_ESEG_VOID) {
2160       GRN_IO_SEG_UNREF(reader->ja->io, reader->einfo_seg_id);
2161     }
2162     reader->einfo_seg_id = seg_id;
2163     reader->einfo_seg_addr = seg_addr;
2164   }
2165   einfo = (grn_ja_einfo *)reader->einfo_seg_addr;
2166   einfo += id & JA_M_EINFO_IN_A_SEGMENT;
2167   reader->einfo = einfo;
2168   if (ETINY_P(einfo)) {
2169     ETINY_DEC(einfo, reader->value_size);
2170     reader->ref_avail = GRN_FALSE;
2171   } else {
2172     if (EHUGE_P(einfo)) {
2173       EHUGE_DEC(einfo, seg_id, reader->value_size);
2174       reader->ref_avail = GRN_FALSE;
2175     } else {
2176       EINFO_DEC(einfo, seg_id, reader->body_seg_offset, reader->value_size);
2177       reader->ref_avail = GRN_TRUE;
2178     }
2179     if (reader->body_seg_addr) {
2180       if (seg_id != reader->body_seg_id) {
2181         GRN_IO_SEG_UNREF(reader->ja->io, reader->body_seg_id);
2182         reader->body_seg_addr = NULL;
2183       }
2184     }
2185     reader->body_seg_id = seg_id;
2186   }
2187   return GRN_SUCCESS;
2188 }
2189 
2190 grn_rc
grn_ja_reader_seek(grn_ctx * ctx,grn_ja_reader * reader,grn_id id)2191 grn_ja_reader_seek(grn_ctx *ctx, grn_ja_reader *reader, grn_id id)
2192 {
2193   switch (reader->ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
2194 #ifdef GRN_WITH_ZLIB
2195   case GRN_OBJ_COMPRESS_ZLIB :
2196     return grn_ja_reader_seek_compressed(ctx, reader, id);
2197 #endif /* GRN_WITH_ZLIB */
2198 #ifdef GRN_WITH_LZ4
2199   case GRN_OBJ_COMPRESS_LZ4 :
2200     return grn_ja_reader_seek_compressed(ctx, reader, id);
2201 #endif /* GRN_WITH_LZ4 */
2202 #ifdef GRN_WITH_ZSTD
2203   case GRN_OBJ_COMPRESS_ZSTD :
2204     return grn_ja_reader_seek_compressed(ctx, reader, id);
2205 #endif /* GRN_WITH_ZSTD */
2206   default :
2207     return grn_ja_reader_seek_raw(ctx, reader, id);
2208   }
2209 }
2210 
2211 grn_rc
grn_ja_reader_ref(grn_ctx * ctx,grn_ja_reader * reader,void ** addr)2212 grn_ja_reader_ref(grn_ctx *ctx, grn_ja_reader *reader, void **addr)
2213 {
2214   if (!reader->ref_avail) {
2215     return GRN_INVALID_ARGUMENT;
2216   }
2217   if (reader->body_seg_id != reader->ref_seg_id) {
2218     void *seg_addr;
2219     if (reader->nref_seg_ids == reader->ref_seg_ids_size) {
2220       size_t n_bytes;
2221       uint32_t new_size, *new_seg_ids;
2222       if (reader->ref_seg_ids_size == 0) {
2223         new_size = GRN_JA_READER_INITIAL_REF_SEG_IDS_SIZE;
2224       } else {
2225         new_size = reader->ref_seg_ids_size * 2;
2226       }
2227       n_bytes = sizeof(uint32_t) * new_size;
2228       new_seg_ids = (uint32_t *)GRN_REALLOC(reader->ref_seg_ids, n_bytes);
2229       if (!new_seg_ids) {
2230         return GRN_NO_MEMORY_AVAILABLE;
2231       }
2232       reader->ref_seg_ids = new_seg_ids;
2233       reader->ref_seg_ids_size = new_size;
2234     }
2235     GRN_IO_SEG_REF(reader->ja->io, reader->body_seg_id, seg_addr);
2236     if (!seg_addr) {
2237       return GRN_UNKNOWN_ERROR;
2238     }
2239     reader->ref_seg_id = reader->body_seg_id;
2240     reader->ref_seg_addr = seg_addr;
2241     reader->ref_seg_ids[reader->nref_seg_ids++] = reader->body_seg_id;
2242   }
2243   *addr = (char *)reader->ref_seg_addr + reader->body_seg_offset;
2244   return GRN_SUCCESS;
2245 }
2246 
2247 grn_rc
grn_ja_reader_unref(grn_ctx * ctx,grn_ja_reader * reader)2248 grn_ja_reader_unref(grn_ctx *ctx, grn_ja_reader *reader)
2249 {
2250   uint32_t i;
2251   for (i = 0; i < reader->nref_seg_ids; i++) {
2252     GRN_IO_SEG_UNREF(reader->ja->io, reader->ref_seg_ids[i]);
2253   }
2254   reader->ref_seg_id = JA_ESEG_VOID;
2255   reader->nref_seg_ids = 0;
2256   return GRN_FUNCTION_NOT_IMPLEMENTED;
2257 }
2258 
2259 #ifdef GRN_WITH_ZLIB
2260 /* grn_ja_reader_read_zlib() reads a value compressed with zlib. */
2261 static grn_rc
grn_ja_reader_read_zlib(grn_ctx * ctx,grn_ja_reader * reader,void * buf)2262 grn_ja_reader_read_zlib(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
2263 {
2264   uLong dest_size = reader->value_size;
2265   z_stream *stream = (z_stream *)reader->stream;
2266   grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
2267   if (EHUGE_P(einfo)) {
2268     /* TODO: Use z_stream to avoid copy. */
2269     grn_io *io = reader->ja->io;
2270     void *seg_addr;
2271     char *packed_ptr;
2272     uint32_t size, seg_id;
2273     if (reader->packed_size > reader->packed_buf_size) {
2274       void *new_buf = GRN_REALLOC(reader->packed_buf, reader->packed_size);
2275       if (!new_buf) {
2276         return GRN_NO_MEMORY_AVAILABLE;
2277       }
2278       reader->packed_buf = new_buf;
2279       reader->packed_buf_size = reader->packed_size;
2280     }
2281     packed_ptr = (char *)reader->packed_buf;
2282     grn_memcpy(packed_ptr, (char *)reader->body_seg_addr + sizeof(uint64_t),
2283                io->header->segment_size - sizeof(uint64_t));
2284     packed_ptr += io->header->segment_size - sizeof(uint64_t);
2285     size = reader->packed_size - (io->header->segment_size - sizeof(uint64_t));
2286     seg_id = reader->body_seg_id + 1;
2287     while (size > io->header->segment_size) {
2288       GRN_IO_SEG_REF(io, seg_id, seg_addr);
2289       if (!seg_addr) {
2290         return GRN_UNKNOWN_ERROR;
2291       }
2292       grn_memcpy(packed_ptr, seg_addr, io->header->segment_size);
2293       GRN_IO_SEG_UNREF(io, seg_id);
2294       seg_id++;
2295       size -= io->header->segment_size;
2296       packed_ptr += io->header->segment_size;
2297     }
2298     GRN_IO_SEG_REF(io, seg_id, seg_addr);
2299     if (!seg_addr) {
2300       return GRN_UNKNOWN_ERROR;
2301     }
2302     grn_memcpy(packed_ptr, seg_addr, size);
2303     GRN_IO_SEG_UNREF(io, seg_id);
2304     seg_id++;
2305     if (uncompress((Bytef *)buf, &dest_size, (Bytef *)reader->packed_buf,
2306                    reader->packed_size - sizeof(uint64_t)) != Z_OK) {
2307       return GRN_ZLIB_ERROR;
2308     }
2309     if (dest_size != reader->value_size) {
2310       return GRN_ZLIB_ERROR;
2311     }
2312   } else {
2313     char *packed_addr = (char *)reader->body_seg_addr;
2314     packed_addr += reader->body_seg_offset + sizeof(uint64_t);
2315     if (inflateReset(stream) != Z_OK) {
2316       return GRN_ZLIB_ERROR;
2317     }
2318     stream->next_in = (Bytef *)packed_addr;
2319     stream->avail_in = reader->packed_size - sizeof(uint64_t);
2320     stream->next_out = (Bytef *)buf;
2321     stream->avail_out = dest_size;
2322     if ((inflate(stream, Z_FINISH) != Z_STREAM_END) || stream->avail_out) {
2323       return GRN_ZLIB_ERROR;
2324     }
2325   }
2326   return GRN_SUCCESS;
2327 }
2328 #endif /* GRN_WITH_ZLIB */
2329 
2330 #ifdef GRN_WITH_LZ4
2331 /* grn_ja_reader_read_lz4() reads a value compressed with LZ4. */
2332 static grn_rc
grn_ja_reader_read_lz4(grn_ctx * ctx,grn_ja_reader * reader,void * buf)2333 grn_ja_reader_read_lz4(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
2334 {
2335   int src_size, dest_size;
2336   grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
2337   if (EHUGE_P(einfo)) {
2338     grn_io *io = reader->ja->io;
2339     void *seg_addr;
2340     char *packed_ptr;
2341     uint32_t size, seg_id;
2342     if (reader->packed_size > reader->packed_buf_size) {
2343       void *new_buf = GRN_REALLOC(reader->packed_buf, reader->packed_size);
2344       if (!new_buf) {
2345         return GRN_NO_MEMORY_AVAILABLE;
2346       }
2347       reader->packed_buf = new_buf;
2348       reader->packed_buf_size = reader->packed_size;
2349     }
2350     packed_ptr = (char *)reader->packed_buf;
2351     grn_memcpy(packed_ptr, (char *)reader->body_seg_addr + sizeof(uint64_t),
2352                io->header->segment_size - sizeof(uint64_t));
2353     packed_ptr += io->header->segment_size - sizeof(uint64_t);
2354     size = reader->packed_size - (io->header->segment_size - sizeof(uint64_t));
2355     seg_id = reader->body_seg_id + 1;
2356     while (size > io->header->segment_size) {
2357       GRN_IO_SEG_REF(io, seg_id, seg_addr);
2358       if (!seg_addr) {
2359         return GRN_UNKNOWN_ERROR;
2360       }
2361       grn_memcpy(packed_ptr, seg_addr, io->header->segment_size);
2362       GRN_IO_SEG_UNREF(io, seg_id);
2363       seg_id++;
2364       size -= io->header->segment_size;
2365       packed_ptr += io->header->segment_size;
2366     }
2367     GRN_IO_SEG_REF(io, seg_id, seg_addr);
2368     if (!seg_addr) {
2369       return GRN_UNKNOWN_ERROR;
2370     }
2371     grn_memcpy(packed_ptr, seg_addr, size);
2372     GRN_IO_SEG_UNREF(io, seg_id);
2373     seg_id++;
2374     src_size = (int)(reader->packed_size - sizeof(uint64_t));
2375     dest_size = LZ4_decompress_safe(reader->packed_buf, buf, src_size,
2376                                     (int)reader->value_size);
2377   } else {
2378     char *packed_addr = (char *)reader->body_seg_addr;
2379     packed_addr += reader->body_seg_offset + sizeof(uint64_t);
2380     src_size = (int)(reader->packed_size - sizeof(uint64_t));
2381     dest_size = LZ4_decompress_safe(packed_addr, buf, src_size,
2382                                     (int)reader->value_size);
2383   }
2384   if ((uint32_t)dest_size != reader->value_size) {
2385     return GRN_LZ4_ERROR;
2386   }
2387   return GRN_SUCCESS;
2388 }
2389 #endif /* GRN_WITH_LZ4 */
2390 
2391 #ifdef GRN_WITH_ZSTD
2392 /* grn_ja_reader_read_zstd() reads a value compressed with Zstandard. */
2393 static grn_rc
grn_ja_reader_read_zstd(grn_ctx * ctx,grn_ja_reader * reader,void * buf)2394 grn_ja_reader_read_zstd(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
2395 {
2396   int src_size, dest_size;
2397   grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
2398   if (EHUGE_P(einfo)) {
2399     grn_io *io = reader->ja->io;
2400     void *seg_addr;
2401     char *packed_ptr;
2402     uint32_t size, seg_id;
2403     if (reader->packed_size > reader->packed_buf_size) {
2404       void *new_buf = GRN_REALLOC(reader->packed_buf, reader->packed_size);
2405       if (!new_buf) {
2406         return GRN_NO_MEMORY_AVAILABLE;
2407       }
2408       reader->packed_buf = new_buf;
2409       reader->packed_buf_size = reader->packed_size;
2410     }
2411     packed_ptr = (char *)reader->packed_buf;
2412     grn_memcpy(packed_ptr, (char *)reader->body_seg_addr + sizeof(uint64_t),
2413                io->header->segment_size - sizeof(uint64_t));
2414     packed_ptr += io->header->segment_size - sizeof(uint64_t);
2415     size = reader->packed_size - (io->header->segment_size - sizeof(uint64_t));
2416     seg_id = reader->body_seg_id + 1;
2417     while (size > io->header->segment_size) {
2418       GRN_IO_SEG_REF(io, seg_id, seg_addr);
2419       if (!seg_addr) {
2420         return GRN_UNKNOWN_ERROR;
2421       }
2422       grn_memcpy(packed_ptr, seg_addr, io->header->segment_size);
2423       GRN_IO_SEG_UNREF(io, seg_id);
2424       seg_id++;
2425       size -= io->header->segment_size;
2426       packed_ptr += io->header->segment_size;
2427     }
2428     GRN_IO_SEG_REF(io, seg_id, seg_addr);
2429     if (!seg_addr) {
2430       return GRN_UNKNOWN_ERROR;
2431     }
2432     grn_memcpy(packed_ptr, seg_addr, size);
2433     GRN_IO_SEG_UNREF(io, seg_id);
2434     seg_id++;
2435     src_size = (int)(reader->packed_size - sizeof(uint64_t));
2436     dest_size = ZSTD_decompress(reader->packed_buf, reader->value_size,
2437                                 buf, src_size);
2438   } else {
2439     char *packed_addr = (char *)reader->body_seg_addr;
2440     packed_addr += reader->body_seg_offset + sizeof(uint64_t);
2441     src_size = (int)(reader->packed_size - sizeof(uint64_t));
2442     dest_size = ZSTD_decompress(packed_addr, reader->value_size,
2443                                 buf, src_size);
2444   }
2445   if ((uint32_t)dest_size != reader->value_size) {
2446     return GRN_ZSTD_ERROR;
2447   }
2448   return GRN_SUCCESS;
2449 }
2450 #endif /* GRN_WITH_ZSTD */
2451 
2452 /* grn_ja_reader_read_raw() reads a value. */
2453 static grn_rc
grn_ja_reader_read_raw(grn_ctx * ctx,grn_ja_reader * reader,void * buf)2454 grn_ja_reader_read_raw(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
2455 {
2456   grn_io *io = reader->ja->io;
2457   grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
2458   if (ETINY_P(einfo)) {
2459     grn_memcpy(buf, einfo, reader->value_size);
2460   } else if (EHUGE_P(einfo)) {
2461     char *buf_ptr = (char *)buf;
2462     void *seg_addr;
2463     uint32_t seg_id = reader->body_seg_id;
2464     uint32_t size = reader->value_size;
2465     while (size > io->header->segment_size) {
2466       GRN_IO_SEG_REF(io, seg_id, seg_addr);
2467       if (!seg_addr) {
2468         return GRN_UNKNOWN_ERROR;
2469       }
2470       grn_memcpy(buf_ptr, seg_addr, io->header->segment_size);
2471       GRN_IO_SEG_UNREF(io, seg_id);
2472       seg_id++;
2473       size -= io->header->segment_size;
2474       buf_ptr += io->header->segment_size;
2475     }
2476     GRN_IO_SEG_REF(io, seg_id, seg_addr);
2477     if (!seg_addr) {
2478       return GRN_UNKNOWN_ERROR;
2479     }
2480     grn_memcpy(buf_ptr, seg_addr, size);
2481     GRN_IO_SEG_UNREF(io, seg_id);
2482     seg_id++;
2483   } else {
2484     if (!reader->body_seg_addr) {
2485       GRN_IO_SEG_REF(io, reader->body_seg_id, reader->body_seg_addr);
2486       if (!reader->body_seg_addr) {
2487         return GRN_UNKNOWN_ERROR;
2488       }
2489     }
2490     grn_memcpy(buf, (char *)reader->body_seg_addr + reader->body_seg_offset,
2491                reader->value_size);
2492   }
2493   return GRN_SUCCESS;
2494 }
2495 
2496 grn_rc
grn_ja_reader_read(grn_ctx * ctx,grn_ja_reader * reader,void * buf)2497 grn_ja_reader_read(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
2498 {
2499   switch (reader->ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
2500 #ifdef GRN_WITH_ZLIB
2501   case GRN_OBJ_COMPRESS_ZLIB :
2502     return grn_ja_reader_read_zlib(ctx, reader, buf);
2503 #endif /* GRN_WITH_ZLIB */
2504 #ifdef GRN_WITH_LZ4
2505   case GRN_OBJ_COMPRESS_LZ4 :
2506     return grn_ja_reader_read_lz4(ctx, reader, buf);
2507 #endif /* GRN_WITH_LZ4 */
2508 #ifdef GRN_WITH_ZSTD
2509   case GRN_OBJ_COMPRESS_ZSTD :
2510     return grn_ja_reader_read_zstd(ctx, reader, buf);
2511 #endif /* GRN_WITH_ZSTD */
2512   default :
2513     return grn_ja_reader_read_raw(ctx, reader, buf);
2514   }
2515 }
2516 
2517 #ifdef GRN_WITH_ZLIB
2518 /* grn_ja_reader_pread_zlib() reads a part of a value compressed with zlib. */
2519 static grn_rc
grn_ja_reader_pread_zlib(grn_ctx * ctx,grn_ja_reader * reader,size_t offset,size_t size,void * buf)2520 grn_ja_reader_pread_zlib(grn_ctx *ctx, grn_ja_reader *reader,
2521                          size_t offset, size_t size, void *buf)
2522 {
2523   /* TODO: To be supported? */
2524   return GRN_FUNCTION_NOT_IMPLEMENTED;
2525 }
2526 #endif /* GRN_WITH_ZLIB */
2527 
2528 #ifdef GRN_WITH_LZ4
2529 /* grn_ja_reader_pread_lz4() reads a part of a value compressed with LZ4. */
2530 static grn_rc
grn_ja_reader_pread_lz4(grn_ctx * ctx,grn_ja_reader * reader,size_t offset,size_t size,void * buf)2531 grn_ja_reader_pread_lz4(grn_ctx *ctx, grn_ja_reader *reader,
2532                         size_t offset, size_t size, void *buf)
2533 {
2534   /* TODO: To be supported? */
2535   return GRN_FUNCTION_NOT_IMPLEMENTED;
2536 }
2537 #endif /* GRN_WITH_LZ4 */
2538 
2539 #ifdef GRN_WITH_ZSTD
2540 /* grn_ja_reader_pread_zstd() reads a part of a value compressed with ZSTD. */
2541 static grn_rc
grn_ja_reader_pread_zstd(grn_ctx * ctx,grn_ja_reader * reader,size_t offset,size_t size,void * buf)2542 grn_ja_reader_pread_zstd(grn_ctx *ctx, grn_ja_reader *reader,
2543                          size_t offset, size_t size, void *buf)
2544 {
2545   /* TODO: To be supported? */
2546   return GRN_FUNCTION_NOT_IMPLEMENTED;
2547 }
2548 #endif /* GRN_WITH_ZSTD */
2549 
2550 /* grn_ja_reader_pread_raw() reads a part of a value. */
2551 static grn_rc
grn_ja_reader_pread_raw(grn_ctx * ctx,grn_ja_reader * reader,size_t offset,size_t size,void * buf)2552 grn_ja_reader_pread_raw(grn_ctx *ctx, grn_ja_reader *reader,
2553                         size_t offset, size_t size, void *buf)
2554 {
2555   grn_io *io = reader->ja->io;
2556   grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
2557   if ((offset >= reader->value_size) || !size) {
2558     return GRN_SUCCESS;
2559   }
2560   if (size > (reader->value_size - offset)) {
2561     size = reader->value_size - offset;
2562   }
2563   if (ETINY_P(einfo)) {
2564     grn_memcpy(buf, (char *)einfo + offset, size);
2565   } else if (EHUGE_P(einfo)) {
2566     char *buf_ptr = (char *)buf;
2567     void *seg_addr;
2568     uint32_t seg_id = reader->body_seg_id;
2569     if (offset >= io->header->segment_size) {
2570       seg_id += offset / io->header->segment_size;
2571       offset %= io->header->segment_size;
2572     }
2573     GRN_IO_SEG_REF(io, seg_id, seg_addr);
2574     if (!seg_addr) {
2575       return GRN_UNKNOWN_ERROR;
2576     }
2577     grn_memcpy(buf_ptr, (char *)seg_addr + offset,
2578                io->header->segment_size - offset);
2579     GRN_IO_SEG_UNREF(io, seg_id);
2580     seg_id++;
2581     size -= io->header->segment_size - offset;
2582     buf_ptr += io->header->segment_size - offset;
2583     while (size > io->header->segment_size) {
2584       GRN_IO_SEG_REF(io, seg_id, seg_addr);
2585       if (!seg_addr) {
2586         return GRN_UNKNOWN_ERROR;
2587       }
2588       grn_memcpy(buf_ptr, (char *)seg_addr, io->header->segment_size);
2589       GRN_IO_SEG_UNREF(io, seg_id);
2590       seg_id++;
2591       size -= io->header->segment_size;
2592       buf_ptr += io->header->segment_size;
2593     }
2594     GRN_IO_SEG_REF(io, seg_id, seg_addr);
2595     if (!seg_addr) {
2596       return GRN_UNKNOWN_ERROR;
2597     }
2598     grn_memcpy(buf_ptr, seg_addr, size);
2599     GRN_IO_SEG_UNREF(io, seg_id);
2600   } else {
2601     if (!reader->body_seg_addr) {
2602       GRN_IO_SEG_REF(io, reader->body_seg_id, reader->body_seg_addr);
2603       if (!reader->body_seg_addr) {
2604         return GRN_UNKNOWN_ERROR;
2605       }
2606     }
2607     offset += reader->body_seg_offset;
2608     grn_memcpy(buf, (char *)reader->body_seg_addr + offset, size);
2609   }
2610   return GRN_SUCCESS;
2611 }
2612 
2613 grn_rc
grn_ja_reader_pread(grn_ctx * ctx,grn_ja_reader * reader,size_t offset,size_t size,void * buf)2614 grn_ja_reader_pread(grn_ctx *ctx, grn_ja_reader *reader,
2615                     size_t offset, size_t size, void *buf)
2616 {
2617   switch (reader->ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
2618 #ifdef GRN_WITH_ZLIB
2619   case GRN_OBJ_COMPRESS_ZLIB :
2620     return grn_ja_reader_pread_zlib(ctx, reader, offset, size, buf);
2621 #endif /* GRN_WITH_ZLIB */
2622 #ifdef GRN_WITH_LZ4
2623   case GRN_OBJ_COMPRESS_LZ4 :
2624     return grn_ja_reader_pread_lz4(ctx, reader, offset, size, buf);
2625 #endif /* GRN_WITH_LZ4 */
2626 #ifdef GRN_WITH_ZSTD
2627   case GRN_OBJ_COMPRESS_ZSTD :
2628     return grn_ja_reader_pread_zstd(ctx, reader, offset, size, buf);
2629 #endif /* GRN_WITH_ZSTD */
2630   default :
2631     return grn_ja_reader_pread_raw(ctx, reader, offset, size, buf);
2632   }
2633 }
2634 
2635 /**** vgram ****/
2636 
2637 /*
2638 
2639 static int len_sum = 0;
2640 static int img_sum = 0;
2641 static int simple_sum = 0;
2642 static int skip_sum = 0;
2643 
2644 grn_vgram *
2645 grn_vgram_create(const char *path)
2646 {
2647   grn_vgram *s;
2648   if (!(s = GRN_MALLOCN(grn_vgram, 1))) { return NULL; }
2649   s->vgram = grn_sym_create(path, sizeof(grn_id) * 2, 0, GRN_ENC_NONE);
2650   if (!s->vgram) {
2651     GRN_FREE(s);
2652     return NULL;
2653   }
2654   return s;
2655 }
2656 
2657 grn_vgram *
2658 grn_vgram_open(const char *path)
2659 {
2660   grn_vgram *s;
2661   if (!(s = GRN_MALLOCN(grn_vgram, 1))) { return NULL; }
2662   s->vgram = grn_sym_open(path);
2663   if (!s->vgram) {
2664     GRN_FREE(s);
2665     return NULL;
2666   }
2667   return s;
2668 }
2669 
2670 grn_vgram_buf *
2671 grn_vgram_buf_open(size_t len)
2672 {
2673   grn_vgram_buf *b;
2674   if (!(b = GRN_MALLOCN(grn_vgram_buf, 1))) { return NULL; }
2675   b->len = len;
2676   b->tvs = b->tvp = GRN_MALLOCN(grn_id, len);
2677   if (!b->tvp) { GRN_FREE(b); return NULL; }
2678   b->tve = b->tvs + len;
2679   b->vps = b->vpp = GRN_MALLOCN(grn_vgram_vnode, len * 2);
2680   if (!b->vpp) { GRN_FREE(b->tvp); GRN_FREE(b); return NULL; }
2681   b->vpe = b->vps + len;
2682   return b;
2683 }
2684 
2685 grn_rc
2686 grn_vgram_buf_add(grn_vgram_buf *b, grn_id tid)
2687 {
2688   uint8_t dummybuf[8], *dummyp;
2689   if (b->tvp < b->tve) { *b->tvp++ = tid; }
2690   dummyp = dummybuf;
2691   GRN_B_ENC(tid, dummyp);
2692   simple_sum += dummyp - dummybuf;
2693   return GRN_SUCCESS;
2694 }
2695 
2696 typedef struct {
2697   grn_id vid;
2698   grn_id tid;
2699 } vgram_key;
2700 
2701 grn_rc
2702 grn_vgram_update(grn_vgram *vgram, grn_id rid, grn_vgram_buf *b, grn_hash *terms)
2703 {
2704   grn_inv_updspec **u;
2705   if (b && b->tvs < b->tvp) {
2706     grn_id *t0, *tn;
2707     for (t0 = b->tvs; t0 < b->tvp - 1; t0++) {
2708       grn_vgram_vnode *v, **vp;
2709       if (grn_set_at(terms, t0, (void **) &u)) {
2710         vp = &(*u)->vnodes;
2711         for (tn = t0 + 1; tn < b->tvp; tn++) {
2712           for (v = *vp; v && v->tid != *tn; v = v->cdr) ;
2713           if (!v) {
2714             if (b->vpp < b->vpe) {
2715               v = b->vpp++;
2716             } else {
2717               // todo;
2718               break;
2719             }
2720             v->car = NULL;
2721             v->cdr = *vp;
2722             *vp = v;
2723             v->tid = *tn;
2724             v->vid = 0;
2725             v->freq = 0;
2726             v->len = tn - t0;
2727           }
2728           v->freq++;
2729           if (v->vid) {
2730             vp = &v->car;
2731           } else {
2732             break;
2733           }
2734         }
2735       }
2736     }
2737     {
2738       grn_set *th = grn_set_open(sizeof(grn_id), sizeof(int), 0);
2739       if (!th) { return GRN_NO_MEMORY_AVAILABLE; }
2740       if (t0 == b->tvp) { GRN_LOG(ctx, GRN_LOG_DEBUG, "t0 == tvp"); }
2741       for (t0 = b->tvs; t0 < b->tvp; t0++) {
2742         grn_id vid, vid0 = *t0, vid1 = 0;
2743         grn_vgram_vnode *v, *v2 = NULL, **vp;
2744         if (grn_set_at(terms, t0, (void **) &u)) {
2745           vp = &(*u)->vnodes;
2746           for (tn = t0 + 1; tn < b->tvp; tn++) {
2747             for (v = *vp; v; v = v->cdr) {
2748               if (!v->vid && (v->freq < 2 || v->freq * v->len < 4)) {
2749                 *vp = v->cdr;
2750                 v->freq = 0;
2751               }
2752               if (v->tid == *tn) { break; }
2753               vp = &v->cdr;
2754             }
2755             if (v) {
2756               if (v->freq) {
2757                 v2 = v;
2758                 vid1 = vid0;
2759                 vid0 = v->vid;
2760               }
2761               if (v->vid) {
2762                 vp = &v->car;
2763                 continue;
2764               }
2765             }
2766             break;
2767           }
2768         }
2769         if (v2) {
2770           if (!v2->vid) {
2771             vgram_key key;
2772             key.vid = vid1;
2773             key.tid = v2->tid;
2774             if (!(v2->vid = grn_sym_get(vgram->vgram, (char *)&key))) {
2775               grn_set_close(th);
2776               return GRN_NO_MEMORY_AVAILABLE;
2777             }
2778           }
2779           vid = *t0 = v2->vid * 2 + 1;
2780           memset(t0 + 1, 0, sizeof(grn_id) * v2->len);
2781           t0 += v2->len;
2782         } else {
2783           vid = *t0 *= 2;
2784         }
2785         {
2786           int *tf;
2787           if (!grn_set_get(th, &vid, (void **) &tf)) {
2788             grn_set_close(th);
2789             return GRN_NO_MEMORY_AVAILABLE;
2790           }
2791           (*tf)++;
2792         }
2793       }
2794       if (!th->n_entries) { GRN_LOG(ctx, GRN_LOG_DEBUG, "th->n_entries == 0"); }
2795       {
2796         int j = 0;
2797         int skip = 0;
2798         grn_set_eh *ehs, *ehp, *ehe;
2799         grn_set_sort_optarg arg;
2800         uint8_t *ps = GRN_MALLOC(b->len * 2), *pp, *pe;
2801         if (!ps) {
2802           grn_set_close(th);
2803           return GRN_NO_MEMORY_AVAILABLE;
2804         }
2805         pp = ps;
2806         pe = ps + b->len * 2;
2807         arg.mode = grn_sort_descending;
2808         arg.compar = NULL;
2809         arg.compar_arg = (void *)(intptr_t)sizeof(grn_id);
2810         ehs = grn_set_sort(th, 0, &arg);
2811         if (!ehs) {
2812           GRN_FREE(ps);
2813           grn_set_close(th);
2814           return GRN_NO_MEMORY_AVAILABLE;
2815         }
2816         GRN_B_ENC(th->n_entries, pp);
2817         for (ehp = ehs, ehe = ehs + th->n_entries; ehp < ehe; ehp++, j++) {
2818           int *id = (int *)GRN_SET_INTVAL(*ehp);
2819           GRN_B_ENC(*GRN_SET_INTKEY(*ehp), pp);
2820           *id = j;
2821         }
2822         for (t0 = b->tvs; t0 < b->tvp; t0++) {
2823           if (*t0) {
2824             int *id;
2825             if (!grn_set_at(th, t0, (void **) &id)) {
2826               GRN_LOG(ctx, GRN_LOG_ERROR, "lookup error (%d)", *t0);
2827             }
2828             GRN_B_ENC(*id, pp);
2829           } else {
2830             skip++;
2831           }
2832         }
2833         len_sum += b->len;
2834         img_sum += pp - ps;
2835         skip_sum += skip;
2836         GRN_FREE(ehs);
2837         GRN_FREE(ps);
2838       }
2839       grn_set_close(th);
2840     }
2841   }
2842   return GRN_SUCCESS;
2843 }
2844 
2845 grn_rc
2846 grn_vgram_buf_close(grn_vgram_buf *b)
2847 {
2848   if (!b) { return GRN_INVALID_ARGUMENT; }
2849   if (b->tvs) { GRN_FREE(b->tvs); }
2850   if (b->vps) { GRN_FREE(b->vps); }
2851   GRN_FREE(b);
2852   return GRN_SUCCESS;
2853 }
2854 
2855 grn_rc
2856 grn_vgram_close(grn_vgram *vgram)
2857 {
2858   if (!vgram) { return GRN_INVALID_ARGUMENT; }
2859   GRN_LOG(ctx, GRN_LOG_DEBUG, "len=%d img=%d skip=%d simple=%d", len_sum, img_sum, skip_sum, simple_sum);
2860   grn_sym_close(vgram->vgram);
2861   GRN_FREE(vgram);
2862   return GRN_SUCCESS;
2863 }
2864 */
2865