1/* -*- c-basic-offset: 2 -*- */
2/*
3 Copyright(C) 2009-2017 Brazil
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License version 2.1 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19#pragma once
20
21#include "grn.h"
22#include "grn_error.h"
23
24#ifdef __cplusplus
25extern "C" {
26#endif
27
28#ifdef WIN32
29# define GRN_IO_FILE_CREATE_MODE (GENERIC_READ | GENERIC_WRITE)
30#else /* WIN32 */
31# define GRN_IO_FILE_CREATE_MODE 0644
32#endif /* WIN32 */
33
34typedef enum {
35 grn_io_rdonly,
36 grn_io_wronly,
37 grn_io_rdwr
38} grn_io_rw_mode;
39
40typedef enum {
41 grn_io_auto,
42 grn_io_manual
43} grn_io_mode;
44
45/**** grn_io ****/
46
47typedef struct _grn_io grn_io;
48
49typedef struct {
50 grn_io *io;
51 grn_ctx *ctx;
52 uint8_t mode;
53 uint8_t tiny_p;
54 uint32_t pseg;
55 uint32_t segment;
56 uint32_t offset;
57 uint32_t size;
58 uint32_t nseg;
59 off_t pos;
60 void *addr;
61 uint32_t diff;
62 int32_t cached;
63#ifdef WIN32
64 HANDLE fmo;
65#endif /* WIN32 */
66 void *uncompressed_value;
67} grn_io_win;
68
69typedef struct {
70 void *map;
71 uint32_t nref;
72 uint32_t count;
73#ifdef WIN32
74 HANDLE fmo;
75#endif /* WIN32 */
76} grn_io_mapinfo;
77
78typedef struct _grn_io_array_info grn_io_array_info;
79
80struct _grn_io_header {
81 char idstr[16];
82 uint32_t type;
83 uint32_t version;
84 uint32_t flags;
85 uint32_t header_size;
86 uint32_t segment_size;
87 uint32_t max_segment;
88 uint32_t n_arrays;
89 uint32_t lock;
90 uint64_t curr_size;
91 uint32_t segment_tail;
92 uint32_t last_modified;
93};
94
95struct _grn_io {
96 char path[PATH_MAX];
97 struct _grn_io_header *header;
98 byte *user_header;
99 grn_io_mapinfo *maps;
100 uint32_t base;
101 uint32_t base_seg;
102 grn_io_mode mode;
103 struct _grn_io_fileinfo *fis;
104 grn_io_array_info *ainfo;
105 uint32_t max_map_seg;
106 uint32_t nmaps;
107 uint32_t nref;
108 uint32_t count;
109 uint8_t flags;
110 uint32_t *lock;
111};
112
113GRN_API grn_io *grn_io_create(grn_ctx *ctx, const char *path,
114 uint32_t header_size, uint32_t segment_size,
115 uint32_t max_segment, grn_io_mode mode,
116 unsigned int flags);
117grn_io *grn_io_open(grn_ctx *ctx, const char *path, grn_io_mode mode);
118GRN_API grn_rc grn_io_close(grn_ctx *ctx, grn_io *io);
119grn_rc grn_io_remove(grn_ctx *ctx, const char *path);
120grn_rc grn_io_remove_if_exist(grn_ctx *ctx, const char *path);
121grn_rc grn_io_size(grn_ctx *ctx, grn_io *io, uint64_t *size);
122grn_rc grn_io_rename(grn_ctx *ctx, const char *old_name, const char *new_name);
123GRN_API void *grn_io_header(grn_io *io);
124
125void *grn_io_win_map(grn_io *io, grn_ctx *ctx, grn_io_win *iw, uint32_t segment,
126 uint32_t offset, uint32_t size, grn_io_rw_mode mode);
127grn_rc grn_io_win_unmap(grn_io_win *iw);
128
129typedef struct _grn_io_ja_einfo grn_io_ja_einfo;
130typedef struct _grn_io_ja_ehead grn_io_ja_ehead;
131
132struct _grn_io_ja_einfo {
133 uint32_t pos;
134 uint32_t size;
135};
136
137struct _grn_io_ja_ehead {
138 uint32_t size;
139 uint32_t key;
140};
141
142grn_rc grn_io_read_ja(grn_io *io, grn_ctx *ctx, grn_io_ja_einfo *einfo, uint32_t epos,
143 uint32_t key, uint32_t segment, uint32_t offset,
144 void **value, uint32_t *value_len);
145grn_rc grn_io_write_ja(grn_io *io, grn_ctx *ctx,
146 uint32_t key, uint32_t segment, uint32_t offset,
147 void *value, uint32_t value_len);
148
149grn_rc grn_io_write_ja_ehead(grn_io *io, grn_ctx *ctx, uint32_t key,
150 uint32_t segment, uint32_t offset, uint32_t value_len);
151
152#define GRN_TABLE_ADD (0x01<<6)
153#define GRN_TABLE_ADDED (0x01<<7)
154
155#define GRN_IO_MAX_RETRY (0x10000)
156#define GRN_IO_MAX_REF (0x80000000)
157
158#define GRN_IO_EXPIRE_GTICK (0x01)
159#define GRN_IO_EXPIRE_SEGMENT (0x02)
160#define GRN_IO_TEMPORARY (0x04)
161
162void grn_io_seg_map_(grn_ctx *ctx, grn_io *io, uint32_t segno, grn_io_mapinfo *info);
163
164/* arguments must be validated by caller;
165 * io mustn't be NULL;
166 * segno must be in valid range;
167 * addr must be set NULL;
168 */
169#define GRN_IO_SEG_REF(io,segno,addr) do {\
170 grn_io_mapinfo *info = &(io)->maps[segno];\
171 uint32_t nref, retry, *pnref = &info->nref;\
172 if (io->flags & GRN_IO_EXPIRE_SEGMENT) {\
173 if (io->flags & GRN_IO_EXPIRE_GTICK) {\
174 for (retry = 0; !info->map || info->count != grn_gtick; retry++) {\
175 GRN_ATOMIC_ADD_EX(pnref, 1, nref);\
176 if (nref) {\
177 GRN_ATOMIC_ADD_EX(pnref, -1, nref);\
178 if (retry >= GRN_IO_MAX_RETRY) {\
179 GRN_LOG(ctx, GRN_LOG_CRIT,\
180 "deadlock detected! in GRN_IO_SEG_REF(%p, %u)", io, segno);\
181 break;\
182 }\
183 GRN_FUTEX_WAIT(pnref);\
184 } else {\
185 info->count = grn_gtick;\
186 if (!info->map) {\
187 grn_io_seg_map_(ctx, io, segno, info);\
188 if (!info->map) {\
189 GRN_LOG(ctx, GRN_LOG_CRIT,\
190 "mmap failed! in GRN_IO_SEG_REF(%p, %u): %s",\
191 io, segno, grn_current_error_message());\
192 }\
193 }\
194 GRN_ATOMIC_ADD_EX(pnref, -1, nref);\
195 GRN_FUTEX_WAKE(pnref);\
196 break;\
197 }\
198 }\
199 } else {\
200 for (retry = 0;; retry++) {\
201 GRN_ATOMIC_ADD_EX(pnref, 1, nref);\
202 if (nref >= GRN_IO_MAX_REF) {\
203 GRN_ATOMIC_ADD_EX(pnref, -1, nref);\
204 if (retry >= GRN_IO_MAX_RETRY) {\
205 GRN_LOG(ctx, GRN_LOG_CRIT,\
206 "deadlock detected!! in GRN_IO_SEG_REF(%p, %u, %u)",\
207 io, segno, nref);\
208 *pnref = 0; /* force reset */ \
209 break;\
210 }\
211 GRN_FUTEX_WAIT(pnref);\
212 continue;\
213 }\
214 if (nref >= 0x40000000) {\
215 ALERT("strange nref value!! in GRN_IO_SEG_REF(%p, %u, %u)",\
216 io, segno, nref); \
217 }\
218 if (!info->map) {\
219 if (nref) {\
220 GRN_ATOMIC_ADD_EX(pnref, -1, nref);\
221 if (retry >= GRN_IO_MAX_RETRY) {\
222 GRN_LOG(ctx, GRN_LOG_CRIT,\
223 "deadlock detected!!! in GRN_IO_SEG_REF(%p, %u, %u)",\
224 io, segno, nref);\
225 break;\
226 }\
227 GRN_FUTEX_WAIT(pnref);\
228 continue;\
229 } else {\
230 grn_io_seg_map_(ctx, io, segno, info);\
231 if (!info->map) {\
232 GRN_ATOMIC_ADD_EX(pnref, -1, nref);\
233 GRN_LOG(ctx, GRN_LOG_CRIT,\
234 "mmap failed!!! in GRN_IO_SEG_REF(%p, %u, %u): %s",\
235 io, segno, nref, grn_current_error_message());\
236 }\
237 \
238 GRN_FUTEX_WAKE(pnref);\
239 }\
240 }\
241 break;\
242 }\
243 info->count = grn_gtick;\
244 }\
245 } else {\
246 for (retry = 0; !info->map; retry++) {\
247 GRN_ATOMIC_ADD_EX(pnref, 1, nref);\
248 if (nref) {\
249 GRN_ATOMIC_ADD_EX(pnref, -1, nref);\
250 if (retry >= GRN_IO_MAX_RETRY) {\
251 GRN_LOG(ctx, GRN_LOG_CRIT,\
252 "deadlock detected!!!! in GRN_IO_SEG_REF(%p, %u)",\
253 io, segno);\
254 break;\
255 }\
256 GRN_FUTEX_WAIT(pnref);\
257 } else {\
258 if (!info->map) {\
259 grn_io_seg_map_(ctx, io, segno, info);\
260 if (!info->map) {\
261 GRN_LOG(ctx, GRN_LOG_CRIT,\
262 "mmap failed!!!! in GRN_IO_SEG_REF(%p, %u): %s",\
263 io, segno, grn_current_error_message());\
264 }\
265 }\
266 GRN_ATOMIC_ADD_EX(pnref, -1, nref);\
267 GRN_FUTEX_WAKE(pnref);\
268 break;\
269 }\
270 }\
271 info->count = grn_gtick;\
272 }\
273 addr = info->map;\
274} while (0)
275
276#define GRN_IO_SEG_UNREF(io,segno) do {\
277 if (GRN_IO_EXPIRE_SEGMENT ==\
278 (io->flags & (GRN_IO_EXPIRE_GTICK|GRN_IO_EXPIRE_SEGMENT))) {\
279 uint32_t nref, *pnref = &(io)->maps[segno].nref;\
280 GRN_ATOMIC_ADD_EX(pnref, -1, nref);\
281 }\
282} while (0)
283
284uint32_t grn_io_base_seg(grn_io *io);
285const char *grn_io_path(grn_io *io);
286
287typedef struct _grn_io_array_spec grn_io_array_spec;
288
289struct _grn_io_array_spec {
290 uint32_t w_of_element;
291 uint32_t max_n_segments;
292};
293
294struct _grn_io_array_info {
295 uint32_t w_of_elm_in_a_segment;
296 uint32_t elm_mask_in_a_segment;
297 uint32_t max_n_segments;
298 uint32_t element_size;
299 uint32_t *segments;
300 void **addrs;
301};
302
303grn_io *grn_io_create_with_array(grn_ctx *ctx, const char *path, uint32_t header_size,
304 uint32_t segment_size, grn_io_mode mode,
305 int n_arrays, grn_io_array_spec *array_specs);
306
307void *grn_io_array_at(grn_ctx *ctx, grn_io *io, uint32_t array, off_t offset, int *flags);
308
309void grn_io_segment_alloc(grn_ctx *ctx, grn_io *io, grn_io_array_info *ai,
310 uint32_t lseg, int *flags, void **p);
311
312GRN_API grn_rc grn_io_lock(grn_ctx *ctx, grn_io *io, int timeout);
313GRN_API void grn_io_unlock(grn_io *io);
314void grn_io_clear_lock(grn_io *io);
315uint32_t grn_io_is_locked(grn_io *io);
316grn_bool grn_io_is_corrupt(grn_ctx *ctx, grn_io *io);
317size_t grn_io_get_disk_usage(grn_ctx *ctx, grn_io *io);
318
319#define GRN_IO_ARRAY_AT(io,array,offset,flags,res) do {\
320 grn_io_array_info *ainfo = &(io)->ainfo[array];\
321 uint32_t lseg = (offset) >> ainfo->w_of_elm_in_a_segment;\
322 void **p_ = &ainfo->addrs[lseg];\
323 if (!*p_) {\
324 grn_io_segment_alloc(ctx, (io), ainfo, lseg, (flags), p_);\
325 if (!*p_) { (res) = NULL; break; }\
326 }\
327 *((byte **)(&(res))) = (((byte *)*p_) + \
328 (((offset) & ainfo->elm_mask_in_a_segment) * ainfo->element_size));\
329} while (0)
330
331#define GRN_IO_ARRAY_BIT_AT(io,array,offset,res) do {\
332 uint8_t *ptr_;\
333 int flags_ = 0;\
334 GRN_IO_ARRAY_AT((io), (array), ((offset) >> 3) + 1, &flags_, ptr_);\
335 res = ptr_ ? ((*ptr_ >> ((offset) & 7)) & 1) : 0;\
336} while (0)
337
338#define GRN_IO_ARRAY_BIT_ON(io,array,offset) do {\
339 uint8_t *ptr_;\
340 int flags_ = GRN_TABLE_ADD;\
341 GRN_IO_ARRAY_AT((io), (array), ((offset) >> 3) + 1, &flags_, ptr_);\
342 if (ptr_) { *ptr_ |= (1 << ((offset) & 7)); }\
343} while (0)
344
345#define GRN_IO_ARRAY_BIT_OFF(io,array,offset) do {\
346 uint8_t *ptr_;\
347 int flags_ = GRN_TABLE_ADD;\
348 GRN_IO_ARRAY_AT((io), (array), ((offset) >> 3) + 1, &flags_, ptr_);\
349 if (ptr_) { *ptr_ &= ~(1 << ((offset) & 7)); }\
350} while (0)
351
352#define GRN_IO_ARRAY_BIT_FLIP(io,array,offset) do {\
353 uint8_t *ptr_;\
354 int flags_ = GRN_TABLE_ADD;\
355 GRN_IO_ARRAY_AT((io), (array), ((offset) >> 3) + 1, &flags_, ptr_);\
356 if (ptr_) { *ptr_ ^= (1 << ((offset) & 7)); }\
357} while (0)
358
359void *grn_io_anon_map(grn_ctx *ctx, grn_io_mapinfo *mi, size_t length);
360void grn_io_anon_unmap(grn_ctx *ctx, grn_io_mapinfo *mi, size_t length);
361uint32_t grn_io_detect_type(grn_ctx *ctx, const char *path);
362grn_rc grn_io_set_type(grn_io *io, uint32_t type);
363uint32_t grn_io_get_type(grn_io *io);
364
365void grn_io_init_from_env(void);
366
367uint32_t grn_io_expire(grn_ctx *ctx, grn_io *io, int count_thresh, uint32_t limit);
368
369grn_rc grn_io_flush(grn_ctx *ctx, grn_io *io);
370
371/* encode/decode */
372
373#define GRN_B_ENC(v,p) do {\
374 uint8_t *_p = (uint8_t *)p; \
375 uint32_t _v = v; \
376 if (_v < 0x8f) { \
377 *_p++ = _v; \
378 } else if (_v < 0x408f) { \
379 _v -= 0x8f; \
380 *_p++ = 0xc0 + (_v >> 8); \
381 *_p++ = _v & 0xff; \
382 } else if (_v < 0x20408f) { \
383 _v -= 0x408f; \
384 *_p++ = 0xa0 + (_v >> 16); \
385 *_p++ = (_v >> 8) & 0xff; \
386 *_p++ = _v & 0xff; \
387 } else if (_v < 0x1020408f) { \
388 _v -= 0x20408f; \
389 *_p++ = 0x90 + (_v >> 24); \
390 *_p++ = (_v >> 16) & 0xff; \
391 *_p++ = (_v >> 8) & 0xff; \
392 *_p++ = _v & 0xff; \
393 } else { \
394 *_p++ = 0x8f; \
395 grn_memcpy(_p, &_v, sizeof(uint32_t));\
396 _p += sizeof(uint32_t); \
397 } \
398 p = _p; \
399} while (0)
400
401#define GRN_B_ENC_SIZE(v) \
402 ((v) < 0x8f ? 1 : ((v) < 0x408f ? 2 : ((v) < 0x20408f ? 3 : ((v) < 0x1020408f ? 4 : 5))))
403
404#define GRN_B_DEC(v,p) do { \
405 uint8_t *_p = (uint8_t *)p; \
406 uint32_t _v = *_p++; \
407 switch (_v >> 4) { \
408 case 0x08 : \
409 if (_v == 0x8f) { \
410 grn_memcpy(&_v, _p, sizeof(uint32_t));\
411 _p += sizeof(uint32_t); \
412 } \
413 break; \
414 case 0x09 : \
415 _v = (_v - 0x90) * 0x100 + *_p++; \
416 _v = _v * 0x100 + *_p++; \
417 _v = _v * 0x100 + *_p++ + 0x20408f; \
418 break; \
419 case 0x0a : \
420 case 0x0b : \
421 _v = (_v - 0xa0) * 0x100 + *_p++; \
422 _v = _v * 0x100 + *_p++ + 0x408f; \
423 break; \
424 case 0x0c : \
425 case 0x0d : \
426 case 0x0e : \
427 case 0x0f : \
428 _v = (_v - 0xc0) * 0x100 + *_p++ + 0x8f; \
429 break; \
430 } \
431 v = _v; \
432 p = _p; \
433} while (0)
434
435#define GRN_B_SKIP(p) do { \
436 uint8_t *_p = (uint8_t *)p; \
437 uint32_t _v = *_p++; \
438 switch (_v >> 4) { \
439 case 0x08 : \
440 if (_v == 0x8f) { \
441 _p += sizeof(uint32_t); \
442 } \
443 break; \
444 case 0x09 : \
445 _p += 3; \
446 break; \
447 case 0x0a : \
448 case 0x0b : \
449 _p += 2; \
450 break; \
451 case 0x0c : \
452 case 0x0d : \
453 case 0x0e : \
454 case 0x0f : \
455 _p += 1; \
456 break; \
457 } \
458 p = _p; \
459} while (0)
460
461#define GRN_B_COPY(p2,p1) do { \
462 uint32_t size = 0, _v = *p1++; \
463 *p2++ = _v; \
464 switch (_v >> 4) { \
465 case 0x08 : \
466 size = (_v == 0x8f) ? 4 : 0; \
467 break; \
468 case 0x09 : \
469 size = 3; \
470 break; \
471 case 0x0a : \
472 case 0x0b : \
473 size = 2; \
474 break; \
475 case 0x0c : \
476 case 0x0d : \
477 case 0x0e : \
478 case 0x0f : \
479 size = 1; \
480 break; \
481 } \
482 while (size--) { *p2++ = *p1++; } \
483} while (0)
484
485#ifdef __cplusplus
486}
487#endif
488