isomorfeus-ferret 0.14.3 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +56 -6
  3. data/ext/isomorfeus_ferret_ext/extconf.rb +19 -1
  4. data/ext/isomorfeus_ferret_ext/frb_analysis.c +0 -4
  5. data/ext/isomorfeus_ferret_ext/frb_field_info.c +65 -55
  6. data/ext/isomorfeus_ferret_ext/frb_index.c +21 -23
  7. data/ext/isomorfeus_ferret_ext/frb_lazy_doc.c +4 -0
  8. data/ext/isomorfeus_ferret_ext/frb_qparser.c +1 -6
  9. data/ext/isomorfeus_ferret_ext/frb_search.c +0 -5
  10. data/ext/isomorfeus_ferret_ext/frb_store.c +66 -4
  11. data/ext/isomorfeus_ferret_ext/frb_utils.c +0 -4
  12. data/ext/isomorfeus_ferret_ext/frt_compound_io.c +4 -4
  13. data/ext/isomorfeus_ferret_ext/frt_except.c +11 -11
  14. data/ext/isomorfeus_ferret_ext/frt_fs_store.c +62 -88
  15. data/ext/isomorfeus_ferret_ext/frt_hash.c +32 -70
  16. data/ext/isomorfeus_ferret_ext/frt_ind.c +21 -21
  17. data/ext/isomorfeus_ferret_ext/frt_ind.h +1 -1
  18. data/ext/isomorfeus_ferret_ext/frt_index.c +144 -223
  19. data/ext/isomorfeus_ferret_ext/frt_index.h +35 -58
  20. data/ext/isomorfeus_ferret_ext/frt_mdbx_store.c +691 -0
  21. data/ext/isomorfeus_ferret_ext/frt_q_parser.c +4 -4
  22. data/ext/isomorfeus_ferret_ext/frt_q_span.c +2 -2
  23. data/ext/isomorfeus_ferret_ext/frt_ram_store.c +9 -9
  24. data/ext/isomorfeus_ferret_ext/frt_search.c +0 -3
  25. data/ext/isomorfeus_ferret_ext/frt_search.h +1 -1
  26. data/ext/isomorfeus_ferret_ext/frt_sort.c +2 -2
  27. data/ext/isomorfeus_ferret_ext/frt_store.c +6 -8
  28. data/ext/isomorfeus_ferret_ext/frt_store.h +43 -21
  29. data/ext/isomorfeus_ferret_ext/frt_threading.h +0 -16
  30. data/ext/isomorfeus_ferret_ext/isomorfeus_ferret.c +0 -9
  31. data/ext/isomorfeus_ferret_ext/mdbx.c +33632 -0
  32. data/ext/isomorfeus_ferret_ext/mdbx.h +5495 -0
  33. data/ext/isomorfeus_ferret_ext/test.c +20 -18
  34. data/ext/isomorfeus_ferret_ext/test_1710.c +1 -1
  35. data/ext/isomorfeus_ferret_ext/test_fields.c +39 -39
  36. data/ext/isomorfeus_ferret_ext/test_file_deleter.c +1 -1
  37. data/ext/isomorfeus_ferret_ext/test_filter.c +1 -1
  38. data/ext/isomorfeus_ferret_ext/test_highlighter.c +1 -2
  39. data/ext/isomorfeus_ferret_ext/test_index.c +36 -36
  40. data/ext/isomorfeus_ferret_ext/test_mdbx_store.c +19 -0
  41. data/ext/isomorfeus_ferret_ext/test_q_fuzzy.c +2 -2
  42. data/ext/isomorfeus_ferret_ext/test_q_span.c +1 -1
  43. data/ext/isomorfeus_ferret_ext/test_search.c +4 -4
  44. data/ext/isomorfeus_ferret_ext/test_segments.c +1 -4
  45. data/ext/isomorfeus_ferret_ext/test_sort.c +2 -2
  46. data/ext/isomorfeus_ferret_ext/test_store.c +4 -8
  47. data/ext/isomorfeus_ferret_ext/test_term_vectors.c +6 -6
  48. data/ext/isomorfeus_ferret_ext/test_threading.c +4 -4
  49. data/ext/isomorfeus_ferret_ext/tests_all.h +2 -0
  50. data/lib/isomorfeus/ferret/version.rb +1 -1
  51. metadata +9 -5
