kyotocabinet-ruby 1.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. data/extconf.rb +30 -0
  2. data/kyotocabinet.cc +4120 -0
  3. metadata +68 -0
@@ -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
@@ -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_set, 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