Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
hash.c
Go to the documentation of this file.
1 /* -*- c-basic-offset: 2 -*- */
2 /*
3  Copyright(C) 2009-2012 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-1301 USA
17 */
18 #include "hash.h"
19 #include "output.h"
20 #include <string.h>
21 #include <limits.h>
22 
23 #include "store.h"
24 #include "normalizer_in.h"
25 
26 /* grn_tiny_array */
27 
28 /* Requirements: id != GRN_ID_NIL. */
29 inline static int
30 grn_tiny_array_get_block_id(grn_id id)
31 {
32  int most_significant_one_bit_offset;
33  GRN_BIT_SCAN_REV(id, most_significant_one_bit_offset);
34  return most_significant_one_bit_offset >> GRN_TINY_ARRAY_FACTOR;
35 }
36 
37 /* Requirements: id != GRN_ID_NIL. */
38 inline static void *
39 grn_tiny_array_get(grn_tiny_array *array, grn_id id) {
40  const int block_id = grn_tiny_array_get_block_id(id);
41  uint8_t * const block = (uint8_t *)array->blocks[block_id];
42  if (block) {
43  const size_t offset = GRN_TINY_ARRAY_GET_OFFSET(block_id);
44  return block + (id - offset) * array->element_size;
45  }
46  return NULL;
47 }
48 
49 /* Requirements: id != GRN_ID_NIL. */
50 inline static void *
51 grn_tiny_array_put(grn_tiny_array *array, grn_id id) {
52  const int block_id = grn_tiny_array_get_block_id(id);
53  void ** const block = &array->blocks[block_id];
54  const size_t offset = GRN_TINY_ARRAY_GET_OFFSET(block_id);
55  if (!*block) {
56  grn_ctx * const ctx = array->ctx;
57  if (array->flags & GRN_TINY_ARRAY_THREADSAFE) {
58  CRITICAL_SECTION_ENTER(array->lock);
59  }
60  if (!*block) {
61  const size_t block_size =
63  if (array->flags & GRN_TINY_ARRAY_USE_MALLOC) {
64  if (array->flags & GRN_TINY_ARRAY_CLEAR) {
65  *block = GRN_CALLOC(block_size);
66  } else {
67  *block = GRN_MALLOC(block_size);
68  }
69  } else {
70  *block = GRN_CTX_ALLOC(ctx, block_size);
71  }
72  }
73  if (array->flags & GRN_TINY_ARRAY_THREADSAFE) {
74  CRITICAL_SECTION_LEAVE(array->lock);
75  }
76  if (!*block) {
77  return NULL;
78  }
79  }
80  if (id > array->max) {
81  array->max = id;
82  }
83  return (uint8_t *)*block + (id - offset) * array->element_size;
84 }
85 
86 inline static void *
87 grn_tiny_array_at_inline(grn_tiny_array *array, grn_id id)
88 {
89  return id ? grn_tiny_array_put(array, id) : NULL;
90 }
91 
92 inline static void *
93 grn_tiny_array_next(grn_tiny_array *array)
94 {
95  return grn_tiny_array_put(array, array->max + 1);
96 }
97 
98 void
100  uint16_t element_size, uint16_t flags)
101 {
102  array->ctx = ctx;
103  array->max = 0;
104  array->element_size = element_size;
105  array->flags = flags;
106  memset(array->blocks, 0, sizeof(array->blocks));
107  if (flags & GRN_TINY_ARRAY_THREADSAFE) {
108  CRITICAL_SECTION_INIT(array->lock);
109  }
110 }
111 
112 void
114 {
115  int block_id;
116  grn_ctx * const ctx = array->ctx;
117  for (block_id = 0; block_id < GRN_TINY_ARRAY_NUM_BLOCKS; block_id++) {
118  if (array->blocks[block_id]) {
119  if (array->flags & GRN_TINY_ARRAY_USE_MALLOC) {
120  GRN_FREE(array->blocks[block_id]);
121  } else {
122  GRN_CTX_FREE(ctx, array->blocks[block_id]);
123  }
124  array->blocks[block_id] = NULL;
125  }
126  }
127 }
128 
129 void *
131 {
132  return grn_tiny_array_at_inline(array, id);
133 }
134 
135 grn_id
136 grn_tiny_array_id(grn_tiny_array *array, const void *element_address)
137 {
138  const uint8_t * const ptr = (const uint8_t *)element_address;
139  uint32_t block_id, offset = 1;
140  for (block_id = 0; block_id < GRN_TINY_ARRAY_NUM_BLOCKS; block_id++) {
141  const uint32_t block_size = GRN_TINY_ARRAY_GET_BLOCK_SIZE(block_id);
142  const uint8_t * const block = (const uint8_t *)array->blocks[block_id];
143  if (block) {
144  if (block <= ptr && ptr < (block + block_size * array->element_size)) {
145  return offset + ((ptr - block) / array->element_size);
146  }
147  }
148  offset += block_size;
149  }
150  return GRN_ID_NIL;
151 }
152 
153 /* grn_tiny_bitmap */
154 
155 static void
156 grn_tiny_bitmap_init(grn_ctx *ctx, grn_tiny_bitmap *bitmap)
157 {
158  bitmap->ctx = ctx;
159  memset(bitmap->blocks, 0, sizeof(bitmap->blocks));
160 }
161 
162 static void
163 grn_tiny_bitmap_fin(grn_tiny_bitmap *bitmap)
164 {
165  int block_id;
166  grn_ctx * const ctx = bitmap->ctx;
167  for (block_id = 0; block_id < GRN_TINY_ARRAY_NUM_BLOCKS; block_id++) {
168  if (bitmap->blocks[block_id]) {
169  GRN_CTX_FREE(ctx, bitmap->blocks[block_id]);
170  bitmap->blocks[block_id] = NULL;
171  }
172  }
173 }
174 
175 /* Requirements: bit_id != GRN_ID_NIL. */
176 inline static uint8_t *
177 grn_tiny_bitmap_get_byte(grn_tiny_bitmap *bitmap, grn_id bit_id) {
178  const uint32_t byte_id = (bit_id >> 3) + 1;
179  const int block_id = grn_tiny_array_get_block_id(byte_id);
180  uint8_t * const block = (uint8_t *)bitmap->blocks[block_id];
181  if (block) {
182  const size_t offset = GRN_TINY_ARRAY_GET_OFFSET(block_id);
183  return block + byte_id - offset;
184  }
185  return NULL;
186 }
187 
188 /* Requirements: bit_id != GRN_ID_NIL. */
189 inline static uint8_t *
190 grn_tiny_bitmap_put_byte(grn_tiny_bitmap *bitmap, grn_id bit_id) {
191  const uint32_t byte_id = (bit_id >> 3) + 1;
192  const int block_id = grn_tiny_array_get_block_id(byte_id);
193  void ** const block = &bitmap->blocks[block_id];
194  const size_t offset = GRN_TINY_ARRAY_GET_OFFSET(block_id);
195  if (!*block) {
196  grn_ctx * const ctx = bitmap->ctx;
197  *block = GRN_CTX_ALLOC(ctx, GRN_TINY_ARRAY_GET_BLOCK_SIZE(block_id));
198  if (!*block) {
199  return NULL;
200  }
201  }
202  return (uint8_t *)*block + byte_id - offset;
203 }
204 
205 /* Requirements: bit_id != GRN_ID_NIL. */
206 /* Return value: 1/0 on success, -1 on failure. */
207 inline static int
208 grn_tiny_bitmap_get(grn_tiny_bitmap *bitmap, grn_id bit_id)
209 {
210  uint8_t * const ptr = grn_tiny_bitmap_get_byte(bitmap, bit_id);
211  return ptr ? ((*ptr >> (bit_id & 7)) & 1) : -1;
212 }
213 
214 /* Requirements: bit_id != GRN_ID_NIL. */
215 /* Return value: 1/0 on success, -1 on failure. */
216 /* Note: A bitmap is extended if needed. */
217 inline static int
218 grn_tiny_bitmap_put(grn_tiny_bitmap *bitmap, grn_id bit_id)
219 {
220  uint8_t * const ptr = grn_tiny_bitmap_put_byte(bitmap, bit_id);
221  return ptr ? ((*ptr >> (bit_id & 7)) & 1) : -1;
222 }
223 
224 /* Requirements: bit_id != GRN_ID_NIL. */
225 inline static uint8_t *
226 grn_tiny_bitmap_get_and_set(grn_tiny_bitmap *bitmap, grn_id bit_id,
227  grn_bool bit)
228 {
229  uint8_t * const ptr = grn_tiny_bitmap_get_byte(bitmap, bit_id);
230  if (ptr) {
231  /* This branch will be removed because the given `bit' is constant. */
232  if (bit) {
233  *ptr |= 1 << (bit_id & 7);
234  } else {
235  *ptr &= ~(1 << (bit_id & 7));
236  }
237  }
238  return ptr;
239 }
240 
241 /* Requirements: bit_id != GRN_ID_NIL. */
242 /* Note: A bitmap is extended if needed. */
243 inline static uint8_t *
244 grn_tiny_bitmap_put_and_set(grn_tiny_bitmap *bitmap, grn_id bit_id,
245  grn_bool bit)
246 {
247  uint8_t * const ptr = grn_tiny_bitmap_put_byte(bitmap, bit_id);
248  if (ptr) {
249  /* This branch will be removed because the given `bit' is constant. */
250  if (bit) {
251  *ptr |= 1 << (bit_id & 7);
252  } else {
253  *ptr &= ~(1 << (bit_id & 7));
254  }
255  }
256  return ptr;
257 }
258 
259 /* grn_io_array */
260 
261 #define GRN_ARRAY_MAX (GRN_ID_MAX - 8)
262 
263 inline static void *
264 grn_io_array_at_inline(grn_ctx *ctx, grn_io *io, uint32_t segment_id,
265  uint32_t offset, int flags)
266 {
267  void *ptr;
268  GRN_IO_ARRAY_AT(io, segment_id, offset, &flags, ptr);
269  return ptr;
270 }
271 
272 /*
273  * grn_io_array_bit_at() returns 1/0 on success, -1 on failure.
274  */
275 inline static int
276 grn_io_array_bit_at(grn_ctx *ctx, grn_io *io,
277  uint32_t segment_id, uint32_t offset)
278 {
279  uint8_t * const ptr = (uint8_t *)grn_io_array_at_inline(
280  ctx, io, segment_id, (offset >> 3) + 1, 0);
281  return ptr ? ((*ptr >> (offset & 7)) & 1) : -1;
282 }
283 
284 /*
285  * The following functions, grn_io_array_bit_*(), return a non-NULL pointer on
286  * success, a NULL pointer on failure.
287  */
288 inline static void *
289 grn_io_array_bit_on(grn_ctx *ctx, grn_io *io,
290  uint32_t segment_id, uint32_t offset)
291 {
292  uint8_t * const ptr = (uint8_t *)grn_io_array_at_inline(
293  ctx, io, segment_id, (offset >> 3) + 1, GRN_TABLE_ADD);
294  if (ptr) {
295  *ptr |= 1 << (offset & 7);
296  }
297  return ptr;
298 }
299 
300 inline static void *
301 grn_io_array_bit_off(grn_ctx *ctx, grn_io *io,
302  uint32_t segment_id, uint32_t offset)
303 {
304  uint8_t * const ptr = (uint8_t *)grn_io_array_at_inline(
305  ctx, io, segment_id, (offset >> 3) + 1, GRN_TABLE_ADD);
306  if (ptr) {
307  *ptr &= ~(1 << (offset & 7));
308  }
309  return ptr;
310 }
311 
312 inline static void *
313 grn_io_array_bit_flip(grn_ctx *ctx, grn_io *io,
314  uint32_t segment_id, uint32_t offset)
315 {
316  uint8_t * const ptr = (uint8_t *)grn_io_array_at_inline(
317  ctx, io, segment_id, (offset >> 3) + 1, GRN_TABLE_ADD);
318  if (ptr) {
319  *ptr ^= 1 << (offset & 7);
320  }
321  return ptr;
322 }
323 
324 /* grn_table_queue */
325 
326 static void
327 grn_table_queue_lock_init(grn_ctx *ctx, grn_table_queue *queue)
328 {
329  MUTEX_INIT_SHARED(queue->mutex);
330  COND_INIT_SHARED(queue->cond);
331 }
332 
333 static void
334 grn_table_queue_init(grn_ctx *ctx, grn_table_queue *queue)
335 {
336  queue->head = 0;
337  queue->tail = 0;
338  queue->cap = GRN_ARRAY_MAX;
339  queue->unblock_requested = GRN_FALSE;
340  grn_table_queue_lock_init(ctx, queue);
341 }
342 
343 uint32_t
345 {
346  return (queue->head < queue->tail)
347  ? 2 * queue->cap + queue->head - queue->tail
348  : queue->head - queue->tail;
349 }
350 
351 void
353 {
354  if (queue->head == 2 * queue->cap) {
355  queue->head = 1;
356  } else {
357  queue->head++;
358  }
359 }
360 
361 void
363 {
364  if (queue->tail == 2 * queue->cap) {
365  queue->tail = 1;
366  } else {
367  queue->tail++;
368  }
369 }
370 
371 grn_id
373 {
374  return queue->head > queue->cap
375  ? queue->head - queue->cap
376  : queue->head;
377 }
378 
379 grn_id
381 {
382  return queue->tail > queue->cap
383  ? queue->tail - queue->cap
384  : queue->tail;
385 }
386 
387 /* grn_array */
388 
389 #define GRN_ARRAY_SEGMENT_SIZE 0x400000
390 
391 /* Header of grn_io-based grn_array. */
393  uint32_t flags;
394  uint32_t curr_rec;
395  uint32_t value_size;
396  uint32_t n_entries;
397  uint32_t n_garbages;
399  uint32_t lock;
400  uint32_t reserved[9];
402 };
403 
404 /*
405  * A grn_io-based grn_array consists of the following 2 segments.
406  * GRN_ARRAY_VALUE_SEGMENT: stores values.
407  * GRN_ARRAY_BITMAP_SEGMENT: stores whether entries are valid or not.
408  */
409 enum {
412 };
413 
414 inline static grn_bool
415 grn_array_is_io_array(grn_array *array)
416 {
417  return array->io != NULL;
418 }
419 
420 inline static void *
421 grn_array_io_entry_at(grn_ctx *ctx, grn_array *array, grn_id id, int flags)
422 {
423  return grn_io_array_at_inline(ctx, array->io, GRN_ARRAY_VALUE_SEGMENT, id, flags);
424 }
425 
426 inline static void *
427 grn_array_entry_at(grn_ctx *ctx, grn_array *array, grn_id id, int flags)
428 {
429  if (grn_array_is_io_array(array)) {
430  return grn_array_io_entry_at(ctx, array, id, flags);
431  } else {
432  return grn_tiny_array_at_inline(&array->array, id);
433  }
434 }
435 
436 /* grn_array_bitmap_at() returns 1/0 on success, -1 on failure. */
437 inline static int
438 grn_array_bitmap_at(grn_ctx *ctx, grn_array *array, grn_id id)
439 {
440  if (grn_array_is_io_array(array)) {
441  return grn_io_array_bit_at(ctx, array->io, GRN_ARRAY_BITMAP_SEGMENT, id);
442  } else {
443  return grn_tiny_bitmap_put(&array->bitmap, id);
444  }
445 }
446 
447 static grn_rc
448 grn_array_init_tiny_array(grn_ctx *ctx, grn_array *array, const char *path,
449  uint32_t value_size, uint32_t flags)
450 {
451  if (path) {
452  ERR(GRN_INVALID_ARGUMENT, "failed to create tiny array");
453  return ctx->rc;
454  }
455  array->obj.header.flags = flags;
456  array->ctx = ctx;
457  array->value_size = value_size;
458  array->n_keys = 0;
459  array->keys = NULL;
460  array->n_garbages = &array->n_garbages_buf;
461  array->n_entries = &array->n_entries_buf;
462  array->n_garbages_buf = 0;
463  array->n_entries_buf = 0;
464  array->io = NULL;
465  array->garbages = GRN_ID_NIL;
466  grn_tiny_array_init(ctx, &array->array, value_size, GRN_TINY_ARRAY_CLEAR);
467  grn_tiny_bitmap_init(ctx, &array->bitmap);
468  return GRN_SUCCESS;
469 }
470 
471 static grn_io *
472 grn_array_create_io_array(grn_ctx *ctx, const char *path, uint32_t value_size)
473 {
474  uint32_t w_of_element = 0;
475  grn_io_array_spec array_spec[2];
476 
477  while ((1U << w_of_element) < value_size) {
478  w_of_element++;
479  }
480 
481  array_spec[GRN_ARRAY_VALUE_SEGMENT].w_of_element = w_of_element;
483  1U << (30 - (22 - w_of_element));
484  array_spec[GRN_ARRAY_BITMAP_SEGMENT].w_of_element = 0;
485  array_spec[GRN_ARRAY_BITMAP_SEGMENT].max_n_segments = 1U << (30 - (22 + 3));
486  return grn_io_create_with_array(ctx, path, sizeof(struct grn_array_header),
488  2, array_spec);
489 }
490 
491 static grn_rc
492 grn_array_init_io_array(grn_ctx *ctx, grn_array *array, const char *path,
493  uint32_t value_size, uint32_t flags)
494 {
495  grn_io *io;
496  struct grn_array_header *header;
497 
498  io = grn_array_create_io_array(ctx, path, value_size);
499  if (!io) {
500  return ctx->rc;
501  }
503 
504  header = grn_io_header(io);
505  header->flags = flags;
506  header->curr_rec = 0;
507  header->lock = 0;
508  header->value_size = value_size;
509  header->n_entries = 0;
510  header->n_garbages = 0;
511  header->garbages = GRN_ID_NIL;
512  grn_table_queue_init(ctx, &header->queue);
513  array->obj.header.flags = flags;
514  array->ctx = ctx;
515  array->value_size = value_size;
516  array->n_keys = 0;
517  array->keys = NULL;
518  array->n_garbages = &header->n_garbages;
519  array->n_entries = &header->n_entries;
520  array->io = io;
521  array->header = header;
522  array->lock = &header->lock;
523  return GRN_SUCCESS;
524 }
525 
526 void
528 {
529  struct grn_array_header *header;
530  header = grn_io_header(array->io);
531  grn_table_queue_lock_init(ctx, &header->queue);
532 }
533 
536 {
537  if (grn_array_is_io_array(array)) {
538  struct grn_array_header *header;
539  header = grn_io_header(array->io);
540  return &header->queue;
541  } else {
542  return NULL;
543  }
544 }
545 
546 static grn_rc
547 grn_array_init(grn_ctx *ctx, grn_array *array,
548  const char *path, uint32_t value_size, uint32_t flags)
549 {
550  if (flags & GRN_ARRAY_TINY) {
551  return grn_array_init_tiny_array(ctx, array, path, value_size, flags);
552  } else {
553  return grn_array_init_io_array(ctx, array, path, value_size, flags);
554  }
555 }
556 
557 grn_array *
558 grn_array_create(grn_ctx *ctx, const char *path, uint32_t value_size, uint32_t flags)
559 {
560  if (ctx) {
561  grn_array * const array = (grn_array *)GRN_MALLOC(sizeof(grn_array));
562  if (array) {
564  if (!grn_array_init(ctx, array, path, value_size, flags)) {
565  return array;
566  }
567  GRN_FREE(array);
568  }
569  }
570  return NULL;
571 }
572 
573 grn_array *
574 grn_array_open(grn_ctx *ctx, const char *path)
575 {
576  if (ctx) {
577  grn_io * const io = grn_io_open(ctx, path, grn_io_auto);
578  if (io) {
579  struct grn_array_header * const header = grn_io_header(io);
580  if (grn_io_get_type(io) == GRN_TABLE_NO_KEY) {
581  grn_array * const array = (grn_array *)GRN_MALLOC(sizeof(grn_array));
582  if (array) {
583  if (!(header->flags & GRN_ARRAY_TINY)) {
585  array->obj.header.flags = header->flags;
586  array->ctx = ctx;
587  array->value_size = header->value_size;
588  array->n_keys = 0;
589  array->keys = NULL;
590  array->n_garbages = &header->n_garbages;
591  array->n_entries = &header->n_entries;
592  array->io = io;
593  array->header = header;
594  array->lock = &header->lock;
595  return array;
596  } else {
597  GRN_LOG(ctx, GRN_LOG_NOTICE, "invalid array flags. (%x)", header->flags);
598  }
599  GRN_FREE(array);
600  }
601  } else {
602  ERR(GRN_INVALID_FORMAT, "file type unmatch");
603  }
604  grn_io_close(ctx, io);
605  }
606  }
607  return NULL;
608 }
609 
610 grn_rc
612 {
613  grn_rc rc = GRN_SUCCESS;
614  if (!ctx || !array) { return GRN_INVALID_ARGUMENT; }
615  if (array->keys) { GRN_FREE(array->keys); }
616  if (grn_array_is_io_array(array)) {
617  rc = grn_io_close(ctx, array->io);
618  } else {
619  GRN_ASSERT(ctx == array->ctx);
620  grn_tiny_array_fin(&array->array);
621  grn_tiny_bitmap_fin(&array->bitmap);
622  }
623  GRN_FREE(array);
624  return rc;
625 }
626 
627 grn_rc
628 grn_array_remove(grn_ctx *ctx, const char *path)
629 {
630  if (!ctx || !path) { return GRN_INVALID_ARGUMENT; }
631  return grn_io_remove(ctx, path);
632 }
633 
634 grn_rc
636 {
637  grn_rc rc = GRN_SUCCESS;
638  char *path = NULL;
639  uint32_t value_size, flags;
640 
641  if (!ctx || !array) { return GRN_INVALID_ARGUMENT; }
642  if (grn_array_is_io_array(array)) {
643  const char * const io_path = grn_io_path(array->io);
644  if (io_path && *io_path) {
645  path = GRN_STRDUP(io_path);
646  if (!path) {
647  ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_path);
649  }
650  }
651  }
652  value_size = array->value_size;
653  flags = array->obj.header.flags;
654 
655  if (grn_array_is_io_array(array)) {
656  rc = grn_io_close(ctx, array->io);
657  if (!rc) {
658  array->io = NULL;
659  if (path) {
660  rc = grn_io_remove(ctx, path);
661  }
662  }
663  }
664  if (!rc) {
665  rc = grn_array_init(ctx, array, path, value_size, flags);
666  }
667  if (path) { GRN_FREE(path); }
668  return rc;
669 }
670 
671 inline static grn_id
672 grn_array_get_max_id(grn_array *array)
673 {
674  return grn_array_is_io_array(array) ? array->header->curr_rec : array->array.max;
675 }
676 
677 inline static void *
678 grn_array_get_value_inline(grn_ctx *ctx, grn_array *array, grn_id id)
679 {
680  if (!ctx || !array) {
681  return NULL;
682  }
683  if (*array->n_garbages) {
684  /*
685  * grn_array_bitmap_at() is a time-consuming function, so it is called only
686  * when there are garbages in the array.
687  */
688  if (grn_array_bitmap_at(ctx, array, id) != 1) {
689  return NULL;
690  }
691  } else if (id == 0 || id > grn_array_get_max_id(array)) {
692  return NULL;
693  }
694  return grn_array_entry_at(ctx, array, id, 0);
695 }
696 
697 int
698 grn_array_get_value(grn_ctx *ctx, grn_array *array, grn_id id, void *valuebuf)
699 {
700  void * const value = grn_array_get_value_inline(ctx, array, id);
701  if (value) {
702  if (valuebuf) {
703  memcpy(valuebuf, value, array->value_size);
704  }
705  return array->value_size;
706  }
707  return 0;
708 }
709 
710 void *
712 {
713  return grn_array_get_value_inline(ctx, array, id);
714 }
715 
716 inline static grn_rc
717 grn_array_set_value_inline(grn_ctx *ctx, grn_array *array, grn_id id,
718  const void *value, int flags)
719 {
720  void * const entry = grn_array_entry_at(ctx, array, id, 0);
721  if (!entry) {
723  }
724 
725  switch ((flags & GRN_OBJ_SET_MASK)) {
726  case GRN_OBJ_SET :
727  memcpy(entry, value, array->value_size);
728  return GRN_SUCCESS;
729  case GRN_OBJ_INCR :
730  switch (array->value_size) {
731  case sizeof(int32_t) :
732  *((int32_t *)entry) += *((int32_t *)value);
733  return GRN_SUCCESS;
734  case sizeof(int64_t) :
735  *((int64_t *)entry) += *((int64_t *)value);
736  return GRN_SUCCESS;
737  default :
738  return GRN_INVALID_ARGUMENT;
739  }
740  break;
741  case GRN_OBJ_DECR :
742  switch (array->value_size) {
743  case sizeof(int32_t) :
744  *((int32_t *)entry) -= *((int32_t *)value);
745  return GRN_SUCCESS;
746  case sizeof(int64_t) :
747  *((int64_t *)entry) -= *((int64_t *)value);
748  return GRN_SUCCESS;
749  default :
750  return GRN_INVALID_ARGUMENT;
751  }
752  break;
753  default :
754  /* todo : support other types. */
755  return GRN_INVALID_ARGUMENT;
756  }
757 }
758 
759 grn_rc
761  const void *value, int flags)
762 {
763  if (!ctx || !array || !value) {
764  return GRN_INVALID_ARGUMENT;
765  }
766  if (*array->n_garbages) {
767  /*
768  * grn_array_bitmap_at() is a time-consuming function, so it is called only
769  * when there are garbages in the array.
770  */
771  if (grn_array_bitmap_at(ctx, array, id) != 1) {
772  return GRN_INVALID_ARGUMENT;
773  }
774  } else if (id == 0 || id > grn_array_get_max_id(array)) {
775  return GRN_INVALID_ARGUMENT;
776  }
777  return grn_array_set_value_inline(ctx, array, id, value, flags);
778 }
779 
780 grn_rc
782  grn_table_delete_optarg *optarg)
783 {
784  if (!ctx || !array) {
785  return GRN_INVALID_ARGUMENT;
786  }
787  if (grn_array_bitmap_at(ctx, array, id) != 1) {
788  return GRN_INVALID_ARGUMENT;
789  }
790 
791  {
792  grn_rc rc = GRN_SUCCESS;
793  /* lock */
794  if (grn_array_is_io_array(array)) {
795  if (array->value_size >= sizeof(grn_id)) {
796  struct grn_array_header * const header = array->header;
797  void * const entry = grn_array_io_entry_at(ctx, array, id, 0);
798  if (!entry) {
800  } else {
801  *((grn_id *)entry) = header->garbages;
802  header->garbages = id;
803  }
804  }
805  if (!rc) {
806  (*array->n_entries)--;
807  (*array->n_garbages)++;
808  /*
809  * The following grn_io_array_bit_off() fails iff a problem has
810  * occurred after the above grn_array_bitmap_at(). That is to say,
811  * an unexpected case.
812  */
813  grn_io_array_bit_off(ctx, array->io, GRN_ARRAY_BITMAP_SEGMENT, id);
814  }
815  } else {
816  if (array->value_size >= sizeof(grn_id)) {
817  void * const entry = grn_tiny_array_get(&array->array, id);
818  if (!entry) {
820  } else {
821  *((grn_id *)entry) = array->garbages;
822  array->garbages = id;
823  }
824  }
825  if (!rc) {
826  (*array->n_entries)--;
827  (*array->n_garbages)++;
828  /*
829  * The following grn_io_array_bit_off() fails iff a problem has
830  * occurred after the above grn_array_bitmap_at(). That is to say,
831  * an unexpected case.
832  */
833  grn_tiny_bitmap_get_and_set(&array->bitmap, id, 0);
834  }
835  }
836  /* unlock */
837  return rc;
838  }
839 }
840 
841 grn_id
843 {
844  if (*array->n_garbages) {
845  /*
846  * grn_array_bitmap_at() is a time-consuming function, so it is called only
847  * when there are garbages in the array.
848  */
849  if (grn_array_bitmap_at(ctx, array, id) != 1) {
850  return GRN_ID_NIL;
851  }
852  } else if (id > grn_array_get_max_id(array)) {
853  return GRN_ID_NIL;
854  }
855  return id;
856 }
857 
858 grn_rc
860  grn_table_sort_key *keys, int n_keys)
861 {
863  if (!array->keys) {
864  return ctx->rc;
865  }
866  memcpy(array->keys, keys, sizeof(grn_table_sort_key) * n_keys);
867  array->n_keys = n_keys;
868  return GRN_SUCCESS;
869 }
870 
871 void
873 {
874  GRN_ASSERT(cursor->ctx == ctx);
875  GRN_FREE(cursor);
876 }
877 
880  int offset, int limit, int flags)
881 {
882  grn_array_cursor *cursor;
883  if (!array || !ctx) { return NULL; }
884 
886  if (!cursor) { return NULL; }
887 
889  cursor->array = array;
890  cursor->ctx = ctx;
891  cursor->obj.header.flags = flags;
892  cursor->obj.header.domain = GRN_ID_NIL;
893 
894  if (flags & GRN_CURSOR_DESCENDING) {
895  cursor->dir = -1;
896  if (max) {
897  cursor->curr_rec = max;
898  if (!(flags & GRN_CURSOR_LT)) { cursor->curr_rec++; }
899  } else {
900  cursor->curr_rec = grn_array_get_max_id(array) + 1;
901  }
902  if (min) {
903  cursor->tail = min;
904  if ((flags & GRN_CURSOR_GT)) { cursor->tail++; }
905  } else {
906  cursor->tail = GRN_ID_NIL + 1;
907  }
908  if (cursor->curr_rec < cursor->tail) { cursor->tail = cursor->curr_rec; }
909  } else {
910  cursor->dir = 1;
911  if (min) {
912  cursor->curr_rec = min;
913  if (!(flags & GRN_CURSOR_GT)) { cursor->curr_rec--; }
914  } else {
915  cursor->curr_rec = GRN_ID_NIL;
916  }
917  if (max) {
918  cursor->tail = max;
919  if ((flags & GRN_CURSOR_LT)) { cursor->tail--; }
920  } else {
921  cursor->tail = grn_array_get_max_id(array);
922  }
923  if (cursor->tail < cursor->curr_rec) { cursor->tail = cursor->curr_rec; }
924  }
925 
926  if (*array->n_garbages) {
927  while (offset && cursor->curr_rec != cursor->tail) {
928  cursor->curr_rec += cursor->dir;
929  if (grn_array_bitmap_at(ctx, cursor->array, cursor->curr_rec) == 1) {
930  offset--;
931  }
932  }
933  } else {
934  cursor->curr_rec += cursor->dir * offset;
935  }
936  cursor->rest = (limit < 0) ? GRN_ARRAY_MAX : limit;
937  return cursor;
938 }
939 
940 grn_id
942 {
943  if (cursor && cursor->rest) {
944  while (cursor->curr_rec != cursor->tail) {
945  cursor->curr_rec += cursor->dir;
946  if (*cursor->array->n_garbages) {
947  if (grn_array_bitmap_at(ctx, cursor->array, cursor->curr_rec) != 1) {
948  continue;
949  }
950  }
951  cursor->rest--;
952  return cursor->curr_rec;
953  }
954  }
955  return GRN_ID_NIL;
956 }
957 
958 grn_id
960 {
961  const grn_id max_id = grn_array_get_max_id(array);
962  while (++id <= max_id) {
963  if (!*array->n_garbages ||
964  grn_array_bitmap_at(ctx, array, id) == 1) {
965  return id;
966  }
967  }
968  return GRN_ID_NIL;
969 }
970 
971 int
973 {
974  if (cursor && value) {
975  void * const entry = grn_array_entry_at(ctx, cursor->array, cursor->curr_rec, 0);
976  if (entry) {
977  *value = entry;
978  return cursor->array->value_size;
979  }
980  }
981  return 0;
982 }
983 
984 grn_rc
986  const void *value, int flags)
987 {
988  return grn_array_set_value_inline(ctx, cursor->array, cursor->curr_rec,
989  value, flags);
990 }
991 
992 grn_rc
994  grn_table_delete_optarg *optarg)
995 {
996  return grn_array_delete_by_id(ctx, cursor->array, cursor->curr_rec, optarg);
997 }
998 
999 inline static grn_id
1000 grn_array_add_to_tiny_array(grn_ctx *ctx, grn_array *array, void **value)
1001 {
1002  grn_id id = array->garbages;
1003  void *entry;
1004  if (id) {
1005  /* These operations fail iff the array is broken. */
1006  entry = grn_tiny_array_get(&array->array, id);
1007  if (!entry) {
1008  return GRN_ID_NIL;
1009  }
1010  array->garbages = *(grn_id *)entry;
1011  memset(entry, 0, array->value_size);
1012  (*array->n_garbages)--;
1013  if (!grn_tiny_bitmap_get_and_set(&array->bitmap, id, 1)) {
1014  /* Actually, it is difficult to recover from this error. */
1015  *(grn_id *)entry = array->garbages;
1016  array->garbages = id;
1017  (*array->n_garbages)++;
1018  return GRN_ID_NIL;
1019  }
1020  } else {
1021  id = array->array.max + 1;
1022  if (!grn_tiny_bitmap_put_and_set(&array->bitmap, id, 1)) {
1023  return GRN_ID_NIL;
1024  }
1025  entry = grn_tiny_array_put(&array->array, id);
1026  if (!entry) {
1027  grn_tiny_bitmap_get_and_set(&array->bitmap, id, 0);
1028  return GRN_ID_NIL;
1029  }
1030  array->array.max = id;
1031  }
1032  (*array->n_entries)++;
1033  if (value) { *value = entry; }
1034  return id;
1035 }
1036 
1037 inline static grn_id
1038 grn_array_add_to_io_array(grn_ctx *ctx, grn_array *array, void **value)
1039 {
1040  struct grn_array_header * const header = array->header;
1041  grn_id id = header->garbages;
1042  void *entry;
1043  if (id) {
1044  /* These operations fail iff the array is broken. */
1045  entry = grn_array_io_entry_at(ctx, array, id, GRN_TABLE_ADD);
1046  if (!entry) {
1047  return GRN_ID_NIL;
1048  }
1049  header->garbages = *(grn_id *)entry;
1050  memset(entry, 0, header->value_size);
1051  (*array->n_garbages)--;
1052  if (!grn_io_array_bit_on(ctx, array->io, GRN_ARRAY_BITMAP_SEGMENT, id)) {
1053  /* Actually, it is difficult to recover from this error. */
1054  *(grn_id *)entry = array->garbages;
1055  array->garbages = id;
1056  (*array->n_garbages)++;
1057  return GRN_ID_NIL;
1058  }
1059  } else {
1060  if (header->curr_rec >= GRN_ARRAY_MAX) { return GRN_ID_NIL; }
1061  id = header->curr_rec + 1;
1062  if (!grn_io_array_bit_on(ctx, array->io, GRN_ARRAY_BITMAP_SEGMENT, id)) {
1063  return GRN_ID_NIL;
1064  }
1065  entry = grn_array_io_entry_at(ctx, array, id, GRN_TABLE_ADD);
1066  if (!entry) {
1067  grn_io_array_bit_off(ctx, array->io, GRN_ARRAY_BITMAP_SEGMENT, id);
1068  return GRN_ID_NIL;
1069  }
1070  header->curr_rec = id;
1071  }
1072  (*array->n_entries)++;
1073  if (value) { *value = entry; }
1074  return id;
1075 }
1076 
1077 void
1079 {
1080  struct grn_array_header * const header = array->header;
1081  header->curr_rec = GRN_ID_NIL;
1082 }
1083 
1084 grn_id
1085 grn_array_add(grn_ctx *ctx, grn_array *array, void **value)
1086 {
1087  if (ctx && array) {
1088  if (grn_array_is_io_array(array)) {
1089  return grn_array_add_to_io_array(ctx, array, value);
1090  } else {
1091  return grn_array_add_to_tiny_array(ctx, array, value);
1092  }
1093  }
1094  return GRN_ID_NIL;
1095 }
1096 
1097 grn_id
1099  void (*func)(grn_ctx *, grn_array *, grn_id, void *),
1100  void *func_arg)
1101 {
1102  grn_id id = GRN_ID_NIL;
1103  grn_table_queue *queue = grn_array_queue(ctx, array);
1104  if (queue) {
1105  MUTEX_LOCK(queue->mutex);
1106  if (grn_table_queue_head(queue) == queue->cap) {
1107  grn_array_clear_curr_rec(ctx, array);
1108  }
1109  id = grn_array_add(ctx, array, NULL);
1110  if (func) {
1111  func(ctx, array, id, func_arg);
1112  }
1113  if (grn_table_queue_size(queue) == queue->cap) {
1115  }
1117  COND_SIGNAL(queue->cond);
1118  MUTEX_UNLOCK(queue->mutex);
1119  } else {
1120  ERR(GRN_OPERATION_NOT_SUPPORTED, "only persistent arrays support push");
1121  }
1122  return id;
1123 }
1124 
1125 grn_id
1127  void (*func)(grn_ctx *, grn_array *, grn_id, void *),
1128  void *func_arg)
1129 {
1130  grn_id id = GRN_ID_NIL;
1131  grn_table_queue *queue = grn_array_queue(ctx, array);
1132  if (queue) {
1133  MUTEX_LOCK(queue->mutex);
1134  queue->unblock_requested = GRN_FALSE;
1135  while (grn_table_queue_size(queue) == 0) {
1136  if (!blockp || queue->unblock_requested) {
1137  MUTEX_UNLOCK(queue->mutex);
1138  GRN_OUTPUT_BOOL(0);
1139  return id;
1140  }
1141  COND_WAIT(queue->cond, queue->mutex);
1142  }
1144  id = grn_table_queue_tail(queue);
1145  if (func) {
1146  func(ctx, array, id, func_arg);
1147  }
1148  MUTEX_UNLOCK(queue->mutex);
1149  } else {
1150  ERR(GRN_OPERATION_NOT_SUPPORTED, "only persistent arrays support pull");
1151  }
1152  return id;
1153 }
1154 
1155 void
1157 {
1158  grn_table_queue *queue = grn_array_queue(ctx, array);
1159  if (!queue) {
1160  return;
1161  }
1162 
1163  queue->unblock_requested = GRN_TRUE;
1164  COND_BROADCAST(queue->cond);
1165 }
1166 
1167 /* grn_hash : hash table */
1168 
1169 #define GRN_HASH_MAX_SEGMENT 0x400
1170 #define GRN_HASH_HEADER_SIZE 0x9000
1171 #define GRN_HASH_SEGMENT_SIZE 0x400000
1172 #define W_OF_KEY_IN_A_SEGMENT 22
1173 #define IDX_MASK_IN_A_SEGMENT 0xfffff
1174 
1175 typedef struct {
1176  uint8_t key[4];
1177  uint8_t value[1];
1179 
1180 typedef struct {
1181  uint32_t hash_value;
1182  uint8_t key_and_value[1];
1184 
1185 typedef struct {
1186  uint32_t hash_value;
1187  uint16_t flag;
1188  uint16_t key_size;
1189  union {
1190  uint8_t buf[sizeof(uint32_t)];
1191  uint32_t offset;
1192  } key;
1193  uint8_t value[1];
1195 
1196 typedef struct {
1197  uint32_t hash_value;
1198  uint16_t flag;
1199  uint16_t key_size;
1200  union {
1201  uint8_t buf[sizeof(void *)];
1202  void *ptr;
1203  } key;
1204  uint8_t value[1];
1206 
1207 /*
1208  * hash_value is valid even if the entry is grn_plain_hash_entry. In this case,
1209  * its hash_value equals its key.
1210  * flag, key_size and key.buf are valid if the entry has a variable length key.
1211  */
1212 typedef struct {
1213  uint32_t hash_value;
1214  uint16_t flag;
1215  uint16_t key_size;
1217 
1218 typedef union {
1219  uint32_t hash_value;
1225 } grn_hash_entry;
1226 
1227 typedef struct {
1228  uint32_t key;
1229  uint8_t dummy[1];
1230 } entry;
1231 
1232 typedef struct {
1233  uint32_t key;
1234  uint16_t flag;
1235  uint16_t size;
1236  uint32_t str;
1237  uint8_t dummy[1];
1238 } entry_str;
1239 
1240 typedef struct {
1241  uint32_t key;
1242  uint16_t flag;
1243  uint16_t size;
1244  char *str;
1245  uint8_t dummy[1];
1246 } entry_astr;
1247 
1248 #define LOGICAL_MAX_SEGMENT ((GRN_HASH_MAX_SEGMENT) * 4)
1249 
1250 enum {
1255 };
1256 
1257 inline static grn_bool
1258 grn_hash_is_io_hash(grn_hash *hash)
1259 {
1260  return hash->io != NULL;
1261 }
1262 
1263 inline static void *
1264 grn_io_hash_entry_at(grn_ctx *ctx, grn_hash *hash, grn_id id, int flags)
1265 {
1266  return grn_io_array_at_inline(ctx, hash->io, GRN_HASH_ENTRY_SEGMENT, id, flags);
1267 }
1268 
1269 /* todo : error handling */
1270 inline static void *
1271 grn_hash_entry_at(grn_ctx *ctx, grn_hash *hash, grn_id id, int flags)
1272 {
1273  if (grn_hash_is_io_hash(hash)) {
1274  return grn_io_hash_entry_at(ctx, hash, id, flags);
1275  } else {
1276  return grn_tiny_array_at_inline(&hash->a, id);
1277  }
1278 }
1279 
1280 inline static grn_bool
1281 grn_hash_bitmap_at(grn_ctx *ctx, grn_hash *hash, grn_id id)
1282 {
1283  if (grn_hash_is_io_hash(hash)) {
1284  return grn_io_array_bit_at(ctx, hash->io, GRN_HASH_BITMAP_SEGMENT, id) == 1;
1285  } else {
1286  return grn_tiny_bitmap_put(&hash->bitmap, id) == 1;
1287  }
1288 }
1289 
1290 inline static grn_id *
1291 grn_io_hash_idx_at(grn_ctx *ctx, grn_hash *hash, grn_id id)
1292 {
1293  return grn_io_array_at_inline(ctx, hash->io, GRN_HASH_INDEX_SEGMENT,
1294  id, GRN_TABLE_ADD);
1295 }
1296 
1297 inline static grn_id *
1298 grn_hash_idx_at(grn_ctx *ctx, grn_hash *hash, grn_id id)
1299 {
1300  if (grn_hash_is_io_hash(hash)) {
1301  id = (id & *hash->max_offset) + hash->header->idx_offset;
1302  return grn_io_hash_idx_at(ctx, hash, id);
1303  } else {
1304  return hash->index + (id & *hash->max_offset);
1305  }
1306 }
1307 
1308 inline static void *
1309 grn_io_hash_key_at(grn_ctx *ctx, grn_hash *hash, uint32_t pos)
1310 {
1311  return grn_io_array_at_inline(ctx, hash->io, GRN_HASH_KEY_SEGMENT,
1312  pos, GRN_TABLE_ADD);
1313 }
1314 
1315 #define HASH_IMMEDIATE 1
1316 
1317 #define MAX_INDEX_SIZE ((GRN_HASH_MAX_SEGMENT * (IDX_MASK_IN_A_SEGMENT + 1)) >> 1)
1318 
1319 inline static uint16_t
1320 grn_hash_entry_get_key_size(grn_hash *hash, grn_hash_entry *entry)
1321 {
1322  if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
1323  return entry->header.key_size;
1324  } else {
1325  return hash->key_size;
1326  }
1327 }
1328 
1329 inline static char *
1330 grn_hash_entry_get_key(grn_ctx *ctx, grn_hash *hash, grn_hash_entry *entry)
1331 {
1332  if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
1333  if (grn_hash_is_io_hash(hash)) {
1334  if (entry->io_entry.flag & HASH_IMMEDIATE) {
1335  return (char *)entry->io_entry.key.buf;
1336  } else {
1337  return (char *)grn_io_hash_key_at(ctx, hash, entry->io_entry.key.offset);
1338  }
1339  } else {
1340  if (entry->tiny_entry.flag & HASH_IMMEDIATE) {
1341  return (char *)entry->tiny_entry.key.buf;
1342  } else {
1343  return entry->tiny_entry.key.ptr;
1344  }
1345  }
1346  } else {
1347  if (hash->key_size == sizeof(uint32_t)) {
1348  return (char *)entry->plain_entry.key;
1349  } else {
1350  return (char *)entry->rich_entry.key_and_value;
1351  }
1352  }
1353 }
1354 
1355 inline static void *
1356 grn_hash_entry_get_value(grn_hash *hash, grn_hash_entry *entry)
1357 {
1358  if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
1359  if (grn_hash_is_io_hash(hash)) {
1360  return entry->io_entry.value;
1361  } else {
1362  return entry->tiny_entry.value;
1363  }
1364  } else {
1365  if (hash->key_size == sizeof(uint32_t)) {
1366  return entry->plain_entry.value;
1367  } else {
1368  return entry->rich_entry.key_and_value + hash->key_size;
1369  }
1370  }
1371 }
1372 
1373 inline static grn_rc
1374 grn_io_hash_entry_put_key(grn_ctx *ctx, grn_hash *hash,
1375  grn_io_hash_entry *entry,
1376  const void *key, unsigned int key_size)
1377 {
1378  uint32_t key_offset;
1379  if (entry->key_size) {
1380  key_offset = entry->key.offset;
1381  } else {
1382  uint32_t segment_id;
1383  if (key_size >= GRN_HASH_SEGMENT_SIZE) {
1384  return GRN_INVALID_ARGUMENT;
1385  }
1386  key_offset = hash->header->curr_key;
1387  segment_id = (key_offset + key_size) >> W_OF_KEY_IN_A_SEGMENT;
1388  if ((key_offset >> W_OF_KEY_IN_A_SEGMENT) != segment_id) {
1389  key_offset = hash->header->curr_key = segment_id << W_OF_KEY_IN_A_SEGMENT;
1390  }
1391  hash->header->curr_key += key_size;
1392  entry->key.offset = key_offset;
1393  }
1394 
1395  {
1396  void * const key_ptr = grn_io_hash_key_at(ctx, hash, key_offset);
1397  if (!key_ptr) {
1398  return GRN_NO_MEMORY_AVAILABLE;
1399  }
1400  memcpy(key_ptr, key, key_size);
1401  }
1402  return GRN_SUCCESS;
1403 }
1404 
1405 inline static grn_rc
1406 grn_hash_entry_put_key(grn_ctx *ctx, grn_hash *hash,
1407  grn_hash_entry *entry, uint32_t hash_value,
1408  const void *key, unsigned int key_size)
1409 {
1410  if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
1411  if (grn_hash_is_io_hash(hash)) {
1412  if (key_size <= sizeof(entry->io_entry.key.buf)) {
1413  memcpy(entry->io_entry.key.buf, key, key_size);
1414  entry->io_entry.flag = HASH_IMMEDIATE;
1415  } else {
1416  const grn_rc rc =
1417  grn_io_hash_entry_put_key(ctx, hash, (grn_io_hash_entry *)entry,
1418  key, key_size);
1419  if (rc) {
1420  return rc;
1421  }
1422  entry->io_entry.flag = 0;
1423  }
1424  entry->io_entry.hash_value = hash_value;
1425  entry->io_entry.key_size = key_size;
1426  } else {
1427  if (key_size <= sizeof(entry->tiny_entry.key.buf)) {
1428  memcpy(entry->tiny_entry.key.buf, key, key_size);
1429  entry->tiny_entry.flag = HASH_IMMEDIATE;
1430  } else {
1431  grn_ctx * const ctx = hash->ctx;
1432  entry->tiny_entry.key.ptr = GRN_CTX_ALLOC(ctx, key_size);
1433  if (!entry->tiny_entry.key.ptr) {
1434  return GRN_NO_MEMORY_AVAILABLE;
1435  }
1436  memcpy(entry->tiny_entry.key.ptr, key, key_size);
1437  entry->tiny_entry.flag = 0;
1438  }
1439  entry->tiny_entry.hash_value = hash_value;
1440  entry->tiny_entry.key_size = key_size;
1441  }
1442  } else {
1443  if (hash->key_size == sizeof(uint32_t)) {
1444  *(uint32_t *)entry->plain_entry.key = hash_value;
1445  } else {
1446  entry->rich_entry.hash_value = hash_value;
1447  memcpy(entry->rich_entry.key_and_value, key, key_size);
1448  }
1449  }
1450  return GRN_SUCCESS;
1451 }
1452 
1453 /*
1454  * grn_hash_entry_compare_key() returns GRN_TRUE if the entry key equals the
1455  * specified key, or GRN_FALSE otherwise.
1456  */
1457 inline static grn_bool
1458 grn_hash_entry_compare_key(grn_ctx *ctx, grn_hash *hash,
1459  grn_hash_entry *entry, uint32_t hash_value,
1460  const void *key, unsigned int key_size)
1461 {
1462  if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
1463  if (entry->hash_value != hash_value ||
1464  entry->header.key_size != key_size) {
1465  return GRN_FALSE;
1466  }
1467  if (grn_hash_is_io_hash(hash)) {
1468  if (entry->io_entry.flag & HASH_IMMEDIATE) {
1469  return !memcmp(key, entry->io_entry.key.buf, key_size);
1470  } else {
1471  const void * const entry_key_ptr =
1472  grn_io_hash_key_at(ctx, hash, entry->io_entry.key.offset);
1473  return !memcmp(key, entry_key_ptr, key_size);
1474  }
1475  } else {
1476  if (entry->tiny_entry.flag & HASH_IMMEDIATE) {
1477  return !memcmp(key, entry->tiny_entry.key.buf, key_size);
1478  } else {
1479  return !memcmp(key, entry->tiny_entry.key.ptr, key_size);
1480  }
1481  }
1482  } else {
1483  if (entry->hash_value != hash_value) {
1484  return GRN_FALSE;
1485  }
1486  if (key_size == sizeof(uint32_t)) {
1487  return GRN_TRUE;
1488  } else {
1489  return !memcmp(key, entry->rich_entry.key_and_value, key_size);
1490  }
1491  }
1492 }
1493 
1494 inline static char *
1495 get_key(grn_ctx *ctx, grn_hash *hash, entry_str *n)
1496 {
1497  return grn_hash_entry_get_key(ctx, hash, (grn_hash_entry *)n);
1498 }
1499 
1500 inline static void *
1501 get_value(grn_hash *hash, entry_str *n)
1502 {
1503  return grn_hash_entry_get_value(hash, (grn_hash_entry *)n);
1504 }
1505 
1506 inline static grn_rc
1507 put_key(grn_ctx *ctx, grn_hash *hash, entry_str *n, uint32_t h,
1508  const char *key, unsigned int len)
1509 {
1510  return grn_hash_entry_put_key(ctx, hash, (grn_hash_entry *)n, h, key, len);
1511 }
1512 
1513 inline static int
1514 match_key(grn_ctx *ctx, grn_hash *hash, entry_str *ee, uint32_t h,
1515  const char *key, unsigned int len)
1516 {
1517  return grn_hash_entry_compare_key(ctx, hash, (grn_hash_entry *)ee,
1518  h, key, len);
1519 }
1520 
1521 #define GARBAGE (0xffffffff)
1522 
1523 inline static uint32_t
1524 grn_io_hash_calculate_entry_size(uint32_t key_size, uint32_t value_size,
1525  uint32_t flags)
1526 {
1527  if (flags & GRN_OBJ_KEY_VAR_SIZE) {
1528  return (uintptr_t)((grn_io_hash_entry *)0)->value + value_size;
1529  } else {
1530  if (key_size == sizeof(uint32_t)) {
1531  return (uintptr_t)((grn_plain_hash_entry *)0)->value + value_size;
1532  } else {
1533  return (uintptr_t)((grn_rich_hash_entry *)0)->key_and_value
1534  + key_size + value_size;
1535  }
1536  }
1537 }
1538 
1539 static grn_io *
1540 grn_io_hash_create_io(grn_ctx *ctx, const char *path, uint32_t entry_size)
1541 {
1542  uint32_t w_of_element = 0;
1543  grn_io_array_spec array_spec[4];
1544 
1545  while ((1U << w_of_element) < entry_size) {
1546  w_of_element++;
1547  }
1548 
1549  array_spec[GRN_HASH_KEY_SEGMENT].w_of_element = 0;
1550  array_spec[GRN_HASH_KEY_SEGMENT].max_n_segments = 0x400;
1551  array_spec[GRN_HASH_ENTRY_SEGMENT].w_of_element = w_of_element;
1553  1U << (30 - (22 - w_of_element));
1554  array_spec[GRN_HASH_INDEX_SEGMENT].w_of_element = 2;
1555  array_spec[GRN_HASH_INDEX_SEGMENT].max_n_segments = 1U << (30 - (22 - 2));
1556  array_spec[GRN_HASH_BITMAP_SEGMENT].w_of_element = 0;
1557  array_spec[GRN_HASH_BITMAP_SEGMENT].max_n_segments = 1U << (30 - (22 + 3));
1560  grn_io_auto, 4, array_spec);
1561 }
1562 
1563 static grn_rc
1564 grn_io_hash_init(grn_ctx *ctx, grn_hash *hash, const char *path,
1565  uint32_t key_size, uint32_t value_size, uint32_t flags,
1566  grn_encoding encoding, uint32_t init_size)
1567 {
1568  grn_io *io;
1569  struct grn_hash_header *header;
1570  uint32_t entry_size, max_offset;
1571 
1572  entry_size = grn_io_hash_calculate_entry_size(key_size, value_size, flags);
1573 
1574  io = grn_io_hash_create_io(ctx, path, entry_size);
1575  if (!io) {
1576  return GRN_NO_MEMORY_AVAILABLE;
1577  }
1579 
1580  max_offset = IDX_MASK_IN_A_SEGMENT + 1;
1581  while (max_offset < init_size * 2) {
1582  max_offset *= 2;
1583  }
1584  max_offset--;
1585 
1586  if (encoding == GRN_ENC_DEFAULT) {
1587  encoding = ctx->encoding;
1588  }
1589 
1590  header = grn_io_header(io);
1591  header->flags = flags;
1592  header->encoding = encoding;
1593  header->key_size = key_size;
1594  header->curr_rec = 0;
1595  header->curr_key = 0;
1596  header->lock = 0;
1597  header->idx_offset = 0;
1598  header->value_size = value_size;
1599  header->entry_size = entry_size;
1600  header->max_offset = max_offset;
1601  header->n_entries = 0;
1602  header->n_garbages = 0;
1603  header->tokenizer = GRN_ID_NIL;
1604  if (header->flags & GRN_OBJ_KEY_NORMALIZE) {
1605  header->flags &= ~GRN_OBJ_KEY_NORMALIZE;
1607  header->normalizer = grn_obj_id(ctx, hash->normalizer);
1608  } else {
1609  hash->normalizer = NULL;
1610  header->normalizer = GRN_ID_NIL;
1611  }
1612  grn_table_queue_init(ctx, &header->queue);
1613 
1614  hash->obj.header.flags = header->flags;
1615  hash->ctx = ctx;
1616  hash->key_size = key_size;
1617  hash->encoding = encoding;
1618  hash->value_size = value_size;
1619  hash->entry_size = entry_size;
1620  hash->n_garbages = &header->n_garbages;
1621  hash->n_entries = &header->n_entries;
1622  hash->max_offset = &header->max_offset;
1623  hash->io = io;
1624  hash->header = header;
1625  hash->lock = &header->lock;
1626  hash->tokenizer = NULL;
1627  return GRN_SUCCESS;
1628 }
1629 
1630 #define INITIAL_INDEX_SIZE 256U
1631 
1632 static uint32_t
1633 grn_tiny_hash_calculate_entry_size(uint32_t key_size, uint32_t value_size,
1634  uint32_t flags)
1635 {
1636  uint32_t entry_size;
1637  if (flags & GRN_OBJ_KEY_VAR_SIZE) {
1638  entry_size = (uintptr_t)((grn_tiny_hash_entry *)0)->value + value_size;
1639  } else {
1640  if (key_size == sizeof(uint32_t)) {
1641  entry_size = (uintptr_t)((grn_plain_hash_entry *)0)->value + value_size;
1642  } else {
1643  entry_size = (uintptr_t)((grn_rich_hash_entry *)0)->key_and_value
1644  + key_size + value_size;
1645  }
1646  }
1647  if (entry_size != sizeof(uint32_t)) {
1648  entry_size += sizeof(uintptr_t) - 1;
1649  entry_size &= ~(sizeof(uintptr_t) - 1);
1650  }
1651  return entry_size;
1652 }
1653 
1654 static grn_rc
1655 grn_tiny_hash_init(grn_ctx *ctx, grn_hash *hash, const char *path,
1656  uint32_t key_size, uint32_t value_size, uint32_t flags,
1657  grn_encoding encoding)
1658 {
1659  uint32_t entry_size;
1660 
1661  if (path) {
1662  return GRN_INVALID_ARGUMENT;
1663  }
1664  hash->index = GRN_CTX_ALLOC(ctx, INITIAL_INDEX_SIZE * sizeof(grn_id));
1665  if (!hash->index) {
1666  return GRN_NO_MEMORY_AVAILABLE;
1667  }
1668 
1669  entry_size = grn_tiny_hash_calculate_entry_size(key_size, value_size, flags);
1670  hash->obj.header.flags = flags;
1671  hash->ctx = ctx;
1672  hash->key_size = key_size;
1673  hash->encoding = encoding;
1674  hash->value_size = value_size;
1675  hash->entry_size = entry_size;
1676  hash->n_garbages = &hash->n_garbages_;
1677  hash->n_entries = &hash->n_entries_;
1678  hash->max_offset = &hash->max_offset_;
1679  hash->max_offset_ = INITIAL_INDEX_SIZE - 1;
1680  hash->io = NULL;
1681  hash->n_garbages_ = 0;
1682  hash->n_entries_ = 0;
1683  hash->garbages = GRN_ID_NIL;
1684  hash->tokenizer = NULL;
1685  hash->normalizer = NULL;
1686  grn_tiny_array_init(ctx, &hash->a, entry_size, GRN_TINY_ARRAY_CLEAR);
1687  grn_tiny_bitmap_init(ctx, &hash->bitmap);
1688  return GRN_SUCCESS;
1689 }
1690 
1691 static grn_rc
1692 grn_hash_init(grn_ctx *ctx, grn_hash *hash, const char *path,
1693  uint32_t key_size, uint32_t value_size, uint32_t flags)
1694 {
1695  if (flags & GRN_HASH_TINY) {
1696  return grn_tiny_hash_init(ctx, hash, path, key_size, value_size,
1697  flags, ctx->encoding);
1698  } else {
1699  return grn_io_hash_init(ctx, hash, path, key_size, value_size,
1700  flags, ctx->encoding, 0);
1701  }
1702 }
1703 
1704 grn_hash *
1705 grn_hash_create(grn_ctx *ctx, const char *path, uint32_t key_size, uint32_t value_size,
1706  uint32_t flags)
1707 {
1708  grn_hash *hash;
1709  if (!ctx) {
1710  return NULL;
1711  }
1712  if (key_size > GRN_HASH_MAX_KEY_SIZE) {
1713  return NULL;
1714  }
1715  hash = (grn_hash *)GRN_MALLOC(sizeof(grn_hash));
1716  if (!hash) {
1717  return NULL;
1718  }
1720  if (grn_hash_init(ctx, hash, path, key_size, value_size, flags)) {
1721  GRN_FREE(hash);
1722  return NULL;
1723  }
1724  return hash;
1725 }
1726 
1727 grn_hash *
1728 grn_hash_open(grn_ctx *ctx, const char *path)
1729 {
1730  if (ctx) {
1731  grn_io * const io = grn_io_open(ctx, path, grn_io_auto);
1732  if (io) {
1733  struct grn_hash_header * const header = grn_io_header(io);
1734  if (grn_io_get_type(io) == GRN_TABLE_HASH_KEY) {
1735  grn_hash * const hash = (grn_hash *)GRN_MALLOC(sizeof(grn_hash));
1736  if (hash) {
1737  if (!(header->flags & GRN_HASH_TINY)) {
1739  hash->ctx = ctx;
1740  hash->key_size = header->key_size;
1741  hash->encoding = header->encoding;
1742  hash->value_size = header->value_size;
1743  hash->entry_size = header->entry_size;
1744  hash->n_garbages = &header->n_garbages;
1745  hash->n_entries = &header->n_entries;
1746  hash->max_offset = &header->max_offset;
1747  hash->io = io;
1748  hash->header = header;
1749  hash->lock = &header->lock;
1750  hash->tokenizer = grn_ctx_at(ctx, header->tokenizer);
1751  if (header->flags & GRN_OBJ_KEY_NORMALIZE) {
1752  header->flags &= ~GRN_OBJ_KEY_NORMALIZE;
1754  header->normalizer = grn_obj_id(ctx, hash->normalizer);
1755  } else {
1756  hash->normalizer = grn_ctx_at(ctx, header->normalizer);
1757  }
1758  hash->obj.header.flags = header->flags;
1759  return hash;
1760  } else {
1761  GRN_LOG(ctx, GRN_LOG_NOTICE,
1762  "invalid hash flag. (%x)", header->flags);
1763  }
1764  GRN_FREE(hash);
1765  }
1766  } else {
1767  ERR(GRN_INVALID_FORMAT, "file type unmatch");
1768  }
1769  grn_io_close(ctx, io);
1770  }
1771  }
1772  return NULL;
1773 }
1774 
1775 static grn_rc
1776 grn_tiny_hash_fin(grn_ctx *ctx, grn_hash *hash)
1777 {
1778  if (!hash->index) {
1779  return GRN_INVALID_ARGUMENT;
1780  }
1781 
1782  if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
1783  uint32_t num_remaining_entries = *hash->n_entries;
1784  grn_id *hash_ptr;
1785  for (hash_ptr = hash->index; num_remaining_entries; hash_ptr++) {
1786  const grn_id id = *hash_ptr;
1787  if (id && id != GARBAGE) {
1788  grn_tiny_hash_entry * const entry =
1789  (grn_tiny_hash_entry *)grn_tiny_array_get(&hash->a, id);
1790  GRN_ASSERT(entry);
1791  num_remaining_entries--;
1792  if (entry && !(entry->flag & HASH_IMMEDIATE)) {
1793  GRN_CTX_FREE(ctx, entry->key.ptr);
1794  }
1795  }
1796  }
1797  }
1798  grn_tiny_array_fin(&hash->a);
1799  grn_tiny_bitmap_fin(&hash->bitmap);
1800  GRN_CTX_FREE(ctx, hash->index);
1801  return GRN_SUCCESS;
1802 }
1803 
1804 grn_rc
1806 {
1807  grn_rc rc;
1808  if (!ctx || !hash) { return GRN_INVALID_ARGUMENT; }
1809  if (grn_hash_is_io_hash(hash)) {
1810  rc = grn_io_close(ctx, hash->io);
1811  } else {
1812  GRN_ASSERT(ctx == hash->ctx);
1813  rc = grn_tiny_hash_fin(ctx, hash);
1814  }
1815  GRN_FREE(hash);
1816  return rc;
1817 }
1818 
1819 grn_rc
1820 grn_hash_remove(grn_ctx *ctx, const char *path)
1821 {
1822  if (!ctx || !path) { return GRN_INVALID_ARGUMENT; }
1823  return grn_io_remove(ctx, path);
1824 }
1825 
1826 grn_rc
1828 {
1829  grn_rc rc = GRN_SUCCESS;
1830  char *path = NULL;
1831  uint32_t key_size, value_size, flags;
1832 
1833  if (!ctx || !hash) {
1834  return GRN_INVALID_ARGUMENT;
1835  }
1836 
1837  if (grn_hash_is_io_hash(hash)) {
1838  const char * const io_path = grn_io_path(hash->io);
1839  if (io_path && *io_path) {
1840  path = GRN_STRDUP(io_path);
1841  if (!path) {
1842  ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_path);
1843  return GRN_NO_MEMORY_AVAILABLE;
1844  }
1845  }
1846  }
1847  key_size = hash->key_size;
1848  value_size = hash->value_size;
1849  flags = hash->obj.header.flags;
1850 
1851  if (grn_hash_is_io_hash(hash)) {
1852  rc = grn_io_close(ctx, hash->io);
1853  if (!rc) {
1854  hash->io = NULL;
1855  if (path) {
1856  rc = grn_io_remove(ctx, path);
1857  }
1858  }
1859  }
1860  if (!rc) {
1861  rc = grn_hash_init(ctx, hash, path, key_size, value_size, flags);
1862  }
1863  if (path) {
1864  GRN_FREE(path);
1865  }
1866  return rc;
1867 }
1868 
1869 inline static uint32_t
1870 grn_hash_calculate_hash_value(const void *ptr, uint32_t size)
1871 {
1872  uint32_t i;
1873  uint32_t hash_value = 0;
1874  for (i = 0; i < size; i++) {
1875  hash_value = (hash_value * 1021) + ((const uint8_t *)ptr)[i];
1876  }
1877  return hash_value;
1878 }
1879 
1880 inline static uint32_t
1881 grn_hash_calculate_step(uint32_t hash_value)
1882 {
1883  return (hash_value >> 2) | 0x1010101;
1884 }
1885 
1886 static grn_rc
1887 grn_hash_reset(grn_ctx *ctx, grn_hash *hash, uint32_t expected_n_entries)
1888 {
1889  grn_id *new_index = NULL;
1890  uint32_t new_index_size = INITIAL_INDEX_SIZE;
1891  grn_id *src_ptr = NULL, *dest_ptr = NULL;
1892  uint32_t src_offset = 0, dest_offset = 0;
1893  const uint32_t n_entries = *hash->n_entries;
1894  const uint32_t max_offset = *hash->max_offset;
1895 
1896  if (!expected_n_entries) {
1897  expected_n_entries = n_entries * 2;
1898  }
1899  if (expected_n_entries > INT_MAX) {
1900  return GRN_NO_MEMORY_AVAILABLE;
1901  }
1902  while (new_index_size <= expected_n_entries) {
1903  new_index_size *= 2;
1904  }
1905 
1906  if (grn_hash_is_io_hash(hash)) {
1907  uint32_t i;
1908  src_offset = hash->header->idx_offset;
1909  dest_offset = MAX_INDEX_SIZE - src_offset;
1910  for (i = 0; i < new_index_size; i += (IDX_MASK_IN_A_SEGMENT + 1)) {
1911  /*
1912  * The following grn_io_hash_idx_at() allocates memory for a new segment
1913  * and returns a pointer to the new segment. It's actually bad manners
1914  * but faster than calling grn_io_hash_idx_at() for each element.
1915  */
1916  dest_ptr = grn_io_hash_idx_at(ctx, hash, i + dest_offset);
1917  if (!dest_ptr) {
1918  return GRN_NO_MEMORY_AVAILABLE;
1919  }
1920  memset(dest_ptr, 0, GRN_HASH_SEGMENT_SIZE);
1921  }
1922  } else {
1923  GRN_ASSERT(ctx == hash->ctx);
1924  new_index = GRN_CTX_ALLOC(ctx, new_index_size * sizeof(grn_id));
1925  if (!new_index) {
1926  return GRN_NO_MEMORY_AVAILABLE;
1927  }
1928  src_ptr = hash->index;
1929  }
1930 
1931  {
1932  uint32_t src_pos, count;
1933  const uint32_t new_max_offset = new_index_size - 1;
1934  for (count = 0, src_pos = 0; count < n_entries && src_pos <= max_offset;
1935  src_pos++, src_ptr++) {
1936  uint32_t i, step;
1937  grn_id entry_id;
1938  grn_hash_entry *entry;
1939  if (grn_hash_is_io_hash(hash) && !(src_pos & IDX_MASK_IN_A_SEGMENT)) {
1940  src_ptr = grn_io_hash_idx_at(ctx, hash, src_pos + src_offset);
1941  if (!src_ptr) {
1942  return GRN_NO_MEMORY_AVAILABLE;
1943  }
1944  }
1945  entry_id = *src_ptr;
1946  if (!entry_id || (entry_id == GARBAGE)) {
1947  continue;
1948  }
1949  entry = grn_hash_entry_at(ctx, hash, entry_id, GRN_TABLE_ADD);
1950  if (!entry) {
1951  return GRN_NO_MEMORY_AVAILABLE;
1952  }
1953  step = grn_hash_calculate_step(entry->hash_value);
1954  for (i = entry->hash_value; ; i += step) {
1955  i &= new_max_offset;
1956  if (grn_hash_is_io_hash(hash)) {
1957  dest_ptr = grn_io_hash_idx_at(ctx, hash, i + dest_offset);
1958  if (!dest_ptr) {
1959  return GRN_NO_MEMORY_AVAILABLE;
1960  }
1961  } else {
1962  dest_ptr = new_index + i;
1963  }
1964  if (!*dest_ptr) {
1965  break;
1966  }
1967  }
1968  *dest_ptr = entry_id;
1969  count++;
1970  }
1971  *hash->max_offset = new_max_offset;
1972  *hash->n_garbages = 0;
1973  }
1974 
1975  if (grn_hash_is_io_hash(hash)) {
1976  hash->header->idx_offset = dest_offset;
1977  } else {
1978  grn_id * const old_index = hash->index;
1979  hash->index = new_index;
1980  GRN_CTX_FREE(ctx, old_index);
1981  }
1982 
1983  return GRN_SUCCESS;
1984 }
1985 
1986 grn_rc
1987 grn_hash_lock(grn_ctx *ctx, grn_hash *hash, int timeout)
1988 {
1989  static int _ncalls = 0, _ncolls = 0;
1990  uint32_t count;
1991  _ncalls++;
1992  for (count = 0;; count++) {
1993  uint32_t lock;
1994  GRN_ATOMIC_ADD_EX(hash->lock, 1, lock);
1995  if (lock) {
1996  GRN_ATOMIC_ADD_EX(hash->lock, -1, lock);
1997  if (!timeout || (timeout > 0 && timeout == count)) { break; }
1998  if (!(++_ncolls % 1000000) && (_ncolls > _ncalls)) {
1999  if (_ncolls < 0 || _ncalls < 0) {
2000  _ncolls = 0; _ncalls = 0;
2001  } else {
2002  GRN_LOG(ctx, GRN_LOG_NOTICE, "hash(%p) collisions(%d/%d)", hash, _ncolls, _ncalls);
2003  }
2004  }
2005  grn_nanosleep(1000000);
2006  continue;
2007  }
2008  return GRN_SUCCESS;
2009  }
2010  ERR(GRN_RESOURCE_DEADLOCK_AVOIDED, "grn_hash_lock");
2011  return ctx->rc;
2012 }
2013 
2014 grn_rc
2016 {
2017  uint32_t lock;
2018  GRN_ATOMIC_ADD_EX(hash->lock, -1, lock);
2019  return GRN_SUCCESS;
2020 }
2021 
2022 grn_rc
2024 {
2025  *hash->lock = 0;
2026  return GRN_SUCCESS;
2027 }
2028 
2029 inline static grn_id
2030 grn_io_hash_add(grn_ctx *ctx, grn_hash *hash, uint32_t hash_value,
2031  const void *key, unsigned int key_size, void **value)
2032 {
2033  grn_id entry_id;
2034  grn_hash_entry *entry;
2035  struct grn_hash_header * const header = hash->header;
2036 
2037  entry_id = header->garbages[key_size - 1];
2038  if (entry_id) {
2039  entry = grn_io_hash_entry_at(ctx, hash, entry_id, GRN_TABLE_ADD);
2040  if (!entry) {
2041  return GRN_ID_NIL;
2042  }
2043  header->garbages[key_size - 1] = *(grn_id *)entry;
2044  if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
2045  /* keep entry->io_entry's hash_value, flag, key_size and key. */
2046  memset(entry->io_entry.value, 0, header->value_size);
2047  } else {
2048  memset(entry, 0, header->entry_size);
2049  }
2050  } else {
2051  entry_id = header->curr_rec + 1;
2052  entry = grn_hash_entry_at(ctx, hash, entry_id, GRN_TABLE_ADD);
2053  if (!entry) {
2054  return GRN_ID_NIL;
2055  }
2056  header->curr_rec = entry_id;
2057  }
2058 
2059  if (!grn_io_array_bit_on(ctx, hash->io, GRN_HASH_BITMAP_SEGMENT, entry_id)) {
2060  /* TODO: error handling. */
2061  }
2062 
2063  if (grn_hash_entry_put_key(ctx, hash, entry, hash_value, key, key_size)) {
2064  /* TODO: error handling. */
2065  }
2066 
2067  if (value) {
2068  *value = grn_hash_entry_get_value(hash, entry);
2069  }
2070  return entry_id;
2071 }
2072 
2073 inline static grn_id
2074 grn_tiny_hash_add(grn_ctx *ctx, grn_hash *hash, uint32_t hash_value,
2075  const void *key, unsigned int key_size, void **value)
2076 {
2077  grn_id entry_id;
2078  grn_hash_entry *entry;
2079  if (hash->garbages) {
2080  entry_id = hash->garbages;
2081  entry = (grn_hash_entry *)grn_tiny_array_get(&hash->a, entry_id);
2082  hash->garbages = *(grn_id *)entry;
2083  memset(entry, 0, hash->entry_size);
2084  } else {
2085  entry_id = hash->a.max + 1;
2086  entry = (grn_hash_entry *)grn_tiny_array_put(&hash->a, entry_id);
2087  if (!entry) {
2088  return GRN_ID_NIL;
2089  }
2090  }
2091 
2092  if (!grn_tiny_bitmap_put_and_set(&hash->bitmap, entry_id, 1)) {
2093  /* TODO: error handling. */
2094  }
2095 
2096  if (grn_hash_entry_put_key(ctx, hash, entry, hash_value, key, key_size)) {
2097  /* TODO: error handling. */
2098  }
2099 
2100  if (value) {
2101  *value = grn_hash_entry_get_value(hash, entry);
2102  }
2103  return entry_id;
2104 }
2105 
2106 grn_id
2107 grn_hash_add(grn_ctx *ctx, grn_hash *hash, const void *key,
2108  unsigned int key_size, void **value, int *added)
2109 {
2110  uint32_t hash_value;
2111  if (!key || !key_size) {
2112  return GRN_ID_NIL;
2113  }
2114  if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
2115  if (key_size > hash->key_size) {
2116  ERR(GRN_INVALID_ARGUMENT, "too long key");
2117  return GRN_ID_NIL;
2118  }
2119  hash_value = grn_hash_calculate_hash_value(key, key_size);
2120  } else {
2121  if (key_size != hash->key_size) {
2122  ERR(GRN_INVALID_ARGUMENT, "key size unmatch");
2123  return GRN_ID_NIL;
2124  }
2125  if (key_size == sizeof(uint32_t)) {
2126  hash_value = *((uint32_t *)key);
2127  } else {
2128  hash_value = grn_hash_calculate_hash_value(key, key_size);
2129  }
2130  }
2131 
2132  {
2133  uint32_t i;
2134  const uint32_t step = grn_hash_calculate_step(hash_value);
2135  grn_id id, *index, *garbage_index = NULL;
2136  grn_hash_entry *entry;
2137 
2138  /* lock */
2139  if ((*hash->n_entries + *hash->n_garbages) * 2 > *hash->max_offset) {
2140  grn_hash_reset(ctx, hash, 0);
2141  }
2142 
2143  for (i = hash_value; ; i += step) {
2144  index = grn_hash_idx_at(ctx, hash, i);
2145  if (!index) {
2146  return GRN_ID_NIL;
2147  }
2148  id = *index;
2149  if (!id) {
2150  break;
2151  }
2152  if (id == GARBAGE) {
2153  if (!garbage_index) {
2154  garbage_index = index;
2155  }
2156  continue;
2157  }
2158 
2159  entry = grn_hash_entry_at(ctx, hash, id, GRN_TABLE_ADD);
2160  if (!entry) {
2161  return GRN_ID_NIL;
2162  }
2163  if (grn_hash_entry_compare_key(ctx, hash, entry, hash_value,
2164  key, key_size)) {
2165  if (value) {
2166  *value = grn_hash_entry_get_value(hash, entry);
2167  }
2168  if (added) {
2169  *added = 0;
2170  }
2171  return id;
2172  }
2173  }
2174 
2175  if (grn_hash_is_io_hash(hash)) {
2176  id = grn_io_hash_add(ctx, hash, hash_value, key, key_size, value);
2177  } else {
2178  id = grn_tiny_hash_add(ctx, hash, hash_value, key, key_size, value);
2179  }
2180  if (!id) {
2181  return GRN_ID_NIL;
2182  }
2183  if (garbage_index) {
2184  (*hash->n_garbages)--;
2185  index = garbage_index;
2186  }
2187  *index = id;
2188  (*hash->n_entries)++;
2189  /* unlock */
2190 
2191  if (added) {
2192  *added = 1;
2193  }
2194  return id;
2195  }
2196 }
2197 
2198 grn_id
2199 grn_hash_get(grn_ctx *ctx, grn_hash *hash, const void *key,
2200  unsigned int key_size, void **value)
2201 {
2202  uint32_t hash_value;
2203  if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
2204  if (key_size > hash->key_size) {
2205  return GRN_ID_NIL;
2206  }
2207  hash_value = grn_hash_calculate_hash_value(key, key_size);
2208  } else {
2209  if (key_size != hash->key_size) {
2210  return GRN_ID_NIL;
2211  }
2212  if (key_size == sizeof(uint32_t)) {
2213  hash_value = *((uint32_t *)key);
2214  } else {
2215  hash_value = grn_hash_calculate_hash_value(key, key_size);
2216  }
2217  }
2218 
2219  {
2220  uint32_t i;
2221  const uint32_t step = grn_hash_calculate_step(hash_value);
2222  for (i = hash_value; ; i += step) {
2223  grn_id id;
2224  grn_id * const index = grn_hash_idx_at(ctx, hash, i);
2225  if (!index) {
2226  return GRN_ID_NIL;
2227  }
2228  id = *index;
2229  if (!id) {
2230  return GRN_ID_NIL;
2231  }
2232  if (id != GARBAGE) {
2233  grn_hash_entry * const entry = grn_hash_entry_at(ctx, hash, id, 0);
2234  if (entry) {
2235  if (grn_hash_entry_compare_key(ctx, hash, entry, hash_value,
2236  key, key_size)) {
2237  if (value) {
2238  *value = grn_hash_entry_get_value(hash, entry);
2239  }
2240  return id;
2241  }
2242  }
2243  }
2244  }
2245  }
2246 }
2247 
2248 inline static grn_hash_entry *
2249 grn_hash_get_entry(grn_ctx *ctx, grn_hash *hash, grn_id id)
2250 {
2251  if (!grn_hash_bitmap_at(ctx, hash, id)) {
2252  return NULL;
2253  }
2254  return grn_hash_entry_at(ctx, hash, id, 0);
2255 }
2256 
2257 const char *
2258 _grn_hash_key(grn_ctx *ctx, grn_hash *hash, grn_id id, uint32_t *key_size)
2259 {
2260  grn_hash_entry * const entry = grn_hash_get_entry(ctx, hash, id);
2261  if (!entry) {
2262  *key_size = 0;
2263  return NULL;
2264  }
2265  *key_size = grn_hash_entry_get_key_size(hash, entry);
2266  return grn_hash_entry_get_key(ctx, hash, entry);
2267 }
2268 
2269 int
2270 grn_hash_get_key(grn_ctx *ctx, grn_hash *hash, grn_id id, void *keybuf, int bufsize)
2271 {
2272  int key_size;
2273  grn_hash_entry * const entry = grn_hash_get_entry(ctx, hash, id);
2274  if (!entry) {
2275  return 0;
2276  }
2277  key_size = grn_hash_entry_get_key_size(hash, entry);
2278  if (bufsize >= key_size) {
2279  memcpy(keybuf, grn_hash_entry_get_key(ctx, hash, entry), key_size);
2280  }
2281  return key_size;
2282 }
2283 
2284 int
2286 {
2287  int key_size;
2288  char *key;
2289  grn_hash_entry * const entry = grn_hash_get_entry(ctx, hash, id);
2290  if (!entry) {
2291  return 0;
2292  }
2293  key_size = grn_hash_entry_get_key_size(hash, entry);
2294  key = grn_hash_entry_get_key(ctx, hash, entry);
2295  if (bulk->header.impl_flags & GRN_OBJ_REFER) {
2296  bulk->u.b.head = key;
2297  bulk->u.b.curr = key + key_size;
2298  } else {
2299  grn_bulk_write(ctx, bulk, key, key_size);
2300  }
2301  return key_size;
2302 }
2303 
2304 int
2305 grn_hash_get_value(grn_ctx *ctx, grn_hash *hash, grn_id id, void *valuebuf)
2306 {
2307  void *value;
2308  grn_hash_entry * const entry = grn_hash_get_entry(ctx, hash, id);
2309  if (!entry) {
2310  return 0;
2311  }
2312  value = grn_hash_entry_get_value(hash, entry);
2313  if (!value) {
2314  return 0;
2315  }
2316  if (valuebuf) {
2317  memcpy(valuebuf, value, hash->value_size);
2318  }
2319  return hash->value_size;
2320 }
2321 
2322 const char *
2323 grn_hash_get_value_(grn_ctx *ctx, grn_hash *hash, grn_id id, uint32_t *size)
2324 {
2325  const void *value;
2326  grn_hash_entry * const entry = grn_hash_get_entry(ctx, hash, id);
2327  if (!entry) {
2328  return NULL;
2329  }
2330  value = grn_hash_entry_get_value(hash, entry);
2331  if (!value) {
2332  return NULL;
2333  }
2334  *size = hash->value_size;
2335  return (const char *)value;
2336 }
2337 
2338 int
2340  void *keybuf, int bufsize, void *valuebuf)
2341 {
2342  void *value;
2343  int key_size;
2344  grn_hash_entry * const entry = grn_hash_get_entry(ctx, hash, id);
2345  if (!entry) {
2346  return 0;
2347  }
2348  key_size = grn_hash_entry_get_key_size(hash, entry);
2349  if (bufsize >= key_size) {
2350  memcpy(keybuf, grn_hash_entry_get_key(ctx, hash, entry), key_size);
2351  }
2352  value = grn_hash_entry_get_value(hash, entry);
2353  if (!value) {
2354  return 0;
2355  }
2356  if (valuebuf) {
2357  memcpy(valuebuf, value, hash->value_size);
2358  }
2359  return key_size;
2360 }
2361 
2362 int
2364  void **key, void **value)
2365 {
2366  int key_size;
2367  grn_hash_entry * const entry = grn_hash_get_entry(ctx, hash, id);
2368  if (!entry) {
2369  return 0;
2370  }
2371  key_size = grn_hash_entry_get_key_size(hash, entry);
2372  *key = grn_hash_entry_get_key(ctx, hash, entry);
2373  *value = grn_hash_entry_get_value(hash, entry);
2374  return *value ? key_size : 0;
2375 }
2376 
2377 grn_rc
2379  const void *value, int flags)
2380 {
2381  void *entry_value;
2382  grn_hash_entry *entry;
2383  if (!value) {
2384  return GRN_INVALID_ARGUMENT;
2385  }
2386  entry = grn_hash_get_entry(ctx, hash, id);
2387  if (!entry) {
2388  return GRN_NO_MEMORY_AVAILABLE;
2389  }
2390  entry_value = grn_hash_entry_get_value(hash, entry);
2391  if (!entry_value) {
2392  return GRN_NO_MEMORY_AVAILABLE;
2393  }
2394 
2395  switch (flags & GRN_OBJ_SET_MASK) {
2396  case GRN_OBJ_SET :
2397  memcpy(entry_value, value, hash->value_size);
2398  return GRN_SUCCESS;
2399  case GRN_OBJ_INCR :
2400  switch (hash->value_size) {
2401  case sizeof(int32_t) :
2402  *((int32_t *)entry_value) += *((int32_t *)value);
2403  return GRN_SUCCESS;
2404  case sizeof(int64_t) :
2405  *((int64_t *)entry_value) += *((int64_t *)value);
2406  return GRN_SUCCESS;
2407  default :
2408  return GRN_INVALID_ARGUMENT;
2409  }
2410  break;
2411  case GRN_OBJ_DECR :
2412  switch (hash->value_size) {
2413  case sizeof(int32_t) :
2414  *((int32_t *)entry_value) -= *((int32_t *)value);
2415  return GRN_SUCCESS;
2416  case sizeof(int64_t) :
2417  *((int64_t *)entry_value) -= *((int64_t *)value);
2418  return GRN_SUCCESS;
2419  default :
2420  return GRN_INVALID_ARGUMENT;
2421  }
2422  break;
2423  default :
2424  ERR(GRN_INVALID_ARGUMENT, "flags = %d", flags);
2425  return ctx->rc;
2426  }
2427 }
2428 
2429 #define DELETE_IT do {\
2430  *ep = GARBAGE;\
2431  if (grn_hash_is_io_hash(hash)) {\
2432  uint32_t size = key_size - 1;\
2433  struct grn_hash_header *hh = hash->header;\
2434  ee->key = hh->garbages[size];\
2435  hh->garbages[size] = e;\
2436  grn_io_array_bit_off(ctx, hash->io, GRN_HASH_BITMAP_SEGMENT, e);\
2437  } else {\
2438  ee->key = hash->garbages;\
2439  hash->garbages = e;\
2440  if ((hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) && !(ee->flag & HASH_IMMEDIATE)) {\
2441  grn_ctx *ctx = hash->ctx;\
2442  GRN_CTX_FREE(ctx, ((entry_astr *)ee)->str);\
2443  }\
2444  grn_tiny_bitmap_get_and_set(&hash->bitmap, e, 0);\
2445  }\
2446  (*hash->n_entries)--;\
2447  (*hash->n_garbages)++;\
2448  rc = GRN_SUCCESS;\
2449 } while (0)
2450 
2451 grn_rc
2453  grn_table_delete_optarg *optarg)
2454 {
2455  entry_str *ee;
2457  if (!hash || !id) { return rc; }
2458  /* lock */
2459  ee = grn_hash_entry_at(ctx, hash, id, 0);
2460  if (ee) {
2461  grn_id e, *ep;
2462  uint32_t i, key_size, h = ee->key, s = grn_hash_calculate_step(h);
2463  key_size = (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) ? ee->size : hash->key_size;
2464  for (i = h; ; i += s) {
2465  if (!(ep = grn_hash_idx_at(ctx, hash, i))) { return GRN_NO_MEMORY_AVAILABLE; }
2466  if (!(e = *ep)) { break; }
2467  if (e == id) {
2468  DELETE_IT;
2469  break;
2470  }
2471  }
2472  }
2473  /* unlock */
2474  return rc;
2475 }
2476 
2477 grn_rc
2478 grn_hash_delete(grn_ctx *ctx, grn_hash *hash, const void *key, uint32_t key_size,
2479  grn_table_delete_optarg *optarg)
2480 {
2481  uint32_t h, i, m, s;
2483  if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
2484  if (key_size > hash->key_size) { return GRN_INVALID_ARGUMENT; }
2485  h = grn_hash_calculate_hash_value(key, key_size);
2486  } else {
2487  if (key_size != hash->key_size) { return GRN_INVALID_ARGUMENT; }
2488  if (key_size == sizeof(uint32_t)) {
2489  h = *((uint32_t *)key);
2490  } else {
2491  h = grn_hash_calculate_hash_value(key, key_size);
2492  }
2493  }
2494  s = grn_hash_calculate_step(h);
2495  {
2496  grn_id e, *ep;
2497  /* lock */
2498  m = *hash->max_offset;
2499  for (i = h; ; i += s) {
2500  if (!(ep = grn_hash_idx_at(ctx, hash, i))) { return GRN_NO_MEMORY_AVAILABLE; }
2501  if (!(e = *ep)) { break; }
2502  if (e == GARBAGE) { continue; }
2503  {
2504  entry_str * const ee = grn_hash_entry_at(ctx, hash, e, 0);
2505  if (ee && match_key(ctx, hash, ee, h, key, key_size)) {
2506  DELETE_IT;
2507  break;
2508  }
2509  }
2510  }
2511  /* unlock */
2512  return rc;
2513  }
2514 }
2515 
2516 /* only valid for hash tables, GRN_OBJ_KEY_VAR_SIZE && GRN_HASH_TINY */
2517 const char *
2518 _grn_hash_strkey_by_val(void *v, uint16_t *size)
2519 {
2520  entry_astr *n = (entry_astr *)((uintptr_t)v -
2521  (uintptr_t)&((entry_astr *)0)->dummy);
2522  *size = n->size;
2523  return (n->flag & HASH_IMMEDIATE) ? (char *)&n->str : n->str;
2524 }
2525 
2526 void
2528 {
2529  GRN_ASSERT(c->ctx == ctx);
2530  GRN_FREE(c);
2531 }
2532 
2533 #define HASH_CURR_MAX(hash) \
2534  ((grn_hash_is_io_hash(hash)) ? (hash)->header->curr_rec : (hash)->a.max)
2535 
2538  const void *min, uint32_t min_size,
2539  const void *max, uint32_t max_size,
2540  int offset, int limit, int flags)
2541 {
2542  grn_hash_cursor *c;
2543  if (!hash || !ctx) { return NULL; }
2544  if (!(c = GRN_MALLOCN(grn_hash_cursor, 1))) { return NULL; }
2546  c->hash = hash;
2547  c->ctx = ctx;
2548  c->obj.header.flags = flags;
2549  c->obj.header.domain = GRN_ID_NIL;
2550  if (flags & GRN_CURSOR_DESCENDING) {
2551  c->dir = -1;
2552  if (max) {
2553  if (!(c->curr_rec = grn_hash_get(ctx, hash, max, max_size, NULL))) {
2554  c->tail = GRN_ID_NIL;
2555  goto exit;
2556  }
2557  if (!(flags & GRN_CURSOR_LT)) { c->curr_rec++; }
2558  } else {
2559  c->curr_rec = HASH_CURR_MAX(hash) + 1;
2560  }
2561  if (min) {
2562  if (!(c->tail = grn_hash_get(ctx, hash, min, min_size, NULL))) {
2563  c->curr_rec = GRN_ID_NIL;
2564  goto exit;
2565  }
2566  if ((flags & GRN_CURSOR_GT)) { c->tail++; }
2567  } else {
2568  c->tail = GRN_ID_NIL + 1;
2569  }
2570  if (c->curr_rec < c->tail) { c->tail = c->curr_rec; }
2571  } else {
2572  c->dir = 1;
2573  if (min) {
2574  if (!(c->curr_rec = grn_hash_get(ctx, hash, min, min_size, NULL))) {
2575  c->tail = GRN_ID_NIL;
2576  goto exit;
2577  }
2578  if (!(flags & GRN_CURSOR_GT)) { c->curr_rec--; }
2579  } else {
2580  c->curr_rec = GRN_ID_NIL;
2581  }
2582  if (max) {
2583  if (!(c->tail = grn_hash_get(ctx, hash, max, max_size, NULL))) {
2584  c->curr_rec = GRN_ID_NIL;
2585  goto exit;
2586  }
2587  if ((flags & GRN_CURSOR_LT)) { c->tail--; }
2588  } else {
2589  c->tail = HASH_CURR_MAX(hash);
2590  }
2591  if (c->tail < c->curr_rec) { c->tail = c->curr_rec; }
2592  }
2593  if (*hash->n_entries != HASH_CURR_MAX(hash)) {
2594  while (offset && c->curr_rec != c->tail) {
2595  c->curr_rec += c->dir;
2596  if (grn_hash_bitmap_at(ctx, c->hash, c->curr_rec)) { offset--; }
2597  }
2598  } else {
2599  c->curr_rec += c->dir * offset;
2600  }
2601 exit :
2602  c->rest = (limit < 0) ? GRN_ARRAY_MAX : limit;
2603  return c;
2604 }
2605 
2606 grn_id
2608 {
2609  if (c && c->rest) {
2610  while (c->curr_rec != c->tail) {
2611  c->curr_rec += c->dir;
2612  if (*c->hash->n_entries != HASH_CURR_MAX(c->hash)) {
2613  if (!grn_hash_bitmap_at(ctx, c->hash, c->curr_rec)) { continue; }
2614  }
2615  c->rest--;
2616  return c->curr_rec;
2617  }
2618  }
2619  return GRN_ID_NIL;
2620 }
2621 
2622 grn_id
2624 {
2625  grn_id max = HASH_CURR_MAX(hash);
2626  while (++id <= max) {
2627  if (grn_hash_bitmap_at(ctx, hash, id)) { return id; }
2628  }
2629  return GRN_ID_NIL;
2630 }
2631 
2632 grn_id
2634 {
2635  return grn_hash_bitmap_at(ctx, hash, id) ? id : GRN_ID_NIL;
2636 }
2637 
2638 int
2640 {
2641  int key_size;
2642  entry_str *ee;
2643  if (!c) { return 0; }
2644  ee = grn_hash_entry_at(ctx, c->hash, c->curr_rec, 0);
2645  if (!ee) { return 0; }
2646  key_size = (c->hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) ? ee->size : c->hash->key_size;
2647  *key = get_key(ctx, c->hash, ee);
2648  return key_size;
2649 }
2650 
2651 int
2653 {
2654  void *v;
2655  entry_str *ee;
2656  if (!c) { return 0; }
2657  ee = grn_hash_entry_at(ctx, c->hash, c->curr_rec, 0);
2658  if (ee && (v = get_value(c->hash, ee))) {
2659  *value = v;
2660  return c->hash->value_size;
2661  }
2662  return 0;
2663 }
2664 
2665 int
2667  void **key, uint32_t *key_size, void **value)
2668 {
2669  entry_str *ee;
2670  if (!c) { return GRN_INVALID_ARGUMENT; }
2671  ee = grn_hash_entry_at(ctx, c->hash, c->curr_rec, 0);
2672  if (!ee) { return GRN_INVALID_ARGUMENT; }
2673  if (key_size) {
2674  *key_size = (c->hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) ? ee->size : c->hash->key_size;
2675  }
2676  if (key) { *key = get_key(ctx, c->hash, ee); }
2677  if (value) { *value = get_value(c->hash, ee); }
2678  return c->hash->value_size;
2679 }
2680 
2681 grn_rc
2683  const void *value, int flags)
2684 {
2685  if (!c) { return GRN_INVALID_ARGUMENT; }
2686  return grn_hash_set_value(ctx, c->hash, c->curr_rec, value, flags);
2687 }
2688 
2689 grn_rc
2691  grn_table_delete_optarg *optarg)
2692 {
2693  if (!c) { return GRN_INVALID_ARGUMENT; }
2694  return grn_hash_delete_by_id(ctx, c->hash, c->curr_rec, optarg);
2695 }
2696 
2697 /* sort */
2698 
2699 #define PREPARE_VAL(e,ep,es) do {\
2700  if ((arg->flags & GRN_TABLE_SORT_BY_VALUE)) {\
2701  ep = ((const uint8_t *)(get_value(hash, (entry_str *)(e))));\
2702  es = hash->value_size;\
2703  } else {\
2704  ep = ((const uint8_t *)(get_key(ctx, hash, (entry_str *)(e))));\
2705  es = ((hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE)\
2706  ? ((entry_str *)(e))->size : hash->key_size); \
2707  }\
2708  ep += arg->offset;\
2709  es -= arg->offset;\
2710 } while (0)
2711 
2712 #define COMPARE_VAL_(ap,as,bp,bs)\
2713  (arg->compar\
2714  ? arg->compar(ctx,\
2715  (grn_obj *)hash, (void *)(ap), as,\
2716  (grn_obj *)hash, (void *)(bp), bs, arg->compar_arg)\
2717  : ((arg->flags & GRN_TABLE_SORT_AS_NUMBER)\
2718  ? ((arg->flags & GRN_TABLE_SORT_AS_UNSIGNED)\
2719  ? ((arg->flags & GRN_TABLE_SORT_AS_INT64)\
2720  ? *((uint64_t *)(ap)) > *((uint64_t *)(bp))\
2721  : *((uint32_t *)(ap)) > *((uint32_t *)(bp)))\
2722  : ((arg->flags & GRN_TABLE_SORT_AS_INT64)\
2723  ? *((int64_t *)(ap)) > *((int64_t *)(bp))\
2724  : *((int32_t *)(ap)) > *((int32_t *)(bp))))\
2725  : grn_str_greater(ap, as, bp, bs)))
2726 
2727 #define COMPARE_VAL(ap,as,bp,bs)\
2728  ((dir) ? COMPARE_VAL_((bp),(bs),(ap),(as)) : COMPARE_VAL_((ap),(as),(bp),(bs)))
2729 
2730 inline static entry **
2731 pack(grn_ctx *ctx, grn_hash *hash, entry **res, grn_table_sort_optarg *arg, int dir)
2732 {
2733  uint32_t n;
2734  uint32_t cs, es;
2735  const uint8_t *cp, *ep;
2736  entry **head, **tail, *e, *c;
2737  grn_id id, m = HASH_CURR_MAX(hash);
2738  for (id = m >> 1;;id = (id == m) ? 1 : id + 1) {
2739  if (grn_hash_bitmap_at(ctx, hash, id)) { break; }
2740  }
2741  c = grn_hash_entry_at(ctx, hash, id, 0);
2742  if (!c) { return NULL; }
2743  PREPARE_VAL(c, cp, cs);
2744  head = res;
2745  n = *hash->n_entries - 1;
2746  tail = res + n;
2747  while (n--) {
2748  do {
2749  id = (id == m) ? 1 : id + 1;
2750  } while (!grn_hash_bitmap_at(ctx, hash, id));
2751  e = grn_hash_entry_at(ctx, hash, id, 0);
2752  if (!e) { return NULL; }
2753  PREPARE_VAL(e, ep, es);
2754  if (COMPARE_VAL(cp, cs, ep, es)) {
2755  *head++ = e;
2756  } else {
2757  *tail-- = e;
2758  }
2759  }
2760  *head = c;
2761  return *hash->n_entries > 2 ? head : NULL;
2762 }
2763 
2764 inline static void
2765 swap(entry **a, entry **b)
2766 {
2767  entry *c_ = *a;
2768  *a = *b;
2769  *b = c_;
2770 }
2771 
2772 #define SWAP(a,ap,as,b,bp,bs) do {\
2773  const uint8_t *cp_ = ap;\
2774  uint32_t cs_ = as;\
2775  ap = bp; bp = cp_;\
2776  as = bs; bs = cs_;\
2777  swap(a,b);\
2778 } while (0)
2779 
2780 inline static entry **
2781 part(grn_ctx *ctx, entry **b, entry **e, grn_table_sort_optarg *arg, grn_hash *hash, int dir)
2782 {
2783  entry **c;
2784  const uint8_t *bp, *cp, *ep;
2785  uint32_t bs, cs, es;
2786  intptr_t d = e - b;
2787  PREPARE_VAL(*b, bp, bs);
2788  PREPARE_VAL(*e, ep, es);
2789  if (COMPARE_VAL(bp, bs, ep, es)) {
2790  SWAP(b, bp, bs, e, ep, es);
2791  }
2792  if (d < 2) { return NULL; }
2793  c = b + (d >> 1);
2794  PREPARE_VAL(*c, cp, cs);
2795  if (COMPARE_VAL(bp, bs, cp, cs)) {
2796  SWAP(b, bp, bs, c, cp, cs);
2797  } else {
2798  if (COMPARE_VAL(cp, cs, ep, es)) {
2799  SWAP(c, cp, cs, e, ep, es);
2800  }
2801  }
2802  if (d < 3) { return NULL; }
2803  b++;
2804  swap(b, c);
2805  c = b;
2806  PREPARE_VAL(*c, cp, cs);
2807  for (;;) {
2808  do {
2809  b++;
2810  PREPARE_VAL(*b, bp, bs);
2811  } while (COMPARE_VAL(cp, cs, bp, bs));
2812  do {
2813  e--;
2814  PREPARE_VAL(*e, ep, es);
2815  } while (COMPARE_VAL(ep, es, cp, cs));
2816  if (b >= e) { break; }
2817  SWAP(b, bp, bs, e, ep, es);
2818  }
2819  SWAP(c, cp, cs, e, ep, es);
2820  return e;
2821 }
2822 
2823 static void
2824 _sort(grn_ctx *ctx, entry **head, entry **tail, int limit,
2825  grn_table_sort_optarg *arg, grn_hash *hash, int dir)
2826 {
2827  entry **c;
2828  if (head < tail && (c = part(ctx, head, tail, arg, hash, dir))) {
2829  intptr_t rest = limit - 1 - (c - head);
2830  _sort(ctx, head, c - 1, limit, arg, hash, dir);
2831  if (rest > 0) { _sort(ctx, c + 1, tail, (int)rest, arg, hash, dir); }
2832  }
2833 }
2834 
2835 static void
2836 sort(grn_ctx *ctx,
2837  grn_hash *hash, entry **res, int limit, grn_table_sort_optarg *arg, int dir)
2838 {
2839  entry **c = pack(ctx, hash, res, arg, dir);
2840  if (c) {
2841  intptr_t rest = limit - 1 - (c - res);
2842  _sort(ctx, res, c - 1, limit, arg, hash, dir);
2843  if (rest > 0 ) {
2844  _sort(ctx, c + 1, res + *hash->n_entries - 1, (int)rest, arg, hash, dir);
2845  }
2846  }
2847 }
2848 
2849 typedef struct {
2851  int32_t v;
2852 } val32;
2853 
2854 #define PREPARE_VAL32(id,e,ep) do {\
2855  (ep)->id = id;\
2856  (ep)->v = (arg->flags & GRN_TABLE_SORT_BY_ID)\
2857  ? (int32_t) id\
2858  : (*((int32_t *)((byte *)((arg->flags & GRN_TABLE_SORT_BY_VALUE)\
2859  ? get_value(hash, (e))\
2860  : get_key(ctx, hash, (e))) + arg->offset)));\
2861 } while (0)
2862 
2863 #define COMPARE_VAL32_(ap,bp) \
2864  (arg->compar\
2865  ? arg->compar(ctx,\
2866  (grn_obj *)hash, (void *)&(ap)->v, sizeof(uint32_t),\
2867  (grn_obj *)hash, (void *)&(bp)->v, sizeof(uint32_t),\
2868  arg->compar_arg)\
2869  : ((arg->flags & GRN_TABLE_SORT_AS_NUMBER)\
2870  ? ((arg->flags & GRN_TABLE_SORT_AS_UNSIGNED)\
2871  ? *((uint32_t *)&(ap)->v) > *((uint32_t *)&(bp)->v)\
2872  : *((int32_t *)&(ap)->v) > *((int32_t *)&(bp)->v))\
2873  : memcmp(&(ap)->v, &(bp)->v, sizeof(uint32_t)) > 0))
2874 
2875 #define COMPARE_VAL32(ap,bp)\
2876  ((dir) ? COMPARE_VAL32_((bp),(ap)) : COMPARE_VAL32_((ap),(bp)))
2877 
2878 inline static val32 *
2879 pack_val32(grn_ctx *ctx, grn_hash *hash, val32 *res, grn_table_sort_optarg *arg, int dir)
2880 {
2881  uint32_t n;
2882  entry_str *e, *c;
2883  val32 *head, *tail, cr, er;
2884  grn_id id, m = HASH_CURR_MAX(hash);
2885  for (id = m >> 1;;id = (id == m) ? 1 : id + 1) {
2886  if (grn_hash_bitmap_at(ctx, hash, id)) { break; }
2887  }
2888  c = grn_hash_entry_at(ctx, hash, id, 0);
2889  if (!c) { return NULL; }
2890  PREPARE_VAL32(id, c, &cr);
2891  head = res;
2892  n = *hash->n_entries - 1;
2893  tail = res + n;
2894  while (n--) {
2895  do {
2896  id = (id == m) ? 1 : id + 1;
2897  } while (!grn_hash_bitmap_at(ctx, hash, id));
2898  e = grn_hash_entry_at(ctx, hash, id, 0);
2899  if (!e) { return NULL; }
2900  PREPARE_VAL32(id, e, &er);
2901  if (COMPARE_VAL32(&cr, &er)) {
2902  *head++ = er;
2903  } else {
2904  *tail-- = er;
2905  }
2906  }
2907  *head = cr;
2908  return *hash->n_entries > 2 ? head : NULL;
2909 }
2910 
2911 #define SWAP_VAL32(ap,bp) do {\
2912  val32 cr_ = *ap;\
2913  *ap = *bp;\
2914  *bp = cr_;\
2915 } while (0)
2916 
2917 inline static val32 *
2918 part_val32(grn_ctx *ctx,
2919  val32 *b, val32 *e, grn_table_sort_optarg *arg, grn_hash *hash, int dir)
2920 {
2921  val32 *c;
2922  intptr_t d = e - b;
2923  if (COMPARE_VAL32(b, e)) { SWAP_VAL32(b, e); }
2924  if (d < 2) { return NULL; }
2925  c = b + (d >> 1);
2926  if (COMPARE_VAL32(b, c)) {
2927  SWAP_VAL32(b, c);
2928  } else {
2929  if (COMPARE_VAL32(c, e)) { SWAP_VAL32(c, e); }
2930  }
2931  if (d < 3) { return NULL; }
2932  b++;
2933  SWAP_VAL32(b, c);
2934  c = b;
2935  for (;;) {
2936  do { b++; } while (COMPARE_VAL32(c, b));
2937  do { e--; } while (COMPARE_VAL32(e, c));
2938  if (b >= e) { break; }
2939  SWAP_VAL32(b, e);
2940  }
2941  SWAP_VAL32(c, e);
2942  return e;
2943 }
2944 
2945 static void
2946 _sort_val32(grn_ctx *ctx, val32 *head, val32 *tail, int limit,
2947  grn_table_sort_optarg *arg, grn_hash *hash, int dir)
2948 {
2949  val32 *c;
2950  if (head < tail && (c = part_val32(ctx, head, tail, arg, hash, dir))) {
2951  intptr_t rest = limit - 1 - (c - head);
2952  _sort_val32(ctx, head, c - 1, limit, arg, hash, dir);
2953  if (rest > 0) { _sort_val32(ctx, c + 1, tail, (int)rest, arg, hash, dir); }
2954  }
2955 }
2956 
2957 static void
2958 sort_val32(grn_ctx *ctx,
2959  grn_hash *hash, val32 *res, int limit, grn_table_sort_optarg *arg, int dir)
2960 {
2961  val32 *c = pack_val32(ctx, hash, res, arg, dir);
2962  if (c) {
2963  intptr_t rest = limit - 1 - (c - res);
2964  _sort_val32(ctx, res, c - 1, limit, arg, hash, dir);
2965  if (rest > 0 ) {
2966  _sort_val32(ctx, c + 1, res + *hash->n_entries - 1, (int)rest, arg, hash, dir);
2967  }
2968  }
2969 }
2970 
2971 inline static grn_id
2972 entry2id(grn_ctx *ctx, grn_hash *hash, entry *e)
2973 {
2974  entry *e2;
2975  grn_id id, *ep;
2976  uint32_t i, h = e->key, s = grn_hash_calculate_step(h);
2977  for (i = h; ; i += s) {
2978  if (!(ep = grn_hash_idx_at(ctx, hash, i))) { return GRN_ID_NIL; }
2979  if (!(id = *ep)) { break; }
2980  if (id != GARBAGE) {
2981  e2 = grn_hash_entry_at(ctx, hash, id, 0);
2982  if (!e2) { return GRN_ID_NIL; }
2983  if (e2 == e) { break; }
2984  }
2985  }
2986  return id;
2987 }
2988 
2989 int
2991  int limit, grn_array *result, grn_table_sort_optarg *optarg)
2992 {
2993  entry **res;
2994  if (!result || !*hash->n_entries) { return 0; }
2995  if (!(res = GRN_MALLOC(sizeof(entry *) * *hash->n_entries))) {
2996  GRN_LOG(ctx, GRN_LOG_ALERT, "allocation of entries failed on grn_hash_sort !");
2997  return 0;
2998  }
2999  if (limit < 0) {
3000  limit += *hash->n_entries + 1;
3001  if (limit < 0) {
3002  GRN_LOG(ctx, GRN_LOG_ALERT, "limit is too small in grn_hash_sort !");
3003  return 0;
3004  }
3005  }
3006  if (limit > *hash->n_entries) { limit = *hash->n_entries; }
3007  /* hash->limit = limit; */
3008  if (optarg) {
3009  int dir = (optarg->flags & GRN_TABLE_SORT_DESC);
3010  if ((optarg->flags & GRN_TABLE_SORT_BY_ID) ||
3011  (optarg->flags & GRN_TABLE_SORT_BY_VALUE)
3012  ? ((hash->value_size - optarg->offset) == sizeof(uint32_t))
3013  : (!(hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE)
3014  && hash->key_size == sizeof(uint32_t))) {
3015  if (sizeof(entry *) != sizeof(val32)) {
3016  GRN_FREE(res);
3017  if (!(res = GRN_MALLOC(sizeof(val32) * *hash->n_entries))) {
3018  GRN_LOG(ctx, GRN_LOG_ALERT, "allocation of entries failed on grn_hash_sort !");
3019  return 0;
3020  }
3021  }
3022  sort_val32(ctx, hash, (val32 *)res, limit, optarg, dir);
3023  {
3024  int i;
3025  grn_id *v;
3026  val32 *rp = (val32 *)res;
3027  for (i = 0; i < limit; i++, rp++) {
3028  if (!grn_array_add(ctx, result, (void **)&v)) { break; }
3029  if (!(*v = rp->id)) { break; }
3030  }
3031  GRN_FREE(res);
3032  return i;
3033  }
3034  } else {
3035  sort(ctx, hash, res, limit, optarg, dir);
3036  }
3037  } else {
3038  grn_table_sort_optarg opt = {0, NULL, NULL, NULL, 0};
3039  sort(ctx, hash, res, limit, &opt, 0);
3040  }
3041  {
3042  int i;
3043  grn_id *v;
3044  entry **rp = res;
3045  for (i = 0; i < limit; i++, rp++) {
3046  if (!grn_array_add(ctx, result, (void **)&v)) { break; }
3047  if (!(*v = entry2id(ctx, hash, *rp))) { break; }
3048  }
3049  GRN_FREE(res);
3050  return i;
3051  }
3052 }
3053 
3054 void
3056 {
3057  char buf[8];
3058  struct grn_hash_header *h = hash->header;
3059  GRN_OUTPUT_ARRAY_OPEN("RESULT", 1);
3060  GRN_OUTPUT_MAP_OPEN("SUMMARY", 25);
3061  GRN_OUTPUT_CSTR("flags");
3062  grn_itoh(h->flags, buf, 8);
3063  GRN_OUTPUT_STR(buf, 8);
3064  GRN_OUTPUT_CSTR("key_size");
3065  GRN_OUTPUT_INT64(hash->key_size);
3066  GRN_OUTPUT_CSTR("value_size");
3068  GRN_OUTPUT_CSTR("tokenizer");
3070  GRN_OUTPUT_CSTR("normalizer");
3072  GRN_OUTPUT_CSTR("curr_rec");
3074  GRN_OUTPUT_CSTR("curr_key");
3076  GRN_OUTPUT_CSTR("idx_offset");
3078  GRN_OUTPUT_CSTR("entry_size");
3080  GRN_OUTPUT_CSTR("max_offset");
3081  GRN_OUTPUT_INT64(*hash->max_offset);
3082  GRN_OUTPUT_CSTR("n_entries");
3083  GRN_OUTPUT_INT64(*hash->n_entries);
3084  GRN_OUTPUT_CSTR("n_garbages");
3085  GRN_OUTPUT_INT64(*hash->n_garbages);
3086  GRN_OUTPUT_CSTR("lock");
3087  GRN_OUTPUT_INT64(h->lock);
3090 }
3091 
3092 /* rhash : grn_hash with subrecs */
3093 
3094 #ifdef USE_GRN_INDEX2
3095 
3096 static uint32_t default_flags = GRN_HASH_TINY;
3097 
3098 grn_rc
3099 grn_rhash_init(grn_ctx *ctx, grn_hash *hash, grn_rec_unit record_unit, int record_size,
3100  grn_rec_unit subrec_unit, int subrec_size, unsigned int max_n_subrecs)
3101 {
3102  grn_rc rc;
3103  record_size = grn_rec_unit_size(record_unit, record_size);
3104  subrec_size = grn_rec_unit_size(subrec_unit, subrec_size);
3105  if (record_unit != grn_rec_userdef && subrec_unit != grn_rec_userdef) {
3106  subrec_size -= record_size;
3107  }
3108  if (!hash) { return GRN_INVALID_ARGUMENT; }
3109  if (record_size < 0) { return GRN_INVALID_ARGUMENT; }
3110  if ((default_flags & GRN_HASH_TINY)) {
3111  rc = grn_tiny_hash_init(ctx, hash, NULL, record_size,
3112  max_n_subrecs * (GRN_RSET_SCORE_SIZE + subrec_size),
3113  default_flags, GRN_ENC_NONE);
3114  } else {
3115  rc = grn_io_hash_init(ctx, hash, NULL, record_size,
3116  max_n_subrecs * (GRN_RSET_SCORE_SIZE + subrec_size),
3117  default_flags, GRN_ENC_NONE, 0);
3118  }
3119  if (rc) { return rc; }
3120  hash->record_unit = record_unit;
3121  hash->subrec_unit = subrec_unit;
3122  hash->subrec_size = subrec_size;
3123  hash->max_n_subrecs = max_n_subrecs;
3124  return rc;
3125 }
3126 
3127 grn_rc
3128 grn_rhash_fin(grn_ctx *ctx, grn_hash *hash)
3129 {
3130  grn_rc rc;
3131  if (grn_hash_is_io_hash(hash)) {
3132  rc = grn_io_close(ctx, hash->io);
3133  } else {
3134  GRN_ASSERT(ctx == hash->ctx);
3135  rc = grn_tiny_hash_fin(ctx, hash);
3136  }
3137  return rc;
3138 }
3139 
3140 inline static void
3141 subrecs_push(byte *subrecs, int size, int n_subrecs, int score, void *body, int dir)
3142 {
3143  byte *v;
3144  int *c2;
3145  int n = n_subrecs - 1, n2;
3146  while (n) {
3147  n2 = (n - 1) >> 1;
3148  c2 = GRN_RSET_SUBRECS_NTH(subrecs,size,n2);
3149  if (GRN_RSET_SUBRECS_CMP(score, *c2, dir) > 0) { break; }
3150  GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
3151  n = n2;
3152  }
3153  v = subrecs + n * (size + GRN_RSET_SCORE_SIZE);
3154  *((int *)v) = score;
3155  memcpy(v + GRN_RSET_SCORE_SIZE, body, size);
3156 }
3157 
3158 inline static void
3159 subrecs_replace_min(byte *subrecs, int size, int n_subrecs, int score, void *body, int dir)
3160 {
3161  byte *v;
3162  int n = 0, n1, n2, *c1, *c2;
3163  for (;;) {
3164  n1 = n * 2 + 1;
3165  n2 = n1 + 1;
3166  c1 = n1 < n_subrecs ? GRN_RSET_SUBRECS_NTH(subrecs,size,n1) : NULL;
3167  c2 = n2 < n_subrecs ? GRN_RSET_SUBRECS_NTH(subrecs,size,n2) : NULL;
3168  if (c1 && GRN_RSET_SUBRECS_CMP(score, *c1, dir) > 0) {
3169  if (c2 &&
3170  GRN_RSET_SUBRECS_CMP(score, *c2, dir) > 0 &&
3171  GRN_RSET_SUBRECS_CMP(*c1, *c2, dir) > 0) {
3172  GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
3173  n = n2;
3174  } else {
3175  GRN_RSET_SUBRECS_COPY(subrecs,size,n,c1);
3176  n = n1;
3177  }
3178  } else {
3179  if (c2 && GRN_RSET_SUBRECS_CMP(score, *c2, dir) > 0) {
3180  GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
3181  n = n2;
3182  } else {
3183  break;
3184  }
3185  }
3186  }
3187  v = subrecs + n * (size + GRN_RSET_SCORE_SIZE);
3188  memcpy(v, &score, GRN_RSET_SCORE_SIZE);
3189  memcpy(v + GRN_RSET_SCORE_SIZE, body, size);
3190 }
3191 
3192 void
3193 grn_rhash_add_subrec(grn_hash *s, grn_rset_recinfo *ri, int score, void *body, int dir)
3194 {
3195  int limit = s->max_n_subrecs;
3196  ri->score += score;
3197  ri->n_subrecs += 1;
3198  if (limit) {
3199  int ssize = s->subrec_size;
3200  int n_subrecs = GRN_RSET_N_SUBRECS(ri);
3201  if (limit < n_subrecs) {
3202  if (GRN_RSET_SUBRECS_CMP(score, *ri->subrecs, dir) > 0) {
3203  subrecs_replace_min(ri->subrecs, ssize, limit, score, body, dir);
3204  }
3205  } else {
3206  subrecs_push(ri->subrecs, ssize, n_subrecs, score, body, dir);
3207  }
3208  }
3209 }
3210 
3211 grn_hash *
3212 grn_rhash_group(grn_hash *s, int limit, grn_group_optarg *optarg)
3213 {
3214  grn_ctx *ctx = s->ctx;
3215  grn_hash *g, h;
3216  grn_rset_recinfo *ri;
3217  grn_rec_unit unit;
3218  grn_hash_cursor *c;
3219  grn_id rh;
3220  byte *key, *ekey, *gkey = NULL;
3221  int funcp, dir;
3222  unsigned int rsize;
3223  if (!s || !s->index) { return NULL; }
3224  if (optarg) {
3225  unit = grn_rec_userdef;
3226  rsize = optarg->key_size;
3227  funcp = optarg->func ? 1 : 0;
3228  dir = (optarg->mode == grn_sort_ascending) ? -1 : 1;
3229  } else {
3230  unit = grn_rec_document;
3231  rsize = grn_rec_unit_size(unit, sizeof(grn_id));
3232  funcp = 0;
3233  dir = 1;
3234  }
3235  if (funcp) {
3236  gkey = GRN_MALLOC(rsize ? rsize : 8192);
3237  if (!gkey) {
3238  GRN_LOG(ctx, GRN_LOG_ALERT, "allocation for gkey failed !");
3239  return NULL;
3240  }
3241  } else {
3242  if (s->key_size <= rsize) { return NULL; }
3243  }
3244  if (!(c = grn_hash_cursor_open(s->ctx, s, NULL, 0, NULL, -1, 0))) {
3245  GRN_LOG(ctx, GRN_LOG_ALERT, "grn_hash_cursor_open on grn_hash_group failed !");
3246  if (gkey) { GRN_FREE(gkey); }
3247  return NULL;
3248  }
3249  memcpy(&h, s, sizeof(grn_hash));
3250  g = s;
3251  s = &h;
3252  if (grn_rhash_init(ctx, g, unit, rsize, s->record_unit, s->key_size, limit)) {
3253  GRN_LOG(ctx, GRN_LOG_ALERT, "grn_rhash_init in grn_hash_group failed !");
3254  grn_hash_cursor_close(s->ctx, c);
3255  if (gkey) { GRN_FREE(gkey); }
3256  return NULL;
3257  }
3258  while ((rh = grn_hash_cursor_next(ctx, c))) {
3259  grn_hash_cursor_get_key_value(ctx, c, (void **)&key, NULL, (void **)&ri);
3260  if (funcp) {
3261  if (optarg->func((grn_records *)s,
3262  (grn_recordh *)(intptr_t)rh, gkey, optarg->func_arg)) { continue; }
3263  ekey = key;
3264  } else {
3265  gkey = key;
3266  ekey = key + rsize;
3267  }
3268  {
3269  grn_rset_recinfo *gri;
3270  if (grn_hash_add(ctx, g, gkey, rsize, (void **)&gri, NULL)) {
3271  grn_rhash_add_subrec(g, gri, ri->score, ekey, dir);
3272  }
3273  }
3274  }
3275  grn_hash_cursor_close(s->ctx, c);
3276  grn_rhash_fin(s->ctx, s);
3277  if (funcp) { GRN_FREE(gkey); }
3278  return g;
3279 }
3280 
3281 grn_rc
3282 grn_rhash_subrec_info(grn_hash *s, grn_id rh, int index,
3283  grn_id *rid, int *section, int *pos, int *score, void **subrec)
3284 {
3285  grn_rset_posinfo *pi;
3286  grn_rset_recinfo *ri;
3287  int *p, unit_size = GRN_RSET_SCORE_SIZE + s->subrec_size;
3288  if (!s || !rh || index < 0) { return GRN_INVALID_ARGUMENT; }
3289  if ((unsigned int)index >= s->max_n_subrecs) { return GRN_INVALID_ARGUMENT; }
3290  {
3291  entry_str *ee;
3292  if (!grn_hash_bitmap_at(ctx, s, rh)) { return GRN_INVALID_ARGUMENT; }
3293  ee = grn_hash_entry_at(ctx, s, rh, 0);
3294  if (!ee) { return GRN_INVALID_ARGUMENT; }
3295  pi = (grn_rset_posinfo *)get_key(ctx, s, ee);
3296  ri = get_value(s, ee);
3297  if (!pi || !ri) { return GRN_INVALID_ARGUMENT; }
3298  }
3299  if (index >= ri->n_subrecs) { return GRN_INVALID_ARGUMENT; }
3300  p = (int *)(ri->subrecs + index * unit_size);
3301  if (score) { *score = p[0]; }
3302  if (subrec) { *subrec = &p[1]; }
3303  switch (s->record_unit) {
3304  case grn_rec_document :
3305  if (rid) { *rid = pi->rid; }
3306  if (section) { *section = (s->subrec_unit != grn_rec_userdef) ? p[1] : 0; }
3307  if (pos) { *pos = (s->subrec_unit == grn_rec_position) ? p[2] : 0; }
3308  break;
3309  case grn_rec_section :
3310  if (rid) { *rid = pi->rid; }
3311  if (section) { *section = pi->sid; }
3312  if (pos) { *pos = (s->subrec_unit == grn_rec_position) ? p[1] : 0; }
3313  break;
3314  default :
3315  pi = (grn_rset_posinfo *)&p[1];
3316  switch (s->subrec_unit) {
3317  case grn_rec_document :
3318  if (rid) { *rid = pi->rid; }
3319  if (section) { *section = 0; }
3320  if (pos) { *pos = 0; }
3321  break;
3322  case grn_rec_section :
3323  if (rid) { *rid = pi->rid; }
3324  if (section) { *section = pi->sid; }
3325  if (pos) { *pos = 0; }
3326  break;
3327  case grn_rec_position :
3328  if (rid) { *rid = pi->rid; }
3329  if (section) { *section = pi->sid; }
3330  if (pos) { *pos = pi->pos; }
3331  break;
3332  default :
3333  if (rid) { *rid = 0; }
3334  if (section) { *section = 0; }
3335  if (pos) { *pos = 0; }
3336  break;
3337  }
3338  break;
3339  }
3340  return GRN_SUCCESS;
3341 }
3342 #endif /* USE_GRN_INDEX2 */