lmdb 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|