gazay-kyotocabinet-ruby 1.28

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