lmdb 0.1.0 → 0.2.0

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