kyotocabinet-ruby-reanimated 1.32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/extconf.rb +31 -0
  3. data/kyotocabinet.cc +4178 -0
  4. metadata +51 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 81dfa0ae4397b351d6f293cb2153df9fc5127df8
4
+ data.tar.gz: 9c69ed31a63631fc335f7bb0a2e50d0160b613c8
5
+ SHA512:
6
+ metadata.gz: 9b04208cf13779c6910f1db229eb8e3b107fa757eaaafa36d9f35147e12addd4315143c950258e763fa9f4a9c40ff17b15acfdf2a6d99632a8443eb92a0c743e
7
+ data.tar.gz: 20608f5b3ef02210d68982c63cf27537fd2d1c383c10a49a671131c9dfef9b794cb2aa13d3fd8b45567d2f00a62d855a1e7c571b03251528e1f00d69afc966f0
@@ -0,0 +1,31 @@
1
+ require "mkmf"
2
+
3
+ File::unlink("Makefile") if (File::exist?("Makefile"))
4
+ dir_config('kyotocabinet')
5
+
6
+ home = ENV["HOME"]
7
+ ENV["PATH"] = ENV["PATH"] + ":/usr/local/bin:$home/bin:."
8
+ kccflags = `kcutilmgr conf -i 2>/dev/null`.chomp
9
+ kcldflags = `kcutilmgr conf -l 2>/dev/null`.chomp
10
+ kcldflags = kcldflags.gsub(/-l[\S]+/, "").strip
11
+ kclibs = `kcutilmgr conf -l 2>/dev/null`.chomp
12
+ kclibs = kclibs.gsub(/-L[\S]+/, "").strip
13
+
14
+ kccflags = "-I/usr/local/include" if(kccflags.length < 1)
15
+ kcldflags = "-L/usr/local/lib" if(kcldflags.length < 1)
16
+ kclibs = "-lkyotocabinet -lz -lstdc++ -lrt -lpthread -lm -lc" if(kclibs.length < 1)
17
+
18
+ RbConfig::CONFIG['CPP'] = "g++ -E"
19
+ $CFLAGS = "-I. #{kccflags} -Wall #{$CFLAGS} -O2"
20
+ $LDFLAGS = "#{$LDFLAGS} -L. #{kcldflags}"
21
+ $libs = "#{$libs} #{kclibs}"
22
+
23
+ printf("setting variables ...\n")
24
+ printf(" \$CFLAGS = %s\n", $CFLAGS)
25
+ printf(" \$LDFLAGS = %s\n", $LDFLAGS)
26
+ printf(" \$libs = %s\n", $libs)
27
+
28
+ if have_header('kccommon.h')
29
+ have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h')
30
+ create_makefile('kyotocabinet')
31
+ end
@@ -0,0 +1,4178 @@
1
+ /*************************************************************************************************
2
+ * Ruby binding of Kyoto Cabinet
3
+ * Copyright (C) 2009-2010 FAL Labs
4
+ * This file is part of Kyoto Cabinet.
5
+ * This program is free software: you can redistribute it and/or modify it under the terms of
6
+ * the GNU General Public License as published by the Free Software Foundation, either version
7
+ * 3 of the License, or any later version.
8
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
+ * See the GNU General Public License for more details.
11
+ * You should have received a copy of the GNU General Public License along with this program.
12
+ * If not, see <http://www.gnu.org/licenses/>.
13
+ *************************************************************************************************/
14
+
15
+
16
+ #include <kcpolydb.h>
17
+
18
+ namespace kc = kyotocabinet;
19
+
20
+ extern "C" {
21
+
22
+ #include <ruby.h>
23
+ #ifdef HAVE_RUBY_THREAD_H
24
+ #include <ruby/thread.h>
25
+ #endif
26
+
27
+ #if RUBY_VM >= 1
28
+ #define _KC_YARV_
29
+ #endif
30
+
31
+
32
+ // precedent type declaration
33
+ class CursorBurrow;
34
+ struct SoftCursor;
35
+ class SoftVisitor;
36
+ class SoftBlockVisitor;
37
+ class SoftEachVisitor;
38
+ class SoftEachKeyVisitor;
39
+ class SoftEachValueVisitor;
40
+ class SoftFileProcessor;
41
+ class SoftBlockFileProcessor;
42
+ class NativeFunction;
43
+ typedef std::map<std::string, std::string> StringMap;
44
+ typedef std::vector<std::string> StringVector;
45
+ typedef VALUE (*METHOD)(...);
46
+
47
+
48
+ // function prototypes
49
+ void Init_kyotocabinet();
50
+ static VALUE StringValueEx(VALUE vobj);
51
+ static int64_t vatoi(VALUE vobj);
52
+ static double vatof(VALUE vobj);
53
+ static VALUE rb_str_new_ex(VALUE vdb, const char* ptr, size_t size);
54
+ static VALUE rb_str_new_ex2(VALUE vdb, const char* str);
55
+ static VALUE findclass(const char* name);
56
+ static VALUE findclass_impl(VALUE args);
57
+ static VALUE maptovhash(VALUE vdb, const StringMap* map);
58
+ static VALUE vectortovarray(VALUE vdb, const StringVector* vec);
59
+ static void define_module();
60
+ static VALUE kc_conv_str(VALUE vself, VALUE vstr);
61
+ static VALUE kc_atoi(VALUE vself, VALUE vstr);
62
+ static VALUE kc_atoix(VALUE vself, VALUE vstr);
63
+ static VALUE kc_atof(VALUE vself, VALUE vstr);
64
+ static VALUE kc_hash_murmur(VALUE vself, VALUE vstr);
65
+ static VALUE kc_hash_fnv(VALUE vself, VALUE vstr);
66
+ static VALUE kc_levdist(int argc, VALUE* argv, VALUE vself);
67
+ static void threadyield();
68
+ static void define_err();
69
+ static void err_define_child(const char* name, uint32_t code);
70
+ static VALUE err_initialize(int argc, VALUE* argv, VALUE vself);
71
+ static VALUE err_set(VALUE vself, VALUE vcode, VALUE vmessage);
72
+ static VALUE err_code(VALUE vself);
73
+ static VALUE err_name(VALUE vself);
74
+ static VALUE err_message(VALUE vself);
75
+ static VALUE err_to_s(VALUE vself);
76
+ static VALUE err_inspect(VALUE vself);
77
+ static VALUE err_op_eq(VALUE vself, VALUE vright);
78
+ static VALUE err_op_ne(VALUE vself, VALUE vright);
79
+ static void define_vis();
80
+ static VALUE vis_magic_initialize(VALUE vself, VALUE vnum);
81
+ static VALUE vis_visit_full(VALUE vself, VALUE vkey, VALUE vvalue);
82
+ static VALUE vis_visit_empty(VALUE vself, VALUE vkey);
83
+ static void define_fproc();
84
+ static VALUE fproc_process(VALUE vself, VALUE vpath);
85
+ static void define_cur();
86
+ static VALUE cur_new(VALUE cls);
87
+ static void cur_del(void* ptr);
88
+ static VALUE cur_initialize(VALUE vself, VALUE vdb);
89
+ static VALUE cur_disable(VALUE vself);
90
+ static VALUE cur_accept(int argc, VALUE* argv, VALUE vself);
91
+ static VALUE cur_set_value(int argc, VALUE* argv, VALUE vself);
92
+ static VALUE cur_remove(VALUE vself);
93
+ static VALUE cur_get_key(int argc, VALUE* argv, VALUE vself);
94
+ static VALUE cur_get_value(int argc, VALUE* argv, VALUE vself);
95
+ static VALUE cur_get(int argc, VALUE* argv, VALUE vself);
96
+ static VALUE cur_seize(VALUE vself);
97
+ static VALUE cur_jump(int argc, VALUE* argv, VALUE vself);
98
+ static VALUE cur_jump_back(int argc, VALUE* argv, VALUE vself);
99
+ static VALUE cur_step(VALUE vself);
100
+ static VALUE cur_step_back(VALUE vself);
101
+ static VALUE cur_db(VALUE vself);
102
+ static VALUE cur_error(VALUE vself);
103
+ static VALUE cur_to_s(VALUE vself);
104
+ static VALUE cur_inspect(VALUE vself);
105
+ static void define_db();
106
+ static VALUE db_new(VALUE cls);
107
+ static void db_del(void* ptr);
108
+ static void db_raise(VALUE vself);
109
+ static VALUE db_initialize(int argc, VALUE* argv, VALUE vself);
110
+ static VALUE db_error(VALUE vself);
111
+ static VALUE db_open(int argc, VALUE* argv, VALUE vself);
112
+ static VALUE db_close(VALUE vself);
113
+ static VALUE db_accept(int argc, VALUE* argv, VALUE vself);
114
+ static VALUE db_accept_bulk(int argc, VALUE* argv, VALUE vself);
115
+ static VALUE db_iterate(int argc, VALUE* argv, VALUE vself);
116
+ static VALUE db_set(VALUE vself, VALUE vkey, VALUE vvalue);
117
+ static VALUE db_add(VALUE vself, VALUE vkey, VALUE vvalue);
118
+ static VALUE db_replace(VALUE vself, VALUE vkey, VALUE vvalue);
119
+ static VALUE db_append(VALUE vself, VALUE vkey, VALUE vvalue);
120
+ static VALUE db_increment(int argc, VALUE* argv, VALUE vself);
121
+ static VALUE db_increment_double(int argc, VALUE* argv, VALUE vself);
122
+ static VALUE db_cas(VALUE vself, VALUE vkey, VALUE voval, VALUE vnval);
123
+ static VALUE db_remove(VALUE vself, VALUE vkey);
124
+ static VALUE db_get(VALUE vself, VALUE vkey);
125
+ static VALUE db_check(VALUE vself, VALUE vkey);
126
+ static VALUE db_seize(VALUE vself, VALUE vkey);
127
+ static VALUE db_set_bulk(int argc, VALUE* argv, VALUE vself);
128
+ static VALUE db_remove_bulk(int argc, VALUE* argv, VALUE vself);
129
+ static VALUE db_get_bulk(int argc, VALUE* argv, VALUE vself);
130
+ static VALUE db_clear(VALUE vself);
131
+ static VALUE db_synchronize(int argc, VALUE* argv, VALUE vself);
132
+ static VALUE db_occupy(int argc, VALUE* argv, VALUE vself);
133
+ static VALUE db_copy(VALUE vself, VALUE vdest);
134
+ static VALUE db_begin_transaction(int argc, VALUE* argv, VALUE vself);
135
+ static VALUE db_end_transaction(int argc, VALUE* argv, VALUE vself);
136
+ static VALUE db_transaction(int argc, VALUE* argv, VALUE vself);
137
+ static VALUE db_transaction_body(VALUE args);
138
+ static VALUE db_transaction_ensure(VALUE args);
139
+ static VALUE db_dump_snapshot(VALUE vself, VALUE vdest);
140
+ static VALUE db_load_snapshot(VALUE vself, VALUE vsrc);
141
+ static VALUE db_count(VALUE vself);
142
+ static VALUE db_size(VALUE vself);
143
+ static VALUE db_path(VALUE vself);
144
+ static VALUE db_status(VALUE vself);
145
+ static VALUE db_match_prefix(int argc, VALUE* argv, VALUE vself);
146
+ static VALUE db_match_regex(int argc, VALUE* argv, VALUE vself);
147
+ static VALUE db_match_similar(int argc, VALUE* argv, VALUE vself);
148
+ static VALUE db_merge(int argc, VALUE* argv, VALUE vself);
149
+ static VALUE db_cursor(VALUE vself);
150
+ static VALUE db_cursor_process(VALUE vself);
151
+ static VALUE db_cursor_process_body(VALUE vargs);
152
+ static VALUE db_cursor_process_ensure(VALUE vargs);
153
+ static VALUE db_tune_exception_rule(VALUE vself, VALUE vcodes);
154
+ static VALUE db_tune_encoding(VALUE vself, VALUE vencname);
155
+ static VALUE db_tune_encoding_impl(VALUE args);
156
+ static VALUE db_to_s(VALUE vself);
157
+ static VALUE db_inspect(VALUE vself);
158
+ static VALUE db_shift(VALUE vself);
159
+ static char* db_shift_impl(kc::PolyDB* db, size_t* ksp, const char** vbp, size_t* vsp);
160
+ static VALUE db_each(VALUE vself);
161
+ static VALUE db_each_key(VALUE vself);
162
+ static VALUE db_each_value(VALUE vself);
163
+ static VALUE db_process(int argc, VALUE* argv, VALUE vself);
164
+ static VALUE db_process_body(VALUE args);
165
+ static VALUE db_process_ensure(VALUE args);
166
+
167
+
168
+ // global variables
169
+ const int32_t VISMAGICNOP = kc::INT32MAX / 4 + 0;
170
+ const int32_t VISMAGICREMOVE = kc::INT32MAX / 4 + 1;
171
+ VALUE mod_kc;
172
+ VALUE cls_ex;
173
+ VALUE cls_str;
174
+ VALUE cls_enc;
175
+ VALUE cls_th;
176
+ VALUE cls_mtx;
177
+ VALUE cls_err;
178
+ VALUE cls_err_children[(int)kc::PolyDB::Error::MISC+1];
179
+ VALUE cls_vis;
180
+ VALUE cls_vis_magic;
181
+ VALUE cls_fproc;
182
+ VALUE cls_cur;
183
+ VALUE cls_db;
184
+ ID id_str_force_encoding;
185
+ ID id_enc_find;
186
+ ID id_th_pass;
187
+ ID id_mtx_lock;
188
+ ID id_mtx_unlock;
189
+ ID id_obj_to_str;
190
+ ID id_obj_to_s;
191
+ ID id_hash_keys;
192
+ ID id_err_code;
193
+ ID id_err_message;
194
+ ID id_vis_magic;
195
+ ID id_vis_nop;
196
+ ID id_vis_remove;
197
+ ID id_vis_visit_full;
198
+ ID id_vis_visit_empty;
199
+ ID id_fproc_process;
200
+ ID id_cur_db;
201
+ ID id_cur_disable;
202
+ ID id_db_error;
203
+ ID id_db_open;
204
+ ID id_db_close;
205
+ ID id_db_begin_transaction;
206
+ ID id_db_end_transaction;
207
+ ID id_db_exbits;
208
+ ID id_db_mutex;
209
+ ID id_db_enc;
210
+
211
+
212
+ /**
213
+ * Generic options.
214
+ */
215
+ enum GenericOption {
216
+ GEXCEPTIONAL = 1 << 0,
217
+ GCONCURRENT = 1 << 1
218
+ };
219
+
220
+
221
+ /**
222
+ * Burrow of cursors no longer in use.
223
+ */
224
+ class CursorBurrow {
225
+ private:
226
+ typedef std::vector<kc::PolyDB::Cursor*> CursorList;
227
+ public:
228
+ explicit CursorBurrow() : dcurs_() {}
229
+ ~CursorBurrow() {
230
+ sweap();
231
+ }
232
+ void sweap() {
233
+ if (dcurs_.size() > 0) {
234
+ CursorList::iterator dit = dcurs_.begin();
235
+ CursorList::iterator ditend = dcurs_.end();
236
+ while (dit != ditend) {
237
+ kc::PolyDB::Cursor* cur = *dit;
238
+ delete cur;
239
+ dit++;
240
+ }
241
+ dcurs_.clear();
242
+ }
243
+ }
244
+ void deposit(kc::PolyDB::Cursor* cur) {
245
+ dcurs_.push_back(cur);
246
+ }
247
+ private:
248
+ CursorList dcurs_;
249
+ } g_curbur;
250
+
251
+
252
+ /**
253
+ * Wrapper of a cursor.
254
+ */
255
+ struct SoftCursor {
256
+ kc::PolyDB::Cursor* cur_;
257
+ SoftCursor() : cur_(NULL) {}
258
+ ~SoftCursor() {
259
+ if (cur_) g_curbur.deposit(cur_);
260
+ }
261
+ };
262
+
263
+
264
+ /**
265
+ * Wrapper of a visitor.
266
+ */
267
+ class SoftVisitor : public kc::PolyDB::Visitor {
268
+ public:
269
+ explicit SoftVisitor(VALUE vdb, VALUE vvisitor, bool writable) :
270
+ vdb_(vdb), vvisitor_(vvisitor), writable_(writable), emsg_(NULL) {}
271
+ const char* emsg() {
272
+ return emsg_;
273
+ }
274
+ private:
275
+ const char* visit_full(const char* kbuf, size_t ksiz,
276
+ const char* vbuf, size_t vsiz, size_t* sp) {
277
+ volatile VALUE vkey = rb_str_new_ex(vdb_, kbuf, ksiz);
278
+ volatile VALUE vvalue = rb_str_new_ex(vdb_, vbuf, vsiz);
279
+ volatile VALUE args = rb_ary_new3(3, vvisitor_, vkey, vvalue);
280
+ int result = 0;
281
+ volatile VALUE vrv = rb_protect(visit_full_impl, args, &result);
282
+ const char* rv;
283
+ if (result) {
284
+ emsg_ = "exception occurred during call back function";
285
+ rv = NOP;
286
+ } else if (rb_obj_is_kind_of(vrv, cls_vis_magic)) {
287
+ volatile VALUE vmagic = rb_ivar_get(vrv, id_vis_magic);
288
+ int32_t num = NUM2INT(vmagic);
289
+ if (num == VISMAGICREMOVE) {
290
+ if (writable_) {
291
+ rv = kc::PolyDB::Visitor::REMOVE;
292
+ } else {
293
+ emsg_ = "confliction with the read-only parameter";
294
+ rv = NOP;
295
+ }
296
+ } else {
297
+ rv = kc::PolyDB::Visitor::NOP;
298
+ }
299
+ } else if (vrv == Qnil || vrv == Qfalse) {
300
+ rv = NOP;
301
+ } else if (!writable_) {
302
+ emsg_ = "confliction with the read-only parameter";
303
+ rv = NOP;
304
+ } else {
305
+ vrv = StringValueEx(vrv);
306
+ rv = RSTRING_PTR(vrv);
307
+ *sp = RSTRING_LEN(vrv);
308
+ }
309
+ return rv;
310
+ }
311
+ const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
312
+ volatile VALUE vkey = rb_str_new_ex(vdb_, kbuf, ksiz);
313
+ volatile VALUE args = rb_ary_new3(2, vvisitor_, vkey);
314
+ int result = 0;
315
+ volatile VALUE vrv = rb_protect(visit_empty_impl, args, &result);
316
+ const char* rv;
317
+ if (result) {
318
+ emsg_ = "exception occurred during call back function";
319
+ rv = NOP;
320
+ } else if (rb_obj_is_kind_of(vrv, cls_vis_magic)) {
321
+ volatile VALUE vmagic = rb_ivar_get(vrv, id_vis_magic);
322
+ int32_t num = NUM2INT(vmagic);
323
+ if (num == VISMAGICREMOVE) {
324
+ if (writable_) {
325
+ rv = kc::PolyDB::Visitor::REMOVE;
326
+ } else {
327
+ emsg_ = "confliction with the read-only parameter";
328
+ rv = NOP;
329
+ }
330
+ } else {
331
+ rv = kc::PolyDB::Visitor::NOP;
332
+ }
333
+ } else if (vrv == Qnil || vrv == Qfalse) {
334
+ rv = NOP;
335
+ } else if (!writable_) {
336
+ emsg_ = "confliction with the read-only parameter";
337
+ rv = NOP;
338
+ } else {
339
+ vrv = StringValueEx(vrv);
340
+ rv = RSTRING_PTR(vrv);
341
+ *sp = RSTRING_LEN(vrv);
342
+ }
343
+ return rv;
344
+ }
345
+ static VALUE visit_full_impl(VALUE args) {
346
+ volatile VALUE vvisitor = rb_ary_shift(args);
347
+ volatile VALUE vkey = rb_ary_shift(args);
348
+ volatile VALUE vvalue = rb_ary_shift(args);
349
+ return rb_funcall(vvisitor, id_vis_visit_full, 2, vkey, vvalue);
350
+ }
351
+ static VALUE visit_empty_impl(VALUE args) {
352
+ volatile VALUE vvisitor = rb_ary_shift(args);
353
+ volatile VALUE vkey = rb_ary_shift(args);
354
+ return rb_funcall(vvisitor, id_vis_visit_empty, 1, vkey);
355
+ }
356
+ volatile VALUE vdb_;
357
+ volatile VALUE vvisitor_;
358
+ bool writable_;
359
+ const char* emsg_;
360
+ };
361
+
362
+
363
+ /**
364
+ * Wrapper of a visitor of the block paramter.
365
+ */
366
+ class SoftBlockVisitor : public kc::PolyDB::Visitor {
367
+ public:
368
+ explicit SoftBlockVisitor(VALUE vdb, bool writable) :
369
+ vdb_(vdb), writable_(writable), emsg_(NULL) {}
370
+ const char* emsg() {
371
+ return emsg_;
372
+ }
373
+ private:
374
+ const char* visit_full(const char* kbuf, size_t ksiz,
375
+ const char* vbuf, size_t vsiz, size_t* sp) {
376
+ volatile VALUE vkey = rb_str_new_ex(vdb_, kbuf, ksiz);
377
+ volatile VALUE vvalue = rb_str_new_ex(vdb_, vbuf, vsiz);
378
+ volatile VALUE args = rb_ary_new3(2, vkey, vvalue);
379
+ int result = 0;
380
+ volatile VALUE vrv = rb_protect(visit_impl, args, &result);
381
+ const char* rv;
382
+ if (result) {
383
+ emsg_ = "exception occurred during call back function";
384
+ rv = NOP;
385
+ } else if (rb_obj_is_kind_of(vrv, cls_vis_magic)) {
386
+ volatile VALUE vmagic = rb_ivar_get(vrv, id_vis_magic);
387
+ int32_t num = NUM2INT(vmagic);
388
+ if (num == VISMAGICREMOVE) {
389
+ if (writable_) {
390
+ rv = kc::PolyDB::Visitor::REMOVE;
391
+ } else {
392
+ emsg_ = "confliction with the read-only parameter";
393
+ rv = NOP;
394
+ }
395
+ } else {
396
+ rv = kc::PolyDB::Visitor::NOP;
397
+ }
398
+ } else if (vrv == Qnil || vrv == Qfalse) {
399
+ rv = NOP;
400
+ } else if (!writable_) {
401
+ emsg_ = "confliction with the read-only parameter";
402
+ rv = NOP;
403
+ } else {
404
+ vrv = StringValueEx(vrv);
405
+ rv = RSTRING_PTR(vrv);
406
+ *sp = RSTRING_LEN(vrv);
407
+ }
408
+ return rv;
409
+ }
410
+ const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
411
+ volatile VALUE vkey = rb_str_new_ex(vdb_, kbuf, ksiz);
412
+ volatile VALUE args = rb_ary_new3(2, vkey, Qnil);
413
+ int result = 0;
414
+ volatile VALUE vrv = rb_protect(visit_impl, args, &result);
415
+ const char* rv;
416
+ if (result) {
417
+ emsg_ = "exception occurred during call back function";
418
+ rv = NOP;
419
+ } else if (rb_obj_is_kind_of(vrv, cls_vis_magic)) {
420
+ volatile VALUE vmagic = rb_ivar_get(vrv, id_vis_magic);
421
+ int32_t num = NUM2INT(vmagic);
422
+ if (num == VISMAGICREMOVE) {
423
+ if (writable_) {
424
+ rv = kc::PolyDB::Visitor::REMOVE;
425
+ } else {
426
+ emsg_ = "confliction with the read-only parameter";
427
+ rv = NOP;
428
+ }
429
+ } else {
430
+ rv = kc::PolyDB::Visitor::NOP;
431
+ }
432
+ } else if (vrv == Qnil || vrv == Qfalse) {
433
+ rv = NOP;
434
+ } else if (!writable_) {
435
+ emsg_ = "confliction with the read-only parameter";
436
+ rv = NOP;
437
+ } else {
438
+ vrv = StringValueEx(vrv);
439
+ rv = RSTRING_PTR(vrv);
440
+ *sp = RSTRING_LEN(vrv);
441
+ }
442
+ return rv;
443
+ }
444
+ static VALUE visit_impl(VALUE args) {
445
+ return rb_yield(args);
446
+ }
447
+ volatile VALUE vdb_;
448
+ bool writable_;
449
+ const char* emsg_;
450
+ };
451
+
452
+
453
+ /**
454
+ * Wrapper of a visitor for the each method.
455
+ */
456
+ class SoftEachVisitor : public kc::PolyDB::Visitor {
457
+ public:
458
+ explicit SoftEachVisitor(VALUE vdb) : vdb_(vdb), emsg_(NULL) {}
459
+ const char* emsg() {
460
+ return emsg_;
461
+ }
462
+ private:
463
+ const char* visit_full(const char* kbuf, size_t ksiz,
464
+ const char* vbuf, size_t vsiz, size_t* sp) {
465
+ volatile VALUE vkey = rb_str_new_ex(vdb_, kbuf, ksiz);
466
+ volatile VALUE vvalue = rb_str_new_ex(vdb_, vbuf, vsiz);
467
+ volatile VALUE args = rb_ary_new3(2, vkey, vvalue);
468
+ int result = 0;
469
+ rb_protect(visit_full_impl, args, &result);
470
+ if (result) emsg_ = "exception occurred during call back function";
471
+ return NOP;
472
+ }
473
+ static VALUE visit_full_impl(VALUE args) {
474
+ return rb_yield(args);
475
+ }
476
+ volatile VALUE vdb_;
477
+ const char* emsg_;
478
+ };
479
+
480
+
481
+ /**
482
+ * Wrapper of a visitor for the each_key method.
483
+ */
484
+ class SoftEachKeyVisitor : public kc::PolyDB::Visitor {
485
+ public:
486
+ explicit SoftEachKeyVisitor(VALUE vdb) : vdb_(vdb), emsg_(NULL) {}
487
+ const char* emsg() {
488
+ return emsg_;
489
+ }
490
+ private:
491
+ const char* visit_full(const char* kbuf, size_t ksiz,
492
+ const char* vbuf, size_t vsiz, size_t* sp) {
493
+ volatile VALUE vkey = rb_str_new_ex(vdb_, kbuf, ksiz);
494
+ volatile VALUE args = rb_ary_new3(1, vkey);
495
+ int result = 0;
496
+ rb_protect(visit_full_impl, args, &result);
497
+ if (result) emsg_ = "exception occurred during call back function";
498
+ return NOP;
499
+ }
500
+ static VALUE visit_full_impl(VALUE args) {
501
+ return rb_yield(args);
502
+ }
503
+ volatile VALUE vdb_;
504
+ const char* emsg_;
505
+ };
506
+
507
+
508
+ /**
509
+ * Wrapper of a visitor for the each_value method.
510
+ */
511
+ class SoftEachValueVisitor : public kc::PolyDB::Visitor {
512
+ public:
513
+ explicit SoftEachValueVisitor(VALUE vdb) : vdb_(vdb), emsg_(NULL) {}
514
+ const char* emsg() {
515
+ return emsg_;
516
+ }
517
+ private:
518
+ const char* visit_full(const char* kbuf, size_t ksiz,
519
+ const char* vbuf, size_t vsiz, size_t* sp) {
520
+ volatile VALUE vvalue = rb_str_new_ex(vdb_, vbuf, vsiz);
521
+ volatile VALUE args = rb_ary_new3(1, vvalue);
522
+ int result = 0;
523
+ rb_protect(visit_full_impl, args, &result);
524
+ if (result) emsg_ = "exception occurred during call back function";
525
+ return NOP;
526
+ }
527
+ static VALUE visit_full_impl(VALUE args) {
528
+ return rb_yield(args);
529
+ }
530
+ volatile VALUE vdb_;
531
+ const char* emsg_;
532
+ };
533
+
534
+
535
+ /**
536
+ * Wrapper of a file processor.
537
+ */
538
+ class SoftFileProcessor : public kc::PolyDB::FileProcessor {
539
+ public:
540
+ explicit SoftFileProcessor(VALUE vdb, VALUE vproc) : vdb_(vdb), vproc_(vproc), emsg_(NULL) {}
541
+ const char* emsg() {
542
+ return emsg_;
543
+ }
544
+ private:
545
+ bool process(const std::string& path, int64_t count, int64_t size) {
546
+ volatile VALUE vpath = rb_str_new_ex2(vdb_, path.c_str());
547
+ volatile VALUE vcount = LL2NUM(count);
548
+ volatile VALUE vsize = LL2NUM(size);
549
+ volatile VALUE args = rb_ary_new3(4, vproc_, vpath, vcount, vsize);
550
+ int result = 0;
551
+ volatile VALUE vrv = rb_protect(process_impl, args, &result);
552
+ if (result) emsg_ = "exception occurred during call back function";
553
+ return !result && vrv != Qnil && vrv != Qfalse;
554
+ }
555
+ static VALUE process_impl(VALUE args) {
556
+ volatile VALUE vproc = rb_ary_shift(args);
557
+ volatile VALUE vpath = rb_ary_shift(args);
558
+ volatile VALUE vcount = rb_ary_shift(args);
559
+ volatile VALUE vsize = rb_ary_shift(args);
560
+ return rb_funcall(vproc, id_fproc_process, 3, vpath, vcount, vsize);
561
+ }
562
+ volatile VALUE vdb_;
563
+ volatile VALUE vproc_;
564
+ const char* emsg_;
565
+ };
566
+
567
+
568
+ /**
569
+ * Wrapper of a file processor of the block parameter.
570
+ */
571
+ class SoftBlockFileProcessor : public kc::PolyDB::FileProcessor {
572
+ public:
573
+ explicit SoftBlockFileProcessor(VALUE vdb) : vdb_(vdb), emsg_(NULL) {}
574
+ const char* emsg() {
575
+ return emsg_;
576
+ }
577
+ private:
578
+ bool process(const std::string& path, int64_t count, int64_t size) {
579
+ volatile VALUE vpath = rb_str_new_ex2(vdb_, path.c_str());
580
+ volatile VALUE vcount = LL2NUM(count);
581
+ volatile VALUE vsize = LL2NUM(size);
582
+ volatile VALUE args = rb_ary_new3(3, vpath, vcount, vsize);
583
+ int result = 0;
584
+ volatile VALUE vrv = rb_protect(process_impl, args, &result);
585
+ if (result) emsg_ = "exception occurred during call back function";
586
+ return !result && vrv != Qnil && vrv != Qfalse;
587
+ }
588
+ static VALUE process_impl(VALUE args) {
589
+ return rb_yield(args);
590
+ }
591
+ volatile VALUE vdb_;
592
+ const char* emsg_;
593
+ };
594
+
595
+
596
+ /**
597
+ * Wrapper of a native function.
598
+ */
599
+ class NativeFunction {
600
+ public:
601
+ virtual ~NativeFunction() {}
602
+ virtual void operate() = 0;
603
+ static void execute(NativeFunction* func) {
604
+ #if defined(_KC_YARV_)
605
+ #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
606
+ rb_thread_call_without_gvl(execute_impl, func, RUBY_UBF_IO, NULL);
607
+ #else
608
+ rb_thread_blocking_region((rb_blocking_function_t *)execute_impl, func, RUBY_UBF_IO, NULL);
609
+ #endif
610
+ #else
611
+ func->operate();
612
+ #endif
613
+ }
614
+ private:
615
+ static void* execute_impl(void* ptr) {
616
+ NativeFunction* func = (NativeFunction*)ptr;
617
+ func->operate();
618
+ return NULL;
619
+ }
620
+ };
621
+
622
+
623
+ /**
624
+ * Entry point of the library.
625
+ */
626
+ void Init_kyotocabinet() {
627
+ define_module();
628
+ define_err();
629
+ define_vis();
630
+ define_fproc();
631
+ define_cur();
632
+ define_db();
633
+ }
634
+
635
+
636
+ /**
637
+ * Generate a string expression of an arbitrary object.
638
+ */
639
+ static VALUE StringValueEx(VALUE vobj) {
640
+ switch (TYPE(vobj)) {
641
+ case T_STRING: {
642
+ return vobj;
643
+ }
644
+ case T_FIXNUM: {
645
+ char kbuf[kc::NUMBUFSIZ];
646
+ size_t ksiz = std::sprintf(kbuf, "%d", (int)FIX2INT(vobj));
647
+ return rb_str_new(kbuf, ksiz);
648
+ }
649
+ case T_NIL: {
650
+ return rb_str_new("", 0);
651
+ }
652
+ }
653
+ if (rb_respond_to(vobj, id_obj_to_str)) return StringValue(vobj);
654
+ if (rb_respond_to(vobj, id_obj_to_s)) return rb_funcall(vobj, id_obj_to_s, 0);
655
+ char kbuf[kc::NUMBUFSIZ*2];
656
+ std::sprintf(kbuf, "#<Object:0x%llx>", (long long)rb_obj_id(vobj));
657
+ return rb_str_new2(kbuf);
658
+ }
659
+
660
+
661
+ /**
662
+ * Convert a numeric parameter to an integer.
663
+ */
664
+ static int64_t vatoi(VALUE vobj) {
665
+ switch (TYPE(vobj)) {
666
+ case T_FIXNUM: {
667
+ return FIX2INT(vobj);
668
+ }
669
+ case T_BIGNUM: {
670
+ return NUM2LL(vobj);
671
+ }
672
+ case T_FLOAT: {
673
+ double dnum = NUM2DBL(vobj);
674
+ if (kc::chknan(dnum)) {
675
+ return kc::INT64MIN;
676
+ } else if (kc::chkinf(dnum)) {
677
+ return dnum < 0 ? kc::INT64MIN : kc::INT64MAX;
678
+ }
679
+ return dnum;
680
+ }
681
+ case T_TRUE: {
682
+ return 1;
683
+ }
684
+ case T_STRING: {
685
+ const char* str = RSTRING_PTR(vobj);
686
+ double dnum = kc::atof(str);
687
+ if (kc::chknan(dnum)) {
688
+ return kc::INT64MIN;
689
+ } else if (kc::chkinf(dnum)) {
690
+ return dnum < 0 ? kc::INT64MIN : kc::INT64MAX;
691
+ }
692
+ return dnum;
693
+ }
694
+ }
695
+ return 0;
696
+ }
697
+
698
+
699
+ /**
700
+ * Convert a numeric parameter to a real number.
701
+ */
702
+ static double vatof(VALUE vobj) {
703
+ switch (TYPE(vobj)) {
704
+ case T_FIXNUM: {
705
+ return FIX2INT(vobj);
706
+ }
707
+ case T_BIGNUM: {
708
+ return NUM2LL(vobj);
709
+ }
710
+ case T_FLOAT: {
711
+ return NUM2DBL(vobj);
712
+ }
713
+ case T_TRUE: {
714
+ return 1.0;
715
+ }
716
+ case T_STRING: {
717
+ const char* str = RSTRING_PTR(vobj);
718
+ return kc::atof(str);
719
+ }
720
+ }
721
+ return 0.0;
722
+ }
723
+
724
+
725
+ /**
726
+ * Generate a string object with the internal encoding of the database.
727
+ */
728
+ static VALUE rb_str_new_ex(VALUE vdb, const char* ptr, size_t size) {
729
+ volatile VALUE venc = rb_ivar_get(vdb, id_db_enc);
730
+ if (venc == Qnil) return rb_str_new(ptr, size);
731
+ volatile VALUE vstr = rb_str_new(ptr, size);
732
+ rb_funcall(vstr, id_str_force_encoding, 1, venc);
733
+ return vstr;
734
+ }
735
+
736
+
737
+ /**
738
+ * Generate a string object with the internal encoding of the database.
739
+ */
740
+ static VALUE rb_str_new_ex2(VALUE vdb, const char* str) {
741
+ volatile VALUE venc = rb_ivar_get(vdb, id_db_enc);
742
+ if (venc == Qnil) return rb_str_new2(str);
743
+ volatile VALUE vstr = rb_str_new2(str);
744
+ rb_funcall(vstr, id_str_force_encoding, 1, venc);
745
+ return vstr;
746
+ }
747
+
748
+
749
+ /**
750
+ * Find the class object of a name.
751
+ */
752
+ static VALUE findclass(const char* name) {
753
+ volatile VALUE vname = rb_str_new2(name);
754
+ volatile VALUE args = rb_ary_new3(1, vname);
755
+ int result = 0;
756
+ volatile VALUE cls = rb_protect(findclass_impl, args, &result);
757
+ if (result) return Qnil;
758
+ return cls;
759
+ }
760
+
761
+
762
+ /**
763
+ * Find the class object of a name.
764
+ */
765
+ static VALUE findclass_impl(VALUE args) {
766
+ volatile VALUE vname = rb_ary_shift(args);
767
+ return rb_path2class(RSTRING_PTR(vname));
768
+ }
769
+
770
+
771
+ /**
772
+ * Convert an internal map to a Ruby hash.
773
+ */
774
+ static VALUE maptovhash(VALUE vdb, const StringMap* map) {
775
+ volatile VALUE vhash = rb_hash_new();
776
+ StringMap::const_iterator it = map->begin();
777
+ StringMap::const_iterator itend = map->end();
778
+ while (it != itend) {
779
+ volatile VALUE vkey = rb_str_new_ex(vdb, it->first.data(), it->first.size());
780
+ volatile VALUE vvalue = rb_str_new_ex(vdb, it->second.data(), it->second.size());
781
+ rb_hash_aset(vhash, vkey, vvalue);
782
+ it++;
783
+ }
784
+ return vhash;
785
+ }
786
+
787
+
788
+ /**
789
+ * Convert an internal vector to a Ruby array.
790
+ */
791
+ static VALUE vectortovarray(VALUE vdb, const StringVector* vec) {
792
+ volatile VALUE vary = rb_ary_new2(vec->size());
793
+ StringVector::const_iterator it = vec->begin();
794
+ StringVector::const_iterator itend = vec->end();
795
+ while (it != itend) {
796
+ volatile VALUE vstr = rb_str_new_ex(vdb, it->data(), it->size());
797
+ rb_ary_push(vary, vstr);
798
+ it++;
799
+ }
800
+ return vary;
801
+ }
802
+
803
+
804
+ /**
805
+ * Pass the current execution state.
806
+ */
807
+ static void threadyield() {
808
+ rb_funcall(cls_th, id_th_pass, 0);
809
+ }
810
+
811
+
812
+ /**
813
+ * Define objects of the module.
814
+ */
815
+ static void define_module() {
816
+ mod_kc = rb_define_module("KyotoCabinet");
817
+ rb_require("thread");
818
+ rb_define_const(mod_kc, "VERSION", rb_str_new2(kc::VERSION));
819
+ rb_define_module_function(mod_kc, "conv_str", (METHOD)kc_conv_str, 1);
820
+ rb_define_module_function(mod_kc, "atoi", (METHOD)kc_atoi, 1);
821
+ rb_define_module_function(mod_kc, "atoix", (METHOD)kc_atoix, 1);
822
+ rb_define_module_function(mod_kc, "atof", (METHOD)kc_atof, 1);
823
+ rb_define_module_function(mod_kc, "hash_murmur", (METHOD)kc_hash_murmur, 1);
824
+ rb_define_module_function(mod_kc, "hash_fnv", (METHOD)kc_hash_fnv, 1);
825
+ rb_define_module_function(mod_kc, "levdist", (METHOD)kc_levdist, -1);
826
+ cls_ex = findclass("RuntimeError");
827
+ cls_str = findclass("String");
828
+ id_str_force_encoding = rb_intern("force_encoding");
829
+ cls_enc = findclass("Encoding");
830
+ id_enc_find = rb_intern("find");
831
+ cls_th = findclass("Thread");
832
+ id_th_pass = rb_intern("pass");
833
+ cls_mtx = findclass("Mutex");
834
+ id_mtx_lock = rb_intern("lock");
835
+ id_mtx_unlock = rb_intern("unlock");
836
+ id_obj_to_str = rb_intern("to_str");
837
+ id_obj_to_s = rb_intern("to_s");
838
+ id_hash_keys = rb_intern("keys");
839
+ }
840
+
841
+
842
+ /**
843
+ * Implementation of conv_str.
844
+ */
845
+ static VALUE kc_conv_str(VALUE vself, VALUE vstr) {
846
+ return StringValueEx(vstr);
847
+ }
848
+
849
+
850
+ /**
851
+ * Implementation of atoi.
852
+ */
853
+ static VALUE kc_atoi(VALUE vself, VALUE vstr) {
854
+ vstr = StringValueEx(vstr);
855
+ int64_t num = kc::atoi(RSTRING_PTR(vstr));
856
+ return LL2NUM(num);
857
+ }
858
+
859
+
860
+ /**
861
+ * Implementation of atoix.
862
+ */
863
+ static VALUE kc_atoix(VALUE vself, VALUE vstr) {
864
+ vstr = StringValueEx(vstr);
865
+ int64_t num = kc::atoix(RSTRING_PTR(vstr));
866
+ return LL2NUM(num);
867
+ }
868
+
869
+
870
+ /**
871
+ * Implementation of atof.
872
+ */
873
+ static VALUE kc_atof(VALUE vself, VALUE vstr) {
874
+ vstr = StringValueEx(vstr);
875
+ double num = kc::atof(RSTRING_PTR(vstr));
876
+ return rb_float_new(num);
877
+ }
878
+
879
+
880
+ /**
881
+ * Implementation of hash_murmur.
882
+ */
883
+ static VALUE kc_hash_murmur(VALUE vself, VALUE vstr) {
884
+ vstr = StringValueEx(vstr);
885
+ uint64_t hash = kc::hashmurmur(RSTRING_PTR(vstr), RSTRING_LEN(vstr));
886
+ return ULL2NUM(hash);
887
+ }
888
+
889
+
890
+ /**
891
+ * Implementation of hash_fnv.
892
+ */
893
+ static VALUE kc_hash_fnv(VALUE vself, VALUE vstr) {
894
+ vstr = StringValueEx(vstr);
895
+ uint64_t hash = kc::hashfnv(RSTRING_PTR(vstr), RSTRING_LEN(vstr));
896
+ return ULL2NUM(hash);
897
+ }
898
+
899
+
900
+ /**
901
+ * Implementation of levdist.
902
+ */
903
+ static VALUE kc_levdist(int argc, VALUE* argv, VALUE vself) {
904
+ volatile VALUE va, vb, vutf;
905
+ rb_scan_args(argc, argv, "21", &va, &vb, &vutf);
906
+ va = StringValueEx(va);
907
+ const char* abuf = RSTRING_PTR(va);
908
+ size_t asiz = RSTRING_LEN(va);
909
+ vb = StringValueEx(vb);
910
+ const char* bbuf = RSTRING_PTR(vb);
911
+ size_t bsiz = RSTRING_LEN(vb);
912
+ bool utf = vutf != Qnil && vutf != Qfalse;
913
+ size_t dist;
914
+ if (utf) {
915
+ uint32_t astack[128];
916
+ uint32_t* aary = asiz > sizeof(astack) / sizeof(*astack) ? new uint32_t[asiz] : astack;
917
+ size_t anum;
918
+ kc::strutftoucs(abuf, asiz, aary, &anum);
919
+ uint32_t bstack[128];
920
+ uint32_t* bary = bsiz > sizeof(bstack) / sizeof(*bstack) ? new uint32_t[bsiz] : bstack;
921
+ size_t bnum;
922
+ kc::strutftoucs(bbuf, bsiz, bary, &bnum);
923
+ dist = kc::strucsdist(aary, anum, bary, bnum);
924
+ if (bary != bstack) delete[] bary;
925
+ if (aary != astack) delete[] aary;
926
+ } else {
927
+ dist = kc::memdist(abuf, asiz, bbuf, bsiz);
928
+ }
929
+ return INT2FIX((int)dist);
930
+ }
931
+
932
+
933
+ /**
934
+ * Define objects of the Error class.
935
+ */
936
+ static void define_err() {
937
+ cls_err = rb_define_class_under(mod_kc, "Error", cls_ex);
938
+ for (size_t i = 0; i < sizeof(cls_err_children) / sizeof(*cls_err_children); i++) {
939
+ cls_err_children[i] = Qnil;
940
+ }
941
+ err_define_child("SUCCESS", kc::PolyDB::Error::SUCCESS);
942
+ err_define_child("NOIMPL", kc::PolyDB::Error::NOIMPL);
943
+ err_define_child("INVALID", kc::PolyDB::Error::INVALID);
944
+ err_define_child("NOREPOS", kc::PolyDB::Error::NOREPOS);
945
+ err_define_child("NOPERM", kc::PolyDB::Error::NOPERM);
946
+ err_define_child("BROKEN", kc::PolyDB::Error::BROKEN);
947
+ err_define_child("DUPREC", kc::PolyDB::Error::DUPREC);
948
+ err_define_child("NOREC", kc::PolyDB::Error::NOREC);
949
+ err_define_child("LOGIC", kc::PolyDB::Error::LOGIC);
950
+ err_define_child("SYSTEM", kc::PolyDB::Error::SYSTEM);
951
+ err_define_child("MISC", kc::PolyDB::Error::MISC);
952
+ rb_define_private_method(cls_err, "initialize", (METHOD)err_initialize, -1);
953
+ rb_define_method(cls_err, "set", (METHOD)err_set, 2);
954
+ rb_define_method(cls_err, "code", (METHOD)err_code, 0);
955
+ rb_define_method(cls_err, "name", (METHOD)err_name, 0);
956
+ rb_define_method(cls_err, "message", (METHOD)err_message, 0);
957
+ rb_define_method(cls_err, "to_i", (METHOD)err_code, 0);
958
+ rb_define_method(cls_err, "to_s", (METHOD)err_to_s, 0);
959
+ rb_define_method(cls_err, "inspect", (METHOD)err_inspect, 0);
960
+ rb_define_method(cls_err, "==", (METHOD)err_op_eq, 1);
961
+ rb_define_method(cls_err, "!=", (METHOD)err_op_ne, 1);
962
+ id_err_code = rb_intern("@code");
963
+ id_err_message = rb_intern("@message");
964
+ }
965
+
966
+
967
+ /**
968
+ * Define the constant and the subclass of an error code.
969
+ */
970
+ static void err_define_child(const char* name, uint32_t code) {
971
+ rb_define_const(cls_err, name, INT2FIX(code));
972
+ char xname[kc::NUMBUFSIZ];
973
+ sprintf(xname, "X%s", name);
974
+ cls_err_children[code] = rb_define_class_under(cls_err, xname, cls_err);
975
+ }
976
+
977
+
978
+ /**
979
+ * Implementation of initialize.
980
+ */
981
+ static VALUE err_initialize(int argc, VALUE* argv, VALUE vself) {
982
+ volatile VALUE vcode, vmessage;
983
+ rb_scan_args(argc, argv, "02", &vcode, &vmessage);
984
+ if (argc == 1 && TYPE(vcode) == T_STRING) {
985
+ const char* expr = RSTRING_PTR(vcode);
986
+ uint32_t code = kc::atoi(expr);
987
+ const char* rp = std::strchr(expr, ':');
988
+ if (rp) expr = rp + 1;
989
+ while (*expr == ' ') {
990
+ expr++;
991
+ }
992
+ vcode = INT2FIX(code);
993
+ vmessage = rb_str_new2(expr);
994
+ } else {
995
+ if (vcode == Qnil) vcode = INT2FIX(kc::PolyDB::Error::SUCCESS);
996
+ if (vmessage == Qnil) vmessage = rb_str_new2("error");
997
+ }
998
+ rb_ivar_set(vself, id_err_code, vcode);
999
+ rb_ivar_set(vself, id_err_message, vmessage);
1000
+ return Qnil;
1001
+ }
1002
+
1003
+
1004
+ /**
1005
+ * Implementation of set.
1006
+ */
1007
+ static VALUE err_set(VALUE vself, VALUE vcode, VALUE vmessage) {
1008
+ rb_ivar_set(vself, id_err_code, vcode);
1009
+ rb_ivar_set(vself, id_err_message, vmessage);
1010
+ return Qnil;
1011
+ }
1012
+
1013
+
1014
+ /**
1015
+ * Implementation of code.
1016
+ */
1017
+ static VALUE err_code(VALUE vself) {
1018
+ return rb_ivar_get(vself, id_err_code);
1019
+ }
1020
+
1021
+
1022
+ /**
1023
+ * Implementation of name.
1024
+ */
1025
+ static VALUE err_name(VALUE vself) {
1026
+ int32_t code = FIX2INT(rb_ivar_get(vself, id_err_code));
1027
+ return rb_str_new2(kc::PolyDB::Error::codename((kc::PolyDB::Error::Code)code));
1028
+ }
1029
+
1030
+
1031
+ /**
1032
+ * Implementation of message.
1033
+ */
1034
+ static VALUE err_message(VALUE vself) {
1035
+ return rb_ivar_get(vself, id_err_message);
1036
+ }
1037
+
1038
+
1039
+ /**
1040
+ * Implementation of to_s.
1041
+ */
1042
+ static VALUE err_to_s(VALUE vself) {
1043
+ int32_t code = NUM2INT(rb_ivar_get(vself, id_err_code));
1044
+ volatile VALUE vmessage = rb_ivar_get(vself, id_err_message);
1045
+ const char* message = RSTRING_PTR(vmessage);
1046
+ std::string str = kc::strprintf("%s: %s",
1047
+ kc::PolyDB::Error::codename((kc::PolyDB::Error::Code)code),
1048
+ message);
1049
+ return rb_str_new(str.data(), str.size());
1050
+ }
1051
+
1052
+
1053
+ /**
1054
+ * Implementation of inspect.
1055
+ */
1056
+ static VALUE err_inspect(VALUE vself) {
1057
+ int32_t code = NUM2INT(rb_ivar_get(vself, id_err_code));
1058
+ volatile VALUE vmessage = rb_ivar_get(vself, id_err_message);
1059
+ const char* message = RSTRING_PTR(vmessage);
1060
+ std::string str = kc::strprintf("#<KyotoCabinet::Error: %d: %s: %s>", code,
1061
+ kc::PolyDB::Error::codename((kc::PolyDB::Error::Code)code),
1062
+ message);
1063
+ return rb_str_new(str.data(), str.size());
1064
+ }
1065
+
1066
+
1067
+ /**
1068
+ * Implementation of op_eq.
1069
+ */
1070
+ static VALUE err_op_eq(VALUE vself, VALUE vright) {
1071
+ if (vright == Qnil) return Qfalse;
1072
+ if (TYPE(vright) == T_FIXNUM)
1073
+ return NUM2INT(rb_ivar_get(vself, id_err_code)) == FIX2INT(vright) ? Qtrue : Qfalse;
1074
+ return NUM2INT(rb_ivar_get(vself, id_err_code)) == NUM2INT(rb_ivar_get(vright, id_err_code)) ?
1075
+ Qtrue : Qfalse;
1076
+ }
1077
+
1078
+
1079
+ /**
1080
+ * Implementation of op_ne.
1081
+ */
1082
+ static VALUE err_op_ne(VALUE vself, VALUE vright) {
1083
+ if (vright == Qnil) return Qtrue;
1084
+ if (TYPE(vright) == T_FIXNUM)
1085
+ return NUM2INT(rb_ivar_get(vself, id_err_code)) != FIX2INT(vright) ? Qtrue : Qfalse;
1086
+ return NUM2INT(rb_ivar_get(vself, id_err_code)) != NUM2INT(rb_ivar_get(vright, id_err_code)) ?
1087
+ Qtrue : Qfalse;
1088
+ }
1089
+
1090
+
1091
+ /**
1092
+ * Define objects of the Visitor class.
1093
+ */
1094
+ static void define_vis() {
1095
+ cls_vis = rb_define_class_under(mod_kc, "Visitor", rb_cObject);
1096
+ cls_vis_magic = rb_define_class_under(mod_kc, "VisitorMagic", rb_cObject);
1097
+ rb_define_private_method(cls_vis_magic, "initialize", (METHOD)vis_magic_initialize, 1);
1098
+ id_vis_magic = rb_intern("@magic_");
1099
+ volatile VALUE vnopnum = INT2FIX(VISMAGICNOP);
1100
+ volatile VALUE vnop = rb_class_new_instance(1, (VALUE*)&vnopnum, cls_vis_magic);
1101
+ rb_define_const(cls_vis, "NOP", vnop);
1102
+ volatile VALUE vremovenum = INT2FIX(VISMAGICREMOVE);
1103
+ volatile VALUE vremove = rb_class_new_instance(1, (VALUE*)&vremovenum, cls_vis_magic);
1104
+ rb_define_const(cls_vis, "REMOVE", vremove);
1105
+ rb_define_method(cls_vis, "visit_full", (METHOD)vis_visit_full, 2);
1106
+ rb_define_method(cls_vis, "visit_empty", (METHOD)vis_visit_empty, 1);
1107
+ id_vis_nop = rb_intern("NOP");
1108
+ id_vis_remove = rb_intern("REMOVE");
1109
+ id_vis_visit_full = rb_intern("visit_full");
1110
+ id_vis_visit_empty = rb_intern("visit_empty");
1111
+ }
1112
+
1113
+
1114
+ /**
1115
+ * Implementation of magic_initialize.
1116
+ */
1117
+ static VALUE vis_magic_initialize(VALUE vself, VALUE vnum) {
1118
+ rb_ivar_set(vself, id_vis_magic, vnum);
1119
+ return Qnil;
1120
+ }
1121
+
1122
+
1123
+ /**
1124
+ * Implementation of visit_full.
1125
+ */
1126
+ static VALUE vis_visit_full(VALUE vself, VALUE vkey, VALUE vvalue) {
1127
+ return rb_const_get(cls_vis, id_vis_nop);
1128
+ }
1129
+
1130
+
1131
+ /**
1132
+ * Implementation of visit_empty.
1133
+ */
1134
+ static VALUE vis_visit_empty(VALUE vself, VALUE vkey) {
1135
+ return rb_const_get(cls_vis, id_vis_nop);
1136
+ }
1137
+
1138
+
1139
+ /**
1140
+ * Define objects of the FileProcessor class.
1141
+ */
1142
+ static void define_fproc() {
1143
+ cls_fproc = rb_define_class_under(mod_kc, "FileProcessor", rb_cObject);
1144
+ rb_define_method(cls_fproc, "process", (METHOD)fproc_process, 1);
1145
+ id_fproc_process = rb_intern("process");
1146
+ }
1147
+
1148
+
1149
+ /**
1150
+ * Implementation of process.
1151
+ */
1152
+ static VALUE fproc_process(VALUE vself, VALUE vpath) {
1153
+ return Qtrue;
1154
+ }
1155
+
1156
+
1157
+ /**
1158
+ * Define objects of the Cursor class.
1159
+ */
1160
+ static void define_cur() {
1161
+ cls_cur = rb_define_class_under(mod_kc, "Cursor", rb_cObject);
1162
+ rb_define_alloc_func(cls_cur, cur_new);
1163
+ rb_define_private_method(cls_cur, "initialize", (METHOD)cur_initialize, 1);
1164
+ rb_define_method(cls_cur, "disable", (METHOD)cur_disable, 0);
1165
+ rb_define_method(cls_cur, "accept", (METHOD)cur_accept, -1);
1166
+ rb_define_method(cls_cur, "set_value", (METHOD)cur_set_value, -1);
1167
+ rb_define_method(cls_cur, "remove", (METHOD)cur_remove, 0);
1168
+ rb_define_method(cls_cur, "get_key", (METHOD)cur_get_key, -1);
1169
+ rb_define_method(cls_cur, "get_value", (METHOD)cur_get_value, -1);
1170
+ rb_define_method(cls_cur, "get", (METHOD)cur_get, -1);
1171
+ rb_define_method(cls_cur, "seize", (METHOD)cur_seize, 0);
1172
+ rb_define_method(cls_cur, "jump", (METHOD)cur_jump, -1);
1173
+ rb_define_method(cls_cur, "jump_back", (METHOD)cur_jump_back, -1);
1174
+ rb_define_method(cls_cur, "step", (METHOD)cur_step, 0);
1175
+ rb_define_method(cls_cur, "step_back", (METHOD)cur_step_back, 0);
1176
+ rb_define_method(cls_cur, "db", (METHOD)cur_db, 0);
1177
+ rb_define_method(cls_cur, "error", (METHOD)cur_error, 0);
1178
+ rb_define_method(cls_cur, "to_s", (METHOD)cur_to_s, 0);
1179
+ rb_define_method(cls_cur, "inspect", (METHOD)cur_inspect, 0);
1180
+ id_cur_db = rb_intern("@db_");
1181
+ id_cur_disable= rb_intern("disable");
1182
+ }
1183
+
1184
+
1185
+ /**
1186
+ * Implementation of new.
1187
+ */
1188
+ static VALUE cur_new(VALUE cls) {
1189
+ SoftCursor* cur = new SoftCursor;
1190
+ return Data_Wrap_Struct(cls_cur, 0, cur_del, cur);
1191
+ }
1192
+
1193
+
1194
+ /**
1195
+ * Implementation of del.
1196
+ */
1197
+ static void cur_del(void* ptr) {
1198
+ delete (SoftCursor*)ptr;
1199
+ }
1200
+
1201
+
1202
+ /**
1203
+ * Implementation of initialize.
1204
+ */
1205
+ static VALUE cur_initialize(VALUE vself, VALUE vdb) {
1206
+ SoftCursor* cur;
1207
+ Data_Get_Struct(vself, SoftCursor, cur);
1208
+ if (!rb_obj_is_kind_of(vdb, cls_db)) return Qnil;
1209
+ kc::PolyDB* db;
1210
+ Data_Get_Struct(vdb, kc::PolyDB, db);
1211
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1212
+ if (vmutex == Qnil) {
1213
+ g_curbur.sweap();
1214
+ cur->cur_ = db->cursor();
1215
+ } else {
1216
+ rb_funcall(vmutex, id_mtx_lock, 0);
1217
+ g_curbur.sweap();
1218
+ cur->cur_ = db->cursor();
1219
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1220
+ }
1221
+ if (cur->cur_) {
1222
+ rb_ivar_set(vself, id_cur_db, vdb);
1223
+ } else {
1224
+ rb_ivar_set(vself, id_cur_db, Qnil);
1225
+ }
1226
+ return Qnil;
1227
+ }
1228
+
1229
+
1230
+ /**
1231
+ * Implementation of disable.
1232
+ */
1233
+ static VALUE cur_disable(VALUE vself) {
1234
+ volatile VALUE vdb = rb_ivar_get(vself, id_cur_db);
1235
+ if (vdb == Qnil) return Qnil;
1236
+ SoftCursor* cur;
1237
+ Data_Get_Struct(vself, SoftCursor, cur);
1238
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1239
+ if (vmutex == Qnil) {
1240
+ delete cur->cur_;
1241
+ cur->cur_ = NULL;
1242
+ } else {
1243
+ rb_funcall(vmutex, id_mtx_lock, 0);
1244
+ delete cur->cur_;
1245
+ cur->cur_ = NULL;
1246
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1247
+ }
1248
+ rb_ivar_set(vself, id_cur_db, Qnil);
1249
+ return Qnil;
1250
+ }
1251
+
1252
+
1253
+ /**
1254
+ * Implementation of accept.
1255
+ */
1256
+ static VALUE cur_accept(int argc, VALUE* argv, VALUE vself) {
1257
+ volatile VALUE vdb = rb_ivar_get(vself, id_cur_db);
1258
+ if (vdb == Qnil) return Qfalse;
1259
+ SoftCursor* cur;
1260
+ Data_Get_Struct(vself, SoftCursor, cur);
1261
+ volatile VALUE vvisitor, vwritable, vstep;
1262
+ rb_scan_args(argc, argv, "03", &vvisitor, &vwritable, &vstep);
1263
+ volatile VALUE vrv;
1264
+ if (vvisitor == Qnil) {
1265
+ bool writable = vwritable != Qfalse;
1266
+ bool step = vstep != Qnil && vstep != Qfalse;
1267
+ SoftBlockVisitor visitor(vdb, writable);
1268
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1269
+ if (vmutex == Qnil) {
1270
+ cur->cur_->db()->set_error(kc::PolyDB::Error::INVALID, "unsuppotred method");
1271
+ db_raise(vdb);
1272
+ return Qnil;
1273
+ }
1274
+ rb_funcall(vmutex, id_mtx_lock, 0);
1275
+ bool rv = cur->cur_->accept(&visitor, writable, step);
1276
+ const char *emsg = visitor.emsg();
1277
+ if (emsg) {
1278
+ cur->cur_->db()->set_error(kc::PolyDB::Error::LOGIC, emsg);
1279
+ rv = false;
1280
+ }
1281
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1282
+ if (rv) {
1283
+ vrv = Qtrue;
1284
+ } else {
1285
+ vrv = Qfalse;
1286
+ db_raise(vdb);
1287
+ }
1288
+ } else {
1289
+ bool writable = vwritable != Qfalse;
1290
+ bool step = vstep != Qnil && vstep != Qfalse;
1291
+ SoftVisitor visitor(vdb, vvisitor, writable);
1292
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1293
+ if (vmutex == Qnil) {
1294
+ cur->cur_->db()->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
1295
+ db_raise(vdb);
1296
+ return Qnil;
1297
+ }
1298
+ rb_funcall(vmutex, id_mtx_lock, 0);
1299
+ bool rv = cur->cur_->accept(&visitor, writable, step);
1300
+ const char *emsg = visitor.emsg();
1301
+ if (emsg) {
1302
+ cur->cur_->db()->set_error(kc::PolyDB::Error::LOGIC, emsg);
1303
+ rv = false;
1304
+ }
1305
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1306
+ if (rv) {
1307
+ vrv = Qtrue;
1308
+ } else {
1309
+ vrv = Qfalse;
1310
+ db_raise(vdb);
1311
+ }
1312
+ }
1313
+ return vrv;
1314
+ }
1315
+
1316
+
1317
+ /**
1318
+ * Implementation of set_value.
1319
+ */
1320
+ static VALUE cur_set_value(int argc, VALUE* argv, VALUE vself) {
1321
+ volatile VALUE vdb = rb_ivar_get(vself, id_cur_db);
1322
+ if (vdb == Qnil) return Qfalse;
1323
+ SoftCursor* cur;
1324
+ Data_Get_Struct(vself, SoftCursor, cur);
1325
+ volatile VALUE vvalue, vstep;
1326
+ rb_scan_args(argc, argv, "11", &vvalue, &vstep);
1327
+ vvalue = StringValueEx(vvalue);
1328
+ const char* vbuf = RSTRING_PTR(vvalue);
1329
+ size_t vsiz = RSTRING_LEN(vvalue);
1330
+ bool step = vstep != Qnil && vstep != Qfalse;
1331
+ bool rv;
1332
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1333
+ if (vmutex == Qnil) {
1334
+ class FuncImpl : public NativeFunction {
1335
+ public:
1336
+ explicit FuncImpl(kc::PolyDB::Cursor* cur, const char* vbuf, size_t vsiz, bool step) :
1337
+ cur_(cur), vbuf_(vbuf), vsiz_(vsiz), step_(step), rv_(false) {}
1338
+ bool rv() {
1339
+ return rv_;
1340
+ }
1341
+ private:
1342
+ void operate() {
1343
+ rv_ = cur_->set_value(vbuf_, vsiz_, step_);
1344
+ }
1345
+ kc::PolyDB::Cursor* cur_;
1346
+ const char* vbuf_;
1347
+ size_t vsiz_;
1348
+ bool step_;
1349
+ bool rv_;
1350
+ } func(cur->cur_, vbuf, vsiz, step);
1351
+ NativeFunction::execute(&func);
1352
+ rv = func.rv();
1353
+ } else {
1354
+ rb_funcall(vmutex, id_mtx_lock, 0);
1355
+ rv = cur->cur_->set_value(vbuf, vsiz, step);
1356
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1357
+ }
1358
+ if (rv) return Qtrue;
1359
+ db_raise(vdb);
1360
+ return Qfalse;
1361
+ }
1362
+
1363
+
1364
+ /**
1365
+ * Implementation of remove.
1366
+ */
1367
+ static VALUE cur_remove(VALUE vself) {
1368
+ volatile VALUE vdb = rb_ivar_get(vself, id_cur_db);
1369
+ if (vdb == Qnil) return Qfalse;
1370
+ SoftCursor* cur;
1371
+ Data_Get_Struct(vself, SoftCursor, cur);
1372
+ bool rv;
1373
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1374
+ if (vmutex == Qnil) {
1375
+ class FuncImpl : public NativeFunction {
1376
+ public:
1377
+ explicit FuncImpl(kc::PolyDB::Cursor* cur) : cur_(cur), rv_(false) {}
1378
+ bool rv() {
1379
+ return rv_;
1380
+ }
1381
+ private:
1382
+ void operate() {
1383
+ rv_ = cur_->remove();
1384
+ }
1385
+ kc::PolyDB::Cursor* cur_;
1386
+ bool rv_;
1387
+ } func(cur->cur_);
1388
+ NativeFunction::execute(&func);
1389
+ rv = func.rv();
1390
+ } else {
1391
+ rb_funcall(vmutex, id_mtx_lock, 0);
1392
+ rv = cur->cur_->remove();
1393
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1394
+ }
1395
+ if (rv) return Qtrue;
1396
+ db_raise(vdb);
1397
+ return Qfalse;
1398
+ }
1399
+
1400
+
1401
+ /**
1402
+ * Implementation of get_key.
1403
+ */
1404
+ static VALUE cur_get_key(int argc, VALUE* argv, VALUE vself) {
1405
+ volatile VALUE vdb = rb_ivar_get(vself, id_cur_db);
1406
+ if (vdb == Qnil) return Qnil;
1407
+ SoftCursor* cur;
1408
+ Data_Get_Struct(vself, SoftCursor, cur);
1409
+ volatile VALUE vstep;
1410
+ rb_scan_args(argc, argv, "01", &vstep);
1411
+ bool step = vstep != Qnil && vstep != Qfalse;
1412
+ char* kbuf;
1413
+ size_t ksiz;
1414
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1415
+ if (vmutex == Qnil) {
1416
+ class FuncImpl : public NativeFunction {
1417
+ public:
1418
+ explicit FuncImpl(kc::PolyDB::Cursor* cur, bool step) :
1419
+ cur_(cur), step_(step), kbuf_(NULL), ksiz_(0) {}
1420
+ char* rv(size_t* ksp) {
1421
+ *ksp = ksiz_;
1422
+ return kbuf_;
1423
+ }
1424
+ private:
1425
+ void operate() {
1426
+ kbuf_ = cur_->get_key(&ksiz_, step_);
1427
+ }
1428
+ kc::PolyDB::Cursor* cur_;
1429
+ bool step_;
1430
+ char* kbuf_;
1431
+ size_t ksiz_;
1432
+ } func(cur->cur_, step);
1433
+ NativeFunction::execute(&func);
1434
+ kbuf = func.rv(&ksiz);
1435
+ } else {
1436
+ rb_funcall(vmutex, id_mtx_lock, 0);
1437
+ kbuf = cur->cur_->get_key(&ksiz, step);
1438
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1439
+ }
1440
+ volatile VALUE vrv;
1441
+ if (kbuf) {
1442
+ vrv = rb_str_new_ex(vdb, kbuf, ksiz);
1443
+ delete[] kbuf;
1444
+ } else {
1445
+ vrv = Qnil;
1446
+ db_raise(vdb);
1447
+ }
1448
+ return vrv;
1449
+ }
1450
+
1451
+
1452
+ /**
1453
+ * Implementation of get_value.
1454
+ */
1455
+ static VALUE cur_get_value(int argc, VALUE* argv, VALUE vself) {
1456
+ volatile VALUE vdb = rb_ivar_get(vself, id_cur_db);
1457
+ if (vdb == Qnil) return Qnil;
1458
+ SoftCursor* cur;
1459
+ Data_Get_Struct(vself, SoftCursor, cur);
1460
+ volatile VALUE vstep;
1461
+ rb_scan_args(argc, argv, "01", &vstep);
1462
+ bool step = vstep != Qnil && vstep != Qfalse;
1463
+ char* vbuf;
1464
+ size_t vsiz;
1465
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1466
+ if (vmutex == Qnil) {
1467
+ class FuncImpl : public NativeFunction {
1468
+ public:
1469
+ explicit FuncImpl(kc::PolyDB::Cursor* cur, bool step) :
1470
+ cur_(cur), step_(step), vbuf_(NULL), vsiz_(0) {}
1471
+ char* rv(size_t* vsp) {
1472
+ *vsp = vsiz_;
1473
+ return vbuf_;
1474
+ }
1475
+ private:
1476
+ void operate() {
1477
+ vbuf_ = cur_->get_value(&vsiz_, step_);
1478
+ }
1479
+ kc::PolyDB::Cursor* cur_;
1480
+ bool step_;
1481
+ char* vbuf_;
1482
+ size_t vsiz_;
1483
+ } func(cur->cur_, step);
1484
+ NativeFunction::execute(&func);
1485
+ vbuf = func.rv(&vsiz);
1486
+ } else {
1487
+ rb_funcall(vmutex, id_mtx_lock, 0);
1488
+ vbuf = cur->cur_->get_value(&vsiz, step);
1489
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1490
+ }
1491
+ volatile VALUE vrv;
1492
+ if (vbuf) {
1493
+ vrv = rb_str_new_ex(vdb, vbuf, vsiz);
1494
+ delete[] vbuf;
1495
+ } else {
1496
+ vrv = Qnil;
1497
+ db_raise(vdb);
1498
+ }
1499
+ return vrv;
1500
+ }
1501
+
1502
+
1503
+ /**
1504
+ * Implementation of get.
1505
+ */
1506
+ static VALUE cur_get(int argc, VALUE* argv, VALUE vself) {
1507
+ volatile VALUE vdb = rb_ivar_get(vself, id_cur_db);
1508
+ if (vdb == Qnil) return Qnil;
1509
+ SoftCursor* cur;
1510
+ Data_Get_Struct(vself, SoftCursor, cur);
1511
+ volatile VALUE vstep;
1512
+ rb_scan_args(argc, argv, "01", &vstep);
1513
+ bool step = vstep != Qnil && vstep != Qfalse;
1514
+ char* kbuf;
1515
+ const char* vbuf;
1516
+ size_t ksiz, vsiz;
1517
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1518
+ if (vmutex == Qnil) {
1519
+ class FuncImpl : public NativeFunction {
1520
+ public:
1521
+ explicit FuncImpl(kc::PolyDB::Cursor* cur, bool step) :
1522
+ cur_(cur), step_(step), kbuf_(NULL), ksiz_(0), vbuf_(NULL), vsiz_(0) {}
1523
+ char* rv(size_t* ksp, const char** vbp, size_t* vsp) {
1524
+ *ksp = ksiz_;
1525
+ *vbp = vbuf_;
1526
+ *vsp = vsiz_;
1527
+ return kbuf_;
1528
+ }
1529
+ private:
1530
+ void operate() {
1531
+ kbuf_ = cur_->get(&ksiz_, &vbuf_, &vsiz_, step_);
1532
+ }
1533
+ kc::PolyDB::Cursor* cur_;
1534
+ bool step_;
1535
+ char* kbuf_;
1536
+ size_t ksiz_;
1537
+ const char* vbuf_;
1538
+ size_t vsiz_;
1539
+ } func(cur->cur_, step);
1540
+ NativeFunction::execute(&func);
1541
+ kbuf = func.rv(&ksiz, &vbuf, &vsiz);
1542
+ } else {
1543
+ rb_funcall(vmutex, id_mtx_lock, 0);
1544
+ kbuf = cur->cur_->get(&ksiz, &vbuf, &vsiz, step);
1545
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1546
+ }
1547
+ volatile VALUE vrv;
1548
+ if (kbuf) {
1549
+ volatile VALUE vkey = rb_str_new_ex(vdb, kbuf, ksiz);
1550
+ volatile VALUE vvalue = rb_str_new_ex(vdb, vbuf, vsiz);
1551
+ vrv = rb_ary_new3(2, vkey, vvalue);
1552
+ delete[] kbuf;
1553
+ } else {
1554
+ vrv = Qnil;
1555
+ db_raise(vdb);
1556
+ }
1557
+ return vrv;
1558
+ }
1559
+
1560
+
1561
+ /**
1562
+ * Implementation of seize.
1563
+ */
1564
+ static VALUE cur_seize(VALUE vself) {
1565
+ volatile VALUE vdb = rb_ivar_get(vself, id_cur_db);
1566
+ if (vdb == Qnil) return Qnil;
1567
+ SoftCursor* cur;
1568
+ Data_Get_Struct(vself, SoftCursor, cur);
1569
+ char* kbuf;
1570
+ const char* vbuf;
1571
+ size_t ksiz, vsiz;
1572
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1573
+ if (vmutex == Qnil) {
1574
+ class FuncImpl : public NativeFunction {
1575
+ public:
1576
+ explicit FuncImpl(kc::PolyDB::Cursor* cur) :
1577
+ cur_(cur), kbuf_(NULL), ksiz_(0), vbuf_(NULL), vsiz_(0) {}
1578
+ char* rv(size_t* ksp, const char** vbp, size_t* vsp) {
1579
+ *ksp = ksiz_;
1580
+ *vbp = vbuf_;
1581
+ *vsp = vsiz_;
1582
+ return kbuf_;
1583
+ }
1584
+ private:
1585
+ void operate() {
1586
+ kbuf_ = cur_->seize(&ksiz_, &vbuf_, &vsiz_);
1587
+ }
1588
+ kc::PolyDB::Cursor* cur_;
1589
+ char* kbuf_;
1590
+ size_t ksiz_;
1591
+ const char* vbuf_;
1592
+ size_t vsiz_;
1593
+ } func(cur->cur_);
1594
+ NativeFunction::execute(&func);
1595
+ kbuf = func.rv(&ksiz, &vbuf, &vsiz);
1596
+ } else {
1597
+ rb_funcall(vmutex, id_mtx_lock, 0);
1598
+ kbuf = cur->cur_->seize(&ksiz, &vbuf, &vsiz);
1599
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1600
+ }
1601
+ volatile VALUE vrv;
1602
+ if (kbuf) {
1603
+ volatile VALUE vkey = rb_str_new_ex(vdb, kbuf, ksiz);
1604
+ volatile VALUE vvalue = rb_str_new_ex(vdb, vbuf, vsiz);
1605
+ vrv = rb_ary_new3(2, vkey, vvalue);
1606
+ delete[] kbuf;
1607
+ } else {
1608
+ vrv = Qnil;
1609
+ db_raise(vdb);
1610
+ }
1611
+ return vrv;
1612
+ }
1613
+
1614
+
1615
+ /**
1616
+ * Implementation of jump.
1617
+ */
1618
+ static VALUE cur_jump(int argc, VALUE* argv, VALUE vself) {
1619
+ volatile VALUE vdb = rb_ivar_get(vself, id_cur_db);
1620
+ if (vdb == Qnil) return Qfalse;
1621
+ SoftCursor* cur;
1622
+ Data_Get_Struct(vself, SoftCursor, cur);
1623
+ volatile VALUE vkey;
1624
+ rb_scan_args(argc, argv, "01", &vkey);
1625
+ volatile VALUE vrv;
1626
+ if (vkey == Qnil) {
1627
+ bool rv;
1628
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1629
+ if (vmutex == Qnil) {
1630
+ class FuncImpl : public NativeFunction {
1631
+ public:
1632
+ explicit FuncImpl(kc::PolyDB::Cursor* cur) : cur_(cur), rv_(false) {}
1633
+ bool rv() {
1634
+ return rv_;
1635
+ }
1636
+ private:
1637
+ void operate() {
1638
+ rv_ = cur_->jump();
1639
+ }
1640
+ kc::PolyDB::Cursor* cur_;
1641
+ bool rv_;
1642
+ } func(cur->cur_);
1643
+ NativeFunction::execute(&func);
1644
+ rv = func.rv();
1645
+ } else {
1646
+ rb_funcall(vmutex, id_mtx_lock, 0);
1647
+ rv = cur->cur_->jump();
1648
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1649
+ }
1650
+ if (rv) {
1651
+ vrv = Qtrue;
1652
+ } else {
1653
+ vrv = Qfalse;
1654
+ db_raise(vdb);
1655
+ }
1656
+ } else {
1657
+ vkey = StringValueEx(vkey);
1658
+ const char* kbuf = RSTRING_PTR(vkey);
1659
+ size_t ksiz = RSTRING_LEN(vkey);
1660
+ bool rv;
1661
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1662
+ if (vmutex == Qnil) {
1663
+ class FuncImpl : public NativeFunction {
1664
+ public:
1665
+ explicit FuncImpl(kc::PolyDB::Cursor* cur, const char*kbuf, size_t ksiz) :
1666
+ cur_(cur), kbuf_(kbuf), ksiz_(ksiz), rv_(false) {}
1667
+ bool rv() {
1668
+ return rv_;
1669
+ }
1670
+ private:
1671
+ void operate() {
1672
+ rv_ = cur_->jump(kbuf_, ksiz_);
1673
+ }
1674
+ kc::PolyDB::Cursor* cur_;
1675
+ const char* kbuf_;
1676
+ size_t ksiz_;
1677
+ bool rv_;
1678
+ } func(cur->cur_, kbuf, ksiz);
1679
+ NativeFunction::execute(&func);
1680
+ rv = func.rv();
1681
+ } else {
1682
+ rb_funcall(vmutex, id_mtx_lock, 0);
1683
+ rv = cur->cur_->jump(kbuf, ksiz);
1684
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1685
+ }
1686
+ if (rv) {
1687
+ vrv = Qtrue;
1688
+ } else {
1689
+ vrv = Qfalse;
1690
+ db_raise(vdb);
1691
+ }
1692
+ }
1693
+ return vrv;
1694
+ }
1695
+
1696
+
1697
+ /**
1698
+ * Implementation of jump_back.
1699
+ */
1700
+ static VALUE cur_jump_back(int argc, VALUE* argv, VALUE vself) {
1701
+ volatile VALUE vdb = rb_ivar_get(vself, id_cur_db);
1702
+ if (vdb == Qnil) return Qfalse;
1703
+ SoftCursor* cur;
1704
+ Data_Get_Struct(vself, SoftCursor, cur);
1705
+ volatile VALUE vkey;
1706
+ rb_scan_args(argc, argv, "01", &vkey);
1707
+ volatile VALUE vrv;
1708
+ if (vkey == Qnil) {
1709
+ bool rv;
1710
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1711
+ if (vmutex == Qnil) {
1712
+ class FuncImpl : public NativeFunction {
1713
+ public:
1714
+ explicit FuncImpl(kc::PolyDB::Cursor* cur) : cur_(cur), rv_(false) {}
1715
+ bool rv() {
1716
+ return rv_;
1717
+ }
1718
+ private:
1719
+ void operate() {
1720
+ rv_ = cur_->jump_back();
1721
+ }
1722
+ kc::PolyDB::Cursor* cur_;
1723
+ bool rv_;
1724
+ } func(cur->cur_);
1725
+ NativeFunction::execute(&func);
1726
+ rv = func.rv();
1727
+ } else {
1728
+ rb_funcall(vmutex, id_mtx_lock, 0);
1729
+ rv = cur->cur_->jump_back();
1730
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1731
+ }
1732
+ if (rv) {
1733
+ vrv = Qtrue;
1734
+ } else {
1735
+ vrv = Qfalse;
1736
+ db_raise(vdb);
1737
+ }
1738
+ } else {
1739
+ vkey = StringValueEx(vkey);
1740
+ const char* kbuf = RSTRING_PTR(vkey);
1741
+ size_t ksiz = RSTRING_LEN(vkey);
1742
+ bool rv;
1743
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1744
+ if (vmutex == Qnil) {
1745
+ class FuncImpl : public NativeFunction {
1746
+ public:
1747
+ explicit FuncImpl(kc::PolyDB::Cursor* cur, const char*kbuf, size_t ksiz) :
1748
+ cur_(cur), kbuf_(kbuf), ksiz_(ksiz), rv_(false) {}
1749
+ bool rv() {
1750
+ return rv_;
1751
+ }
1752
+ private:
1753
+ void operate() {
1754
+ rv_ = cur_->jump_back(kbuf_, ksiz_);
1755
+ }
1756
+ kc::PolyDB::Cursor* cur_;
1757
+ const char* kbuf_;
1758
+ size_t ksiz_;
1759
+ bool rv_;
1760
+ } func(cur->cur_, kbuf, ksiz);
1761
+ NativeFunction::execute(&func);
1762
+ rv = func.rv();
1763
+ } else {
1764
+ rb_funcall(vmutex, id_mtx_lock, 0);
1765
+ rv = cur->cur_->jump_back(kbuf, ksiz);
1766
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1767
+ }
1768
+ if (rv) {
1769
+ vrv = Qtrue;
1770
+ } else {
1771
+ vrv = Qfalse;
1772
+ db_raise(vdb);
1773
+ }
1774
+ }
1775
+ return vrv;
1776
+ }
1777
+
1778
+
1779
+ /**
1780
+ * Implementation of step.
1781
+ */
1782
+ static VALUE cur_step(VALUE vself) {
1783
+ volatile VALUE vdb = rb_ivar_get(vself, id_cur_db);
1784
+ if (vdb == Qnil) return Qfalse;
1785
+ SoftCursor* cur;
1786
+ Data_Get_Struct(vself, SoftCursor, cur);
1787
+ bool rv;
1788
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1789
+ if (vmutex == Qnil) {
1790
+ class FuncImpl : public NativeFunction {
1791
+ public:
1792
+ explicit FuncImpl(kc::PolyDB::Cursor* cur) : cur_(cur), rv_(false) {}
1793
+ bool rv() {
1794
+ return rv_;
1795
+ }
1796
+ private:
1797
+ void operate() {
1798
+ rv_ = cur_->step();
1799
+ }
1800
+ kc::PolyDB::Cursor* cur_;
1801
+ bool rv_;
1802
+ } func(cur->cur_);
1803
+ NativeFunction::execute(&func);
1804
+ rv = func.rv();
1805
+ } else {
1806
+ rb_funcall(vmutex, id_mtx_lock, 0);
1807
+ rv = cur->cur_->step();
1808
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1809
+ }
1810
+ if (rv) return Qtrue;
1811
+ db_raise(vdb);
1812
+ return Qfalse;
1813
+ }
1814
+
1815
+
1816
+ /**
1817
+ * Implementation of step_back.
1818
+ */
1819
+ static VALUE cur_step_back(VALUE vself) {
1820
+ volatile VALUE vdb = rb_ivar_get(vself, id_cur_db);
1821
+ if (vdb == Qnil) return Qfalse;
1822
+ SoftCursor* cur;
1823
+ Data_Get_Struct(vself, SoftCursor, cur);
1824
+ bool rv;
1825
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1826
+ if (vmutex == Qnil) {
1827
+ class FuncImpl : public NativeFunction {
1828
+ public:
1829
+ explicit FuncImpl(kc::PolyDB::Cursor* cur) : cur_(cur), rv_(false) {}
1830
+ bool rv() {
1831
+ return rv_;
1832
+ }
1833
+ private:
1834
+ void operate() {
1835
+ rv_ = cur_->step_back();
1836
+ }
1837
+ kc::PolyDB::Cursor* cur_;
1838
+ bool rv_;
1839
+ } func(cur->cur_);
1840
+ NativeFunction::execute(&func);
1841
+ rv = func.rv();
1842
+ } else {
1843
+ rb_funcall(vmutex, id_mtx_lock, 0);
1844
+ rv = cur->cur_->step_back();
1845
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1846
+ }
1847
+ if (rv) return Qtrue;
1848
+ db_raise(vdb);
1849
+ return Qfalse;
1850
+ }
1851
+
1852
+
1853
+ /**
1854
+ * Implementation of db.
1855
+ */
1856
+ static VALUE cur_db(VALUE vself) {
1857
+ volatile VALUE vdb = rb_ivar_get(vself, id_cur_db);
1858
+ if (vdb == Qnil) return Qnil;
1859
+ return vdb;
1860
+ }
1861
+
1862
+
1863
+ /**
1864
+ * Implementation of error.
1865
+ */
1866
+ static VALUE cur_error(VALUE vself) {
1867
+ volatile VALUE vdb = rb_ivar_get(vself, id_cur_db);
1868
+ if (vdb == Qnil) return Qnil;
1869
+ SoftCursor* cur;
1870
+ Data_Get_Struct(vself, SoftCursor, cur);
1871
+ kc::PolyDB::Error err = cur->cur_->error();
1872
+ volatile VALUE args[2];
1873
+ args[0] = INT2FIX(err.code());
1874
+ args[1] = rb_str_new_ex2(vdb, err.message());
1875
+ return rb_class_new_instance(2, (VALUE*)args, cls_err);
1876
+ }
1877
+
1878
+
1879
+ /**
1880
+ * Implementation of to_s.
1881
+ */
1882
+ static VALUE cur_to_s(VALUE vself) {
1883
+ volatile VALUE vdb = rb_ivar_get(vself, id_cur_db);
1884
+ if (vdb == Qnil) return rb_str_new2("(disabled)");
1885
+ SoftCursor* cur;
1886
+ Data_Get_Struct(vself, SoftCursor, cur);
1887
+ std::string str;
1888
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1889
+ if (vmutex == Qnil) {
1890
+ kc::PolyDB* db = cur->cur_->db();
1891
+ std::string path = db->path();
1892
+ if (path.size() < 1) path = "(nil)";
1893
+ kc::strprintf(&str, "%s: ", path.c_str());
1894
+ size_t ksiz;
1895
+ char* kbuf = cur->cur_->get_key(&ksiz);
1896
+ if (kbuf) {
1897
+ str.append(kbuf, ksiz);
1898
+ delete[] kbuf;
1899
+ } else {
1900
+ str.append("(nil)");
1901
+ }
1902
+ } else {
1903
+ rb_funcall(vmutex, id_mtx_lock, 0);
1904
+ kc::PolyDB* db = cur->cur_->db();
1905
+ std::string path = db->path();
1906
+ if (path.size() < 1) path = "(nil)";
1907
+ kc::strprintf(&str, "%s: ", path.c_str());
1908
+ size_t ksiz;
1909
+ char* kbuf = cur->cur_->get_key(&ksiz);
1910
+ if (kbuf) {
1911
+ str.append(kbuf, ksiz);
1912
+ delete[] kbuf;
1913
+ } else {
1914
+ str.append("(nil)");
1915
+ }
1916
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1917
+ }
1918
+ return rb_str_new_ex2(vdb, str.c_str());
1919
+ }
1920
+
1921
+
1922
+ /**
1923
+ * Implementation of inspect.
1924
+ */
1925
+ static VALUE cur_inspect(VALUE vself) {
1926
+ volatile VALUE vdb = rb_ivar_get(vself, id_cur_db);
1927
+ if (vdb == Qnil) return rb_str_new2("#<KyotoCabinet::Cursor:(disabled)>");
1928
+ SoftCursor* cur;
1929
+ Data_Get_Struct(vself, SoftCursor, cur);
1930
+ std::string str;
1931
+ volatile VALUE vmutex = rb_ivar_get(vdb, id_db_mutex);
1932
+ if (vmutex == Qnil) {
1933
+ kc::PolyDB* db = cur->cur_->db();
1934
+ std::string path = db->path();
1935
+ if (path.size() < 1) path = "(nil)";
1936
+ kc::strprintf(&str, "#<KyotoCabinet::Cursor:%p: %s: ", cur, path.c_str());
1937
+ size_t ksiz;
1938
+ char* kbuf = cur->cur_->get_key(&ksiz);
1939
+ if (kbuf) {
1940
+ str.append(kbuf, ksiz);
1941
+ delete[] kbuf;
1942
+ } else {
1943
+ str.append("(nil)");
1944
+ }
1945
+ kc::strprintf(&str, ">");
1946
+ } else {
1947
+ rb_funcall(vmutex, id_mtx_lock, 0);
1948
+ kc::PolyDB* db = cur->cur_->db();
1949
+ std::string path = db->path();
1950
+ if (path.size() < 1) path = "(nil)";
1951
+ kc::strprintf(&str, "#<KyotoCabinet::Cursor:%p: %s: ", cur, path.c_str());
1952
+ size_t ksiz;
1953
+ char* kbuf = cur->cur_->get_key(&ksiz);
1954
+ if (kbuf) {
1955
+ str.append(kbuf, ksiz);
1956
+ delete[] kbuf;
1957
+ } else {
1958
+ str.append("(nil)");
1959
+ }
1960
+ kc::strprintf(&str, ">");
1961
+ rb_funcall(vmutex, id_mtx_unlock, 0);
1962
+ }
1963
+ return rb_str_new_ex2(vdb, str.c_str());
1964
+ }
1965
+
1966
+
1967
+ /**
1968
+ * Define objects of the DB class.
1969
+ */
1970
+ static void define_db() {
1971
+ cls_db = rb_define_class_under(mod_kc, "DB", rb_cObject);
1972
+ rb_define_alloc_func(cls_db, db_new);
1973
+ rb_define_const(cls_db, "GEXCEPTIONAL", INT2FIX(GEXCEPTIONAL));
1974
+ rb_define_const(cls_db, "GCONCURRENT", INT2FIX(GCONCURRENT));
1975
+ rb_define_const(cls_db, "OREADER", INT2FIX(kc::PolyDB::OREADER));
1976
+ rb_define_const(cls_db, "OWRITER", INT2FIX(kc::PolyDB::OWRITER));
1977
+ rb_define_const(cls_db, "OCREATE", INT2FIX(kc::PolyDB::OCREATE));
1978
+ rb_define_const(cls_db, "OTRUNCATE", INT2FIX(kc::PolyDB::OTRUNCATE));
1979
+ rb_define_const(cls_db, "OAUTOTRAN", INT2FIX(kc::PolyDB::OAUTOTRAN));
1980
+ rb_define_const(cls_db, "OAUTOSYNC", INT2FIX(kc::PolyDB::OAUTOSYNC));
1981
+ rb_define_const(cls_db, "ONOLOCK", INT2FIX(kc::PolyDB::ONOLOCK));
1982
+ rb_define_const(cls_db, "OTRYLOCK", INT2FIX(kc::PolyDB::OTRYLOCK));
1983
+ rb_define_const(cls_db, "ONOREPAIR", INT2FIX(kc::PolyDB::ONOREPAIR));
1984
+ rb_define_const(cls_db, "MSET", INT2FIX(kc::PolyDB::MSET));
1985
+ rb_define_const(cls_db, "MADD", INT2FIX(kc::PolyDB::MADD));
1986
+ rb_define_const(cls_db, "MREPLACE", INT2FIX(kc::PolyDB::MREPLACE));
1987
+ rb_define_const(cls_db, "MAPPEND", INT2FIX(kc::PolyDB::MAPPEND));
1988
+ rb_define_private_method(cls_db, "initialize", (METHOD)db_initialize, -1);
1989
+ rb_define_method(cls_db, "error", (METHOD)db_error, 0);
1990
+ rb_define_method(cls_db, "open", (METHOD)db_open, -1);
1991
+ rb_define_method(cls_db, "close", (METHOD)db_close, 0);
1992
+ rb_define_method(cls_db, "accept", (METHOD)db_accept, -1);
1993
+ rb_define_method(cls_db, "accept_bulk", (METHOD)db_accept_bulk, -1);
1994
+ rb_define_method(cls_db, "iterate", (METHOD)db_iterate, -1);
1995
+ rb_define_method(cls_db, "set", (METHOD)db_set, 2);
1996
+ rb_define_method(cls_db, "add", (METHOD)db_add, 2);
1997
+ rb_define_method(cls_db, "replace", (METHOD)db_replace, 2);
1998
+ rb_define_method(cls_db, "append", (METHOD)db_append, 2);
1999
+ rb_define_method(cls_db, "increment", (METHOD)db_increment, -1);
2000
+ rb_define_method(cls_db, "increment_double", (METHOD)db_increment_double, -1);
2001
+ rb_define_method(cls_db, "cas", (METHOD)db_cas, 3);
2002
+ rb_define_method(cls_db, "remove", (METHOD)db_remove, 1);
2003
+ rb_define_method(cls_db, "get", (METHOD)db_get, 1);
2004
+ rb_define_method(cls_db, "check", (METHOD)db_check, 1);
2005
+ rb_define_method(cls_db, "seize", (METHOD)db_seize, 1);
2006
+ rb_define_method(cls_db, "set_bulk", (METHOD)db_set_bulk, -1);
2007
+ rb_define_method(cls_db, "remove_bulk", (METHOD)db_remove_bulk, -1);
2008
+ rb_define_method(cls_db, "get_bulk", (METHOD)db_get_bulk, -1);
2009
+ rb_define_method(cls_db, "clear", (METHOD)db_clear, 0);
2010
+ rb_define_method(cls_db, "synchronize", (METHOD)db_synchronize, -1);
2011
+ rb_define_method(cls_db, "occupy", (METHOD)db_occupy, -1);
2012
+ rb_define_method(cls_db, "copy", (METHOD)db_copy, 1);
2013
+ rb_define_method(cls_db, "begin_transaction", (METHOD)db_begin_transaction, -1);
2014
+ rb_define_method(cls_db, "end_transaction", (METHOD)db_end_transaction, -1);
2015
+ rb_define_method(cls_db, "transaction", (METHOD)db_transaction, -1);
2016
+ rb_define_method(cls_db, "dump_snapshot", (METHOD)db_dump_snapshot, 1);
2017
+ rb_define_method(cls_db, "load_snapshot", (METHOD)db_load_snapshot, 1);
2018
+ rb_define_method(cls_db, "count", (METHOD)db_count, 0);
2019
+ rb_define_method(cls_db, "size", (METHOD)db_size, 0);
2020
+ rb_define_method(cls_db, "path", (METHOD)db_path, 0);
2021
+ rb_define_method(cls_db, "status", (METHOD)db_status, 0);
2022
+ rb_define_method(cls_db, "match_prefix", (METHOD)db_match_prefix, -1);
2023
+ rb_define_method(cls_db, "match_regex", (METHOD)db_match_regex, -1);
2024
+ rb_define_method(cls_db, "match_similar", (METHOD)db_match_similar, -1);
2025
+ rb_define_method(cls_db, "merge", (METHOD)db_merge, -1);
2026
+ rb_define_method(cls_db, "cursor", (METHOD)db_cursor, 0);
2027
+ rb_define_method(cls_db, "cursor_process", (METHOD)db_cursor_process, 0);
2028
+ rb_define_method(cls_db, "tune_exception_rule", (METHOD)db_tune_exception_rule, 1);
2029
+ rb_define_method(cls_db, "tune_encoding", (METHOD)db_tune_encoding, 1);
2030
+ rb_define_method(cls_db, "to_s", (METHOD)db_to_s, 0);
2031
+ rb_define_method(cls_db, "inspect", (METHOD)db_inspect, 0);
2032
+ rb_define_method(cls_db, "[]", (METHOD)db_get, 1);
2033
+ rb_define_method(cls_db, "[]=", (METHOD)db_set, 2);
2034
+ rb_define_method(cls_db, "store", (METHOD)db_set, 2);
2035
+ rb_define_method(cls_db, "delete", (METHOD)db_remove, 1);
2036
+ rb_define_method(cls_db, "fetch", (METHOD)db_set, 1);
2037
+ rb_define_method(cls_db, "shift", (METHOD)db_shift, 0);
2038
+ rb_define_method(cls_db, "length", (METHOD)db_count, 0);
2039
+ rb_define_method(cls_db, "each", (METHOD)db_each, 0);
2040
+ rb_define_method(cls_db, "each_pair", (METHOD)db_each, 0);
2041
+ rb_define_method(cls_db, "each_key", (METHOD)db_each_key, 0);
2042
+ rb_define_method(cls_db, "each_value", (METHOD)db_each_value, 0);
2043
+ id_db_error = rb_intern("error");
2044
+ id_db_open = rb_intern("open");
2045
+ id_db_close = rb_intern("close");
2046
+ id_db_begin_transaction = rb_intern("begin_transaction");
2047
+ id_db_end_transaction = rb_intern("end_transaction");
2048
+ id_db_exbits = rb_intern("@exbits_");
2049
+ id_db_mutex = rb_intern("@mutex_");
2050
+ id_db_enc = rb_intern("@enc_");
2051
+ rb_define_singleton_method(cls_db, "process", (METHOD)db_process, -1);
2052
+ }
2053
+
2054
+
2055
+ /**
2056
+ * Implementation of new.
2057
+ */
2058
+ static VALUE db_new(VALUE cls) {
2059
+ kc::PolyDB* db = new kc::PolyDB();
2060
+ return Data_Wrap_Struct(cls_db, 0, db_del, db);
2061
+ }
2062
+
2063
+
2064
+ /**
2065
+ * Implementation of del.
2066
+ */
2067
+ static void db_del(void* ptr) {
2068
+ delete (kc::PolyDB*)ptr;
2069
+ }
2070
+
2071
+
2072
+ /**
2073
+ * Raise the exception of an error code.
2074
+ */
2075
+ static void db_raise(VALUE vself) {
2076
+ volatile VALUE vexbits = rb_ivar_get(vself, id_db_exbits);
2077
+ if (vexbits == Qnil) return;
2078
+ uint32_t exbits = NUM2INT(vexbits);
2079
+ kc::PolyDB* db;
2080
+ Data_Get_Struct(vself, kc::PolyDB, db);
2081
+ kc::PolyDB::Error err = db->error();
2082
+ uint32_t code = err.code();
2083
+ if (exbits & (1 << code)) rb_raise(cls_err_children[code], "%u: %s", code, err.message());
2084
+ }
2085
+
2086
+
2087
+ /**
2088
+ * Implementation of initialize.
2089
+ */
2090
+ static VALUE db_initialize(int argc, VALUE* argv, VALUE vself) {
2091
+ volatile VALUE vopts;
2092
+ rb_scan_args(argc, argv, "01", &vopts);
2093
+ int32_t opts = TYPE(vopts) == T_FIXNUM ? FIX2INT(vopts) : 0;
2094
+ volatile VALUE vexbits = Qnil;
2095
+ if (opts & GEXCEPTIONAL) {
2096
+ uint32_t exbits = 0;
2097
+ exbits |= 1 << kc::PolyDB::Error::NOIMPL;
2098
+ exbits |= 1 << kc::PolyDB::Error::INVALID;
2099
+ exbits |= 1 << kc::PolyDB::Error::NOREPOS;
2100
+ exbits |= 1 << kc::PolyDB::Error::NOPERM;
2101
+ exbits |= 1 << kc::PolyDB::Error::BROKEN;
2102
+ exbits |= 1 << kc::PolyDB::Error::SYSTEM;
2103
+ exbits |= 1 << kc::PolyDB::Error::MISC;
2104
+ vexbits = INT2FIX(exbits);
2105
+ }
2106
+ rb_ivar_set(vself, id_db_exbits, vexbits);
2107
+ volatile VALUE vmutex = (opts & GCONCURRENT) ? Qnil : rb_class_new_instance(0, NULL, cls_mtx);
2108
+ rb_ivar_set(vself, id_db_mutex, vmutex);
2109
+ rb_ivar_set(vself, id_db_enc, Qnil);
2110
+ rb_ivar_set(vself, id_db_enc, Qnil);
2111
+ return Qnil;
2112
+ }
2113
+
2114
+
2115
+ /**
2116
+ * Implementation of error.
2117
+ */
2118
+ static VALUE db_error(VALUE vself) {
2119
+ kc::PolyDB* db;
2120
+ Data_Get_Struct(vself, kc::PolyDB, db);
2121
+ kc::PolyDB::Error err = db->error();
2122
+ uint32_t code = err.code();
2123
+ volatile VALUE args[2];
2124
+ args[0] = INT2FIX(code);
2125
+ args[1] = rb_str_new_ex2(vself, err.message());
2126
+ return rb_class_new_instance(2, (VALUE*)args, cls_err_children[code]);
2127
+ }
2128
+
2129
+
2130
+ /**
2131
+ * Implementation of open.
2132
+ */
2133
+ static VALUE db_open(int argc, VALUE* argv, VALUE vself) {
2134
+ kc::PolyDB* db;
2135
+ Data_Get_Struct(vself, kc::PolyDB, db);
2136
+ volatile VALUE vpath, vmode;
2137
+ rb_scan_args(argc, argv, "02", &vpath, &vmode);
2138
+ if (vpath == Qnil) vpath = rb_str_new2(":");
2139
+ vpath = StringValueEx(vpath);
2140
+ const char* path = RSTRING_PTR(vpath);
2141
+ uint32_t mode = vmode == Qnil ? kc::PolyDB::OWRITER | kc::PolyDB::OCREATE : NUM2INT(vmode);
2142
+ bool rv;
2143
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2144
+ if (vmutex == Qnil) {
2145
+ class FuncImpl : public NativeFunction {
2146
+ public:
2147
+ explicit FuncImpl(kc::PolyDB* db, const char* path, uint32_t mode) :
2148
+ db_(db), path_(path), mode_(mode), rv_(false) {}
2149
+ bool rv() {
2150
+ return rv_;
2151
+ }
2152
+ private:
2153
+ void operate() {
2154
+ rv_ = db_->open(path_, mode_);
2155
+ }
2156
+ kc::PolyDB* db_;
2157
+ const char* path_;
2158
+ uint32_t mode_;
2159
+ bool rv_;
2160
+ } func(db, path, mode);
2161
+ NativeFunction::execute(&func);
2162
+ rv = func.rv();
2163
+ } else {
2164
+ rb_funcall(vmutex, id_mtx_lock, 0);
2165
+ rv = db->open(path, mode);
2166
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2167
+ }
2168
+ if (rv) return Qtrue;
2169
+ db_raise(vself);
2170
+ return Qfalse;
2171
+ }
2172
+
2173
+
2174
+ /**
2175
+ * Implementation of close.
2176
+ */
2177
+ static VALUE db_close(VALUE vself) {
2178
+ kc::PolyDB* db;
2179
+ Data_Get_Struct(vself, kc::PolyDB, db);
2180
+ bool rv;
2181
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2182
+ if (vmutex == Qnil) {
2183
+ class FuncImpl : public NativeFunction {
2184
+ public:
2185
+ explicit FuncImpl(kc::PolyDB* db) : db_(db), rv_(false) {}
2186
+ bool rv() {
2187
+ return rv_;
2188
+ }
2189
+ private:
2190
+ void operate() {
2191
+ g_curbur.sweap();
2192
+ rv_ = db_->close();
2193
+ }
2194
+ kc::PolyDB* db_;
2195
+ bool rv_;
2196
+ } func(db);
2197
+ NativeFunction::execute(&func);
2198
+ rv = func.rv();
2199
+ } else {
2200
+ rb_funcall(vmutex, id_mtx_lock, 0);
2201
+ g_curbur.sweap();
2202
+ rv = db->close();
2203
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2204
+ }
2205
+ if (rv) return Qtrue;
2206
+ db_raise(vself);
2207
+ return Qfalse;
2208
+ }
2209
+
2210
+
2211
+ /**
2212
+ * Implementation of accept.
2213
+ */
2214
+ static VALUE db_accept(int argc, VALUE* argv, VALUE vself) {
2215
+ kc::PolyDB* db;
2216
+ Data_Get_Struct(vself, kc::PolyDB, db);
2217
+ volatile VALUE vkey, vvisitor, vwritable;
2218
+ rb_scan_args(argc, argv, "12", &vkey, &vvisitor, &vwritable);
2219
+ vkey = StringValueEx(vkey);
2220
+ const char* kbuf = RSTRING_PTR(vkey);
2221
+ size_t ksiz = RSTRING_LEN(vkey);
2222
+ volatile VALUE vrv;
2223
+ if (vvisitor == Qnil) {
2224
+ bool writable = vwritable != Qfalse;
2225
+ SoftBlockVisitor visitor(vself, writable);
2226
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2227
+ if (vmutex == Qnil) {
2228
+ db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
2229
+ db_raise(vself);
2230
+ return Qnil;
2231
+ }
2232
+ rb_funcall(vmutex, id_mtx_lock, 0);
2233
+ bool rv = db->accept(kbuf, ksiz, &visitor, writable);
2234
+ const char *emsg = visitor.emsg();
2235
+ if (emsg) {
2236
+ db->set_error(kc::PolyDB::Error::LOGIC, emsg);
2237
+ rv = false;
2238
+ }
2239
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2240
+ if (rv) {
2241
+ vrv = Qtrue;
2242
+ } else {
2243
+ vrv = Qfalse;
2244
+ db_raise(vself);
2245
+ }
2246
+ } else {
2247
+ bool writable = vwritable != Qfalse;
2248
+ SoftVisitor visitor(vself, vvisitor, writable);
2249
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2250
+ if (vmutex == Qnil) {
2251
+ db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
2252
+ db_raise(vself);
2253
+ return Qnil;
2254
+ }
2255
+ rb_funcall(vmutex, id_mtx_lock, 0);
2256
+ bool rv = db->accept(kbuf, ksiz, &visitor, writable);
2257
+ const char *emsg = visitor.emsg();
2258
+ if (emsg) {
2259
+ db->set_error(kc::PolyDB::Error::LOGIC, emsg);
2260
+ rv = false;
2261
+ }
2262
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2263
+ if (rv) {
2264
+ vrv = Qtrue;
2265
+ } else {
2266
+ vrv = Qfalse;
2267
+ db_raise(vself);
2268
+ }
2269
+ }
2270
+ return vrv;
2271
+ }
2272
+
2273
+
2274
+ /**
2275
+ * Implementation of accept_bulk.
2276
+ */
2277
+ static VALUE db_accept_bulk(int argc, VALUE* argv, VALUE vself) {
2278
+ kc::PolyDB* db;
2279
+ Data_Get_Struct(vself, kc::PolyDB, db);
2280
+ volatile VALUE vkeys, vvisitor, vwritable;
2281
+ rb_scan_args(argc, argv, "12", &vkeys, &vvisitor, &vwritable);
2282
+ StringVector keys;
2283
+ if (TYPE(vkeys) == T_ARRAY) {
2284
+ int32_t knum = RARRAY_LEN(vkeys);
2285
+ for (int32_t i = 0; i < knum; i++) {
2286
+ volatile VALUE vkey = rb_ary_entry(vkeys, i);
2287
+ vkey = StringValueEx(vkey);
2288
+ keys.push_back(std::string(RSTRING_PTR(vkey), RSTRING_LEN(vkey)));
2289
+ }
2290
+ }
2291
+ volatile VALUE vrv;
2292
+ if (vvisitor == Qnil) {
2293
+ bool writable = vwritable != Qfalse;
2294
+ SoftBlockVisitor visitor(vself, writable);
2295
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2296
+ if (vmutex == Qnil) {
2297
+ db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
2298
+ db_raise(vself);
2299
+ return Qnil;
2300
+ }
2301
+ rb_funcall(vmutex, id_mtx_lock, 0);
2302
+ bool rv = db->accept_bulk(keys, &visitor, writable);
2303
+ const char *emsg = visitor.emsg();
2304
+ if (emsg) {
2305
+ db->set_error(kc::PolyDB::Error::LOGIC, emsg);
2306
+ rv = false;
2307
+ }
2308
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2309
+ if (rv) {
2310
+ vrv = Qtrue;
2311
+ } else {
2312
+ vrv = Qfalse;
2313
+ db_raise(vself);
2314
+ }
2315
+ } else {
2316
+ bool writable = vwritable != Qfalse;
2317
+ SoftVisitor visitor(vself, vvisitor, writable);
2318
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2319
+ if (vmutex == Qnil) {
2320
+ db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
2321
+ db_raise(vself);
2322
+ return Qnil;
2323
+ }
2324
+ rb_funcall(vmutex, id_mtx_lock, 0);
2325
+ bool rv = db->accept_bulk(keys, &visitor, writable);
2326
+ const char *emsg = visitor.emsg();
2327
+ if (emsg) {
2328
+ db->set_error(kc::PolyDB::Error::LOGIC, emsg);
2329
+ rv = false;
2330
+ }
2331
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2332
+ if (rv) {
2333
+ vrv = Qtrue;
2334
+ } else {
2335
+ vrv = Qfalse;
2336
+ db_raise(vself);
2337
+ }
2338
+ }
2339
+ return vrv;
2340
+ }
2341
+
2342
+
2343
+ /**
2344
+ * Implementation of iterate.
2345
+ */
2346
+ static VALUE db_iterate(int argc, VALUE* argv, VALUE vself) {
2347
+ kc::PolyDB* db;
2348
+ Data_Get_Struct(vself, kc::PolyDB, db);
2349
+ volatile VALUE vvisitor, vwritable;
2350
+ rb_scan_args(argc, argv, "02", &vvisitor, &vwritable);
2351
+ volatile VALUE vrv;
2352
+ if (vvisitor == Qnil) {
2353
+ bool writable = vwritable != Qfalse;
2354
+ SoftBlockVisitor visitor(vself, writable);
2355
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2356
+ if (vmutex == Qnil) {
2357
+ db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
2358
+ db_raise(vself);
2359
+ return Qnil;
2360
+ }
2361
+ rb_funcall(vmutex, id_mtx_lock, 0);
2362
+ bool rv = db->iterate(&visitor, writable);
2363
+ const char *emsg = visitor.emsg();
2364
+ if (emsg) {
2365
+ db->set_error(kc::PolyDB::Error::LOGIC, emsg);
2366
+ rv = false;
2367
+ }
2368
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2369
+ if (rv) {
2370
+ vrv = Qtrue;
2371
+ } else {
2372
+ vrv = Qfalse;
2373
+ db_raise(vself);
2374
+ }
2375
+ } else {
2376
+ bool writable = vwritable != Qfalse;
2377
+ SoftVisitor visitor(vself, vvisitor, writable);
2378
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2379
+ if (vmutex == Qnil) {
2380
+ db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
2381
+ db_raise(vself);
2382
+ return Qnil;
2383
+ }
2384
+ rb_funcall(vmutex, id_mtx_lock, 0);
2385
+ bool rv = db->iterate(&visitor, writable);
2386
+ const char *emsg = visitor.emsg();
2387
+ if (emsg) {
2388
+ db->set_error(kc::PolyDB::Error::LOGIC, emsg);
2389
+ rv = false;
2390
+ }
2391
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2392
+ if (rv) {
2393
+ vrv = Qtrue;
2394
+ } else {
2395
+ vrv = Qfalse;
2396
+ db_raise(vself);
2397
+ }
2398
+ }
2399
+ return vrv;
2400
+ }
2401
+
2402
+
2403
+ /**
2404
+ * Implementation of set.
2405
+ */
2406
+ static VALUE db_set(VALUE vself, VALUE vkey, VALUE vvalue) {
2407
+ kc::PolyDB* db;
2408
+ Data_Get_Struct(vself, kc::PolyDB, db);
2409
+ vkey = StringValueEx(vkey);
2410
+ const char* kbuf = RSTRING_PTR(vkey);
2411
+ size_t ksiz = RSTRING_LEN(vkey);
2412
+ vvalue = StringValueEx(vvalue);
2413
+ const char* vbuf = RSTRING_PTR(vvalue);
2414
+ size_t vsiz = RSTRING_LEN(vvalue);
2415
+ bool rv;
2416
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2417
+ if (vmutex == Qnil) {
2418
+ class FuncImpl : public NativeFunction {
2419
+ public:
2420
+ explicit FuncImpl(kc::PolyDB* db, const char* kbuf, size_t ksiz,
2421
+ const char* vbuf, size_t vsiz) :
2422
+ db_(db), kbuf_(kbuf), ksiz_(ksiz), vbuf_(vbuf), vsiz_(vsiz), rv_(false) {}
2423
+ bool rv() {
2424
+ return rv_;
2425
+ }
2426
+ private:
2427
+ void operate() {
2428
+ rv_ = db_->set(kbuf_, ksiz_, vbuf_, vsiz_);
2429
+ }
2430
+ kc::PolyDB* db_;
2431
+ const char* kbuf_;
2432
+ size_t ksiz_;
2433
+ const char* vbuf_;
2434
+ size_t vsiz_;
2435
+ bool rv_;
2436
+ } func(db, kbuf, ksiz, vbuf, vsiz);
2437
+ NativeFunction::execute(&func);
2438
+ rv = func.rv();
2439
+ } else {
2440
+ rb_funcall(vmutex, id_mtx_lock, 0);
2441
+ rv = db->set(kbuf, ksiz, vbuf, vsiz);
2442
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2443
+ }
2444
+ if (rv) return Qtrue;
2445
+ db_raise(vself);
2446
+ return Qfalse;
2447
+ }
2448
+
2449
+
2450
+ /**
2451
+ * Implementation of add.
2452
+ */
2453
+ static VALUE db_add(VALUE vself, VALUE vkey, VALUE vvalue) {
2454
+ kc::PolyDB* db;
2455
+ Data_Get_Struct(vself, kc::PolyDB, db);
2456
+ vkey = StringValueEx(vkey);
2457
+ const char* kbuf = RSTRING_PTR(vkey);
2458
+ size_t ksiz = RSTRING_LEN(vkey);
2459
+ vvalue = StringValueEx(vvalue);
2460
+ const char* vbuf = RSTRING_PTR(vvalue);
2461
+ size_t vsiz = RSTRING_LEN(vvalue);
2462
+ bool rv;
2463
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2464
+ if (vmutex == Qnil) {
2465
+ class FuncImpl : public NativeFunction {
2466
+ public:
2467
+ explicit FuncImpl(kc::PolyDB* db, const char* kbuf, size_t ksiz,
2468
+ const char* vbuf, size_t vsiz) :
2469
+ db_(db), kbuf_(kbuf), ksiz_(ksiz), vbuf_(vbuf), vsiz_(vsiz), rv_(false) {}
2470
+ bool rv() {
2471
+ return rv_;
2472
+ }
2473
+ private:
2474
+ void operate() {
2475
+ rv_ = db_->add(kbuf_, ksiz_, vbuf_, vsiz_);
2476
+ }
2477
+ kc::PolyDB* db_;
2478
+ const char* kbuf_;
2479
+ size_t ksiz_;
2480
+ const char* vbuf_;
2481
+ size_t vsiz_;
2482
+ bool rv_;
2483
+ } func(db, kbuf, ksiz, vbuf, vsiz);
2484
+ NativeFunction::execute(&func);
2485
+ rv = func.rv();
2486
+ } else {
2487
+ rb_funcall(vmutex, id_mtx_lock, 0);
2488
+ rv = db->add(kbuf, ksiz, vbuf, vsiz);
2489
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2490
+ }
2491
+ if (rv) return Qtrue;
2492
+ db_raise(vself);
2493
+ return Qfalse;
2494
+ }
2495
+
2496
+
2497
+ /**
2498
+ * Implementation of replace.
2499
+ */
2500
+ static VALUE db_replace(VALUE vself, VALUE vkey, VALUE vvalue) {
2501
+ kc::PolyDB* db;
2502
+ Data_Get_Struct(vself, kc::PolyDB, db);
2503
+ vkey = StringValueEx(vkey);
2504
+ const char* kbuf = RSTRING_PTR(vkey);
2505
+ size_t ksiz = RSTRING_LEN(vkey);
2506
+ vvalue = StringValueEx(vvalue);
2507
+ const char* vbuf = RSTRING_PTR(vvalue);
2508
+ size_t vsiz = RSTRING_LEN(vvalue);
2509
+ bool rv;
2510
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2511
+ if (vmutex == Qnil) {
2512
+ class FuncImpl : public NativeFunction {
2513
+ public:
2514
+ explicit FuncImpl(kc::PolyDB* db, const char* kbuf, size_t ksiz,
2515
+ const char* vbuf, size_t vsiz) :
2516
+ db_(db), kbuf_(kbuf), ksiz_(ksiz), vbuf_(vbuf), vsiz_(vsiz), rv_(false) {}
2517
+ bool rv() {
2518
+ return rv_;
2519
+ }
2520
+ private:
2521
+ void operate() {
2522
+ rv_ = db_->replace(kbuf_, ksiz_, vbuf_, vsiz_);
2523
+ }
2524
+ kc::PolyDB* db_;
2525
+ const char* kbuf_;
2526
+ size_t ksiz_;
2527
+ const char* vbuf_;
2528
+ size_t vsiz_;
2529
+ bool rv_;
2530
+ } func(db, kbuf, ksiz, vbuf, vsiz);
2531
+ NativeFunction::execute(&func);
2532
+ rv = func.rv();
2533
+ } else {
2534
+ rb_funcall(vmutex, id_mtx_lock, 0);
2535
+ rv = db->replace(kbuf, ksiz, vbuf, vsiz);
2536
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2537
+ }
2538
+ if (rv) return Qtrue;
2539
+ db_raise(vself);
2540
+ return Qfalse;
2541
+ }
2542
+
2543
+
2544
+ /**
2545
+ * Implementation of append.
2546
+ */
2547
+ static VALUE db_append(VALUE vself, VALUE vkey, VALUE vvalue) {
2548
+ kc::PolyDB* db;
2549
+ Data_Get_Struct(vself, kc::PolyDB, db);
2550
+ vkey = StringValueEx(vkey);
2551
+ const char* kbuf = RSTRING_PTR(vkey);
2552
+ size_t ksiz = RSTRING_LEN(vkey);
2553
+ vvalue = StringValueEx(vvalue);
2554
+ const char* vbuf = RSTRING_PTR(vvalue);
2555
+ size_t vsiz = RSTRING_LEN(vvalue);
2556
+ bool rv;
2557
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2558
+ if (vmutex == Qnil) {
2559
+ class FuncImpl : public NativeFunction {
2560
+ public:
2561
+ explicit FuncImpl(kc::PolyDB* db, const char* kbuf, size_t ksiz,
2562
+ const char* vbuf, size_t vsiz) :
2563
+ db_(db), kbuf_(kbuf), ksiz_(ksiz), vbuf_(vbuf), vsiz_(vsiz), rv_(false) {}
2564
+ bool rv() {
2565
+ return rv_;
2566
+ }
2567
+ private:
2568
+ void operate() {
2569
+ rv_ = db_->append(kbuf_, ksiz_, vbuf_, vsiz_);
2570
+ }
2571
+ kc::PolyDB* db_;
2572
+ const char* kbuf_;
2573
+ size_t ksiz_;
2574
+ const char* vbuf_;
2575
+ size_t vsiz_;
2576
+ bool rv_;
2577
+ } func(db, kbuf, ksiz, vbuf, vsiz);
2578
+ NativeFunction::execute(&func);
2579
+ rv = func.rv();
2580
+ } else {
2581
+ rb_funcall(vmutex, id_mtx_lock, 0);
2582
+ rv = db->append(kbuf, ksiz, vbuf, vsiz);
2583
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2584
+ }
2585
+ if (rv) return Qtrue;
2586
+ db_raise(vself);
2587
+ return Qfalse;
2588
+ }
2589
+
2590
+
2591
+ /**
2592
+ * Implementation of increment.
2593
+ */
2594
+ static VALUE db_increment(int argc, VALUE* argv, VALUE vself) {
2595
+ kc::PolyDB* db;
2596
+ Data_Get_Struct(vself, kc::PolyDB, db);
2597
+ volatile VALUE vkey, vnum, vorig;
2598
+ rb_scan_args(argc, argv, "12", &vkey, &vnum, &vorig);
2599
+ vkey = StringValueEx(vkey);
2600
+ const char* kbuf = RSTRING_PTR(vkey);
2601
+ size_t ksiz = RSTRING_LEN(vkey);
2602
+ int64_t num = vnum == Qnil ? 0 : vatoi(vnum);
2603
+ int64_t orig = vorig == Qnil ? 0 : vatoi(vorig);
2604
+ volatile VALUE vrv;
2605
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2606
+ if (vmutex == Qnil) {
2607
+ class FuncImpl : public NativeFunction {
2608
+ public:
2609
+ explicit FuncImpl(kc::PolyDB* db, const char* kbuf, size_t ksiz,
2610
+ int64_t num, int64_t orig) :
2611
+ db_(db), kbuf_(kbuf), ksiz_(ksiz), num_(num), orig_(orig) {}
2612
+ int64_t rv() {
2613
+ return num_;
2614
+ }
2615
+ private:
2616
+ void operate() {
2617
+ num_ = db_->increment(kbuf_, ksiz_, num_, orig_);
2618
+ }
2619
+ kc::PolyDB* db_;
2620
+ const char* kbuf_;
2621
+ size_t ksiz_;
2622
+ int64_t num_;
2623
+ int64_t orig_;
2624
+ } func(db, kbuf, ksiz, num, orig);
2625
+ NativeFunction::execute(&func);
2626
+ num = func.rv();
2627
+ } else {
2628
+ rb_funcall(vmutex, id_mtx_lock, 0);
2629
+ num = db->increment(kbuf, ksiz, num, orig);
2630
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2631
+ }
2632
+ if (num == kc::INT64MIN) {
2633
+ vrv = Qnil;
2634
+ db_raise(vself);
2635
+ } else {
2636
+ vrv = LL2NUM(num);
2637
+ }
2638
+ return vrv;
2639
+ }
2640
+
2641
+
2642
+ /**
2643
+ * Implementation of increment_double.
2644
+ */
2645
+ static VALUE db_increment_double(int argc, VALUE* argv, VALUE vself) {
2646
+ kc::PolyDB* db;
2647
+ Data_Get_Struct(vself, kc::PolyDB, db);
2648
+ volatile VALUE vkey, vnum, vorig;
2649
+ rb_scan_args(argc, argv, "12", &vkey, &vnum, &vorig);
2650
+ vkey = StringValueEx(vkey);
2651
+ const char* kbuf = RSTRING_PTR(vkey);
2652
+ size_t ksiz = RSTRING_LEN(vkey);
2653
+ double num = vnum == Qnil ? 0.0 : vatof(vnum);
2654
+ double orig = vorig == Qnil ? 0.0 : vatof(vorig);
2655
+ volatile VALUE vrv;
2656
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2657
+ if (vmutex == Qnil) {
2658
+ class FuncImpl : public NativeFunction {
2659
+ public:
2660
+ explicit FuncImpl(kc::PolyDB* db, const char* kbuf, size_t ksiz,
2661
+ double num, double orig) :
2662
+ db_(db), kbuf_(kbuf), ksiz_(ksiz), num_(num), orig_(orig) {}
2663
+ double rv() {
2664
+ return num_;
2665
+ }
2666
+ private:
2667
+ void operate() {
2668
+ num_ = db_->increment_double(kbuf_, ksiz_, num_, orig_);
2669
+ }
2670
+ kc::PolyDB* db_;
2671
+ const char* kbuf_;
2672
+ size_t ksiz_;
2673
+ double num_;
2674
+ double orig_;
2675
+ } func(db, kbuf, ksiz, num, orig);
2676
+ NativeFunction::execute(&func);
2677
+ num = func.rv();
2678
+ } else {
2679
+ rb_funcall(vmutex, id_mtx_lock, 0);
2680
+ num = db->increment_double(kbuf, ksiz, num, orig);
2681
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2682
+ }
2683
+ if (kc::chknan(num)) {
2684
+ vrv = Qnil;
2685
+ db_raise(vself);
2686
+ } else {
2687
+ vrv = rb_float_new(num);
2688
+ }
2689
+ return vrv;
2690
+ }
2691
+
2692
+
2693
+
2694
+ /**
2695
+ * Implementation of cas.
2696
+ */
2697
+ static VALUE db_cas(VALUE vself, VALUE vkey, VALUE voval, VALUE vnval) {
2698
+ kc::PolyDB* db;
2699
+ Data_Get_Struct(vself, kc::PolyDB, db);
2700
+ vkey = StringValueEx(vkey);
2701
+ const char* kbuf = RSTRING_PTR(vkey);
2702
+ size_t ksiz = RSTRING_LEN(vkey);
2703
+ const char* ovbuf = NULL;
2704
+ size_t ovsiz = 0;
2705
+ if (voval != Qnil) {
2706
+ voval = StringValueEx(voval);
2707
+ ovbuf = RSTRING_PTR(voval);
2708
+ ovsiz = RSTRING_LEN(voval);
2709
+ }
2710
+ const char* nvbuf = NULL;
2711
+ size_t nvsiz = 0;
2712
+ if (vnval != Qnil) {
2713
+ vnval = StringValueEx(vnval);
2714
+ nvbuf = RSTRING_PTR(vnval);
2715
+ nvsiz = RSTRING_LEN(vnval);
2716
+ }
2717
+ bool rv;
2718
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2719
+ if (vmutex == Qnil) {
2720
+ class FuncImpl : public NativeFunction {
2721
+ public:
2722
+ explicit FuncImpl(kc::PolyDB* db, const char* kbuf, size_t ksiz,
2723
+ const char* ovbuf, size_t ovsiz, const char* nvbuf, size_t nvsiz) :
2724
+ db_(db), kbuf_(kbuf), ksiz_(ksiz),
2725
+ ovbuf_(ovbuf), ovsiz_(ovsiz), nvbuf_(nvbuf), nvsiz_(nvsiz), rv_(false) {}
2726
+ bool rv() {
2727
+ return rv_;
2728
+ }
2729
+ private:
2730
+ void operate() {
2731
+ rv_ = db_->cas(kbuf_, ksiz_, ovbuf_, ovsiz_, nvbuf_, nvsiz_);
2732
+ }
2733
+ kc::PolyDB* db_;
2734
+ const char* kbuf_;
2735
+ size_t ksiz_;
2736
+ const char* ovbuf_;
2737
+ size_t ovsiz_;
2738
+ const char* nvbuf_;
2739
+ size_t nvsiz_;
2740
+ bool rv_;
2741
+ } func(db, kbuf, ksiz, ovbuf, ovsiz, nvbuf, nvsiz);
2742
+ NativeFunction::execute(&func);
2743
+ rv = func.rv();
2744
+ } else {
2745
+ rb_funcall(vmutex, id_mtx_lock, 0);
2746
+ rv = db->cas(kbuf, ksiz, ovbuf, ovsiz, nvbuf, nvsiz);
2747
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2748
+ }
2749
+ if (rv) return Qtrue;
2750
+ db_raise(vself);
2751
+ return Qfalse;
2752
+ }
2753
+
2754
+
2755
+ /**
2756
+ * Implementation of remove.
2757
+ */
2758
+ static VALUE db_remove(VALUE vself, VALUE vkey) {
2759
+ kc::PolyDB* db;
2760
+ Data_Get_Struct(vself, kc::PolyDB, db);
2761
+ vkey = StringValueEx(vkey);
2762
+ const char* kbuf = RSTRING_PTR(vkey);
2763
+ size_t ksiz = RSTRING_LEN(vkey);
2764
+ bool rv;
2765
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2766
+ if (vmutex == Qnil) {
2767
+ class FuncImpl : public NativeFunction {
2768
+ public:
2769
+ explicit FuncImpl(kc::PolyDB* db, const char* kbuf, size_t ksiz) :
2770
+ db_(db), kbuf_(kbuf), ksiz_(ksiz), rv_(false) {}
2771
+ bool rv() {
2772
+ return rv_;
2773
+ }
2774
+ private:
2775
+ void operate() {
2776
+ rv_ = db_->remove(kbuf_, ksiz_);
2777
+ }
2778
+ kc::PolyDB* db_;
2779
+ const char* kbuf_;
2780
+ size_t ksiz_;
2781
+ bool rv_;
2782
+ } func(db, kbuf, ksiz);
2783
+ NativeFunction::execute(&func);
2784
+ rv = func.rv();
2785
+ } else {
2786
+ rb_funcall(vmutex, id_mtx_lock, 0);
2787
+ rv = db->remove(kbuf, ksiz);
2788
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2789
+ }
2790
+ if (rv) return Qtrue;;
2791
+ db_raise(vself);
2792
+ return Qfalse;
2793
+ }
2794
+
2795
+
2796
+ /**
2797
+ * Implementation of get.
2798
+ */
2799
+ static VALUE db_get(VALUE vself, VALUE vkey) {
2800
+ kc::PolyDB* db;
2801
+ Data_Get_Struct(vself, kc::PolyDB, db);
2802
+ vkey = StringValueEx(vkey);
2803
+ const char* kbuf = RSTRING_PTR(vkey);
2804
+ size_t ksiz = RSTRING_LEN(vkey);
2805
+ char* vbuf;
2806
+ size_t vsiz;
2807
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2808
+ if (vmutex == Qnil) {
2809
+ class FuncImpl : public NativeFunction {
2810
+ public:
2811
+ explicit FuncImpl(kc::PolyDB* db, const char* kbuf, size_t ksiz) :
2812
+ db_(db), kbuf_(kbuf), ksiz_(ksiz), vbuf_(NULL), vsiz_(0) {}
2813
+ char* rv(size_t* vsp) {
2814
+ *vsp = vsiz_;
2815
+ return vbuf_;
2816
+ }
2817
+ private:
2818
+ void operate() {
2819
+ vbuf_ = db_->get(kbuf_, ksiz_, &vsiz_);
2820
+ }
2821
+ kc::PolyDB* db_;
2822
+ const char* kbuf_;
2823
+ size_t ksiz_;
2824
+ char* vbuf_;
2825
+ size_t vsiz_;
2826
+ } func(db, kbuf, ksiz);
2827
+ NativeFunction::execute(&func);
2828
+ vbuf = func.rv(&vsiz);
2829
+ } else {
2830
+ rb_funcall(vmutex, id_mtx_lock, 0);
2831
+ vbuf = db->get(kbuf, ksiz, &vsiz);
2832
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2833
+ }
2834
+ volatile VALUE vrv;
2835
+ if (vbuf) {
2836
+ vrv = rb_str_new_ex(vself, vbuf, vsiz);
2837
+ delete[] vbuf;
2838
+ } else {
2839
+ vrv = Qnil;
2840
+ db_raise(vself);
2841
+ }
2842
+ return vrv;
2843
+ }
2844
+
2845
+
2846
+ /**
2847
+ * Implementation of check.
2848
+ */
2849
+ static VALUE db_check(VALUE vself, VALUE vkey) {
2850
+ kc::PolyDB* db;
2851
+ Data_Get_Struct(vself, kc::PolyDB, db);
2852
+ vkey = StringValueEx(vkey);
2853
+ const char* kbuf = RSTRING_PTR(vkey);
2854
+ size_t ksiz = RSTRING_LEN(vkey);
2855
+ int32_t vsiz;
2856
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2857
+ if (vmutex == Qnil) {
2858
+ class FuncImpl : public NativeFunction {
2859
+ public:
2860
+ explicit FuncImpl(kc::PolyDB* db, const char* kbuf, size_t ksiz) :
2861
+ db_(db), kbuf_(kbuf), ksiz_(ksiz), vsiz_(-1) {}
2862
+ int32_t rv() {
2863
+ return vsiz_;
2864
+ }
2865
+ private:
2866
+ void operate() {
2867
+ vsiz_ = db_->check(kbuf_, ksiz_);
2868
+ }
2869
+ kc::PolyDB* db_;
2870
+ const char* kbuf_;
2871
+ size_t ksiz_;
2872
+ int32_t vsiz_;
2873
+ } func(db, kbuf, ksiz);
2874
+ NativeFunction::execute(&func);
2875
+ vsiz = func.rv();
2876
+ } else {
2877
+ rb_funcall(vmutex, id_mtx_lock, 0);
2878
+ vsiz = db->check(kbuf, ksiz);
2879
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2880
+ }
2881
+ if (vsiz < 0) db_raise(vself);
2882
+ return LL2NUM(vsiz);
2883
+ }
2884
+
2885
+
2886
+ /**
2887
+ * Implementation of seize.
2888
+ */
2889
+ static VALUE db_seize(VALUE vself, VALUE vkey) {
2890
+ kc::PolyDB* db;
2891
+ Data_Get_Struct(vself, kc::PolyDB, db);
2892
+ vkey = StringValueEx(vkey);
2893
+ const char* kbuf = RSTRING_PTR(vkey);
2894
+ size_t ksiz = RSTRING_LEN(vkey);
2895
+ char* vbuf;
2896
+ size_t vsiz;
2897
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2898
+ if (vmutex == Qnil) {
2899
+ class FuncImpl : public NativeFunction {
2900
+ public:
2901
+ explicit FuncImpl(kc::PolyDB* db, const char* kbuf, size_t ksiz) :
2902
+ db_(db), kbuf_(kbuf), ksiz_(ksiz), vbuf_(NULL), vsiz_(0) {}
2903
+ char* rv(size_t* vsp) {
2904
+ *vsp = vsiz_;
2905
+ return vbuf_;
2906
+ }
2907
+ private:
2908
+ void operate() {
2909
+ vbuf_ = db_->seize(kbuf_, ksiz_, &vsiz_);
2910
+ }
2911
+ kc::PolyDB* db_;
2912
+ const char* kbuf_;
2913
+ size_t ksiz_;
2914
+ char* vbuf_;
2915
+ size_t vsiz_;
2916
+ } func(db, kbuf, ksiz);
2917
+ NativeFunction::execute(&func);
2918
+ vbuf = func.rv(&vsiz);
2919
+ } else {
2920
+ rb_funcall(vmutex, id_mtx_lock, 0);
2921
+ vbuf = db->seize(kbuf, ksiz, &vsiz);
2922
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2923
+ }
2924
+ volatile VALUE vrv;
2925
+ if (vbuf) {
2926
+ vrv = rb_str_new_ex(vself, vbuf, vsiz);
2927
+ delete[] vbuf;
2928
+ } else {
2929
+ vrv = Qnil;
2930
+ db_raise(vself);
2931
+ }
2932
+ return vrv;
2933
+ }
2934
+
2935
+
2936
+ /**
2937
+ * Implementation of set_bulk.
2938
+ */
2939
+ static VALUE db_set_bulk(int argc, VALUE* argv, VALUE vself) {
2940
+ kc::PolyDB* db;
2941
+ Data_Get_Struct(vself, kc::PolyDB, db);
2942
+ volatile VALUE vrecs, vatomic;
2943
+ rb_scan_args(argc, argv, "11", &vrecs, &vatomic);
2944
+ StringMap recs;
2945
+ if (TYPE(vrecs) == T_HASH) {
2946
+ VALUE vkeys = rb_funcall(vrecs, id_hash_keys, 0);
2947
+ int32_t knum = RARRAY_LEN(vkeys);
2948
+ for (int32_t i = 0; i < knum; i++) {
2949
+ volatile VALUE vkey = rb_ary_entry(vkeys, i);
2950
+ volatile VALUE vvalue = rb_hash_aref(vrecs, vkey);
2951
+ vkey = StringValueEx(vkey);
2952
+ vvalue = StringValueEx(vvalue);
2953
+ recs[std::string(RSTRING_PTR(vkey), RSTRING_LEN(vkey))] =
2954
+ std::string(RSTRING_PTR(vvalue), RSTRING_LEN(vvalue));
2955
+ }
2956
+ }
2957
+ bool atomic = vatomic != Qfalse;
2958
+ int64_t rv;
2959
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
2960
+ if (vmutex == Qnil) {
2961
+ class FuncImpl : public NativeFunction {
2962
+ public:
2963
+ explicit FuncImpl(kc::PolyDB* db, const StringMap* recs, bool atomic) :
2964
+ db_(db), recs_(recs), atomic_(atomic), rv_(0) {}
2965
+ int64_t rv() {
2966
+ return rv_;
2967
+ }
2968
+ private:
2969
+ void operate() {
2970
+ rv_ = db_->set_bulk(*recs_, atomic_);
2971
+ }
2972
+ kc::PolyDB* db_;
2973
+ const StringMap* recs_;
2974
+ bool atomic_;
2975
+ int64_t rv_;
2976
+ } func(db, &recs, atomic);
2977
+ NativeFunction::execute(&func);
2978
+ rv = func.rv();
2979
+ } else {
2980
+ rb_funcall(vmutex, id_mtx_lock, 0);
2981
+ rv = db->set_bulk(recs, atomic);
2982
+ rb_funcall(vmutex, id_mtx_unlock, 0);
2983
+ }
2984
+ if (rv < 0) {
2985
+ db_raise(vself);
2986
+ return LL2NUM(-1);
2987
+ }
2988
+ return LL2NUM(rv);
2989
+ }
2990
+
2991
+
2992
+ /**
2993
+ * Implementation of remove_bulk.
2994
+ */
2995
+ static VALUE db_remove_bulk(int argc, VALUE* argv, VALUE vself) {
2996
+ kc::PolyDB* db;
2997
+ Data_Get_Struct(vself, kc::PolyDB, db);
2998
+ volatile VALUE vkeys, vatomic;
2999
+ rb_scan_args(argc, argv, "11", &vkeys, &vatomic);
3000
+ StringVector keys;
3001
+ if (TYPE(vkeys) == T_ARRAY) {
3002
+ int32_t knum = RARRAY_LEN(vkeys);
3003
+ for (int32_t i = 0; i < knum; i++) {
3004
+ volatile VALUE vkey = rb_ary_entry(vkeys, i);
3005
+ vkey = StringValueEx(vkey);
3006
+ keys.push_back(std::string(RSTRING_PTR(vkey), RSTRING_LEN(vkey)));
3007
+ }
3008
+ }
3009
+ bool atomic = vatomic != Qfalse;
3010
+ int64_t rv;
3011
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3012
+ if (vmutex == Qnil) {
3013
+ class FuncImpl : public NativeFunction {
3014
+ public:
3015
+ explicit FuncImpl(kc::PolyDB* db, const StringVector* keys, bool atomic) :
3016
+ db_(db), keys_(keys), atomic_(atomic), rv_(0) {}
3017
+ int64_t rv() {
3018
+ return rv_;
3019
+ }
3020
+ private:
3021
+ void operate() {
3022
+ rv_ = db_->remove_bulk(*keys_, atomic_);
3023
+ }
3024
+ kc::PolyDB* db_;
3025
+ const StringVector* keys_;
3026
+ bool atomic_;
3027
+ int64_t rv_;
3028
+ } func(db, &keys, atomic);
3029
+ NativeFunction::execute(&func);
3030
+ rv = func.rv();
3031
+ } else {
3032
+ rb_funcall(vmutex, id_mtx_lock, 0);
3033
+ rv = db->remove_bulk(keys, atomic);
3034
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3035
+ }
3036
+ if (rv < 0) {
3037
+ db_raise(vself);
3038
+ return LL2NUM(-1);
3039
+ }
3040
+ return LL2NUM(rv);
3041
+ }
3042
+
3043
+
3044
+ /**
3045
+ * Implementation of get_bulk.
3046
+ */
3047
+ static VALUE db_get_bulk(int argc, VALUE* argv, VALUE vself) {
3048
+ kc::PolyDB* db;
3049
+ Data_Get_Struct(vself, kc::PolyDB, db);
3050
+ volatile VALUE vkeys, vatomic;
3051
+ rb_scan_args(argc, argv, "11", &vkeys, &vatomic);
3052
+ StringVector keys;
3053
+ if (TYPE(vkeys) == T_ARRAY) {
3054
+ int32_t knum = RARRAY_LEN(vkeys);
3055
+ for (int32_t i = 0; i < knum; i++) {
3056
+ volatile VALUE vkey = rb_ary_entry(vkeys, i);
3057
+ vkey = StringValueEx(vkey);
3058
+ keys.push_back(std::string(RSTRING_PTR(vkey), RSTRING_LEN(vkey)));
3059
+ }
3060
+ }
3061
+ bool atomic = vatomic != Qfalse;
3062
+ StringMap recs;
3063
+ int64_t rv;
3064
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3065
+ if (vmutex == Qnil) {
3066
+ class FuncImpl : public NativeFunction {
3067
+ public:
3068
+ explicit FuncImpl(kc::PolyDB* db, const StringVector* keys, StringMap* recs, bool atomic) :
3069
+ db_(db), keys_(keys), recs_(recs), atomic_(atomic), rv_(0) {}
3070
+ int64_t rv() {
3071
+ return rv_;
3072
+ }
3073
+ private:
3074
+ void operate() {
3075
+ rv_ = db_->get_bulk(*keys_, recs_, atomic_);
3076
+ }
3077
+ kc::PolyDB* db_;
3078
+ const StringVector* keys_;
3079
+ StringMap* recs_;
3080
+ bool atomic_;
3081
+ int64_t rv_;
3082
+ } func(db, &keys, &recs, atomic);
3083
+ NativeFunction::execute(&func);
3084
+ rv = func.rv();
3085
+ } else {
3086
+ rb_funcall(vmutex, id_mtx_lock, 0);
3087
+ rv = db->get_bulk(keys, &recs, atomic);
3088
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3089
+ }
3090
+ if (rv < 0) {
3091
+ db_raise(vself);
3092
+ return Qnil;
3093
+ }
3094
+ return maptovhash(vself, &recs);
3095
+ }
3096
+
3097
+
3098
+ /**
3099
+ * Implementation of clear.
3100
+ */
3101
+ static VALUE db_clear(VALUE vself) {
3102
+ kc::PolyDB* db;
3103
+ Data_Get_Struct(vself, kc::PolyDB, db);
3104
+ bool rv;
3105
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3106
+ if (vmutex == Qnil) {
3107
+ class FuncImpl : public NativeFunction {
3108
+ public:
3109
+ explicit FuncImpl(kc::PolyDB* db) : db_(db), rv_(false) {}
3110
+ bool rv() {
3111
+ return rv_;
3112
+ }
3113
+ private:
3114
+ void operate() {
3115
+ rv_ = db_->clear();
3116
+ }
3117
+ kc::PolyDB* db_;
3118
+ bool rv_;
3119
+ } func(db);
3120
+ NativeFunction::execute(&func);
3121
+ rv = func.rv();
3122
+ } else {
3123
+ rb_funcall(vmutex, id_mtx_lock, 0);
3124
+ rv = db->clear();
3125
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3126
+ }
3127
+ if (rv) return Qtrue;
3128
+ db_raise(vself);
3129
+ return Qfalse;
3130
+ }
3131
+
3132
+
3133
+ /**
3134
+ * Implementation of synchronize.
3135
+ */
3136
+ static VALUE db_synchronize(int argc, VALUE* argv, VALUE vself) {
3137
+ kc::PolyDB* db;
3138
+ Data_Get_Struct(vself, kc::PolyDB, db);
3139
+ volatile VALUE vhard, vproc;
3140
+ rb_scan_args(argc, argv, "02", &vhard, &vproc);
3141
+ bool hard = vhard != Qnil && vhard != Qfalse;
3142
+ volatile VALUE vrv;
3143
+ if (rb_respond_to(vproc, id_fproc_process)) {
3144
+ SoftFileProcessor proc(vself, vproc);
3145
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3146
+ if (vmutex == Qnil) {
3147
+ db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
3148
+ db_raise(vself);
3149
+ return Qnil;
3150
+ }
3151
+ rb_funcall(vmutex, id_mtx_lock, 0);
3152
+ bool rv = db->synchronize(hard, &proc);
3153
+ const char *emsg = proc.emsg();
3154
+ if (emsg) {
3155
+ db->set_error(kc::PolyDB::Error::LOGIC, emsg);
3156
+ rv = false;
3157
+ }
3158
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3159
+ if (rv) {
3160
+ vrv = Qtrue;
3161
+ } else {
3162
+ vrv = Qfalse;
3163
+ db_raise(vself);
3164
+ }
3165
+ } else if (rb_block_given_p()) {
3166
+ SoftBlockFileProcessor proc(vself);
3167
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3168
+ if (vmutex == Qnil) {
3169
+ db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
3170
+ db_raise(vself);
3171
+ return Qnil;
3172
+ }
3173
+ rb_funcall(vmutex, id_mtx_lock, 0);
3174
+ bool rv = db->synchronize(hard, &proc);
3175
+ const char *emsg = proc.emsg();
3176
+ if (emsg) {
3177
+ db->set_error(kc::PolyDB::Error::LOGIC, emsg);
3178
+ rv = false;
3179
+ }
3180
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3181
+ if (rv) {
3182
+ vrv = Qtrue;
3183
+ } else {
3184
+ vrv = Qfalse;
3185
+ db_raise(vself);
3186
+ }
3187
+ } else {
3188
+ bool rv;
3189
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3190
+ if (vmutex == Qnil) {
3191
+ class FuncImpl : public NativeFunction {
3192
+ public:
3193
+ explicit FuncImpl(kc::PolyDB* db, bool hard) : db_(db), hard_(hard), rv_(false) {}
3194
+ bool rv() {
3195
+ return rv_;
3196
+ }
3197
+ private:
3198
+ void operate() {
3199
+ rv_ = db_->synchronize(hard_, NULL);
3200
+ }
3201
+ kc::PolyDB* db_;
3202
+ bool hard_;
3203
+ bool rv_;
3204
+ } func(db, hard);
3205
+ NativeFunction::execute(&func);
3206
+ rv = func.rv();
3207
+ } else {
3208
+ rb_funcall(vmutex, id_mtx_lock, 0);
3209
+ rv = db->synchronize(hard, NULL);
3210
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3211
+ }
3212
+ if (rv) {
3213
+ vrv = Qtrue;
3214
+ } else {
3215
+ vrv = Qfalse;
3216
+ db_raise(vself);
3217
+ }
3218
+ }
3219
+ return vrv;
3220
+ }
3221
+
3222
+
3223
+ /**
3224
+ * Implementation of occupy.
3225
+ */
3226
+ static VALUE db_occupy(int argc, VALUE* argv, VALUE vself) {
3227
+ kc::PolyDB* db;
3228
+ Data_Get_Struct(vself, kc::PolyDB, db);
3229
+ volatile VALUE vwritable, vproc;
3230
+ rb_scan_args(argc, argv, "02", &vwritable, &vproc);
3231
+ bool writable = vwritable != Qnil && vwritable != Qfalse;
3232
+ volatile VALUE vrv;
3233
+ if (rb_respond_to(vproc, id_fproc_process)) {
3234
+ SoftFileProcessor proc(vself, vproc);
3235
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3236
+ if (vmutex == Qnil) {
3237
+ db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
3238
+ db_raise(vself);
3239
+ return Qnil;
3240
+ }
3241
+ rb_funcall(vmutex, id_mtx_lock, 0);
3242
+ bool rv = db->occupy(writable, &proc);
3243
+ const char *emsg = proc.emsg();
3244
+ if (emsg) {
3245
+ db->set_error(kc::PolyDB::Error::LOGIC, emsg);
3246
+ rv = false;
3247
+ }
3248
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3249
+ if (rv) {
3250
+ vrv = Qtrue;
3251
+ } else {
3252
+ vrv = Qfalse;
3253
+ db_raise(vself);
3254
+ }
3255
+ } else if (rb_block_given_p()) {
3256
+ SoftBlockFileProcessor proc(vself);
3257
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3258
+ if (vmutex == Qnil) {
3259
+ db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
3260
+ db_raise(vself);
3261
+ return Qnil;
3262
+ }
3263
+ rb_funcall(vmutex, id_mtx_lock, 0);
3264
+ bool rv = db->occupy(writable, &proc);
3265
+ const char *emsg = proc.emsg();
3266
+ if (emsg) {
3267
+ db->set_error(kc::PolyDB::Error::LOGIC, emsg);
3268
+ rv = false;
3269
+ }
3270
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3271
+ if (rv) {
3272
+ vrv = Qtrue;
3273
+ } else {
3274
+ vrv = Qfalse;
3275
+ db_raise(vself);
3276
+ }
3277
+ } else {
3278
+ bool rv;
3279
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3280
+ if (vmutex == Qnil) {
3281
+ class FuncImpl : public NativeFunction {
3282
+ public:
3283
+ explicit FuncImpl(kc::PolyDB* db, bool writable) :
3284
+ db_(db), writable_(writable), rv_(false) {}
3285
+ bool rv() {
3286
+ return rv_;
3287
+ }
3288
+ private:
3289
+ void operate() {
3290
+ rv_ = db_->occupy(writable_, NULL);
3291
+ }
3292
+ kc::PolyDB* db_;
3293
+ bool writable_;
3294
+ bool rv_;
3295
+ } func(db, writable);
3296
+ NativeFunction::execute(&func);
3297
+ rv = func.rv();
3298
+ } else {
3299
+ rb_funcall(vmutex, id_mtx_lock, 0);
3300
+ rv = db->occupy(writable, NULL);
3301
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3302
+ }
3303
+ if (rv) {
3304
+ vrv = Qtrue;
3305
+ } else {
3306
+ vrv = Qfalse;
3307
+ db_raise(vself);
3308
+ }
3309
+ }
3310
+ return vrv;
3311
+ }
3312
+
3313
+
3314
+ /**
3315
+ * Implementation of copy.
3316
+ */
3317
+ static VALUE db_copy(VALUE vself, VALUE vdest) {
3318
+ kc::PolyDB* db;
3319
+ Data_Get_Struct(vself, kc::PolyDB, db);
3320
+ vdest = StringValueEx(vdest);
3321
+ const char* dest = RSTRING_PTR(vdest);
3322
+ bool rv;
3323
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3324
+ if (vmutex == Qnil) {
3325
+ class FuncImpl : public NativeFunction {
3326
+ public:
3327
+ explicit FuncImpl(kc::PolyDB* db, const char* dest) : db_(db), dest_(dest), rv_(false) {}
3328
+ bool rv() {
3329
+ return rv_;
3330
+ }
3331
+ private:
3332
+ void operate() {
3333
+ rv_ = db_->copy(dest_);
3334
+ }
3335
+ kc::PolyDB* db_;
3336
+ const char* dest_;
3337
+ bool rv_;
3338
+ } func(db, dest);
3339
+ NativeFunction::execute(&func);
3340
+ rv = func.rv();
3341
+ } else {
3342
+ rb_funcall(vmutex, id_mtx_lock, 0);
3343
+ rv = db->copy(dest);
3344
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3345
+ }
3346
+ if (rv) return Qtrue;
3347
+ db_raise(vself);
3348
+ return Qfalse;
3349
+ }
3350
+
3351
+
3352
+ /**
3353
+ * Implementation of begin_transaction.
3354
+ */
3355
+ static VALUE db_begin_transaction(int argc, VALUE* argv, VALUE vself) {
3356
+ kc::PolyDB* db;
3357
+ Data_Get_Struct(vself, kc::PolyDB, db);
3358
+ volatile VALUE vhard;
3359
+ rb_scan_args(argc, argv, "01", &vhard);
3360
+ bool hard = vhard != Qnil && vhard != Qfalse;
3361
+ bool err = false;
3362
+ while (true) {
3363
+ bool rv;
3364
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3365
+ if (vmutex == Qnil) {
3366
+ rv = db->begin_transaction_try(hard);
3367
+ } else {
3368
+ rb_funcall(vmutex, id_mtx_lock, 0);
3369
+ rv = db->begin_transaction_try(hard);
3370
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3371
+ }
3372
+ if (rv) break;
3373
+ if (db->error() != kc::PolyDB::Error::LOGIC) {
3374
+ err = true;
3375
+ break;
3376
+ }
3377
+ threadyield();
3378
+ }
3379
+ if (err) {
3380
+ db_raise(vself);
3381
+ return Qfalse;
3382
+ }
3383
+ return Qtrue;
3384
+ }
3385
+
3386
+
3387
+ /**
3388
+ * Implementation of end_transaction.
3389
+ */
3390
+ static VALUE db_end_transaction(int argc, VALUE* argv, VALUE vself) {
3391
+ kc::PolyDB* db;
3392
+ Data_Get_Struct(vself, kc::PolyDB, db);
3393
+ volatile VALUE vcommit;
3394
+ rb_scan_args(argc, argv, "01", &vcommit);
3395
+ bool commit = vcommit != Qfalse;
3396
+ bool rv;
3397
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3398
+ if (vmutex == Qnil) {
3399
+ rv = db->end_transaction(commit);
3400
+ } else {
3401
+ rb_funcall(vmutex, id_mtx_lock, 0);
3402
+ rv = db->end_transaction(commit);
3403
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3404
+ }
3405
+ if (rv) return Qtrue;
3406
+ db_raise(vself);
3407
+ return Qfalse;
3408
+ }
3409
+
3410
+
3411
+ /**
3412
+ * Implementation of transaction.
3413
+ */
3414
+ static VALUE db_transaction(int argc, VALUE* argv, VALUE vself) {
3415
+ volatile VALUE vhard;
3416
+ rb_scan_args(argc, argv, "01", &vhard);
3417
+ volatile VALUE vrv = rb_funcall(vself, id_db_begin_transaction, 1, vhard);
3418
+ if (vrv == Qnil || vrv == Qfalse) return Qfalse;
3419
+ volatile VALUE vbargs = rb_ary_new3(1, vself);
3420
+ volatile VALUE veargs = rb_ary_new3(2, vself, vbargs);
3421
+ rb_ensure((METHOD)db_transaction_body, vbargs, (METHOD)db_transaction_ensure, veargs);
3422
+ return rb_ary_pop(veargs);
3423
+ }
3424
+
3425
+
3426
+ /**
3427
+ * Implementation of transaction_body.
3428
+ */
3429
+ static VALUE db_transaction_body(VALUE vargs) {
3430
+ volatile VALUE vdb = rb_ary_shift(vargs);
3431
+ rb_ary_push(vargs, rb_yield(vdb));
3432
+ return Qnil;
3433
+ }
3434
+
3435
+
3436
+ /**
3437
+ * Implementation of transaction_ensure.
3438
+ */
3439
+ static VALUE db_transaction_ensure(VALUE vargs) {
3440
+ volatile VALUE vdb = rb_ary_shift(vargs);
3441
+ volatile VALUE vbargs = rb_ary_shift(vargs);
3442
+ volatile VALUE vrv = rb_ary_shift(vbargs);
3443
+ volatile VALUE vcommit = vrv != Qnil && vrv != Qfalse ? Qtrue : Qfalse;
3444
+ vrv = rb_funcall(vdb, id_db_end_transaction, 1, vcommit);
3445
+ rb_ary_push(vargs, vrv);
3446
+ return Qnil;
3447
+ }
3448
+
3449
+
3450
+ /**
3451
+ * Implementation of dump_snapshot.
3452
+ */
3453
+ static VALUE db_dump_snapshot(VALUE vself, VALUE vdest) {
3454
+ kc::PolyDB* db;
3455
+ Data_Get_Struct(vself, kc::PolyDB, db);
3456
+ vdest = StringValueEx(vdest);
3457
+ const char* dest = RSTRING_PTR(vdest);
3458
+ bool rv;
3459
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3460
+ if (vmutex == Qnil) {
3461
+ class FuncImpl : public NativeFunction {
3462
+ public:
3463
+ explicit FuncImpl(kc::PolyDB* db, const char* dest) : db_(db), dest_(dest), rv_(false) {}
3464
+ bool rv() {
3465
+ return rv_;
3466
+ }
3467
+ private:
3468
+ void operate() {
3469
+ rv_ = db_->dump_snapshot(dest_);
3470
+ }
3471
+ kc::PolyDB* db_;
3472
+ const char* dest_;
3473
+ bool rv_;
3474
+ } func(db, dest);
3475
+ NativeFunction::execute(&func);
3476
+ rv = func.rv();
3477
+ } else {
3478
+ rb_funcall(vmutex, id_mtx_lock, 0);
3479
+ rv = db->dump_snapshot(dest);
3480
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3481
+ }
3482
+ if (rv) return Qtrue;
3483
+ db_raise(vself);
3484
+ return Qfalse;
3485
+ }
3486
+
3487
+
3488
+ /**
3489
+ * Implementation of load_snapshot.
3490
+ */
3491
+ static VALUE db_load_snapshot(VALUE vself, VALUE vsrc) {
3492
+ kc::PolyDB* db;
3493
+ Data_Get_Struct(vself, kc::PolyDB, db);
3494
+ vsrc = StringValueEx(vsrc);
3495
+ const char* src = RSTRING_PTR(vsrc);
3496
+ bool rv;
3497
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3498
+ if (vmutex == Qnil) {
3499
+ class FuncImpl : public NativeFunction {
3500
+ public:
3501
+ explicit FuncImpl(kc::PolyDB* db, const char* src) : db_(db), src_(src), rv_(false) {}
3502
+ bool rv() {
3503
+ return rv_;
3504
+ }
3505
+ private:
3506
+ void operate() {
3507
+ rv_ = db_->load_snapshot(src_);
3508
+ }
3509
+ kc::PolyDB* db_;
3510
+ const char* src_;
3511
+ bool rv_;
3512
+ } func(db, src);
3513
+ NativeFunction::execute(&func);
3514
+ rv = func.rv();
3515
+ } else {
3516
+ rb_funcall(vmutex, id_mtx_lock, 0);
3517
+ rv = db->load_snapshot(src);
3518
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3519
+ }
3520
+ if (rv) return Qtrue;
3521
+ db_raise(vself);
3522
+ return Qfalse;
3523
+ }
3524
+
3525
+
3526
+ /**
3527
+ * Implementation of count.
3528
+ */
3529
+ static VALUE db_count(VALUE vself) {
3530
+ kc::PolyDB* db;
3531
+ Data_Get_Struct(vself, kc::PolyDB, db);
3532
+ int64_t count;
3533
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3534
+ if (vmutex == Qnil) {
3535
+ count = db->count();
3536
+ } else {
3537
+ rb_funcall(vmutex, id_mtx_lock, 0);
3538
+ count = db->count();
3539
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3540
+ }
3541
+ if (count < 0) db_raise(vself);
3542
+ return LL2NUM(count);
3543
+ }
3544
+
3545
+
3546
+ /**
3547
+ * Implementation of size.
3548
+ */
3549
+ static VALUE db_size(VALUE vself) {
3550
+ kc::PolyDB* db;
3551
+ Data_Get_Struct(vself, kc::PolyDB, db);
3552
+ int64_t size;
3553
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3554
+ if (vmutex == Qnil) {
3555
+ size = db->size();
3556
+ } else {
3557
+ rb_funcall(vmutex, id_mtx_lock, 0);
3558
+ size = db->size();
3559
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3560
+ }
3561
+ if (size < 0) db_raise(vself);
3562
+ return LL2NUM(size);
3563
+ }
3564
+
3565
+
3566
+ /**
3567
+ * Implementation of path.
3568
+ */
3569
+ static VALUE db_path(VALUE vself) {
3570
+ kc::PolyDB* db;
3571
+ Data_Get_Struct(vself, kc::PolyDB, db);
3572
+ std::string path;
3573
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3574
+ if (vmutex == Qnil) {
3575
+ path = db->path();
3576
+ } else {
3577
+ rb_funcall(vmutex, id_mtx_lock, 0);
3578
+ path = db->path();
3579
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3580
+ }
3581
+ if (path.size() < 1) {
3582
+ db_raise(vself);
3583
+ return Qnil;
3584
+ }
3585
+ return rb_str_new_ex2(vself, path.c_str());
3586
+ }
3587
+
3588
+
3589
+ /**
3590
+ * Implementation of status.
3591
+ */
3592
+ static VALUE db_status(VALUE vself) {
3593
+ kc::PolyDB* db;
3594
+ Data_Get_Struct(vself, kc::PolyDB, db);
3595
+ StringMap status;
3596
+ bool rv;
3597
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3598
+ if (vmutex == Qnil) {
3599
+ rv = db->status(&status);
3600
+ } else {
3601
+ rb_funcall(vmutex, id_mtx_lock, 0);
3602
+ rv = db->status(&status);
3603
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3604
+ }
3605
+ if (rv) return maptovhash(vself, &status);
3606
+ db_raise(vself);
3607
+ return Qnil;
3608
+ }
3609
+
3610
+
3611
+ /**
3612
+ * Implementation of match_prefix.
3613
+ */
3614
+ static VALUE db_match_prefix(int argc, VALUE* argv, VALUE vself) {
3615
+ kc::PolyDB* db;
3616
+ Data_Get_Struct(vself, kc::PolyDB, db);
3617
+ volatile VALUE vprefix, vmax;
3618
+ rb_scan_args(argc, argv, "11", &vprefix, &vmax);
3619
+ vprefix = StringValueEx(vprefix);
3620
+ const char* pbuf = RSTRING_PTR(vprefix);
3621
+ size_t psiz = RSTRING_LEN(vprefix);
3622
+ int64_t max = vmax == Qnil ? -1 : vatoi(vmax);
3623
+ volatile VALUE vrv;
3624
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3625
+ StringVector keys;
3626
+ int64_t rv;
3627
+ if (vmutex == Qnil) {
3628
+ class FuncImpl : public NativeFunction {
3629
+ public:
3630
+ explicit FuncImpl(kc::PolyDB* db, const char* pbuf, size_t psiz,
3631
+ StringVector* keys, int64_t max) :
3632
+ db_(db), pbuf_(pbuf), psiz_(psiz), keys_(keys), max_(max), rv_(0) {}
3633
+ int64_t rv() {
3634
+ return rv_;
3635
+ }
3636
+ private:
3637
+ void operate() {
3638
+ rv_ = db_->match_prefix(std::string(pbuf_, psiz_), keys_, max_);
3639
+ }
3640
+ kc::PolyDB* db_;
3641
+ const char* pbuf_;
3642
+ size_t psiz_;
3643
+ StringVector* keys_;
3644
+ int64_t max_;
3645
+ int64_t rv_;
3646
+ } func(db, pbuf, psiz, &keys, max);
3647
+ NativeFunction::execute(&func);
3648
+ rv = func.rv();
3649
+ } else {
3650
+ rb_funcall(vmutex, id_mtx_lock, 0);
3651
+ rv = db->match_prefix(std::string(pbuf, psiz), &keys, max);
3652
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3653
+ }
3654
+ if (rv >= 0) {
3655
+ vrv = vectortovarray(vself, &keys);
3656
+ } else {
3657
+ vrv = Qnil;
3658
+ db_raise(vself);
3659
+ }
3660
+ return vrv;
3661
+ }
3662
+
3663
+
3664
+ /**
3665
+ * Implementation of match_regex.
3666
+ */
3667
+ static VALUE db_match_regex(int argc, VALUE* argv, VALUE vself) {
3668
+ kc::PolyDB* db;
3669
+ Data_Get_Struct(vself, kc::PolyDB, db);
3670
+ volatile VALUE vregex, vmax;
3671
+ rb_scan_args(argc, argv, "11", &vregex, &vmax);
3672
+ vregex = StringValueEx(vregex);
3673
+ const char* rbuf = RSTRING_PTR(vregex);
3674
+ size_t rsiz = RSTRING_LEN(vregex);
3675
+ int64_t max = vmax == Qnil ? -1 : vatoi(vmax);
3676
+ volatile VALUE vrv;
3677
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3678
+ StringVector keys;
3679
+ int64_t rv;
3680
+ if (vmutex == Qnil) {
3681
+ class FuncImpl : public NativeFunction {
3682
+ public:
3683
+ explicit FuncImpl(kc::PolyDB* db, const char* rbuf, size_t rsiz,
3684
+ StringVector* keys, int64_t max) :
3685
+ db_(db), rbuf_(rbuf), rsiz_(rsiz), keys_(keys), max_(max), rv_(0) {}
3686
+ int64_t rv() {
3687
+ return rv_;
3688
+ }
3689
+ private:
3690
+ void operate() {
3691
+ rv_ = db_->match_regex(std::string(rbuf_, rsiz_), keys_, max_);
3692
+ }
3693
+ kc::PolyDB* db_;
3694
+ const char* rbuf_;
3695
+ size_t rsiz_;
3696
+ StringVector* keys_;
3697
+ int64_t max_;
3698
+ int64_t rv_;
3699
+ } func(db, rbuf, rsiz, &keys, max);
3700
+ NativeFunction::execute(&func);
3701
+ rv = func.rv();
3702
+ } else {
3703
+ rb_funcall(vmutex, id_mtx_lock, 0);
3704
+ rv = db->match_regex(std::string(rbuf, rsiz), &keys, max);
3705
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3706
+ }
3707
+ if (rv >= 0) {
3708
+ vrv = vectortovarray(vself, &keys);
3709
+ } else {
3710
+ vrv = Qnil;
3711
+ db_raise(vself);
3712
+ }
3713
+ return vrv;
3714
+ }
3715
+
3716
+
3717
+ /**
3718
+ * Implementation of match_similar.
3719
+ */
3720
+ static VALUE db_match_similar(int argc, VALUE* argv, VALUE vself) {
3721
+ kc::PolyDB* db;
3722
+ Data_Get_Struct(vself, kc::PolyDB, db);
3723
+ volatile VALUE vorigin, vrange, vutf, vmax;
3724
+ rb_scan_args(argc, argv, "13", &vorigin, &vrange, &vutf, &vmax);
3725
+ vorigin = StringValueEx(vorigin);
3726
+ const char* obuf = RSTRING_PTR(vorigin);
3727
+ size_t osiz = RSTRING_LEN(vorigin);
3728
+ int64_t range = vrange == Qnil ? 1 : vatoi(vrange);
3729
+ bool utf = vutf != Qnil && vutf != Qfalse;
3730
+ int64_t max = vmax == Qnil ? -1 : vatoi(vmax);
3731
+ volatile VALUE vrv;
3732
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3733
+ StringVector keys;
3734
+ int64_t rv;
3735
+ if (vmutex == Qnil) {
3736
+ class FuncImpl : public NativeFunction {
3737
+ public:
3738
+ explicit FuncImpl(kc::PolyDB* db, const char* obuf, size_t osiz, int64_t range, bool utf,
3739
+ StringVector* keys, int64_t max) :
3740
+ db_(db), obuf_(obuf), osiz_(osiz), range_(range), utf_(utf),
3741
+ keys_(keys), max_(max), rv_(0) {}
3742
+ int64_t rv() {
3743
+ return rv_;
3744
+ }
3745
+ private:
3746
+ void operate() {
3747
+ rv_ = db_->match_similar(std::string(obuf_, osiz_), range_, utf_, keys_, max_);
3748
+ }
3749
+ kc::PolyDB* db_;
3750
+ const char* obuf_;
3751
+ size_t osiz_;
3752
+ size_t range_;
3753
+ bool utf_;
3754
+ StringVector* keys_;
3755
+ int64_t max_;
3756
+ int64_t rv_;
3757
+ } func(db, obuf, osiz, range, utf, &keys, max);
3758
+ NativeFunction::execute(&func);
3759
+ rv = func.rv();
3760
+ } else {
3761
+ rb_funcall(vmutex, id_mtx_lock, 0);
3762
+ rv = db->match_similar(std::string(obuf, osiz), range, utf, &keys, max);
3763
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3764
+ }
3765
+ if (rv >= 0) {
3766
+ vrv = vectortovarray(vself, &keys);
3767
+ } else {
3768
+ vrv = Qnil;
3769
+ db_raise(vself);
3770
+ }
3771
+ return vrv;
3772
+ }
3773
+
3774
+
3775
+ /**
3776
+ * Implementation of merge.
3777
+ */
3778
+ static VALUE db_merge(int argc, VALUE* argv, VALUE vself) {
3779
+ kc::PolyDB* db;
3780
+ Data_Get_Struct(vself, kc::PolyDB, db);
3781
+ volatile VALUE vsrcary, vmode;
3782
+ rb_scan_args(argc, argv, "11", &vsrcary, &vmode);
3783
+ if (TYPE(vsrcary) != T_ARRAY) return Qfalse;
3784
+ uint32_t mode = vmode == Qnil ? kc::PolyDB::MSET : NUM2INT(vmode);
3785
+ int32_t num = RARRAY_LEN(vsrcary);
3786
+ if (num < 1) return Qtrue;
3787
+ kc::BasicDB** srcary = new kc::BasicDB*[num];
3788
+ size_t srcnum = 0;
3789
+ for (int32_t i = 0; i < num; i++) {
3790
+ volatile VALUE vsrcdb = rb_ary_entry(vsrcary, i);
3791
+ if (rb_obj_is_kind_of(vsrcdb, cls_db)) {
3792
+ kc::PolyDB* srcdb;
3793
+ Data_Get_Struct(vsrcdb, kc::PolyDB, srcdb);
3794
+ srcary[srcnum++] = srcdb;
3795
+ }
3796
+ }
3797
+ bool rv;
3798
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3799
+ if (vmutex == Qnil) {
3800
+ class FuncImpl : public NativeFunction {
3801
+ public:
3802
+ explicit FuncImpl(kc::PolyDB* db, kc::BasicDB** srcary, size_t srcnum, uint32_t mode) :
3803
+ db_(db), srcary_(srcary), srcnum_(srcnum), mode_(mode), rv_(false) {}
3804
+ bool rv() {
3805
+ return rv_;
3806
+ }
3807
+ private:
3808
+ void operate() {
3809
+ rv_ = db_->merge(srcary_, srcnum_, (kc::PolyDB::MergeMode)mode_);
3810
+ }
3811
+ kc::PolyDB* db_;
3812
+ kc::BasicDB** srcary_;
3813
+ size_t srcnum_;
3814
+ uint32_t mode_;
3815
+ bool rv_;
3816
+ } func(db, srcary, srcnum, mode);
3817
+ NativeFunction::execute(&func);
3818
+ rv = func.rv();
3819
+ } else {
3820
+ rb_funcall(vmutex, id_mtx_lock, 0);
3821
+ rv = db->merge(srcary, srcnum, (kc::PolyDB::MergeMode)mode);
3822
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3823
+ }
3824
+ delete[] srcary;
3825
+ if (rv) return Qtrue;
3826
+ db_raise(vself);
3827
+ return Qfalse;
3828
+ }
3829
+
3830
+
3831
+ /**
3832
+ * Implementation of cursor.
3833
+ */
3834
+ static VALUE db_cursor(VALUE vself) {
3835
+ return rb_class_new_instance(1, &vself, cls_cur);
3836
+ }
3837
+
3838
+
3839
+ /**
3840
+ * Implementation of cursor_process.
3841
+ */
3842
+ static VALUE db_cursor_process(VALUE vself) {
3843
+ volatile VALUE vcur = rb_class_new_instance(1, &vself, cls_cur);
3844
+ volatile VALUE vbargs = rb_ary_new3(1, vcur);
3845
+ volatile VALUE veargs = rb_ary_new3(1, vcur);
3846
+ rb_ensure((METHOD)db_cursor_process_body, vbargs, (METHOD)db_cursor_process_ensure, veargs);
3847
+ return Qnil;
3848
+ }
3849
+
3850
+
3851
+ /**
3852
+ * Implementation of cursor_process_body.
3853
+ */
3854
+ static VALUE db_cursor_process_body(VALUE vargs) {
3855
+ volatile VALUE vcur = rb_ary_shift(vargs);
3856
+ rb_yield(vcur);
3857
+ return Qnil;
3858
+ }
3859
+
3860
+
3861
+ /**
3862
+ * Implementation of cursor_process_ensure.
3863
+ */
3864
+ static VALUE db_cursor_process_ensure(VALUE vargs) {
3865
+ volatile VALUE vcur = rb_ary_shift(vargs);
3866
+ rb_funcall(vcur, id_cur_disable, 0);
3867
+ return Qnil;
3868
+ }
3869
+
3870
+
3871
+ /**
3872
+ * Implementation of tune_exception_rule.
3873
+ */
3874
+ static VALUE db_tune_exception_rule(VALUE vself, VALUE vcodes) {
3875
+ if (TYPE(vcodes) != T_ARRAY) return Qfalse;
3876
+ uint32_t exbits = 0;
3877
+ int32_t num = RARRAY_LEN(vcodes);
3878
+ for (int32_t i = 0; i < num; i++) {
3879
+ volatile VALUE vcode = rb_ary_entry(vcodes, i);
3880
+ uint32_t code = NUM2INT(vcode);
3881
+ if (code <= kc::PolyDB::Error::MISC) exbits |= 1 << code;
3882
+ }
3883
+ volatile VALUE vexbits = exbits > 0 ? INT2FIX(exbits) : Qnil;
3884
+ rb_ivar_set(vself, id_db_exbits, vexbits);
3885
+ return Qtrue;
3886
+ }
3887
+
3888
+
3889
+ /**
3890
+ * Implementation of tune_encoding.
3891
+ */
3892
+ static VALUE db_tune_encoding(VALUE vself, VALUE venc) {
3893
+ if (cls_enc == Qnil) return Qfalse;
3894
+ if (venc == Qnil) {
3895
+ rb_ivar_set(vself, id_db_enc, Qnil);
3896
+ } else if (rb_obj_is_instance_of(venc, cls_enc)) {
3897
+ rb_ivar_set(vself, id_db_enc, venc);
3898
+ } else {
3899
+ venc = StringValueEx(venc);
3900
+ volatile VALUE args = rb_ary_new3(1, venc);
3901
+ int result = 0;
3902
+ venc = rb_protect(db_tune_encoding_impl, args, &result);
3903
+ if (result) return Qfalse;
3904
+ rb_ivar_set(vself, id_db_enc, venc);
3905
+ }
3906
+ return Qtrue;
3907
+ }
3908
+
3909
+
3910
+ /**
3911
+ * Implementation of tune_encoding_impl.
3912
+ */
3913
+ static VALUE db_tune_encoding_impl(VALUE args) {
3914
+ volatile VALUE venc = rb_ary_shift(args);
3915
+ return rb_funcall(cls_enc, id_enc_find, 1, venc);
3916
+ }
3917
+
3918
+
3919
+ /**
3920
+ * Implementation of to_s.
3921
+ */
3922
+ static VALUE db_to_s(VALUE vself) {
3923
+ kc::PolyDB* db;
3924
+ Data_Get_Struct(vself, kc::PolyDB, db);
3925
+ std::string str;
3926
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3927
+ if (vmutex == Qnil) {
3928
+ std::string path = db->path();
3929
+ if (path.size() < 1) path = "(nil)";
3930
+ kc::strprintf(&str, "%s: %lld: %lld",
3931
+ path.c_str(), (long long)db->count(), (long long)db->size());
3932
+ } else {
3933
+ rb_funcall(vmutex, id_mtx_lock, 0);
3934
+ std::string path = db->path();
3935
+ if (path.size() < 1) path = "(nil)";
3936
+ kc::strprintf(&str, "%s: %lld: %lld",
3937
+ path.c_str(), (long long)db->count(), (long long)db->size());
3938
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3939
+ }
3940
+ return rb_str_new_ex2(vself, str.c_str());
3941
+ }
3942
+
3943
+
3944
+ /**
3945
+ * Implementation of inspect.
3946
+ */
3947
+ static VALUE db_inspect(VALUE vself) {
3948
+ kc::PolyDB* db;
3949
+ Data_Get_Struct(vself, kc::PolyDB, db);
3950
+ std::string str;
3951
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3952
+ if (vmutex == Qnil) {
3953
+ std::string path = db->path();
3954
+ if (path.size() < 1) path = "(nil)";
3955
+ kc::strprintf(&str, "#<KyotoCabinet::DB:%p: %s: %lld: %lld>",
3956
+ db, path.c_str(), (long long)db->count(), (long long)db->size());
3957
+ } else {
3958
+ rb_funcall(vmutex, id_mtx_lock, 0);
3959
+ std::string path = db->path();
3960
+ if (path.size() < 1) path = "(nil)";
3961
+ kc::strprintf(&str, "#<KyotoCabinet::DB:%p: %s: %lld: %lld>",
3962
+ db, path.c_str(), (long long)db->count(), (long long)db->size());
3963
+ rb_funcall(vmutex, id_mtx_unlock, 0);
3964
+ }
3965
+ return rb_str_new_ex2(vself, str.c_str());
3966
+ }
3967
+
3968
+
3969
+ /**
3970
+ * Implementation of shift.
3971
+ */
3972
+ static VALUE db_shift(VALUE vself) {
3973
+ kc::PolyDB* db;
3974
+ Data_Get_Struct(vself, kc::PolyDB, db);
3975
+ char* kbuf;
3976
+ const char* vbuf;
3977
+ size_t ksiz, vsiz;
3978
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
3979
+ if (vmutex == Qnil) {
3980
+ class FuncImpl : public NativeFunction {
3981
+ public:
3982
+ explicit FuncImpl(kc::PolyDB* db) :
3983
+ db_(db), kbuf_(NULL), ksiz_(0), vbuf_(NULL), vsiz_(0) {}
3984
+ char* rv(size_t* ksp, const char** vbp, size_t* vsp) {
3985
+ *ksp = ksiz_;
3986
+ *vbp = vbuf_;
3987
+ *vsp = vsiz_;
3988
+ return kbuf_;
3989
+ }
3990
+ private:
3991
+ void operate() {
3992
+ kbuf_ = db_shift_impl(db_, &ksiz_, &vbuf_, &vsiz_);
3993
+ }
3994
+ kc::PolyDB* db_;
3995
+ char* kbuf_;
3996
+ size_t ksiz_;
3997
+ const char* vbuf_;
3998
+ size_t vsiz_;
3999
+ } func(db);
4000
+ NativeFunction::execute(&func);
4001
+ kbuf = func.rv(&ksiz, &vbuf, &vsiz);
4002
+ } else {
4003
+ rb_funcall(vmutex, id_mtx_lock, 0);
4004
+ kbuf = db_shift_impl(db, &ksiz, &vbuf, &vsiz);
4005
+ rb_funcall(vmutex, id_mtx_unlock, 0);
4006
+ }
4007
+ volatile VALUE vrv;
4008
+ if (kbuf) {
4009
+ volatile VALUE vkey = rb_str_new_ex(vself, kbuf, ksiz);
4010
+ volatile VALUE vvalue = rb_str_new_ex(vself, vbuf, vsiz);
4011
+ vrv = rb_ary_new3(2, vkey, vvalue);
4012
+ delete[] kbuf;
4013
+ } else {
4014
+ vrv = Qnil;
4015
+ db_raise(vself);
4016
+ }
4017
+ return vrv;
4018
+ }
4019
+
4020
+
4021
+ static char* db_shift_impl(kc::PolyDB* db, size_t* ksp, const char** vbp, size_t* vsp) {
4022
+ kc::PolyDB::Cursor cur(db);
4023
+ if (!cur.jump()) return NULL;
4024
+ class VisitorImpl : public kc::PolyDB::Visitor {
4025
+ public:
4026
+ explicit VisitorImpl() : kbuf_(NULL), ksiz_(0), vbuf_(NULL), vsiz_(0) {}
4027
+ char* rv(size_t* ksp, const char** vbp, size_t* vsp) {
4028
+ *ksp = ksiz_;
4029
+ *vbp = vbuf_;
4030
+ *vsp = vsiz_;
4031
+ return kbuf_;
4032
+ }
4033
+ private:
4034
+ const char* visit_full(const char* kbuf, size_t ksiz,
4035
+ const char* vbuf, size_t vsiz, size_t* sp) {
4036
+ size_t rsiz = ksiz + 1 + vsiz + 1;
4037
+ kbuf_ = new char[rsiz];
4038
+ std::memcpy(kbuf_, kbuf, ksiz);
4039
+ kbuf_[ksiz] = '\0';
4040
+ ksiz_ = ksiz;
4041
+ vbuf_ = kbuf_ + ksiz + 1;
4042
+ std::memcpy(vbuf_, vbuf, vsiz);
4043
+ vbuf_[vsiz] = '\0';
4044
+ vsiz_ = vsiz;
4045
+ return REMOVE;
4046
+ }
4047
+ char* kbuf_;
4048
+ size_t ksiz_;
4049
+ char* vbuf_;
4050
+ size_t vsiz_;
4051
+ } visitor;
4052
+ if (!cur.accept(&visitor, true, false)) return NULL;
4053
+ return visitor.rv(ksp, vbp, vsp);
4054
+ }
4055
+
4056
+
4057
+ /**
4058
+ * Implementation of each.
4059
+ */
4060
+ static VALUE db_each(VALUE vself) {
4061
+ kc::PolyDB* db;
4062
+ Data_Get_Struct(vself, kc::PolyDB, db);
4063
+ SoftEachVisitor visitor(vself);
4064
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
4065
+ if (vmutex == Qnil) {
4066
+ db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
4067
+ db_raise(vself);
4068
+ return Qnil;
4069
+ }
4070
+ rb_funcall(vmutex, id_mtx_lock, 0);
4071
+ bool rv = db->iterate(&visitor, false);
4072
+ const char *emsg = visitor.emsg();
4073
+ if (emsg) {
4074
+ db->set_error(kc::PolyDB::Error::LOGIC, emsg);
4075
+ rv = false;
4076
+ }
4077
+ rb_funcall(vmutex, id_mtx_unlock, 0);
4078
+ if (rv) return Qtrue;
4079
+ db_raise(vself);
4080
+ return Qfalse;
4081
+ }
4082
+
4083
+
4084
+ /**
4085
+ * Implementation of each_key.
4086
+ */
4087
+ static VALUE db_each_key(VALUE vself) {
4088
+ kc::PolyDB* db;
4089
+ Data_Get_Struct(vself, kc::PolyDB, db);
4090
+ SoftEachKeyVisitor visitor(vself);
4091
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
4092
+ if (vmutex == Qnil) {
4093
+ db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
4094
+ db_raise(vself);
4095
+ return Qnil;
4096
+ }
4097
+ rb_funcall(vmutex, id_mtx_lock, 0);
4098
+ bool rv = db->iterate(&visitor, false);
4099
+ const char *emsg = visitor.emsg();
4100
+ if (emsg) {
4101
+ db->set_error(kc::PolyDB::Error::LOGIC, emsg);
4102
+ rv = false;
4103
+ }
4104
+ rb_funcall(vmutex, id_mtx_unlock, 0);
4105
+ if (rv) return Qtrue;
4106
+ db_raise(vself);
4107
+ return Qfalse;
4108
+ }
4109
+
4110
+
4111
+ /**
4112
+ * Implementation of each_value.
4113
+ */
4114
+ static VALUE db_each_value(VALUE vself) {
4115
+ kc::PolyDB* db;
4116
+ Data_Get_Struct(vself, kc::PolyDB, db);
4117
+ SoftEachValueVisitor visitor(vself);
4118
+ volatile VALUE vmutex = rb_ivar_get(vself, id_db_mutex);
4119
+ if (vmutex == Qnil) {
4120
+ db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
4121
+ db_raise(vself);
4122
+ return Qnil;
4123
+ }
4124
+ rb_funcall(vmutex, id_mtx_lock, 0);
4125
+ bool rv = db->iterate(&visitor, false);
4126
+ const char *emsg = visitor.emsg();
4127
+ if (emsg) {
4128
+ db->set_error(kc::PolyDB::Error::LOGIC, emsg);
4129
+ rv = false;
4130
+ }
4131
+ rb_funcall(vmutex, id_mtx_unlock, 0);
4132
+ if (rv) return Qtrue;
4133
+ db_raise(vself);
4134
+ return Qfalse;
4135
+ }
4136
+
4137
+
4138
+ /**
4139
+ * Implementation of process.
4140
+ */
4141
+ static VALUE db_process(int argc, VALUE* argv, VALUE vself) {
4142
+ volatile VALUE vpath, vmode, vopts;
4143
+ rb_scan_args(argc, argv, "03", &vpath, &vmode, &vopts);
4144
+ volatile VALUE vdb = rb_class_new_instance(1, (VALUE*)&vopts, cls_db);
4145
+ volatile VALUE vrv = rb_funcall(vdb, id_db_open, 2, vpath, vmode);
4146
+ if (vrv == Qnil || vrv == Qfalse) return rb_funcall(vdb, id_db_error, 0);
4147
+ volatile VALUE vbargs = rb_ary_new3(1, vdb);
4148
+ volatile VALUE veargs = rb_ary_new3(1, vdb);
4149
+ rb_ensure((METHOD)db_process_body, vbargs, (METHOD)db_process_ensure, veargs);
4150
+ return rb_ary_pop(veargs);
4151
+ }
4152
+
4153
+
4154
+ /**
4155
+ * Implementation of process_body.
4156
+ */
4157
+ static VALUE db_process_body(VALUE vargs) {
4158
+ volatile VALUE vdb = rb_ary_shift(vargs);
4159
+ rb_yield(vdb);
4160
+ return Qnil;
4161
+ }
4162
+
4163
+
4164
+ /**
4165
+ * Implementation of process_ensure.
4166
+ */
4167
+ static VALUE db_process_ensure(VALUE vargs) {
4168
+ volatile VALUE vdb = rb_ary_shift(vargs);
4169
+ volatile VALUE vrv = rb_funcall(vdb, id_db_close, 0);
4170
+ if (vrv != Qtrue) rb_ary_push(vargs, rb_funcall(vdb, id_db_error, 0));
4171
+ return Qnil;
4172
+ }
4173
+
4174
+
4175
+ }
4176
+
4177
+
4178
+ // END OF FILE