lmdb 0.2.0 → 0.3.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 +4 -4
- data/CHANGES +8 -0
- data/ext/lmdb_ext/cursor_delete_flags.h +1 -0
- data/ext/lmdb_ext/cursor_put_flags.h +2 -0
- data/ext/lmdb_ext/dbi_flags.h +7 -0
- data/ext/lmdb_ext/env_flags.h +8 -0
- data/ext/lmdb_ext/flag_parser.h +14 -0
- data/ext/lmdb_ext/lmdb_ext.c +237 -160
- data/ext/lmdb_ext/lmdb_ext.h +22 -15
- data/ext/lmdb_ext/put_flags.h +5 -0
- data/lib/lmdb/database.rb +26 -0
- data/lib/lmdb/version.rb +3 -0
- data/lib/lmdb.rb +2 -28
- data/lmdb.gemspec +4 -1
- data/spec/lmdb_spec.rb +63 -44
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e65d2930d0d2e7812f17f527cec9e28227ff86d3
|
4
|
+
data.tar.gz: 9b1be0c534d29babf1ecfb665bc0a93f1cadc158
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79f1fa24f25e0c3dc0971df47ed6eea2d5f2e388a244f6354586c1a15c0cd9934ff302391a7a51b46f50534ddeb5c1b126e842ffb6e59773967e5e5ef49e35dd
|
7
|
+
data.tar.gz: 29a36534234f8da14bce75b157add7d4f259e94addf60e32a2faaf2edf4f84d168580e85090803d4eb16bf095a05c5546c6ea172835ba0d2098305d78d02c4cd
|
data/CHANGES
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
FLAG(NODUPDATA, nodupdata)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
static int METHOD(VALUE key, VALUE value, int* flags) {
|
2
|
+
ID id = rb_to_id(key);
|
3
|
+
|
4
|
+
if (0) {}
|
5
|
+
#define FLAG(const, name) else if (id == rb_intern(#name)) { if (RTEST(value)) { *flags |= MDB_##const; } }
|
6
|
+
#include FILE
|
7
|
+
#undef FLAG
|
8
|
+
else {
|
9
|
+
VALUE s = rb_inspect(key);
|
10
|
+
rb_raise(cError, "Invalid option %s", StringValueCStr(s));
|
11
|
+
}
|
12
|
+
|
13
|
+
return 0;
|
14
|
+
}
|
data/ext/lmdb_ext/lmdb_ext.c
CHANGED
@@ -24,8 +24,10 @@ static void transaction_deref(Transaction* transaction) {
|
|
24
24
|
Transaction* parent = (Transaction*)DATA_PTR(transaction->parent);
|
25
25
|
transaction_deref(parent);
|
26
26
|
}
|
27
|
-
if (transaction->txn)
|
27
|
+
if (transaction->txn) {
|
28
|
+
rb_warn("Garbage collecting active transaction!");
|
28
29
|
mdb_txn_abort(transaction->txn);
|
30
|
+
}
|
29
31
|
free(transaction);
|
30
32
|
}
|
31
33
|
}
|
@@ -36,40 +38,26 @@ static void transaction_mark(Transaction* transaction) {
|
|
36
38
|
}
|
37
39
|
|
38
40
|
static VALUE transaction_commit(VALUE self) {
|
39
|
-
|
40
|
-
ENVIRONMENT(transaction->env, environment);
|
41
|
-
if (!transaction->txn)
|
42
|
-
rb_raise(cError, "Transaction is terminated");
|
43
|
-
|
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");
|
52
|
-
|
53
|
-
mdb_txn_commit(transaction->txn);
|
54
|
-
|
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;
|
62
|
-
|
63
|
-
environment->txn = transaction->parent;
|
41
|
+
transaction_finish(self, 1);
|
64
42
|
return Qnil;
|
65
43
|
}
|
66
44
|
|
67
45
|
static VALUE transaction_abort(VALUE self) {
|
46
|
+
transaction_finish(self, 0);
|
47
|
+
return Qnil;
|
48
|
+
}
|
49
|
+
|
50
|
+
static void transaction_finish(VALUE self, int commit) {
|
68
51
|
TRANSACTION(self, transaction);
|
69
|
-
|
52
|
+
|
53
|
+
if (!transaction->txn)
|
54
|
+
rb_raise(cError, "Transaction is terminated");
|
55
|
+
|
56
|
+
if (transaction->thread != rb_thread_current())
|
57
|
+
rb_raise(cError, "Wrong thread");
|
70
58
|
|
71
59
|
// Check nesting
|
72
|
-
VALUE p =
|
60
|
+
VALUE p = environment_active_txn(transaction->env);
|
73
61
|
while (!NIL_P(p) && p != self) {
|
74
62
|
TRANSACTION(p, txn);
|
75
63
|
p = txn->parent;
|
@@ -77,20 +65,23 @@ static VALUE transaction_abort(VALUE self) {
|
|
77
65
|
if (p != self)
|
78
66
|
rb_raise(cError, "Transaction is not active");
|
79
67
|
|
80
|
-
|
81
|
-
|
82
|
-
|
68
|
+
int ret = 0;
|
69
|
+
if (commit)
|
70
|
+
ret = mdb_txn_commit(transaction->txn);
|
71
|
+
else
|
72
|
+
mdb_txn_abort(transaction->txn);
|
83
73
|
|
84
|
-
p =
|
74
|
+
p = environment_active_txn(transaction->env);
|
85
75
|
while (p != self) {
|
86
76
|
TRANSACTION(p, txn);
|
87
77
|
txn->txn = 0;
|
88
78
|
p = txn->parent;
|
89
|
-
}
|
79
|
+
}
|
90
80
|
transaction->txn = 0;
|
91
81
|
|
92
|
-
|
93
|
-
|
82
|
+
environment_set_active_txn(transaction->env, transaction->thread, transaction->parent);
|
83
|
+
|
84
|
+
check(ret);
|
94
85
|
}
|
95
86
|
|
96
87
|
static VALUE call_with_transaction_helper(VALUE arg) {
|
@@ -107,27 +98,35 @@ static VALUE with_transaction(VALUE venv, VALUE(*fn)(VALUE), VALUE arg, int flag
|
|
107
98
|
ENVIRONMENT(venv, environment);
|
108
99
|
|
109
100
|
MDB_txn* txn;
|
110
|
-
check(mdb_txn_begin(environment->env,
|
101
|
+
check(mdb_txn_begin(environment->env, active_txn(venv), flags, &txn));
|
111
102
|
|
112
103
|
Transaction* transaction;
|
113
104
|
VALUE vtxn = Data_Make_Struct(cTransaction, Transaction, transaction_mark, transaction_deref, transaction);
|
114
105
|
transaction->refcount = 1;
|
115
|
-
transaction->parent =
|
106
|
+
transaction->parent = environment_active_txn(venv);
|
116
107
|
transaction->env = venv;
|
117
108
|
transaction->txn = txn;
|
118
|
-
|
109
|
+
transaction->thread = rb_thread_current();
|
110
|
+
environment_set_active_txn(venv, transaction->thread, vtxn);
|
111
|
+
|
112
|
+
if (!NIL_P(transaction->parent)) {
|
113
|
+
TRANSACTION(transaction->parent, parent);
|
114
|
+
++parent->refcount;
|
115
|
+
}
|
116
|
+
|
117
|
+
++environment->refcount;
|
119
118
|
|
120
119
|
int exception;
|
121
|
-
VALUE
|
120
|
+
VALUE ret = rb_protect(fn, NIL_P(arg) ? vtxn : arg, &exception);
|
122
121
|
|
123
122
|
if (exception) {
|
124
|
-
if (vtxn ==
|
123
|
+
if (vtxn == environment_active_txn(venv))
|
125
124
|
transaction_abort(vtxn);
|
126
125
|
rb_jump_tag(exception);
|
127
126
|
}
|
128
|
-
if (vtxn ==
|
127
|
+
if (vtxn == environment_active_txn(venv))
|
129
128
|
transaction_commit(vtxn);
|
130
|
-
return
|
129
|
+
return ret;
|
131
130
|
}
|
132
131
|
|
133
132
|
static void environment_check(Environment* environment) {
|
@@ -143,6 +142,12 @@ static void environment_deref(Environment *environment) {
|
|
143
142
|
}
|
144
143
|
}
|
145
144
|
|
145
|
+
|
146
|
+
static void environment_mark(Environment* environment) {
|
147
|
+
rb_gc_mark(environment->thread_txn_hash);
|
148
|
+
rb_gc_mark(environment->txn_thread_hash);
|
149
|
+
}
|
150
|
+
|
146
151
|
static VALUE environment_close(VALUE self) {
|
147
152
|
ENVIRONMENT(self, environment);
|
148
153
|
mdb_env_close(environment->env);
|
@@ -151,9 +156,9 @@ static VALUE environment_close(VALUE self) {
|
|
151
156
|
}
|
152
157
|
|
153
158
|
static VALUE stat2hash(const MDB_stat* stat) {
|
154
|
-
VALUE
|
159
|
+
VALUE ret = rb_hash_new();
|
155
160
|
|
156
|
-
#define STAT_SET(name) rb_hash_aset(
|
161
|
+
#define STAT_SET(name) rb_hash_aset(ret, ID2SYM(rb_intern(#name)), INT2NUM(stat->ms_##name))
|
157
162
|
STAT_SET(psize);
|
158
163
|
STAT_SET(depth);
|
159
164
|
STAT_SET(branch_pages);
|
@@ -162,7 +167,7 @@ static VALUE stat2hash(const MDB_stat* stat) {
|
|
162
167
|
STAT_SET(entries);
|
163
168
|
#undef STAT_SET
|
164
169
|
|
165
|
-
return
|
170
|
+
return ret;
|
166
171
|
}
|
167
172
|
|
168
173
|
static VALUE environment_stat(VALUE self) {
|
@@ -178,9 +183,9 @@ static VALUE environment_info(VALUE self) {
|
|
178
183
|
ENVIRONMENT(self, environment);
|
179
184
|
check(mdb_env_info(environment->env, &info));
|
180
185
|
|
181
|
-
VALUE
|
186
|
+
VALUE ret = rb_hash_new();
|
182
187
|
|
183
|
-
#define INFO_SET(name) rb_hash_aset(
|
188
|
+
#define INFO_SET(name) rb_hash_aset(ret, ID2SYM(rb_intern(#name)), INT2NUM((size_t)info.me_##name));
|
184
189
|
INFO_SET(mapaddr);
|
185
190
|
INFO_SET(mapsize);
|
186
191
|
INFO_SET(last_pgno);
|
@@ -189,7 +194,7 @@ static VALUE environment_info(VALUE self) {
|
|
189
194
|
INFO_SET(numreaders);
|
190
195
|
#undef INFO_SET
|
191
196
|
|
192
|
-
return
|
197
|
+
return ret;
|
193
198
|
}
|
194
199
|
|
195
200
|
static VALUE environment_copy(VALUE self, VALUE path) {
|
@@ -208,51 +213,62 @@ static VALUE environment_sync(int argc, VALUE *argv, VALUE self) {
|
|
208
213
|
return Qnil;
|
209
214
|
}
|
210
215
|
|
211
|
-
static
|
212
|
-
|
213
|
-
rb_scan_args(argc, argv, "11", &path, &options);
|
216
|
+
static int environment_options(VALUE key, VALUE value, EnvironmentOptions* options) {
|
217
|
+
ID id = rb_to_id(key);
|
214
218
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
219
|
+
if (id == rb_intern("mode"))
|
220
|
+
options->mode = NUM2INT(value);
|
221
|
+
else if (id == rb_intern("maxreaders"))
|
222
|
+
options->maxreaders = NUM2INT(value);
|
223
|
+
else if (id == rb_intern("maxdbs"))
|
224
|
+
options->maxdbs = NUM2INT(value);
|
225
|
+
else if (id == rb_intern("mapsize"))
|
226
|
+
options->mapsize = NUM2SSIZET(value);
|
222
227
|
|
223
|
-
|
224
|
-
|
225
|
-
|
228
|
+
#define FLAG(const, name) else if (id == rb_intern(#name)) { if (RTEST(value)) { options->flags |= MDB_##const; } }
|
229
|
+
#include "env_flags.h"
|
230
|
+
#undef FLAG
|
226
231
|
|
227
|
-
|
228
|
-
|
229
|
-
|
232
|
+
else {
|
233
|
+
VALUE s = rb_inspect(key);
|
234
|
+
rb_raise(cError, "Invalid option %s", StringValueCStr(s));
|
235
|
+
}
|
230
236
|
|
231
|
-
|
232
|
-
|
233
|
-
maxdbs = NUM2INT(value);
|
237
|
+
return 0;
|
238
|
+
}
|
234
239
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
240
|
+
static VALUE environment_new(int argc, VALUE *argv, VALUE klass) {
|
241
|
+
VALUE path, option_hash;
|
242
|
+
rb_scan_args(argc, argv, "1:", &path, &option_hash);
|
243
|
+
|
244
|
+
EnvironmentOptions options = {
|
245
|
+
.flags = MDB_NOTLS,
|
246
|
+
.maxreaders = -1,
|
247
|
+
.maxdbs = 128,
|
248
|
+
.mapsize = 0,
|
249
|
+
.mode = 0755,
|
250
|
+
};
|
251
|
+
if (!NIL_P(option_hash))
|
252
|
+
rb_hash_foreach(option_hash, environment_options, (VALUE)&options);
|
239
253
|
|
240
254
|
MDB_env* env;
|
241
255
|
check(mdb_env_create(&env));
|
242
256
|
|
243
257
|
Environment* environment;
|
244
|
-
VALUE venv = Data_Make_Struct(cEnvironment, Environment,
|
258
|
+
VALUE venv = Data_Make_Struct(cEnvironment, Environment, environment_mark, environment_deref, environment);
|
245
259
|
environment->env = env;
|
246
260
|
environment->refcount = 1;
|
247
|
-
environment->
|
261
|
+
environment->thread_txn_hash = rb_hash_new();
|
262
|
+
environment->txn_thread_hash = rb_hash_new();
|
248
263
|
|
249
|
-
if (maxreaders > 0)
|
250
|
-
check(mdb_env_set_maxreaders(
|
251
|
-
if (mapsize > 0)
|
252
|
-
check(mdb_env_set_mapsize(
|
264
|
+
if (options.maxreaders > 0)
|
265
|
+
check(mdb_env_set_maxreaders(env, options.maxreaders));
|
266
|
+
if (options.mapsize > 0)
|
267
|
+
check(mdb_env_set_mapsize(env, options.mapsize));
|
268
|
+
|
269
|
+
check(mdb_env_set_maxdbs(env, options.maxdbs <= 0 ? 1 : options.maxdbs));
|
270
|
+
check(mdb_env_open(env, StringValueCStr(path), options.flags, options.mode));
|
253
271
|
|
254
|
-
check(mdb_env_set_maxdbs(environment->env, maxdbs <= 0 ? 1 : maxdbs));
|
255
|
-
check(mdb_env_open(environment->env, StringValueCStr(path), flags, mode));
|
256
272
|
if (rb_block_given_p())
|
257
273
|
return rb_ensure(rb_yield, venv, environment_close, venv);
|
258
274
|
|
@@ -263,7 +279,13 @@ static VALUE environment_flags(VALUE self) {
|
|
263
279
|
unsigned int flags;
|
264
280
|
ENVIRONMENT(self, environment);
|
265
281
|
check(mdb_env_get_flags(environment->env, &flags));
|
266
|
-
|
282
|
+
|
283
|
+
VALUE ret = rb_ary_new();
|
284
|
+
#define FLAG(const, name) if (flags & MDB_##const) rb_ary_push(ret, ID2SYM(rb_intern(#name)));
|
285
|
+
#include "env_flags.h"
|
286
|
+
#undef FLAG
|
287
|
+
|
288
|
+
return ret;
|
267
289
|
}
|
268
290
|
|
269
291
|
static VALUE environment_path(VALUE self) {
|
@@ -273,27 +295,68 @@ static VALUE environment_path(VALUE self) {
|
|
273
295
|
return rb_str_new2(path);
|
274
296
|
}
|
275
297
|
|
276
|
-
static VALUE
|
277
|
-
unsigned int flags = NUM2INT(vflags), oldflags;
|
298
|
+
static VALUE environment_change_flags(int argc, VALUE* argv, VALUE self, int set) {
|
278
299
|
ENVIRONMENT(self, environment);
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
300
|
+
|
301
|
+
int i;
|
302
|
+
for (i = 0; i < argc; ++i) {
|
303
|
+
ID id = rb_to_id(argv[i]);
|
304
|
+
|
305
|
+
if (0) {}
|
306
|
+
#define FLAG(const, name) else if (id == rb_intern(#name)) check(mdb_env_set_flags(environment->env, MDB_##const, set));
|
307
|
+
#include "env_flags.h"
|
308
|
+
#undef FLAG
|
309
|
+
else
|
310
|
+
rb_raise(cError, "Invalid option %s", StringValueCStr(argv[i]));
|
311
|
+
}
|
312
|
+
return Qnil;
|
313
|
+
}
|
314
|
+
|
315
|
+
static VALUE environment_set_flags(int argc, VALUE* argv, VALUE self) {
|
316
|
+
environment_change_flags(argc, argv, self, 1);
|
317
|
+
return Qnil;
|
283
318
|
}
|
284
319
|
|
285
|
-
static
|
320
|
+
static VALUE environment_clear_flags(int argc, VALUE* argv, VALUE self) {
|
321
|
+
environment_change_flags(argc, argv, self, 0);
|
322
|
+
return Qnil;
|
323
|
+
}
|
324
|
+
|
325
|
+
static VALUE environment_active_txn(VALUE self) {
|
286
326
|
ENVIRONMENT(self, environment);
|
287
|
-
|
327
|
+
return rb_hash_aref(environment->thread_txn_hash, rb_thread_current());
|
328
|
+
}
|
329
|
+
|
330
|
+
static void environment_set_active_txn(VALUE self, VALUE thread, VALUE txn) {
|
331
|
+
ENVIRONMENT(self, environment);
|
332
|
+
|
333
|
+
if (NIL_P(txn)) {
|
334
|
+
VALUE oldtxn = rb_hash_aref(environment->thread_txn_hash, thread);
|
335
|
+
if (!NIL_P(oldtxn)) {
|
336
|
+
rb_hash_delete(environment->thread_txn_hash, thread);
|
337
|
+
rb_hash_delete(environment->txn_thread_hash, oldtxn);
|
338
|
+
}
|
339
|
+
} else {
|
340
|
+
rb_hash_aset(environment->txn_thread_hash, txn, thread);
|
341
|
+
rb_hash_aset(environment->thread_txn_hash, thread, txn);
|
342
|
+
}
|
343
|
+
}
|
344
|
+
|
345
|
+
|
346
|
+
static MDB_txn* active_txn(VALUE self) {
|
347
|
+
VALUE vtxn = environment_active_txn(self);
|
348
|
+
if (NIL_P(vtxn))
|
288
349
|
return 0;
|
289
|
-
TRANSACTION(
|
350
|
+
TRANSACTION(vtxn, transaction);
|
290
351
|
if (!transaction->txn)
|
291
352
|
rb_raise(cError, "Transaction is terminated");
|
353
|
+
if (transaction->thread != rb_thread_current())
|
354
|
+
rb_raise(cError, "Wrong thread");
|
292
355
|
return transaction->txn;
|
293
356
|
}
|
294
357
|
|
295
|
-
static MDB_txn*
|
296
|
-
MDB_txn* txn =
|
358
|
+
static MDB_txn* need_txn(VALUE self) {
|
359
|
+
MDB_txn* txn = active_txn(self);
|
297
360
|
if (!txn)
|
298
361
|
rb_raise(cError, "No active transaction");
|
299
362
|
return txn;
|
@@ -321,16 +384,26 @@ static void database_mark(Database* database) {
|
|
321
384
|
rb_gc_mark(database->env);
|
322
385
|
}
|
323
386
|
|
387
|
+
#define METHOD database_flags
|
388
|
+
#define FILE "dbi_flags.h"
|
389
|
+
#include "flag_parser.h"
|
390
|
+
#undef METHOD
|
391
|
+
#undef FILE
|
392
|
+
|
324
393
|
static VALUE environment_database(int argc, VALUE *argv, VALUE self) {
|
325
394
|
ENVIRONMENT(self, environment);
|
326
|
-
if (
|
395
|
+
if (!active_txn(self))
|
327
396
|
return call_with_transaction(self, self, "database", argc, argv, 0);
|
328
397
|
|
329
|
-
VALUE
|
330
|
-
rb_scan_args(argc, argv, "
|
398
|
+
VALUE name, option_hash;
|
399
|
+
rb_scan_args(argc, argv, "01:", &name, &option_hash);
|
400
|
+
|
401
|
+
int flags = 0;
|
402
|
+
if (!NIL_P(option_hash))
|
403
|
+
rb_hash_foreach(option_hash, database_flags, (VALUE)&flags);
|
331
404
|
|
332
405
|
MDB_dbi dbi;
|
333
|
-
check(mdb_dbi_open(
|
406
|
+
check(mdb_dbi_open(need_txn(self), NIL_P(name) ? 0 : StringValueCStr(name), flags, &dbi));
|
334
407
|
|
335
408
|
Database* database;
|
336
409
|
VALUE vdb = Data_Make_Struct(cDatabase, Database, database_mark, database_deref, database);
|
@@ -344,33 +417,33 @@ static VALUE environment_database(int argc, VALUE *argv, VALUE self) {
|
|
344
417
|
|
345
418
|
static VALUE database_stat(VALUE self) {
|
346
419
|
DATABASE(self, database);
|
347
|
-
if (!
|
420
|
+
if (!active_txn(database->env))
|
348
421
|
return call_with_transaction(database->env, self, "stat", 0, 0, MDB_RDONLY);
|
349
422
|
|
350
423
|
MDB_stat stat;
|
351
|
-
check(mdb_stat(
|
424
|
+
check(mdb_stat(need_txn(database->env), database->dbi, &stat));
|
352
425
|
return stat2hash(&stat);
|
353
426
|
}
|
354
427
|
|
355
428
|
static VALUE database_drop(VALUE self) {
|
356
429
|
DATABASE(self, database);
|
357
|
-
if (!
|
430
|
+
if (!active_txn(database->env))
|
358
431
|
return call_with_transaction(database->env, self, "drop", 0, 0, 0);
|
359
|
-
check(mdb_drop(
|
432
|
+
check(mdb_drop(need_txn(database->env), database->dbi, 1));
|
360
433
|
return Qnil;
|
361
434
|
}
|
362
435
|
|
363
436
|
static VALUE database_clear(VALUE self) {
|
364
437
|
DATABASE(self, database);
|
365
|
-
if (!
|
438
|
+
if (!active_txn(database->env))
|
366
439
|
return call_with_transaction(database->env, self, "clear", 0, 0, 0);
|
367
|
-
check(mdb_drop(
|
440
|
+
check(mdb_drop(need_txn(database->env), database->dbi, 0));
|
368
441
|
return Qnil;
|
369
442
|
}
|
370
443
|
|
371
444
|
static VALUE database_get(VALUE self, VALUE vkey) {
|
372
445
|
DATABASE(self, database);
|
373
|
-
if (!
|
446
|
+
if (!active_txn(database->env))
|
374
447
|
return call_with_transaction(database->env, self, "get", 1, &vkey, MDB_RDONLY);
|
375
448
|
|
376
449
|
vkey = StringValue(vkey);
|
@@ -378,20 +451,30 @@ static VALUE database_get(VALUE self, VALUE vkey) {
|
|
378
451
|
key.mv_size = RSTRING_LEN(vkey);
|
379
452
|
key.mv_data = RSTRING_PTR(vkey);
|
380
453
|
|
381
|
-
int ret = mdb_get(
|
454
|
+
int ret = mdb_get(need_txn(database->env), database->dbi, &key, &value);
|
382
455
|
if (ret == MDB_NOTFOUND)
|
383
456
|
return Qnil;
|
384
457
|
check(ret);
|
385
458
|
return rb_str_new(value.mv_data, value.mv_size);
|
386
459
|
}
|
387
460
|
|
461
|
+
#define METHOD database_put_flags
|
462
|
+
#define FILE "put_flags.h"
|
463
|
+
#include "flag_parser.h"
|
464
|
+
#undef METHOD
|
465
|
+
#undef FILE
|
466
|
+
|
388
467
|
static VALUE database_put(int argc, VALUE *argv, VALUE self) {
|
389
468
|
DATABASE(self, database);
|
390
|
-
if (!
|
469
|
+
if (!active_txn(database->env))
|
391
470
|
return call_with_transaction(database->env, self, "put", argc, argv, 0);
|
392
471
|
|
393
|
-
VALUE vkey,
|
394
|
-
rb_scan_args(argc, argv, "
|
472
|
+
VALUE vkey, vval, option_hash;
|
473
|
+
rb_scan_args(argc, argv, "2:", &vkey, &vval, &option_hash);
|
474
|
+
|
475
|
+
int flags = 0;
|
476
|
+
if (!NIL_P(option_hash))
|
477
|
+
rb_hash_foreach(option_hash, database_put_flags, (VALUE)&flags);
|
395
478
|
|
396
479
|
vkey = StringValue(vkey);
|
397
480
|
vval = StringValue(vval);
|
@@ -402,13 +485,13 @@ static VALUE database_put(int argc, VALUE *argv, VALUE self) {
|
|
402
485
|
value.mv_size = RSTRING_LEN(vval);
|
403
486
|
value.mv_data = RSTRING_PTR(vval);
|
404
487
|
|
405
|
-
check(mdb_put(
|
488
|
+
check(mdb_put(need_txn(database->env), database->dbi, &key, &value, flags));
|
406
489
|
return Qnil;
|
407
490
|
}
|
408
491
|
|
409
492
|
static VALUE database_delete(int argc, VALUE *argv, VALUE self) {
|
410
493
|
DATABASE(self, database);
|
411
|
-
if (!
|
494
|
+
if (!active_txn(database->env))
|
412
495
|
return call_with_transaction(database->env, self, "delete", argc, argv, 0);
|
413
496
|
|
414
497
|
VALUE vkey, vval;
|
@@ -421,13 +504,13 @@ static VALUE database_delete(int argc, VALUE *argv, VALUE self) {
|
|
421
504
|
key.mv_data = RSTRING_PTR(vkey);
|
422
505
|
|
423
506
|
if (NIL_P(vval)) {
|
424
|
-
check(mdb_del(
|
507
|
+
check(mdb_del(need_txn(database->env), database->dbi, &key, 0));
|
425
508
|
} else {
|
426
509
|
VALUE vval = StringValue(vval);
|
427
510
|
MDB_val value;
|
428
511
|
value.mv_size = RSTRING_LEN(vval);
|
429
512
|
value.mv_data = RSTRING_PTR(vval);
|
430
|
-
check(mdb_del(
|
513
|
+
check(mdb_del(need_txn(database->env), database->dbi, &key, &value));
|
431
514
|
}
|
432
515
|
|
433
516
|
return Qnil;
|
@@ -459,11 +542,11 @@ static VALUE cursor_close(VALUE self) {
|
|
459
542
|
|
460
543
|
static VALUE database_cursor(VALUE self) {
|
461
544
|
DATABASE(self, database);
|
462
|
-
if (!
|
545
|
+
if (!active_txn(database->env))
|
463
546
|
return call_with_transaction(database->env, self, "cursor", 0, 0, 0);
|
464
547
|
|
465
548
|
MDB_cursor* cur;
|
466
|
-
check(mdb_cursor_open(
|
549
|
+
check(mdb_cursor_open(need_txn(database->env), database->dbi, &cur));
|
467
550
|
|
468
551
|
Cursor* cursor;
|
469
552
|
VALUE vcur = Data_Make_Struct(cCursor, Cursor, cursor_mark, cursor_free, cursor);
|
@@ -473,13 +556,13 @@ static VALUE database_cursor(VALUE self) {
|
|
473
556
|
|
474
557
|
if (rb_block_given_p()) {
|
475
558
|
int exception;
|
476
|
-
VALUE
|
559
|
+
VALUE ret = rb_protect(rb_yield, vcur, &exception);
|
477
560
|
if (exception) {
|
478
561
|
cursor_close(vcur);
|
479
562
|
rb_jump_tag(exception);
|
480
563
|
}
|
481
564
|
cursor_close(vcur);
|
482
|
-
return
|
565
|
+
return ret;
|
483
566
|
}
|
484
567
|
|
485
568
|
return vcur;
|
@@ -548,11 +631,21 @@ static VALUE cursor_get(VALUE self) {
|
|
548
631
|
return rb_assoc_new(rb_str_new(key.mv_data, key.mv_size), rb_str_new(value.mv_data, value.mv_size));
|
549
632
|
}
|
550
633
|
|
634
|
+
#define METHOD cursor_put_flags
|
635
|
+
#define FILE "cursor_put_flags.h"
|
636
|
+
#include "flag_parser.h"
|
637
|
+
#undef METHOD
|
638
|
+
#undef FILE
|
639
|
+
|
551
640
|
static VALUE cursor_put(int argc, VALUE* argv, VALUE self) {
|
552
641
|
CURSOR(self, cursor);
|
553
642
|
|
554
|
-
VALUE vkey,
|
555
|
-
rb_scan_args(argc, argv, "
|
643
|
+
VALUE vkey, vval, option_hash;
|
644
|
+
rb_scan_args(argc, argv, "2:", &vkey, &vval, &option_hash);
|
645
|
+
|
646
|
+
int flags = 0;
|
647
|
+
if (!NIL_P(option_hash))
|
648
|
+
rb_hash_foreach(option_hash, cursor_put_flags, (VALUE)&flags);
|
556
649
|
|
557
650
|
vkey = StringValue(vkey);
|
558
651
|
vval = StringValue(vval);
|
@@ -563,15 +656,27 @@ static VALUE cursor_put(int argc, VALUE* argv, VALUE self) {
|
|
563
656
|
value.mv_size = RSTRING_LEN(vval);
|
564
657
|
value.mv_data = RSTRING_PTR(vval);
|
565
658
|
|
566
|
-
check(mdb_cursor_put(cursor->cur, &key, &value,
|
659
|
+
check(mdb_cursor_put(cursor->cur, &key, &value, flags));
|
567
660
|
return Qnil;
|
568
661
|
}
|
569
662
|
|
663
|
+
#define METHOD cursor_delete_flags
|
664
|
+
#define FILE "cursor_delete_flags.h"
|
665
|
+
#include "flag_parser.h"
|
666
|
+
#undef METHOD
|
667
|
+
#undef FILE
|
668
|
+
|
570
669
|
static VALUE cursor_delete(int argc, VALUE *argv, VALUE self) {
|
571
670
|
CURSOR(self, cursor);
|
572
|
-
|
573
|
-
|
574
|
-
|
671
|
+
|
672
|
+
VALUE option_hash;
|
673
|
+
rb_scan_args(argc, argv, ":", &option_hash);
|
674
|
+
|
675
|
+
int flags = 0;
|
676
|
+
if (!NIL_P(option_hash))
|
677
|
+
rb_hash_foreach(option_hash, cursor_delete_flags, (VALUE)&flags);
|
678
|
+
|
679
|
+
check(mdb_cursor_del(cursor->cur, flags));
|
575
680
|
return Qnil;
|
576
681
|
}
|
577
682
|
|
@@ -586,43 +691,14 @@ void Init_lmdb_ext() {
|
|
586
691
|
VALUE mLMDB;
|
587
692
|
|
588
693
|
mLMDB = rb_define_module("LMDB");
|
589
|
-
rb_define_const(mLMDB, "
|
590
|
-
rb_define_singleton_method(mLMDB, "
|
591
|
-
|
592
|
-
#define
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
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);
|
694
|
+
rb_define_const(mLMDB, "LIB_VERSION", rb_str_new2(MDB_VERSION_STRING));
|
695
|
+
rb_define_singleton_method(mLMDB, "new", environment_new, -1);
|
696
|
+
|
697
|
+
#define VERSION_CONST(name) rb_define_const(mLMDB, "LIB_VERSION_"#name, INT2NUM(MDB_VERSION_##name));
|
698
|
+
VERSION_CONST(MAJOR)
|
699
|
+
VERSION_CONST(MINOR)
|
700
|
+
VERSION_CONST(PATCH)
|
701
|
+
#undef VERSION_CONST
|
626
702
|
|
627
703
|
cError = rb_define_class_under(mLMDB, "Error", rb_eRuntimeError);
|
628
704
|
#define ERROR(name) cError_##name = rb_define_class_under(cError, #name, cError);
|
@@ -630,15 +706,16 @@ void Init_lmdb_ext() {
|
|
630
706
|
#undef ERROR
|
631
707
|
|
632
708
|
cEnvironment = rb_define_class_under(mLMDB, "Environment", rb_cObject);
|
633
|
-
|
634
|
-
rb_define_singleton_method(cEnvironment, "open", environment_open, -1);
|
709
|
+
rb_define_singleton_method(cEnvironment, "new", environment_new, -1);
|
635
710
|
rb_define_method(cEnvironment, "database", environment_database, -1);
|
711
|
+
rb_define_method(cEnvironment, "active_txn", environment_active_txn, 0);
|
636
712
|
rb_define_method(cEnvironment, "close", environment_close, 0);
|
637
713
|
rb_define_method(cEnvironment, "stat", environment_stat, 0);
|
638
714
|
rb_define_method(cEnvironment, "info", environment_info, 0);
|
639
715
|
rb_define_method(cEnvironment, "copy", environment_copy, 1);
|
640
716
|
rb_define_method(cEnvironment, "sync", environment_sync, -1);
|
641
|
-
rb_define_method(cEnvironment, "
|
717
|
+
rb_define_method(cEnvironment, "set_flags", environment_set_flags, -1);
|
718
|
+
rb_define_method(cEnvironment, "clear_flags", environment_clear_flags, -1);
|
642
719
|
rb_define_method(cEnvironment, "flags", environment_flags, 0);
|
643
720
|
rb_define_method(cEnvironment, "path", environment_path, 0);
|
644
721
|
rb_define_method(cEnvironment, "transaction", environment_transaction, -1);
|
data/ext/lmdb_ext/lmdb_ext.h
CHANGED
@@ -4,16 +4,6 @@
|
|
4
4
|
#include "ruby.h"
|
5
5
|
#include "lmdb.h"
|
6
6
|
|
7
|
-
#define ENV_FLAGS ( \
|
8
|
-
MDB_FIXEDMAP | \
|
9
|
-
MDB_NOSUBDIR | \
|
10
|
-
MDB_NOSYNC | \
|
11
|
-
MDB_RDONLY | \
|
12
|
-
MDB_NOMETASYNC | \
|
13
|
-
MDB_WRITEMAP | \
|
14
|
-
MDB_MAPASYNC | \
|
15
|
-
MDB_NOTLS)
|
16
|
-
|
17
7
|
#define ENVIRONMENT(var, var_env) \
|
18
8
|
Environment* var_env; \
|
19
9
|
Data_Get_Struct(var, Environment, var_env); \
|
@@ -37,13 +27,15 @@ typedef struct Transaction Transaction;
|
|
37
27
|
typedef struct Transaction {
|
38
28
|
VALUE env;
|
39
29
|
VALUE parent;
|
30
|
+
VALUE thread;
|
40
31
|
MDB_txn* txn;
|
41
32
|
int refcount;
|
42
33
|
} Transaction;
|
43
34
|
|
44
35
|
typedef struct {
|
45
36
|
MDB_env* env;
|
46
|
-
VALUE
|
37
|
+
VALUE thread_txn_hash;
|
38
|
+
VALUE txn_thread_hash;
|
47
39
|
int refcount;
|
48
40
|
} Environment;
|
49
41
|
|
@@ -65,6 +57,14 @@ typedef struct {
|
|
65
57
|
const VALUE* argv;
|
66
58
|
} HelperArgs;
|
67
59
|
|
60
|
+
typedef struct {
|
61
|
+
mode_t mode;
|
62
|
+
int flags;
|
63
|
+
int maxreaders;
|
64
|
+
int maxdbs;
|
65
|
+
size_t mapsize;
|
66
|
+
} EnvironmentOptions;
|
67
|
+
|
68
68
|
static VALUE cEnvironment, cDatabase, cTransaction, cCursor, cError;
|
69
69
|
|
70
70
|
#define ERROR(name) static VALUE cError_##name;
|
@@ -73,6 +73,7 @@ static VALUE cEnvironment, cDatabase, cTransaction, cCursor, cError;
|
|
73
73
|
|
74
74
|
// BEGIN PROTOTYPES
|
75
75
|
void Init_lmdb_ext();
|
76
|
+
static MDB_txn* active_txn(VALUE self);
|
76
77
|
static VALUE call_with_transaction(VALUE venv, VALUE self, const char* name, int argc, const VALUE* argv, int flags);
|
77
78
|
static VALUE call_with_transaction_helper(VALUE arg);
|
78
79
|
static void check(int code);
|
@@ -98,25 +99,31 @@ static VALUE database_get(VALUE self, VALUE vkey);
|
|
98
99
|
static void database_mark(Database* database);
|
99
100
|
static VALUE database_put(int argc, VALUE *argv, VALUE self);
|
100
101
|
static VALUE database_stat(VALUE self);
|
102
|
+
static VALUE environment_active_txn(VALUE self);
|
103
|
+
static VALUE environment_change_flags(int argc, VALUE* argv, VALUE self, int set);
|
101
104
|
static void environment_check(Environment* environment);
|
105
|
+
static VALUE environment_clear_flags(int argc, VALUE* argv, VALUE self);
|
102
106
|
static VALUE environment_close(VALUE self);
|
103
107
|
static VALUE environment_copy(VALUE self, VALUE path);
|
104
108
|
static VALUE environment_database(int argc, VALUE *argv, VALUE self);
|
105
109
|
static void environment_deref(Environment *environment);
|
106
110
|
static VALUE environment_flags(VALUE self);
|
107
111
|
static VALUE environment_info(VALUE self);
|
108
|
-
static
|
109
|
-
static VALUE
|
112
|
+
static void environment_mark(Environment* environment);
|
113
|
+
static VALUE environment_new(int argc, VALUE *argv, VALUE klass);
|
114
|
+
static int environment_options(VALUE key, VALUE value, EnvironmentOptions* options);
|
110
115
|
static VALUE environment_path(VALUE self);
|
111
|
-
static
|
116
|
+
static void environment_set_active_txn(VALUE self, VALUE thread, VALUE txn);
|
117
|
+
static VALUE environment_set_flags(int argc, VALUE* argv, VALUE self);
|
112
118
|
static VALUE environment_stat(VALUE self);
|
113
119
|
static VALUE environment_sync(int argc, VALUE *argv, VALUE self);
|
114
120
|
static VALUE environment_transaction(int argc, VALUE *argv, VALUE self);
|
115
|
-
static MDB_txn*
|
121
|
+
static MDB_txn* need_txn(VALUE self);
|
116
122
|
static VALUE stat2hash(const MDB_stat* stat);
|
117
123
|
static VALUE transaction_abort(VALUE self);
|
118
124
|
static VALUE transaction_commit(VALUE self);
|
119
125
|
static void transaction_deref(Transaction* transaction);
|
126
|
+
static void transaction_finish(VALUE self, int commit);
|
120
127
|
static void transaction_mark(Transaction* transaction);
|
121
128
|
static VALUE with_transaction(VALUE venv, VALUE(*fn)(VALUE), VALUE arg, int flags);
|
122
129
|
// END PROTOTYPES
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module LMDB
|
2
|
+
class Database
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def each
|
6
|
+
cursor do |c|
|
7
|
+
while i = c.next
|
8
|
+
yield(i)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](key)
|
14
|
+
get(key)
|
15
|
+
end
|
16
|
+
|
17
|
+
def []=(key, value)
|
18
|
+
put(key, value)
|
19
|
+
value
|
20
|
+
end
|
21
|
+
|
22
|
+
def size
|
23
|
+
stat[:entries]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/lmdb/version.rb
ADDED
data/lib/lmdb.rb
CHANGED
@@ -1,29 +1,3 @@
|
|
1
1
|
require 'lmdb_ext'
|
2
|
-
|
3
|
-
|
4
|
-
class Database
|
5
|
-
include Enumerable
|
6
|
-
|
7
|
-
def each
|
8
|
-
cursor do |c|
|
9
|
-
while i = c.next
|
10
|
-
yield(i)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def [](key)
|
16
|
-
get(key)
|
17
|
-
end
|
18
|
-
|
19
|
-
def []=(key, value)
|
20
|
-
put(key, value)
|
21
|
-
value
|
22
|
-
end
|
23
|
-
|
24
|
-
def size
|
25
|
-
stat[:entries]
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
2
|
+
require 'lmdb/version'
|
3
|
+
require 'lmdb/database'
|
data/lmdb.gemspec
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
+
require File.dirname(__FILE__) + '/lib/lmdb/version'
|
3
|
+
require 'date'
|
2
4
|
|
3
5
|
Gem::Specification.new do |s|
|
4
6
|
s.name = File.basename(__FILE__, '.gemspec')
|
5
|
-
s.version =
|
7
|
+
s.version = LMDB::VERSION
|
6
8
|
s.platform = Gem::Platform::RUBY
|
9
|
+
s.date = Date.today.to_s
|
7
10
|
s.licenses = ['MIT']
|
8
11
|
s.summary = 'Ruby bindings to Lightning MDB'
|
9
12
|
s.email = 'mail@daniel-mendler.de'
|
data/spec/lmdb_spec.rb
CHANGED
@@ -2,71 +2,50 @@
|
|
2
2
|
require 'helper'
|
3
3
|
|
4
4
|
describe LMDB do
|
5
|
-
let(:env) { LMDB.
|
5
|
+
let(:env) { LMDB.new(path) }
|
6
6
|
after { env.close rescue nil }
|
7
7
|
|
8
8
|
let(:db) { env.database }
|
9
9
|
|
10
10
|
it 'has version constants' do
|
11
|
-
LMDB::
|
12
|
-
LMDB::
|
13
|
-
LMDB::
|
11
|
+
LMDB::LIB_VERSION_MAJOR.should be_instance_of(Fixnum)
|
12
|
+
LMDB::LIB_VERSION_MINOR.should be_instance_of(Fixnum)
|
13
|
+
LMDB::LIB_VERSION_PATCH.should be_instance_of(Fixnum)
|
14
|
+
LMDB::LIB_VERSION.should be_instance_of(String)
|
14
15
|
LMDB::VERSION.should be_instance_of(String)
|
15
16
|
end
|
16
17
|
|
17
|
-
it 'has environment flags' do
|
18
|
-
LMDB::FIXEDMAP.should be_instance_of(Fixnum)
|
19
|
-
LMDB::NOSUBDIR.should be_instance_of(Fixnum)
|
20
|
-
LMDB::NOSYNC.should be_instance_of(Fixnum)
|
21
|
-
LMDB::RDONLY.should be_instance_of(Fixnum)
|
22
|
-
LMDB::NOMETASYNC.should be_instance_of(Fixnum)
|
23
|
-
LMDB::WRITEMAP.should be_instance_of(Fixnum)
|
24
|
-
LMDB::MAPASYNC.should be_instance_of(Fixnum)
|
25
|
-
LMDB::NOTLS.should be_instance_of(Fixnum)
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'has database flags' do
|
29
|
-
LMDB::REVERSEKEY.should be_instance_of(Fixnum)
|
30
|
-
LMDB::DUPSORT.should be_instance_of(Fixnum)
|
31
|
-
LMDB::INTEGERKEY.should be_instance_of(Fixnum)
|
32
|
-
LMDB::DUPFIXED.should be_instance_of(Fixnum)
|
33
|
-
LMDB::INTEGERDUP.should be_instance_of(Fixnum)
|
34
|
-
LMDB::REVERSEDUP.should be_instance_of(Fixnum)
|
35
|
-
LMDB::CREATE.should be_instance_of(Fixnum)
|
36
|
-
LMDB::NOOVERWRITE.should be_instance_of(Fixnum)
|
37
|
-
LMDB::NODUPDATA.should be_instance_of(Fixnum)
|
38
|
-
LMDB::CURRENT.should be_instance_of(Fixnum)
|
39
|
-
LMDB::RESERVE.should be_instance_of(Fixnum)
|
40
|
-
LMDB::APPEND.should be_instance_of(Fixnum)
|
41
|
-
LMDB::APPENDDUP.should be_instance_of(Fixnum)
|
42
|
-
LMDB::MULTIPLE.should be_instance_of(Fixnum)
|
43
|
-
end
|
44
|
-
|
45
18
|
describe LMDB::Environment do
|
46
19
|
subject { env }
|
47
20
|
|
48
|
-
|
49
|
-
|
21
|
+
it 'should return flags' do
|
22
|
+
subject.flags.should be_instance_of(Array)
|
23
|
+
end
|
50
24
|
|
51
|
-
describe '
|
25
|
+
describe 'new' do
|
52
26
|
it 'returns environment' do
|
53
|
-
env = LMDB::Environment.
|
27
|
+
env = LMDB::Environment.new(path)
|
54
28
|
env.should be_instance_of(described_class::Environment)
|
55
29
|
env.close
|
56
30
|
end
|
57
31
|
|
58
32
|
it 'accepts block' do
|
59
|
-
LMDB::Environment.
|
33
|
+
LMDB::Environment.new(path) do |env|
|
60
34
|
env.should be_instance_of(described_class::Environment)
|
61
35
|
42
|
62
36
|
end.should == 42
|
63
37
|
end
|
64
38
|
|
65
39
|
it 'accepts options' do
|
66
|
-
env = LMDB::Environment.
|
40
|
+
env = LMDB::Environment.new(path, :nosync => true, :mode => 0777, :maxreaders => 777, :mapsize => 111111, :maxdbs => 666)
|
67
41
|
env.should be_instance_of(described_class::Environment)
|
68
42
|
env.info[:maxreaders].should == 777
|
69
43
|
env.info[:mapsize].should == 111111
|
44
|
+
env.flags.should include(:nosync)
|
45
|
+
env.close
|
46
|
+
|
47
|
+
env = LMDB::Environment.new(path, :nosync => false)
|
48
|
+
env.flags.should_not include(:nosync)
|
70
49
|
env.close
|
71
50
|
end
|
72
51
|
end
|
@@ -105,58 +84,84 @@ describe LMDB do
|
|
105
84
|
end
|
106
85
|
|
107
86
|
it 'should accept custom flags' do
|
108
|
-
|
109
|
-
subject.flags.should == LMDB::NOSYNC
|
87
|
+
subject.flags.should_not include(:nosync)
|
110
88
|
|
111
|
-
|
112
|
-
subject.flags.should
|
89
|
+
subject.set_flags :nosync
|
90
|
+
subject.flags.should include(:nosync)
|
91
|
+
|
92
|
+
subject.clear_flags :nosync
|
93
|
+
subject.flags.should_not include(:nosync)
|
113
94
|
end
|
114
95
|
|
115
96
|
describe 'transaction' do
|
116
97
|
subject { env}
|
117
98
|
|
118
99
|
it 'should create transactions' do
|
100
|
+
subject.active_txn.should == nil
|
119
101
|
subject.transaction do |txn|
|
102
|
+
subject.active_txn.should == txn
|
120
103
|
txn.should be_instance_of(described_class::Transaction)
|
121
104
|
txn.abort
|
105
|
+
subject.active_txn.should == nil
|
122
106
|
end
|
107
|
+
subject.active_txn.should == nil
|
123
108
|
end
|
124
109
|
|
125
110
|
it 'should create read-only transactions' do
|
111
|
+
subject.active_txn.should == nil
|
126
112
|
subject.transaction(true) do |txn|
|
113
|
+
subject.active_txn.should == txn
|
127
114
|
txn.should be_instance_of(described_class::Transaction)
|
128
115
|
txn.abort
|
116
|
+
subject.active_txn.should == nil
|
129
117
|
end
|
118
|
+
subject.active_txn.should == nil
|
130
119
|
end
|
131
120
|
|
132
121
|
it 'can create child transactions' do
|
122
|
+
subject.active_txn.should == nil
|
133
123
|
env.transaction do |txn|
|
134
|
-
|
124
|
+
subject.active_txn.should == txn
|
135
125
|
env.transaction do |ctxn|
|
136
|
-
|
126
|
+
subject.active_txn.should == ctxn
|
137
127
|
ctxn.abort
|
128
|
+
subject.active_txn.should == txn
|
138
129
|
end
|
130
|
+
subject.active_txn.should == txn
|
139
131
|
end
|
132
|
+
subject.active_txn.should == nil
|
140
133
|
end
|
141
134
|
|
142
135
|
it 'should support aborting parent transaction' do
|
136
|
+
subject.active_txn.should == nil
|
143
137
|
env.transaction do |txn|
|
138
|
+
subject.active_txn.should == txn
|
144
139
|
env.transaction do |ctxn|
|
140
|
+
subject.active_txn.should == ctxn
|
145
141
|
db['key'] = 'value'
|
146
142
|
txn.abort
|
143
|
+
subject.active_txn.should == nil
|
147
144
|
end
|
145
|
+
subject.active_txn.should == nil
|
148
146
|
end
|
149
147
|
db['key'].should be(nil)
|
148
|
+
subject.active_txn.should == nil
|
150
149
|
end
|
151
150
|
|
152
151
|
it 'should support comitting parent transaction' do
|
152
|
+
subject.active_txn.should == nil
|
153
153
|
env.transaction do |txn|
|
154
|
+
subject.active_txn.should == txn
|
154
155
|
env.transaction do |ctxn|
|
156
|
+
subject.active_txn.should == ctxn
|
155
157
|
db['key'] = 'value'
|
156
158
|
txn.commit
|
159
|
+
subject.active_txn.should == nil
|
157
160
|
end
|
161
|
+
subject.active_txn.should == nil
|
158
162
|
end
|
159
163
|
db['key'].should == 'value'
|
164
|
+
subject.active_txn.should == nil
|
160
165
|
end
|
161
166
|
end
|
162
167
|
end
|
@@ -164,6 +169,20 @@ describe LMDB do
|
|
164
169
|
describe LMDB::Database do
|
165
170
|
subject { db }
|
166
171
|
|
172
|
+
it 'should support named databases' do
|
173
|
+
main = env.database
|
174
|
+
db1 = env.database('db1', :create => true)
|
175
|
+
db2 = env.database('db2', :create => true)
|
176
|
+
|
177
|
+
main['key'] = '1'
|
178
|
+
db1['key'] = '2'
|
179
|
+
db2['key'] = '3'
|
180
|
+
|
181
|
+
main['key'].should == '1'
|
182
|
+
db1['key'].should == '2'
|
183
|
+
db2['key'].should == '3'
|
184
|
+
end
|
185
|
+
|
167
186
|
it 'should get/put data' do
|
168
187
|
subject.get('cat').should be_nil
|
169
188
|
subject.put('cat', 'garfield').should be_nil
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lmdb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Mendler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-09-
|
11
|
+
date: 2013-09-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -66,8 +66,13 @@ files:
|
|
66
66
|
- Gemfile
|
67
67
|
- README.md
|
68
68
|
- Rakefile
|
69
|
+
- ext/lmdb_ext/cursor_delete_flags.h
|
70
|
+
- ext/lmdb_ext/cursor_put_flags.h
|
71
|
+
- ext/lmdb_ext/dbi_flags.h
|
72
|
+
- ext/lmdb_ext/env_flags.h
|
69
73
|
- ext/lmdb_ext/errors.h
|
70
74
|
- ext/lmdb_ext/extconf.rb
|
75
|
+
- ext/lmdb_ext/flag_parser.h
|
71
76
|
- ext/lmdb_ext/liblmdb/.gitignore
|
72
77
|
- ext/lmdb_ext/liblmdb/CHANGES
|
73
78
|
- ext/lmdb_ext/liblmdb/COPYRIGHT
|
@@ -79,7 +84,10 @@ files:
|
|
79
84
|
- ext/lmdb_ext/lmdb_ext.c
|
80
85
|
- ext/lmdb_ext/lmdb_ext.h
|
81
86
|
- ext/lmdb_ext/prototypes.sh
|
87
|
+
- ext/lmdb_ext/put_flags.h
|
82
88
|
- lib/lmdb.rb
|
89
|
+
- lib/lmdb/database.rb
|
90
|
+
- lib/lmdb/version.rb
|
83
91
|
- lmdb.gemspec
|
84
92
|
- spec/helper.rb
|
85
93
|
- spec/lmdb_spec.rb
|
@@ -103,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
111
|
version: '0'
|
104
112
|
requirements: []
|
105
113
|
rubyforge_project:
|
106
|
-
rubygems_version: 2.0.
|
114
|
+
rubygems_version: 2.0.3
|
107
115
|
signing_key:
|
108
116
|
specification_version: 4
|
109
117
|
summary: Ruby bindings to Lightning MDB
|