@@ -0,0 +1,691 @@
1
+ #include "frt_store.h"
2
+ #include "frt_lang.h"
3
+ #include <time.h>
4
+ #include <sys/types.h>
5
+ #include <fcntl.h>
6
+ #include <sys/stat.h>
7
+ #include <errno.h>
8
+ #include <string.h>
9
+ #include <stdio.h>
10
+
11
+ extern void frt_micro_sleep(const int micro_seconds);
12
+
13
+ const char *dbi_name = "segmented_index";
14
+ const char *lock_s = "lock";
15
+
16
+ // helper functions
17
+
18
+ // txn
19
+
20
+ static void mdbxs_begin_txn(FrtStore *store, MDBX_txn **txn) {
21
+ int res = mdbx_txn_begin(store->dir.mdbx->env, NULL, 0, txn);
22
+ if (res != MDBX_SUCCESS) {
23
+ FRT_RAISE(FRT_IO_ERROR, "failed to begin txn, error: %i\n", res);
24
+ }
25
+ }
26
+
27
+ static void mdbxs_begin_ro_txn(FrtStore *store, MDBX_txn **txn) {
28
+ int res = mdbx_txn_begin(store->dir.mdbx->env, NULL, 0 | MDBX_RDONLY, txn);
29
+ if (res != MDBX_SUCCESS) {
30
+ FRT_RAISE(FRT_IO_ERROR, "failed to begin read only txn, error: %i\n", res);
31
+ }
32
+ }
33
+
34
+ static void mdbxs_commit_txn(MDBX_txn *txn) {
35
+ int res = mdbx_txn_commit(txn);
36
+ if (res != MDBX_SUCCESS) {
37
+ FRT_RAISE(FRT_IO_ERROR, "failed to commit txn, error: %i\n", res);
38
+ }
39
+ }
40
+
41
+ static void mdbxs_abort_txn(MDBX_txn *txn) {
42
+ int res = mdbx_txn_abort(txn);
43
+ if (res != MDBX_SUCCESS) {
44
+ FRT_RAISE(FRT_IO_ERROR, "failed to abort txn, error: %i\n", res);
45
+ }
46
+ }
47
+
48
+ // dbi
49
+
50
+ static void mdbxs_open_dbi(MDBX_txn *txn, const char *dbi_name, MDBX_dbi *dbi) {
51
+ int res = mdbx_dbi_open(txn, dbi_name, MDBX_DB_DEFAULTS | MDBX_CREATE, dbi);
52
+ if (res != MDBX_SUCCESS) {
53
+ FRT_RAISE(FRT_IO_ERROR, "failed to open dbi '%s', error: %i\n", dbi_name, res);
54
+ }
55
+ }
56
+
57
+ // cursor
58
+
59
+ static void mdbxs_open_cursor(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **cursor) {
60
+ int res = mdbx_cursor_open(txn, dbi, cursor);
61
+ if (res != MDBX_SUCCESS) {
62
+ FRT_RAISE(FRT_IO_ERROR, "failed to open cursor, error: %i\n", res);
63
+ }
64
+ }
65
+
66
+ // crud
67
+
68
+ static void mdbxs_del(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *val) {
69
+ int res = mdbx_del(txn, dbi, key, val);
70
+ if (res == MDBX_SUCCESS || res == MDBX_NOTFOUND) { return; }
71
+ FRT_RAISE(FRT_IO_ERROR, "failed to del, error: %i\n", res);
72
+ }
73
+
74
+ static void mdbxs_put(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *val) {
75
+ int res = mdbx_put(txn, dbi, key, val, 0);
76
+ if (res != MDBX_SUCCESS) {
77
+ FRT_RAISE(FRT_IO_ERROR, "failed to put, error: %i\n", res);
78
+ }
79
+ }
80
+
81
+ // store API
82
+
83
+ static void mdbxs_touch(FrtStore *store, const char *filename) {
84
+ int res = 0;
85
+ MDBX_txn *txn = NULL;
86
+ MDBX_dbi dbi;
87
+
88
+ MDBX_val key, val;
89
+ key.iov_base = (char *)filename;
90
+ key.iov_len = strlen(filename);
91
+ val.iov_base = NULL;
92
+ val.iov_len = 0;
93
+
94
+ mdbxs_begin_txn(store, &txn);
95
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
96
+ res = mdbx_get(txn, dbi, &key, &val);
97
+
98
+ if (res == MDBX_NOTFOUND) {
99
+ val.iov_base = NULL;
100
+ val.iov_len = 0;
101
+ mdbxs_put(txn, dbi, &key, &val);
102
+ mdbxs_commit_txn(txn);
103
+ } else if (res == MDBX_SUCCESS) {
104
+ mdbxs_abort_txn(txn);
105
+ } else {
106
+ mdbxs_abort_txn(txn);
107
+ FRT_RAISE(FRT_IO_ERROR, "failed to touch '%s', error: %i\n", filename, res);
108
+ }
109
+ }
110
+
111
+ static int mdbxs_exists(FrtStore *store, const char *filename) {
112
+ MDBX_txn *txn = NULL;
113
+ MDBX_dbi dbi;
114
+
115
+ MDBX_val key, val;
116
+ key.iov_base = (char *)filename;
117
+ key.iov_len = strlen(filename);
118
+ val.iov_base = NULL;
119
+ val.iov_len = 0;
120
+
121
+ mdbxs_begin_ro_txn(store, &txn);
122
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
123
+ int res = mdbx_get(txn, dbi, &key, &val);
124
+ mdbxs_abort_txn(txn);
125
+
126
+ if (res == MDBX_SUCCESS) { return true; }
127
+ return false;
128
+ }
129
+
130
+ static int mdbxs_remove(FrtStore *store, const char *filename) {
131
+ MDBX_txn *txn = NULL;
132
+ MDBX_dbi dbi;
133
+
134
+ MDBX_val key;
135
+ key.iov_base = (char *)filename;
136
+ key.iov_len = strlen(filename);
137
+
138
+ mdbxs_begin_txn(store, &txn);
139
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
140
+ mdbxs_del(txn, dbi, &key, NULL);
141
+ mdbxs_commit_txn(txn);
142
+
143
+ return 0;
144
+ }
145
+
146
+ static void mdbxs_rename(FrtStore *store, const char *from, const char *to) {
147
+ int res;
148
+ MDBX_txn *txn = NULL;
149
+ MDBX_dbi dbi;
150
+
151
+ MDBX_val from_key, to_key, val;
152
+ from_key.iov_base = (char *)from;
153
+ from_key.iov_len = strlen(from);
154
+ val.iov_base = NULL;
155
+ val.iov_len = 0;
156
+
157
+ mdbxs_begin_txn(store, &txn);
158
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
159
+ res = mdbx_get(txn, dbi, &from_key, &val);
160
+
161
+ if (res == MDBX_SUCCESS) {
162
+ to_key.iov_base = (char *)to;
163
+ to_key.iov_len = strlen(to);
164
+
165
+ mdbxs_put(txn, dbi, &to_key, &val);
166
+ mdbxs_del(txn, dbi, &from_key, NULL);
167
+ mdbxs_commit_txn(txn);
168
+ } else {
169
+ mdbxs_abort_txn(txn);
170
+ FRT_RAISE(FRT_FILE_NOT_FOUND_ERROR, "tried to open '%s' but its not accessible, error: %i", from, res);
171
+ }
172
+ }
173
+
174
+ static int mdbxs_count(FrtStore *store) {
175
+ MDBX_txn *txn = NULL;
176
+ MDBX_dbi dbi;
177
+ MDBX_stat stat;
178
+ int res = 0;
179
+ int cnt = 0;
180
+
181
+ mdbxs_begin_txn(store, &txn);
182
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
183
+ res = mdbx_dbi_stat(txn, dbi, &stat, sizeof(MDBX_stat));
184
+ cnt = stat.ms_entries;
185
+ mdbxs_abort_txn(txn);
186
+
187
+ if (res != MDBX_SUCCESS) {
188
+ FRT_RAISE(FRT_FILE_NOT_FOUND_ERROR, "failed to stat dbi, error: %i", res);
189
+ }
190
+ return cnt;
191
+ }
192
+
193
+ static void mdbxs_each(FrtStore *store, void (*func)(const char *fname, void *arg), void *arg) {
194
+ MDBX_txn *txn = NULL;
195
+ MDBX_dbi dbi;
196
+ MDBX_cursor *cursor = NULL;
197
+
198
+ MDBX_val key, val;
199
+ key.iov_base = NULL;
200
+ key.iov_len = 0;
201
+ val.iov_base = NULL;
202
+ val.iov_len = 0;
203
+
204
+ mdbxs_begin_txn(store, &txn);
205
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
206
+ mdbxs_open_cursor(txn, dbi, &cursor);
207
+
208
+ int op = MDBX_FIRST;
209
+ while(mdbx_cursor_get(cursor, &key, &val, op) == MDBX_SUCCESS) {
210
+ op = MDBX_NEXT;
211
+ func(key.iov_base, arg);
212
+ }
213
+ mdbxs_commit_txn(txn);
214
+ }
215
+
216
+ static void mdbxs_clear_locks(FrtStore *store) {
217
+ MDBX_txn *txn = NULL;
218
+ MDBX_dbi dbi;
219
+ MDBX_cursor *cursor = NULL;
220
+
221
+ MDBX_val key, val;
222
+ key.iov_base = NULL;
223
+ key.iov_len = 0;
224
+ val.iov_base = NULL;
225
+ val.iov_len = 0;
226
+
227
+ mdbxs_begin_txn(store, &txn);
228
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
229
+ mdbxs_open_cursor(txn, dbi, &cursor);
230
+
231
+ int op = MDBX_FIRST;
232
+ while(mdbx_cursor_get(cursor, &key, &val, op) == MDBX_SUCCESS) {
233
+ op = MDBX_NEXT;
234
+ mdbx_cursor_del(cursor, MDBX_ALLDUPS);
235
+ }
236
+ mdbxs_commit_txn(txn);
237
+ }
238
+
239
+ static bool mdbxs_is_locked(FrtStore *store, MDBX_val *key, MDBX_txn *txn, MDBX_dbi dbi) {
240
+ MDBX_val val;
241
+ val.iov_base = NULL;
242
+ val.iov_len = 0;
243
+
244
+ if (mdbx_get(txn, dbi, key, &val) == MDBX_SUCCESS) {
245
+ return true;
246
+ }
247
+
248
+ return false;
249
+ }
250
+
251
+ static void mdbxs_clear(FrtStore *store) {
252
+ MDBX_txn *txn = NULL;
253
+ MDBX_dbi dbi;
254
+ MDBX_cursor *cursor = NULL;
255
+
256
+ MDBX_val key, val;
257
+ key.iov_base = NULL;
258
+ key.iov_len = 0;
259
+ val.iov_base = NULL;
260
+ val.iov_len = 0;
261
+
262
+ mdbxs_begin_txn(store, &txn);
263
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
264
+ mdbxs_open_cursor(txn, dbi, &cursor);
265
+
266
+ int op = MDBX_FIRST;
267
+ while(mdbx_cursor_get(cursor, &key, &val, op) == MDBX_SUCCESS) {
268
+ op = MDBX_NEXT;
269
+ if (!mdbxs_is_locked(store, &key, txn, dbi)) {
270
+ mdbx_cursor_del(cursor, MDBX_ALLDUPS);
271
+ }
272
+ }
273
+ mdbxs_commit_txn(txn);
274
+ }
275
+
276
+ /**
277
+ * Clear all files which belong to the index. Use mdbxs_clear to clear the
278
+ * directory regardless of the files origin.
279
+ */
280
+ static void mdbxs_clear_all(FrtStore *store) {
281
+ MDBX_txn *txn = NULL;
282
+ MDBX_dbi dbi;
283
+ MDBX_cursor *cursor = NULL;
284
+
285
+ MDBX_val key, val;
286
+ key.iov_base = NULL;
287
+ key.iov_len = 0;
288
+ val.iov_base = NULL;
289
+ val.iov_len = 0;
290
+
291
+ mdbxs_begin_txn(store, &txn);
292
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
293
+ mdbxs_open_cursor(txn, dbi, &cursor);
294
+
295
+ int op = MDBX_FIRST;
296
+ while(mdbx_cursor_get(cursor, &key, &val, op) == MDBX_SUCCESS) {
297
+ op = MDBX_NEXT;
298
+ mdbx_cursor_del(cursor, MDBX_ALLDUPS);
299
+ }
300
+ mdbxs_commit_txn(txn);
301
+
302
+ mdbxs_clear_locks(store);
303
+ }
304
+
305
+ /**
306
+ * Destroy the store.
307
+ *
308
+ * @param p the store to destroy
309
+ * @rb_raise FRT_IO_ERROR if there is an error deleting the locks
310
+ */
311
+ static void mdbxs_destroy(FrtStore *store) {
312
+ FRT_TRY
313
+ if (store->dir.mdbx) {
314
+ mdbxs_clear_locks(store);
315
+ int res = mdbx_env_close(store->dir.mdbx->env);
316
+ if (res != MDBX_SUCCESS) {
317
+ fprintf(stderr, "closing env '%s' failed, error: %i\n", store->dir.mdbx->path, res);
318
+ }
319
+ free(store->dir.mdbx->path);
320
+ free(store->dir.mdbx);
321
+ store->dir.mdbx = NULL;
322
+ }
323
+ FRT_XCATCHALL
324
+ FRT_HANDLED();
325
+ FRT_XENDTRY
326
+ }
327
+
328
+ static frt_off_t mdbxs_length(FrtStore *store, const char *filename) {
329
+ frt_off_t len = 0;
330
+ MDBX_txn *txn = NULL;
331
+ MDBX_dbi dbi;
332
+
333
+ MDBX_val key, val;
334
+ key.iov_base = (char *)filename;
335
+ key.iov_len = strlen(filename);
336
+ val.iov_base = NULL;
337
+ val.iov_len = 0;
338
+
339
+ mdbxs_begin_ro_txn(store, &txn);
340
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
341
+ int res = mdbx_get(txn, dbi, &key, &val);
342
+ if (res != MDBX_SUCCESS) {
343
+ mdbxs_abort_txn(txn);
344
+ FRT_RAISE(FRT_FILE_NOT_FOUND_ERROR, "tried to open \"%s\" but it doesn't exist, error: %i", filename, res);
345
+ }
346
+ len = val.iov_len;
347
+ mdbxs_abort_txn(txn);
348
+ return len;
349
+ }
350
+
351
+ static void mdbxso_close_i(FrtOutStream *os) {
352
+ MDBX_txn *txn = NULL;
353
+ MDBX_dbi dbi;
354
+
355
+ mdbxs_begin_txn(os->store, &txn);
356
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
357
+
358
+ FrtRAMFile *rf = os->file.rf;
359
+
360
+ MDBX_val key, val;
361
+ key.iov_base = rf->name;
362
+ key.iov_len = strlen(rf->name);
363
+
364
+ val.iov_base = frt_emalloc(FRT_BUFFER_SIZE * rf->bufcnt);
365
+ val.iov_len = rf->len;
366
+
367
+ int offset = 0;
368
+ int buffer_number, buffer_offset, bytes_in_buffer, bytes_to_copy;
369
+ int remainder = rf->len;
370
+ frt_off_t start = 0;
371
+ frt_uchar *buffer;
372
+
373
+ while (remainder > 0) {
374
+ buffer_number = (int) (start / FRT_BUFFER_SIZE);
375
+ buffer_offset = start % FRT_BUFFER_SIZE;
376
+ bytes_in_buffer = FRT_BUFFER_SIZE - buffer_offset;
377
+
378
+ if (bytes_in_buffer >= remainder) {
379
+ bytes_to_copy = remainder;
380
+ } else {
381
+ bytes_to_copy = bytes_in_buffer;
382
+ }
383
+ buffer = rf->buffers[buffer_number];
384
+ memcpy(val.iov_base + offset, buffer + buffer_offset, bytes_to_copy);
385
+ offset += bytes_to_copy;
386
+ start += bytes_to_copy;
387
+ remainder -= bytes_to_copy;
388
+ }
389
+
390
+ mdbxs_put(txn, dbi, &key, &val);
391
+ mdbxs_commit_txn(txn);
392
+ free(val.iov_base);
393
+ rf_close(os->file.rf);
394
+ }
395
+
396
+ static const struct FrtOutStreamMethods MDBXS_OUT_STREAM_METHODS = {
397
+ ramo_flush_i,
398
+ ramo_seek_i,
399
+ mdbxso_close_i
400
+ };
401
+
402
+ static FrtOutStream *mdbxs_new_output(FrtStore *store, const char *filename) {
403
+ MDBX_txn *txn = NULL;
404
+ MDBX_dbi dbi;
405
+ MDBX_val key, val;
406
+ key.iov_base = (char *)filename;
407
+ key.iov_len = strlen(filename);
408
+ val.iov_base = NULL;
409
+ val.iov_len = 0;
410
+
411
+ mdbxs_begin_txn(store, &txn);
412
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
413
+ mdbxs_put(txn, dbi, &key, &val);
414
+ mdbxs_commit_txn(txn);
415
+
416
+ FrtRAMFile *rf = rf_new(filename);
417
+ FRT_REF(rf);
418
+ FrtOutStream *os = frt_os_new();
419
+ os->pointer = 0;
420
+ os->file.rf = rf;
421
+ os->m = &MDBXS_OUT_STREAM_METHODS;
422
+ os->store = store;
423
+ return os;
424
+ }
425
+
426
+ static const struct FrtInStreamMethods RAM_IN_STREAM_METHODS = {
427
+ rami_read_i,
428
+ rami_seek_i,
429
+ rami_length_i,
430
+ rami_close_i
431
+ };
432
+
433
+ static FrtInStream *mdbxs_open_input(FrtStore *store, const char *filename) {
434
+ MDBX_txn *txn = NULL;
435
+ MDBX_dbi dbi;
436
+ MDBX_val key, val;
437
+ key.iov_base = (char *)filename;
438
+ key.iov_len = strlen(filename);
439
+ val.iov_base = NULL;
440
+ val.iov_len = 0;
441
+
442
+ FrtRAMFile *rf = NULL;
443
+ FrtInStream *is;
444
+
445
+ mdbxs_begin_ro_txn(store, &txn);
446
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
447
+ if (mdbx_get(txn, dbi, &key, &val) != MDBX_SUCCESS) {
448
+ mdbxs_abort_txn(txn);
449
+ FRT_RAISE(FRT_FILE_NOT_FOUND_ERROR, "tried to open \"%s\" but it doesn't exist", filename);
450
+ }
451
+
452
+ rf = rf_new(filename);
453
+ FRT_REF(rf);
454
+
455
+ if (val.iov_len > 0) {
456
+ frt_uchar *buffer;
457
+ frt_uchar *src = val.iov_base;
458
+ int len = val.iov_len;
459
+ int buffer_number = 0;
460
+ int buffer_offset = 0;
461
+ int bytes_in_buffer = FRT_BUFFER_SIZE;
462
+ int bytes_to_copy = bytes_in_buffer < len ? bytes_in_buffer : len;
463
+ int src_offset;
464
+
465
+ rf_extend_if_necessary(rf, buffer_number);
466
+
467
+ buffer = rf->buffers[buffer_number];
468
+ memcpy(buffer + buffer_offset, src, bytes_to_copy);
469
+ src_offset = bytes_to_copy;
470
+
471
+ while (src_offset < len) {
472
+ bytes_to_copy = bytes_in_buffer < (len - src_offset) ? bytes_in_buffer : (len - src_offset);
473
+ buffer_number += 1;
474
+ rf_extend_if_necessary(rf, buffer_number);
475
+ buffer = rf->buffers[buffer_number];
476
+ memcpy(buffer, src + src_offset, bytes_to_copy);
477
+ src_offset = src_offset + bytes_to_copy;
478
+ }
479
+ rf->len = len;
480
+ }
481
+ mdbxs_abort_txn(txn);
482
+
483
+ is = frt_is_new();
484
+ is->f->file.rf = rf;
485
+ is->f->ref_cnt = 1;
486
+ is->d.pointer = 0;
487
+ is->m = &RAM_IN_STREAM_METHODS;
488
+
489
+ return is;
490
+ }
491
+
492
+ #define LOCK_OBTAIN_TIMEOUT 50
493
+
494
+ static int mdbxs_lock_obtain(FrtLock *lock) {
495
+ MDBX_txn *txn = NULL;
496
+ MDBX_dbi dbi;
497
+ mdbxs_begin_txn(lock->store, &txn);
498
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
499
+
500
+ MDBX_val key, val;
501
+ key.iov_base = lock->name;
502
+ key.iov_len = strlen(lock->name);
503
+ int trys = LOCK_OBTAIN_TIMEOUT;
504
+ bool is_locked = mdbxs_is_locked(lock->store, &key, txn, dbi);
505
+ while (is_locked && (trys > 0)) {
506
+ mdbxs_abort_txn(txn);
507
+
508
+ trys--;
509
+ /* sleep for 10 milliseconds */
510
+ frt_micro_sleep(10000);
511
+
512
+ mdbxs_begin_txn(lock->store, &txn);
513
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
514
+
515
+ is_locked = mdbxs_is_locked(lock->store, &key, txn, dbi);
516
+ }
517
+ if (is_locked) {
518
+ mdbxs_abort_txn(txn);
519
+ return false;
520
+ } else {
521
+ val.iov_base = (char *)lock_s; // could be a number to count locks
522
+ val.iov_len = 4;
523
+ mdbxs_put(txn, dbi, &key, &val);
524
+ mdbxs_commit_txn(txn);
525
+ return true;
526
+ }
527
+ }
528
+
529
+ static int mdbxs_lock_is_locked(FrtLock *lock) {
530
+ int res = 0;
531
+ MDBX_txn *txn = NULL;
532
+ MDBX_dbi dbi;
533
+
534
+ MDBX_val key;
535
+ key.iov_base = lock->name;
536
+ key.iov_len = strlen(lock->name);
537
+
538
+ mdbxs_begin_ro_txn(lock->store, &txn);
539
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
540
+ res = mdbxs_is_locked(lock->store, &key, txn, dbi);
541
+ mdbxs_abort_txn(txn);
542
+
543
+ return res;
544
+ }
545
+
546
+ static void mdbxs_lock_release(FrtLock *lock) {
547
+ MDBX_txn *txn = NULL;
548
+ MDBX_dbi dbi;
549
+
550
+ MDBX_val key;
551
+ key.iov_base = lock->name;
552
+ key.iov_len = strlen(lock->name);
553
+
554
+ mdbxs_begin_txn(lock->store, &txn);
555
+ mdbxs_open_dbi(txn, dbi_name, &dbi);
556
+ mdbxs_del(txn, dbi, &key, NULL);
557
+ mdbxs_commit_txn(txn);
558
+ }
559
+
560
+ static FrtLock *mdbxs_open_lock_i(FrtStore *store, const char *lockname) {
561
+ FrtLock *lock = FRT_ALLOC(FrtLock);
562
+ char lname[100];
563
+ snprintf(lname, 100, "%s%s.lck", FRT_LOCK_PREFIX, lockname);
564
+ lock->name = frt_estrdup(lname);
565
+ lock->store = store;
566
+ FRT_REF(store);
567
+ lock->obtain = &mdbxs_lock_obtain;
568
+ lock->release = &mdbxs_lock_release;
569
+ lock->is_locked = &mdbxs_lock_is_locked;
570
+ lock->rlock = Qnil;
571
+ return lock;
572
+ }
573
+
574
+ static void mdbxs_close_lock_i(FrtLock *lock) {
575
+ mdbxs_lock_release(lock);
576
+ frt_store_close(lock->store);
577
+ free(lock->name);
578
+ free(lock);
579
+ }
580
+
581
+ static FrtHash *mdbx_stores = NULL;
582
+
583
+ static pthread_mutex_t mdbx_stores_mutex = PTHREAD_MUTEX_INITIALIZER;
584
+
585
+ static void mdbxs_close_i(FrtStore *store) {
586
+ pthread_mutex_lock(&mdbx_stores_mutex);
587
+ if (store->dir.mdbx) {
588
+ frt_h_del(mdbx_stores, store->dir.mdbx->path);
589
+ }
590
+ pthread_mutex_unlock(&mdbx_stores_mutex);
591
+ }
592
+
593
+ static FrtStore *mdbx_store_new(const char *pathname) {
594
+ FrtStore *new_store = frt_store_new();
595
+
596
+ new_store->file_mode = S_IRUSR | S_IWUSR;
597
+ #if !defined POSH_OS_WIN32 && !defined POSH_OS_WIN64
598
+ struct stat stt;
599
+ if (!stat(pathname, &stt)) {
600
+ gid_t st_gid = stt.st_gid;
601
+ bool is_grp = (st_gid == getgid());
602
+
603
+ if (!is_grp) {
604
+ int size = getgroups(0, NULL);
605
+ gid_t list[size];
606
+
607
+ if (getgroups(size, list) != -1) {
608
+ int i = 0;
609
+ while (i < size && !(is_grp = (st_gid == list[i]))) i++;
610
+ }
611
+ }
612
+
613
+ if (is_grp) {
614
+ if (stt.st_mode & S_IWGRP) {
615
+ umask(S_IWOTH);
616
+ }
617
+ new_store->file_mode |= stt.st_mode & (S_IRGRP | S_IWGRP);
618
+ }
619
+ }
620
+ #endif
621
+
622
+ MDBX_env *env = NULL;
623
+ int res;
624
+ res = mdbx_env_create(&env);
625
+ if (res != MDBX_SUCCESS) {
626
+ FRT_RAISE(FRT_IO_ERROR, "creating env '%s' failed, error: %i\n", pathname, res);
627
+ }
628
+ res = mdbx_env_set_maxdbs(env, 2);
629
+ if (res != MDBX_SUCCESS) {
630
+ mdbx_env_close(env);
631
+ FRT_RAISE(FRT_IO_ERROR, "setting maxdbs for '%s' failed, error: %i\n", pathname, res);
632
+ }
633
+ res = mdbx_env_set_geometry(env, -1, -1, 40000000000, 4*1024*1024, 4*1024*1024, MDBX_MAX_PAGESIZE);
634
+ if (res != MDBX_SUCCESS) {
635
+ mdbx_env_close(env);
636
+ FRT_RAISE(FRT_IO_ERROR, "setting geometrye for '%s' failed, error: %i\n", pathname, res);
637
+ }
638
+ res = mdbx_env_open(env, pathname, MDBX_ENV_DEFAULTS, new_store->file_mode);
639
+ if (res != MDBX_SUCCESS) {
640
+ mdbx_env_close(env);
641
+ if (res > 0) {
642
+ FRT_RAISE(FRT_IO_ERROR, "opening env '%s' failed, error: %s\n", pathname, strerror(res));
643
+ } else {
644
+ FRT_RAISE(FRT_IO_ERROR, "opening env '%s' failed, error: %i\n", pathname, res);
645
+ }
646
+ }
647
+ MDBXInfo *mdbx = FRT_ALLOC(MDBXInfo);
648
+ mdbx->env = env;
649
+ mdbx->path = frt_estrdup(pathname);
650
+
651
+ new_store->dir.mdbx = mdbx;
652
+ new_store->touch = &mdbxs_touch;
653
+ new_store->exists = &mdbxs_exists;
654
+ new_store->remove = &mdbxs_remove;
655
+ new_store->rename = &mdbxs_rename;
656
+ new_store->count = &mdbxs_count;
657
+ new_store->close_i = &mdbxs_close_i;
658
+ new_store->clear = &mdbxs_clear;
659
+ new_store->clear_all = &mdbxs_clear_all;
660
+ new_store->clear_locks = &mdbxs_clear_locks;
661
+ new_store->length = &mdbxs_length;
662
+ new_store->each = &mdbxs_each;
663
+ new_store->new_output = &mdbxs_new_output;
664
+ new_store->open_input = &mdbxs_open_input;
665
+ new_store->open_lock_i = &mdbxs_open_lock_i;
666
+ new_store->close_lock_i = &mdbxs_close_lock_i;
667
+ return new_store;
668
+ }
669
+
670
+ FrtStore *frt_open_mdbx_store(const char *pathname) {
671
+ FrtStore *store = NULL;
672
+
673
+ if (!mdbx_stores) {
674
+ mdbx_stores = frt_h_new_str(free, (frt_free_ft)mdbxs_destroy);
675
+ frt_register_for_cleanup(mdbx_stores, (frt_free_ft)frt_h_destroy);
676
+ }
677
+
678
+ pthread_mutex_lock(&mdbx_stores_mutex);
679
+
680
+ store = (FrtStore *)frt_h_get(mdbx_stores, pathname);
681
+ if (store) {
682
+ FRT_REF(store);
683
+ } else {
684
+ store = mdbx_store_new(pathname);
685
+ frt_h_set(mdbx_stores, frt_estrdup(pathname), store);
686
+ }
687
+
688
+ pthread_mutex_unlock(&mdbx_stores_mutex);
689
+
690
+ return store;
691
+ }
@@ -2115,7 +2115,7 @@ static int yyerror(FrtQParser *qp, rb_encoding *encoding, char const *msg)
2115
2115
  if (qp->clean_str) {
2116
2116
  free(qp->qstr);
2117
2117
  }
