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 |
25 | extern "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 | |
34 | typedef enum { |
35 | grn_io_rdonly, |
36 | grn_io_wronly, |
37 | grn_io_rdwr |
38 | } grn_io_rw_mode; |
39 | |
40 | typedef enum { |
41 | grn_io_auto, |
42 | grn_io_manual |
43 | } grn_io_mode; |
44 | |
45 | /**** grn_io ****/ |
46 | |
47 | typedef struct _grn_io grn_io; |
48 | |
49 | typedef 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 | |
69 | typedef 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 | |
78 | typedef struct _grn_io_array_info grn_io_array_info; |
79 | |
80 | struct { |
81 | char [16]; |
82 | uint32_t ; |
83 | uint32_t ; |
84 | uint32_t ; |
85 | uint32_t ; |
86 | uint32_t ; |
87 | uint32_t ; |
88 | uint32_t ; |
89 | uint32_t ; |
90 | uint64_t ; |
91 | uint32_t ; |
92 | uint32_t ; |
93 | }; |
94 | |
95 | struct _grn_io { |
96 | char path[PATH_MAX]; |
97 | struct _grn_io_header *; |
98 | byte *; |
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 | |
113 | GRN_API grn_io *grn_io_create(grn_ctx *ctx, const char *path, |
114 | uint32_t , uint32_t segment_size, |
115 | uint32_t max_segment, grn_io_mode mode, |
116 | unsigned int flags); |
117 | grn_io *grn_io_open(grn_ctx *ctx, const char *path, grn_io_mode mode); |
118 | GRN_API grn_rc grn_io_close(grn_ctx *ctx, grn_io *io); |
119 | grn_rc grn_io_remove(grn_ctx *ctx, const char *path); |
120 | grn_rc grn_io_remove_if_exist(grn_ctx *ctx, const char *path); |
121 | grn_rc grn_io_size(grn_ctx *ctx, grn_io *io, uint64_t *size); |
122 | grn_rc grn_io_rename(grn_ctx *ctx, const char *old_name, const char *new_name); |
123 | GRN_API void *(grn_io *io); |
124 | |
125 | void *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); |
127 | grn_rc grn_io_win_unmap(grn_io_win *iw); |
128 | |
129 | typedef struct _grn_io_ja_einfo grn_io_ja_einfo; |
130 | typedef struct _grn_io_ja_ehead grn_io_ja_ehead; |
131 | |
132 | struct _grn_io_ja_einfo { |
133 | uint32_t pos; |
134 | uint32_t size; |
135 | }; |
136 | |
137 | struct _grn_io_ja_ehead { |
138 | uint32_t size; |
139 | uint32_t key; |
140 | }; |
141 | |
142 | grn_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); |
145 | grn_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 | |
149 | grn_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 | |
162 | void 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 | |
284 | uint32_t grn_io_base_seg(grn_io *io); |
285 | const char *grn_io_path(grn_io *io); |
286 | |
287 | typedef struct _grn_io_array_spec grn_io_array_spec; |
288 | |
289 | struct _grn_io_array_spec { |
290 | uint32_t w_of_element; |
291 | uint32_t max_n_segments; |
292 | }; |
293 | |
294 | struct _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 | |
303 | grn_io *grn_io_create_with_array(grn_ctx *ctx, const char *path, uint32_t , |
304 | uint32_t segment_size, grn_io_mode mode, |
305 | int n_arrays, grn_io_array_spec *array_specs); |
306 | |
307 | void *grn_io_array_at(grn_ctx *ctx, grn_io *io, uint32_t array, off_t offset, int *flags); |
308 | |
309 | void grn_io_segment_alloc(grn_ctx *ctx, grn_io *io, grn_io_array_info *ai, |
310 | uint32_t lseg, int *flags, void **p); |
311 | |
312 | GRN_API grn_rc grn_io_lock(grn_ctx *ctx, grn_io *io, int timeout); |
313 | GRN_API void grn_io_unlock(grn_io *io); |
314 | void grn_io_clear_lock(grn_io *io); |
315 | uint32_t grn_io_is_locked(grn_io *io); |
316 | grn_bool grn_io_is_corrupt(grn_ctx *ctx, grn_io *io); |
317 | size_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 | |
359 | void *grn_io_anon_map(grn_ctx *ctx, grn_io_mapinfo *mi, size_t length); |
360 | void grn_io_anon_unmap(grn_ctx *ctx, grn_io_mapinfo *mi, size_t length); |
361 | uint32_t grn_io_detect_type(grn_ctx *ctx, const char *path); |
362 | grn_rc grn_io_set_type(grn_io *io, uint32_t type); |
363 | uint32_t grn_io_get_type(grn_io *io); |
364 | |
365 | void grn_io_init_from_env(void); |
366 | |
367 | uint32_t grn_io_expire(grn_ctx *ctx, grn_io *io, int count_thresh, uint32_t limit); |
368 | |
369 | grn_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 | |