lmdb 0.1.0 → 0.2.0

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.
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
  }