2118
- frt_mutex_unlock(&qp->mutex);
2118
+ pthread_mutex_unlock(&qp->mutex);
2119
2119
  snprintf(frt_xmsg_buffer, FRT_XMSG_BUFFER_SIZE,
2120
2120
  "couldn't parse query ``%s''. Error message "
2121
2121
  " was %s", buf, (char *)msg);
@@ -2806,7 +2806,7 @@ FrtQParser *frt_qp_init(FrtQParser *self, FrtAnalyzer *analyzer) {
2806
2806
  self->buf_index = 0;
2807
2807
  self->dynbuf = NULL;
2808
2808
  self->non_tokenizer = frt_non_tokenizer_new();
2809
- frt_mutex_init(&self->mutex, NULL);
2809
+ pthread_mutex_init(&self->mutex, NULL);
2810
2810
  return self;
2811
2811
  }
2812
2812
 
@@ -2974,7 +2974,7 @@ FrtQuery *qp_parse(FrtQParser *self, char *query_string, rb_encoding *encoding)
2974
2974
  char *qstr;
2975
2975
  unsigned char *dp_start = NULL;
2976
2976
 
2977
- frt_mutex_lock(&self->mutex);
2977
+ pthread_mutex_lock(&self->mutex);
2978
2978
  /* if qp->fields_top->next is not NULL we have a left over field-stack
2979
2979
  * object that was not popped during the last query parse */
2980
2980
  assert(NULL == self->fields_top->next);
@@ -3025,6 +3025,6 @@ FrtQuery *qp_parse(FrtQParser *self, char *query_string, rb_encoding *encoding)
3025
3025
  if (dp_start)
3026
3026
  free(dp_start);
3027
3027
 
3028
- frt_mutex_unlock(&self->mutex);
3028
+ pthread_mutex_unlock(&self->mutex);
3029
3029
  return result;
3030
3030
  }