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