lmdb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,725 @@
1
+ #include "ruby.h"
2
+ #include "lmdb.h"
3
+
4
+ /*-----------------------------------------------------------------------------
5
+ * Macros
6
+ *----------------------------------------------------------------------------*/
7
+
8
+ #define ENV_FLAGS ( \
9
+ MDB_FIXEDMAP | \
10
+ MDB_NOSUBDIR | \
11
+ MDB_NOSYNC | \
12
+ MDB_RDONLY | \
13
+ MDB_NOMETASYNC | \
14
+ MDB_WRITEMAP | \
15
+ MDB_MAPASYNC)
16
+
17
+ #define ENVIRONMENT(var, var_env) \
18
+ Environment* var_env; \
19
+ Data_Get_Struct(var, Environment, var_env); \
20
+ do { if (!var_env->env) rb_raise(cError, "Environment is closed"); } while(0)
21
+
22
+ #define TRANSACTION(var, var_txn, var_env) \
23
+ Transaction* var_txn; \
24
+ Data_Get_Struct(var, Transaction, var_txn); \
25
+ { \
26
+ Transaction* parent = var_txn; \
27
+ for (;;) { \
28
+ if (!parent->txn) \
29
+ rb_raise(cError, "Transaction is terminated"); \
30
+ if (NIL_P(parent->parent)) \
31
+ break; \
32
+ Data_Get_Struct(parent->parent, Transaction, parent); \
33
+ } \
34
+ } \
35
+ ENVIRONMENT(transaction->environment, var_env)
36
+
37
+ #define DATABASE(var, var_db, var_env) \
38
+ Database* var_db; \
39
+ Data_Get_Struct(var, Database, var_db); \
40
+ if (!var_db->open) rb_raise(cError, "Database is closed"); \
41
+ ENVIRONMENT(database->environment, var_env)
42
+
43
+ #define DATABASE_TRANSACTION(dbvar, txvar, var_db, var_txn, var_env) \
44
+ DATABASE(dbvar, var_db, tmp_env); \
45
+ TRANSACTION(txvar, var_txn, var_env); \
46
+ do { if (var_env != tmp_env) rb_raise(cError, "Different environments"); } while(0) \
47
+
48
+ #define CURSOR(var, var_cur, var_db, var_txn, var_env) \
49
+ Cursor* var_cur; \
50
+ Data_Get_Struct(var, Cursor, var_cur); \
51
+ if (!cursor->cur) rb_raise(cError, "Cursor is closed"); \
52
+ DATABASE_TRANSACTION(var_cur->database, var_cur->transaction, var_db, var_txn, var_env)
53
+
54
+ /*-----------------------------------------------------------------------------
55
+ * Static
56
+ *----------------------------------------------------------------------------*/
57
+
58
+ /* Classes */
59
+ static VALUE cEnvironment, cStat, cInfo, cDatabase, cTransaction, cCursor, cError;
60
+
61
+ /* Error Classes */
62
+ #define ERROR(name) static VALUE cError_##name;
63
+ #include "errors.h"
64
+ #undef ERROR
65
+
66
+ /*-----------------------------------------------------------------------------
67
+ * Structs
68
+ *----------------------------------------------------------------------------*/
69
+
70
+ typedef struct {
71
+ MDB_env* env;
72
+ } Environment;
73
+
74
+ typedef struct {
75
+ VALUE environment;
76
+ MDB_dbi dbi;
77
+ int open;
78
+ } Database;
79
+
80
+ typedef struct {
81
+ VALUE environment;
82
+ VALUE parent;
83
+ MDB_txn* txn;
84
+ } Transaction;
85
+
86
+ typedef struct {
87
+ VALUE transaction;
88
+ VALUE database;
89
+ MDB_cursor* cur;
90
+ } Cursor;
91
+
92
+ /*-----------------------------------------------------------------------------
93
+ * Prototypes
94
+ *----------------------------------------------------------------------------*/
95
+
96
+ static void transaction_mark(Transaction* transaction);
97
+ static void transaction_free(Transaction *transaction);
98
+
99
+ /*-----------------------------------------------------------------------------
100
+ * Helpers
101
+ *----------------------------------------------------------------------------*/
102
+
103
+ #define F_STAT(name) \
104
+ static VALUE stat_##name(VALUE self) { \
105
+ MDB_stat* stat; \
106
+ Data_Get_Struct(self, MDB_stat, stat); \
107
+ return INT2NUM(stat->ms_##name); \
108
+ }
109
+ F_STAT(psize)
110
+ F_STAT(depth)
111
+ F_STAT(branch_pages)
112
+ F_STAT(leaf_pages)
113
+ F_STAT(overflow_pages)
114
+ F_STAT(entries)
115
+ #undef F_STAT
116
+
117
+ #define F_INFO(name) \
118
+ static VALUE info_##name(VALUE self) { \
119
+ MDB_envinfo* info; \
120
+ Data_Get_Struct(self, MDB_envinfo, info); \
121
+ return INT2NUM((size_t)info->me_##name); \
122
+ }
123
+ F_INFO(mapaddr)
124
+ F_INFO(mapsize)
125
+ F_INFO(last_pgno)
126
+ F_INFO(last_txnid)
127
+ F_INFO(maxreaders)
128
+ F_INFO(numreaders)
129
+ #undef F_INFO
130
+
131
+ static void check(int code) {
132
+ const char *err, *sep;
133
+ if (!code) return;
134
+
135
+ err = mdb_strerror(code);
136
+ sep = strchr(err, ':');
137
+ if (sep) err = sep + 2;
138
+
139
+ #define ERROR(name) if (code == MDB_##name) rb_raise(cError_##name, "%s", err);
140
+ #include "errors.h"
141
+ #undef ERROR
142
+
143
+ rb_raise(cError, "%s", err); /* fallback */
144
+
145
+ }
146
+
147
+ /*-----------------------------------------------------------------------------
148
+ * Environment functions
149
+ *----------------------------------------------------------------------------*/
150
+
151
+ static void environment_free(Environment *environment) {
152
+ if (environment->env)
153
+ mdb_env_close(environment->env);
154
+ free(environment);
155
+ }
156
+
157
+ static VALUE environment_close(VALUE self) {
158
+ ENVIRONMENT(self, environment);
159
+ mdb_env_close(environment->env);
160
+ environment->env = 0;
161
+ return Qnil;
162
+ }
163
+
164
+ static VALUE environment_stat(VALUE self) {
165
+ MDB_stat* stat;
166
+ VALUE vstat;
167
+
168
+ ENVIRONMENT(self, environment);
169
+ vstat = Data_Make_Struct(cStat, MDB_stat, 0, -1, stat);
170
+ check(mdb_env_stat(environment->env, stat));
171
+ return vstat;
172
+ }
173
+
174
+ static VALUE environment_info(VALUE self) {
175
+ MDB_envinfo* info;
176
+ VALUE vinfo;
177
+
178
+ ENVIRONMENT(self, environment);
179
+ vinfo = Data_Make_Struct(cInfo, MDB_envinfo, 0, -1, info);
180
+ check(mdb_env_info(environment->env, info));
181
+ return vinfo;
182
+ }
183
+
184
+ static VALUE environment_copy(VALUE self, VALUE path) {
185
+ ENVIRONMENT(self, environment);
186
+ check(mdb_env_copy(environment->env, StringValueCStr(path)));
187
+ return Qnil;
188
+ }
189
+
190
+ static VALUE environment_sync(int argc, VALUE *argv, VALUE self) {
191
+ VALUE force;
192
+ int n;
193
+
194
+ ENVIRONMENT(self, environment);
195
+ n = rb_scan_args(argc, argv, "01", &force);
196
+ check(mdb_env_sync(environment->env, n == 1 && RTEST(force) ? 0 : 1));
197
+ return Qnil;
198
+ }
199
+
200
+ static VALUE environment_open(int argc, VALUE *argv, VALUE klass) {
201
+ VALUE path, options, venv;
202
+ MDB_env* env;
203
+ Environment* environment;
204
+
205
+ int n = rb_scan_args(argc, argv, "11", &path, &options);
206
+
207
+ int flags = 0, maxreaders = -1, maxdbs = 10;
208
+ size_t mapsize = 0;
209
+ mode_t mode = 0755;
210
+ if (n == 2) {
211
+ VALUE value = rb_hash_aref(options, ID2SYM(rb_intern("flags")));
212
+ if (!NIL_P(value))
213
+ flags = NUM2INT(value);
214
+
215
+ value = rb_hash_aref(options, ID2SYM(rb_intern("mode")));
216
+ if (!NIL_P(value))
217
+ mode = NUM2INT(value);
218
+
219
+ value = rb_hash_aref(options, ID2SYM(rb_intern("maxreaders")));
220
+ if (!NIL_P(value))
221
+ maxreaders = NUM2INT(value);
222
+
223
+ value = rb_hash_aref(options, ID2SYM(rb_intern("maxdbs")));
224
+ if (!NIL_P(value))
225
+ maxdbs = NUM2INT(value);
226
+
227
+ value = rb_hash_aref(options, ID2SYM(rb_intern("mapsize")));
228
+ if (!NIL_P(value))
229
+ mapsize = NUM2SIZET(value);
230
+ }
231
+
232
+ check(mdb_env_create(&env));
233
+
234
+ venv = Data_Make_Struct(cEnvironment, Environment, 0, environment_free, environment);
235
+ environment->env = env;
236
+
237
+ if (maxreaders > 0)
238
+ check(mdb_env_set_maxreaders(environment->env, maxreaders));
239
+ if (mapsize > 0)
240
+ check(mdb_env_set_mapsize(environment->env, mapsize));
241
+
242
+ check(mdb_env_set_maxdbs(environment->env, maxdbs <= 0 ? 1 : maxdbs));
243
+ check(mdb_env_open(environment->env, StringValueCStr(path), flags, mode));
244
+ if (rb_block_given_p())
245
+ return rb_ensure(rb_yield, venv, environment_close, venv);
246
+ return venv;
247
+ }
248
+
249
+ static VALUE environment_flags(VALUE self) {
250
+ unsigned int flags;
251
+ ENVIRONMENT(self, environment);
252
+ check(mdb_env_get_flags(environment->env, &flags));
253
+ return INT2NUM(flags & ENV_FLAGS);
254
+ }
255
+
256
+ static VALUE environment_path(VALUE self) {
257
+ const char* path;
258
+ ENVIRONMENT(self, environment);
259
+ check(mdb_env_get_path(environment->env, &path));
260
+ return rb_str_new2(path);
261
+ }
262
+
263
+ static VALUE environment_set_flags(VALUE self, VALUE vflags) {
264
+ unsigned int flags = NUM2INT(vflags), oldflags;
265
+ ENVIRONMENT(self, environment);
266
+ check(mdb_env_get_flags(environment->env, &oldflags));
267
+ check(mdb_env_set_flags(environment->env, oldflags & ENV_FLAGS, 0));
268
+ check(mdb_env_set_flags(environment->env, flags, 1));
269
+ return environment_flags(self);
270
+ }
271
+
272
+ static VALUE environment_transaction(int argc, VALUE *argv, VALUE self) {
273
+ VALUE readonly, vtxn;
274
+ MDB_txn* txn;
275
+ unsigned int flags;
276
+ Transaction* transaction;
277
+
278
+ ENVIRONMENT(self, environment);
279
+ flags = (rb_scan_args(argc, argv, "01", &readonly) == 1 && !NIL_P(readonly)) ? MDB_RDONLY : 0;
280
+ check(mdb_txn_begin(environment->env, 0, flags, &txn));
281
+
282
+ vtxn = Data_Make_Struct(cTransaction, Transaction, transaction_mark, transaction_free, transaction);
283
+ transaction->txn = txn;
284
+ transaction->environment = self;
285
+ transaction->parent = Qnil;
286
+
287
+ if (rb_block_given_p()) {
288
+ int exception;
289
+ VALUE result = rb_protect(rb_yield, vtxn, &exception);
290
+ if (exception) {
291
+ mdb_txn_abort(transaction->txn);
292
+ transaction->txn = 0;
293
+ rb_jump_tag(exception);
294
+ }
295
+ mdb_txn_commit(transaction->txn);
296
+ transaction->txn = 0;
297
+ return result;
298
+ }
299
+ return vtxn;
300
+ }
301
+
302
+ /*-----------------------------------------------------------------------------
303
+ * Transaction functions
304
+ *----------------------------------------------------------------------------*/
305
+
306
+ static VALUE transaction_environment(VALUE self) {
307
+ TRANSACTION(self, transaction, environment);
308
+ return transaction->environment;
309
+ }
310
+
311
+ static VALUE transaction_parent(VALUE self) {
312
+ TRANSACTION(self, transaction, environment);
313
+ return transaction->parent;
314
+ }
315
+
316
+ static void transaction_mark(Transaction* transaction) {
317
+ rb_gc_mark(transaction->environment);
318
+ rb_gc_mark(transaction->parent);
319
+ }
320
+
321
+ static void transaction_free(Transaction *transaction) {
322
+ if (transaction->txn)
323
+ mdb_txn_abort(transaction->txn);
324
+ free(transaction);
325
+ }
326
+
327
+ VALUE transaction_abort(VALUE self) {
328
+ TRANSACTION(self, transaction, environment);
329
+ mdb_txn_abort(transaction->txn);
330
+ transaction->txn = 0;
331
+ return Qnil;
332
+ }
333
+
334
+ VALUE transaction_commit(VALUE self) {
335
+ TRANSACTION(self, transaction, environment);
336
+ mdb_txn_commit(transaction->txn);
337
+ transaction->txn = 0;
338
+ return Qnil;
339
+ }
340
+
341
+ VALUE transaction_renew(VALUE self) {
342
+ TRANSACTION(self, transaction, environment);
343
+ mdb_txn_renew(transaction->txn);
344
+ return Qnil;
345
+ }
346
+
347
+ VALUE transaction_reset(VALUE self) {
348
+ TRANSACTION(self, transaction, environment);
349
+ mdb_txn_reset(transaction->txn);
350
+ return Qnil;
351
+ }
352
+
353
+ static VALUE transaction_transaction(VALUE self) {
354
+ MDB_txn* txn;
355
+ Transaction* child;
356
+ VALUE vtxn;
357
+
358
+ TRANSACTION(self, transaction, environment);
359
+ check(mdb_txn_begin(environment->env, transaction->txn, 0, &txn));
360
+
361
+ vtxn = Data_Make_Struct(cTransaction, Transaction, transaction_mark, transaction_free, child);
362
+ child->txn = txn;
363
+ child->environment = transaction->environment;
364
+ child->parent = self;
365
+
366
+ if (rb_block_given_p()) {
367
+ int exception;
368
+ VALUE result = rb_protect(rb_yield, vtxn, &exception);
369
+ if (exception) {
370
+ mdb_txn_abort(child->txn);
371
+ child->txn = 0;
372
+ rb_jump_tag(exception);
373
+ }
374
+ mdb_txn_commit(child->txn);
375
+ child->txn = 0;
376
+ return result;
377
+ }
378
+ return vtxn;
379
+ }
380
+
381
+ /*-----------------------------------------------------------------------------
382
+ * Database functions
383
+ *----------------------------------------------------------------------------*/
384
+
385
+ static VALUE database_environment(VALUE self) {
386
+ DATABASE(self, database, environment);
387
+ return database->environment;
388
+ }
389
+
390
+ static void database_free(Database* database) {
391
+ if (database->open) {
392
+ ENVIRONMENT(database->environment, environment);
393
+ mdb_dbi_close(environment->env, database->dbi);
394
+ }
395
+ free(database);
396
+ }
397
+
398
+ static void database_mark(Database* database) {
399
+ rb_gc_mark(database->environment);
400
+ }
401
+
402
+ static VALUE database_open(int argc, VALUE *argv, VALUE self) {
403
+ ENVIRONMENT(self, environment);
404
+
405
+ VALUE vtxn, vname, vflags;
406
+ int n = rb_scan_args(argc, argv, "21", &vtxn, &vname, &vflags);
407
+
408
+ TRANSACTION(vtxn, transaction, txn_environment);
409
+ if (environment != txn_environment)
410
+ rb_raise(cError, "Different environments");
411
+
412
+ MDB_dbi dbi;
413
+ check(mdb_dbi_open(transaction->txn, StringValueCStr(vname), n == 3 ? NUM2INT(vflags) : 0, &dbi));
414
+
415
+ Database* database;
416
+ VALUE vdb = Data_Make_Struct(cDatabase, Database, database_mark, database_free, database);
417
+ database->dbi = dbi;
418
+ database->environment = self;
419
+ database->open = 1;
420
+
421
+ return vdb;
422
+ }
423
+
424
+ static VALUE database_close(VALUE self) {
425
+ DATABASE(self, database, environment);
426
+ mdb_dbi_close(environment->env, database->dbi);
427
+ database->open = 0;
428
+ return Qnil;
429
+ }
430
+
431
+ static VALUE database_stat(VALUE self, VALUE vtxn) {
432
+ DATABASE_TRANSACTION(self, vtxn, database, transaction, environment);
433
+ MDB_stat* stat;
434
+ VALUE vstat = Data_Make_Struct(cStat, MDB_stat, 0, -1, stat);
435
+ check(mdb_stat(transaction->txn, database->dbi, stat));
436
+ return vstat;
437
+ }
438
+
439
+ static VALUE database_drop(VALUE self, VALUE vtxn) {
440
+ DATABASE_TRANSACTION(self, vtxn, database, transaction, environment);
441
+ check(mdb_drop(transaction->txn, database->dbi, 1));
442
+ database->open = 0;
443
+ return Qnil;
444
+ }
445
+
446
+ static VALUE database_clear(VALUE self, VALUE vtxn) {
447
+ DATABASE_TRANSACTION(self, vtxn, database, transaction, environment);
448
+ check(mdb_drop(transaction->txn, database->dbi, 0));
449
+ return Qnil;
450
+ }
451
+
452
+ static VALUE database_get(VALUE self, VALUE vtxn, VALUE vkey) {
453
+ DATABASE_TRANSACTION(self, vtxn, database, transaction, environment);
454
+ vkey = StringValue(vkey);
455
+ MDB_val key, value;
456
+ key.mv_size = RSTRING_LEN(vkey);
457
+ key.mv_data = RSTRING_PTR(vkey);
458
+ check(mdb_get(transaction->txn, database->dbi, &key, &value));
459
+ return rb_str_new(value.mv_data, value.mv_size);
460
+ }
461
+
462
+ static VALUE database_put(int argc, VALUE *argv, VALUE self) {
463
+ VALUE vtxn, vkey, vval, vflags;
464
+ int n = rb_scan_args(argc, argv, "31", &vtxn, &vkey, &vval, &vflags);
465
+
466
+ DATABASE_TRANSACTION(self, vtxn, database, transaction, environment);
467
+
468
+ vkey = StringValue(vkey);
469
+ vval = StringValue(vval);
470
+
471
+ MDB_val key, value;
472
+ key.mv_size = RSTRING_LEN(vkey);
473
+ key.mv_data = RSTRING_PTR(vkey);
474
+ value.mv_size = RSTRING_LEN(vval);
475
+ value.mv_data = RSTRING_PTR(vval);
476
+
477
+ check(mdb_put(transaction->txn, database->dbi, &key, &value, n == 4 ? NUM2INT(vflags) : 0));
478
+ return Qnil;
479
+ }
480
+
481
+ static VALUE database_delete(int argc, VALUE *argv, VALUE self) {
482
+ VALUE vtxn, vkey, vval;
483
+ int n = rb_scan_args(argc, argv, "21", &vtxn, &vkey, &vval);
484
+
485
+ DATABASE_TRANSACTION(self, vtxn, database, transaction, environment);
486
+
487
+ vkey = StringValue(vkey);
488
+
489
+ MDB_val key;
490
+ key.mv_size = RSTRING_LEN(vkey);
491
+ key.mv_data = RSTRING_PTR(vkey);
492
+
493
+ if (n == 3) {
494
+ vval = StringValue(vval);
495
+ MDB_val value;
496
+ value.mv_size = RSTRING_LEN(vval);
497
+ value.mv_data = RSTRING_PTR(vval);
498
+ check(mdb_del(transaction->txn, database->dbi, &key, &value));
499
+ } else {
500
+ check(mdb_del(transaction->txn, database->dbi, &key, 0));
501
+ }
502
+
503
+ return Qnil;
504
+ }
505
+
506
+ /*-----------------------------------------------------------------------------
507
+ * Cursor functions
508
+ *----------------------------------------------------------------------------*/
509
+
510
+ static void cursor_free(Cursor* cursor) {
511
+ if (cursor->cur)
512
+ mdb_cursor_close(cursor->cur);
513
+ free(cursor);
514
+ }
515
+
516
+ static void cursor_mark(Cursor* cursor) {
517
+ rb_gc_mark(cursor->database);
518
+ rb_gc_mark(cursor->transaction);
519
+ }
520
+
521
+ static VALUE database_cursor(VALUE self, VALUE vtxn) {
522
+ DATABASE_TRANSACTION(self, vtxn, database, transaction, environment);
523
+
524
+ MDB_cursor* cur;
525
+ check(mdb_cursor_open(transaction->txn, database->dbi, &cur));
526
+
527
+ Cursor* cursor;
528
+ VALUE vcur = Data_Make_Struct(cCursor, Cursor, cursor_mark, cursor_free, cursor);
529
+ cursor->cur = cur;
530
+ cursor->database = self;
531
+ cursor->transaction = vtxn;
532
+
533
+ return vcur;
534
+ }
535
+
536
+ static VALUE cursor_transaction(VALUE self) {
537
+ CURSOR(self, cursor, database, transaction, environment);
538
+ return cursor->transaction;
539
+ }
540
+
541
+ static VALUE cursor_database(VALUE self) {
542
+ CURSOR(self, cursor, database, transaction, environment);
543
+ return cursor->database;
544
+ }
545
+
546
+ static VALUE cursor_close(VALUE self) {
547
+ CURSOR(self, cursor, database, transaction, environment);
548
+ mdb_cursor_close(cursor->cur);
549
+ cursor->cur = 0;
550
+ return Qnil;
551
+ }
552
+
553
+ static VALUE cursor_first(VALUE self) {
554
+ CURSOR(self, cursor, database, transaction, environment);
555
+ MDB_val key, value;
556
+
557
+ check(mdb_cursor_get(cursor->cur, &key, &value, MDB_FIRST));
558
+ return rb_assoc_new(rb_str_new(key.mv_data, key.mv_size), rb_str_new(value.mv_data, value.mv_size));
559
+ }
560
+
561
+ static VALUE cursor_next(VALUE self) {
562
+ CURSOR(self, cursor, database, transaction, environment);
563
+ MDB_val key, value;
564
+
565
+ check(mdb_cursor_get(cursor->cur, &key, &value, MDB_NEXT));
566
+ return rb_assoc_new(rb_str_new(key.mv_data, key.mv_size), rb_str_new(value.mv_data, value.mv_size));
567
+ }
568
+
569
+ static VALUE cursor_set(VALUE self, VALUE inkey) {
570
+ CURSOR(self, cursor, database, transaction, environment);
571
+ MDB_val key, value;
572
+
573
+ key.mv_size = RSTRING_LEN(inkey);
574
+ key.mv_data = StringValuePtr(inkey);
575
+
576
+ check(mdb_cursor_get(cursor->cur, &key, &value, MDB_SET));
577
+ return rb_assoc_new(rb_str_new(key.mv_data, key.mv_size), rb_str_new(value.mv_data, value.mv_size));
578
+ }
579
+
580
+ static VALUE cursor_set_range(VALUE self, VALUE inkey) {
581
+ CURSOR(self, cursor, database, transaction, environment);
582
+ MDB_val key, value;
583
+
584
+ key.mv_size = RSTRING_LEN(inkey);
585
+ key.mv_data = StringValuePtr(inkey);
586
+
587
+ check(mdb_cursor_get(cursor->cur, &key, &value, MDB_SET_RANGE));
588
+ return rb_assoc_new(rb_str_new(key.mv_data, key.mv_size), rb_str_new(value.mv_data, value.mv_size));
589
+ }
590
+
591
+ static VALUE cursor_get(VALUE self) {
592
+ CURSOR(self, cursor, database, transaction, environment);
593
+ // TODO
594
+ return Qnil;
595
+ }
596
+
597
+ static VALUE cursor_put(VALUE self) {
598
+ CURSOR(self, cursor, database, transaction, environment);
599
+ // TODO
600
+ return Qnil;
601
+ }
602
+
603
+ static VALUE cursor_delete(int argc, VALUE *argv, VALUE self) {
604
+ CURSOR(self, cursor, database, transaction, environment);
605
+ VALUE flags;
606
+ int n = rb_scan_args(argc, argv, "01", &flags);
607
+ check(mdb_cursor_del(cursor->cur, n == 1 ? NUM2INT(flags) : 0));
608
+ return Qnil;
609
+ }
610
+
611
+ static VALUE cursor_count(VALUE self) {
612
+ CURSOR(self, cursor, database, transaction, environment);
613
+ size_t count;
614
+ check(mdb_cursor_count(cursor->cur, &count));
615
+ return INT2NUM(count);
616
+ }
617
+
618
+
619
+ void Init_lmdb_ext() {
620
+ VALUE mLMDB, mExt;
621
+
622
+ mLMDB = rb_define_module("LMDB");
623
+ rb_define_const(mLMDB, "VERSION", rb_str_new2(MDB_VERSION_STRING));
624
+
625
+ mExt = rb_define_module_under(mLMDB, "Ext");
626
+ rb_define_singleton_method(mExt, "open", environment_open, -1);
627
+
628
+ #define NUM_CONST(name) rb_define_const(mLMDB, #name, INT2NUM(MDB_##name))
629
+
630
+ // Versions
631
+ NUM_CONST(VERSION_MAJOR);
632
+ NUM_CONST(VERSION_MINOR);
633
+ NUM_CONST(VERSION_PATCH);
634
+
635
+ // Environment flags
636
+ NUM_CONST(FIXEDMAP);
637
+ NUM_CONST(NOSUBDIR);
638
+ NUM_CONST(NOSYNC);
639
+ NUM_CONST(RDONLY);
640
+ NUM_CONST(NOMETASYNC);
641
+ NUM_CONST(WRITEMAP);
642
+ NUM_CONST(MAPASYNC);
643
+
644
+ // Database flags
645
+ NUM_CONST(REVERSEKEY);
646
+ NUM_CONST(DUPSORT);
647
+ NUM_CONST(INTEGERKEY);
648
+ NUM_CONST(DUPFIXED);
649
+ NUM_CONST(INTEGERDUP);
650
+ NUM_CONST(REVERSEDUP);
651
+ NUM_CONST(CREATE);
652
+ NUM_CONST(NOOVERWRITE);
653
+ NUM_CONST(NODUPDATA);
654
+ NUM_CONST(CURRENT);
655
+ NUM_CONST(RESERVE);
656
+ NUM_CONST(APPEND);
657
+ NUM_CONST(APPENDDUP);
658
+ NUM_CONST(MULTIPLE);
659
+
660
+ cError = rb_define_class_under(mExt, "Error", rb_eRuntimeError);
661
+ #define ERROR(name) cError_##name = rb_define_class_under(cError, #name, cError);
662
+ #include "errors.h"
663
+ #undef ERROR
664
+
665
+ cStat = rb_define_class_under(mExt, "Stat", rb_cObject);
666
+ rb_define_method(cStat, "psize", stat_psize, 0);
667
+ rb_define_method(cStat, "depth", stat_depth, 0);
668
+ rb_define_method(cStat, "branch_pages", stat_branch_pages, 0);
669
+ rb_define_method(cStat, "leaf_pages", stat_leaf_pages, 0);
670
+ rb_define_method(cStat, "overflow_pages", stat_overflow_pages, 0);
671
+ rb_define_method(cStat, "entries", stat_entries, 0);
672
+
673
+ cInfo = rb_define_class_under(mExt, "Info", rb_cObject);
674
+ rb_define_method(cInfo, "mapaddr", info_mapaddr, 0);
675
+ rb_define_method(cInfo, "mapsize", info_mapsize, 0);
676
+ rb_define_method(cInfo, "last_pgno", info_last_pgno, 0);
677
+ rb_define_method(cInfo, "last_txnid", info_last_txnid, 0);
678
+ rb_define_method(cInfo, "maxreaders", info_maxreaders, 0);
679
+ rb_define_method(cInfo, "numreaders", info_numreaders, 0);
680
+
681
+ cEnvironment = rb_define_class_under(mExt, "Environment", rb_cObject);
682
+ rb_define_singleton_method(cEnvironment, "open", environment_open, -1);
683
+ rb_define_method(cEnvironment, "close", environment_close, 0);
684
+ rb_define_method(cEnvironment, "stat", environment_stat, 0);
685
+ rb_define_method(cEnvironment, "info", environment_info, 0);
686
+ rb_define_method(cEnvironment, "copy", environment_copy, 1);
687
+ rb_define_method(cEnvironment, "sync", environment_sync, -1);
688
+ rb_define_method(cEnvironment, "flags=", environment_set_flags, 1);
689
+ rb_define_method(cEnvironment, "flags", environment_flags, 0);
690
+ rb_define_method(cEnvironment, "path", environment_path, 0);
691
+ rb_define_method(cEnvironment, "transaction", environment_transaction, -1);
692
+ rb_define_method(cEnvironment, "open", database_open, -1);
693
+
694
+ cDatabase = rb_define_class_under(mExt, "Database", rb_cObject);
695
+ rb_define_method(cDatabase, "close", database_close, 0);
696
+ rb_define_method(cDatabase, "stat", database_stat, 1);
697
+ rb_define_method(cDatabase, "drop", database_drop, 1);
698
+ rb_define_method(cDatabase, "clear", database_clear, 1);
699
+ rb_define_method(cDatabase, "get", database_get, 2);
700
+ rb_define_method(cDatabase, "put", database_put, -1);
701
+ rb_define_method(cDatabase, "delete", database_delete, -1);
702
+ rb_define_method(cDatabase, "cursor", database_cursor, 1);
703
+ rb_define_method(cDatabase, "environment", database_environment, 0);
704
+
705
+ cTransaction = rb_define_class_under(mExt, "Transaction", rb_cObject);
706
+ rb_define_method(cTransaction, "abort", transaction_abort, 0);
707
+ rb_define_method(cTransaction, "commit", transaction_commit, 0);
708
+ rb_define_method(cTransaction, "reset", transaction_reset, 0);
709
+ rb_define_method(cTransaction, "renew", transaction_renew, 0);
710
+ rb_define_method(cTransaction, "transaction", transaction_transaction, 0);
711
+ rb_define_method(cTransaction, "environment", transaction_environment, 0);
712
+ rb_define_method(cTransaction, "parent", transaction_parent, 0);
713
+
714
+ cCursor = rb_define_class_under(mExt, "Cursor", rb_cObject);
715
+ rb_define_method(cCursor, "close", cursor_close, 0);
716
+ rb_define_method(cCursor, "get", cursor_get, 0);
717
+ rb_define_method(cCursor, "first", cursor_first, 0);
718
+ rb_define_method(cCursor, "next", cursor_next, 0);
719
+ rb_define_method(cCursor, "set", cursor_set, 1);
720
+ rb_define_method(cCursor, "set_range", cursor_set_range, 1);
721
+ rb_define_method(cCursor, "put", cursor_put, 0);
722
+ rb_define_method(cCursor, "delete", cursor_delete, 0);
723
+ rb_define_method(cCursor, "database", cursor_database, 0);
724
+ rb_define_method(cCursor, "transaction", cursor_transaction, 0);
725
+ }