1 /* -*- c-basic-offset: 2 -*- */
2 /*
3   Copyright(C) 2009-2017 Brazil
4 
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License version 2.1 as published by the Free Software Foundation.
8 
9   This library is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Lesser General Public License for more details.
13 
14   You should have received a copy of the GNU Lesser General Public
15   License along with this library; if not, write to the Free Software
16   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA
17 */
18 
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 _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 
95 struct _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 
113 GRN_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);
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_header(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 header_size,
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