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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e261f77741383fa6cfe1b174ed0856a76d18d92e
4
- data.tar.gz: b44bb1ca05ec5dfec80b13ee9bdac03a3b745e83
3
+ metadata.gz: e65d2930d0d2e7812f17f527cec9e28227ff86d3
4
+ data.tar.gz: 9b1be0c534d29babf1ecfb665bc0a93f1cadc158
5
5
  SHA512:
6
- metadata.gz: 2980d425391ff3ddb32210c7c05970927836648355ed9e31c18fad1e48f32b234ec4c8b9a6509c2b19afaf7e54f4391835fc136c0c61b716733760c103f1d22d
7
- data.tar.gz: 3abc9db5742fac65951e9bc62f0f8c0ed8ebcc7b6625ca336f5fdeda925c3f7b72bc8bff51a3558101de8bee833862725d14a4e34dd5f70316301888e522753e
6
+ metadata.gz: 79f1fa24f25e0c3dc0971df47ed6eea2d5f2e388a244f6354586c1a15c0cd9934ff302391a7a51b46f50534ddeb5c1b126e842ffb6e59773967e5e5ef49e35dd
7
+ data.tar.gz: 29a36534234f8da14bce75b157add7d4f259e94addf60e32a2faaf2edf4f84d168580e85090803d4eb16bf095a05c5546c6ea172835ba0d2098305d78d02c4cd
data/CHANGES CHANGED
@@ -1,3 +1,11 @@
1
+ 0.3.0
2
+
3
+ * Higher level API improved and stabilized
4
+
5
+ 0.2.0
6
+
7
+ * First working version
8
+
1
9
  0.1.0
2
10
 
3
11
  * Initial release
@@ -0,0 +1 @@
1
+ FLAG(NODUPDATA, nodupdata)
@@ -0,0 +1,2 @@
1
+ #include "put_flags.h"
2
+ FLAG(MULTIPLE, multiple)
@@ -0,0 +1,7 @@
1
+ FLAG(REVERSEKEY, reversekey)
2
+ FLAG(DUPSORT, dupsort)
3
+ FLAG(INTEGERKEY, integerkey)
4
+ FLAG(DUPFIXED, dupfixed)
5
+ FLAG(INTEGERDUP, integerdup)
6
+ FLAG(REVERSEDUP, reversedup)
7
+ FLAG(CREATE, create)
@@ -0,0 +1,8 @@
1
+ FLAG(FIXEDMAP, fixedmap)
2
+ FLAG(NOSUBDIR, nosubdir)
3
+ FLAG(NOSYNC, nosync)
4
+ FLAG(RDONLY, rdonly)
5
+ FLAG(NOMETASYNC, nometasync)
6
+ FLAG(WRITEMAP, writemap)
7
+ FLAG(MAPASYNC, mapasync)
8
+ FLAG(NOTLS, notls)
@@ -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
+ }
@@ -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
- TRANSACTION(self, transaction);
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
- ENVIRONMENT(transaction->env, environment);
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 = environment->txn;
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
- if (!transaction->txn)
81
- rb_raise(cError, "Transaction is terminated");
82
- mdb_txn_abort(transaction->txn);
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 = environment->txn;
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
- } while (p != self);
79
+ }
90
80
  transaction->txn = 0;
91
81
 
92
- environment->txn = transaction->parent;
93
- return Qnil;
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, environment_txn(venv), flags, &txn));
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 = environment->txn;
106
+ transaction->parent = environment_active_txn(venv);
116
107
  transaction->env = venv;
117
108
  transaction->txn = txn;
118
- environment->txn = vtxn;
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 result = rb_protect(fn, NIL_P(arg) ? vtxn : arg, &exception);
120
+ VALUE ret = rb_protect(fn, NIL_P(arg) ? vtxn : arg, &exception);
122
121
 
123
122
  if (exception) {
124
- if (vtxn == environment->txn)
123
+ if (vtxn == environment_active_txn(venv))
125
124
  transaction_abort(vtxn);
126
125
  rb_jump_tag(exception);
127
126
  }
128
- if (vtxn == environment->txn)
127
+ if (vtxn == environment_active_txn(venv))
129
128
  transaction_commit(vtxn);
130
- return result;
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 result = rb_hash_new();
159
+ VALUE ret = rb_hash_new();
155
160
 
156
- #define STAT_SET(name) rb_hash_aset(result, ID2SYM(rb_intern(#name)), INT2NUM(stat->ms_##name))
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 result;
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 result = rb_hash_new();
186
+ VALUE ret = rb_hash_new();
182
187
 
183
- #define INFO_SET(name) rb_hash_aset(result, ID2SYM(rb_intern(#name)), INT2NUM((size_t)info.me_##name));
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 result;
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 VALUE environment_open(int argc, VALUE *argv, VALUE klass) {
212
- VALUE path, options;
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
- 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);
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
- value = rb_hash_aref(options, ID2SYM(rb_intern("mode")));
224
- if (!NIL_P(value))
225
- mode = NUM2INT(value);
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
- value = rb_hash_aref(options, ID2SYM(rb_intern("maxreaders")));
228
- if (!NIL_P(value))
229
- maxreaders = NUM2INT(value);
232
+ else {
233
+ VALUE s = rb_inspect(key);
234
+ rb_raise(cError, "Invalid option %s", StringValueCStr(s));
235
+ }
230
236
 
231
- value = rb_hash_aref(options, ID2SYM(rb_intern("maxdbs")));
232
- if (!NIL_P(value))
233
- maxdbs = NUM2INT(value);
237
+ return 0;
238
+ }
234
239
 
235
- value = rb_hash_aref(options, ID2SYM(rb_intern("mapsize")));
236
- if (!NIL_P(value))
237
- mapsize = NUM2SIZET(value);
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, 0, environment_deref, 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->txn = Qnil;
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(environment->env, maxreaders));
251
- if (mapsize > 0)
252
- check(mdb_env_set_mapsize(environment->env, 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
- return INT2NUM(flags & ENV_FLAGS);
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 environment_set_flags(VALUE self, VALUE vflags) {
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
- 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);
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 MDB_txn* environment_txn(VALUE self) {
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
- if (NIL_P(environment->txn))
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(environment->txn, 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* environment_need_txn(VALUE self) {
296
- MDB_txn* txn = environment_txn(self);
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 (NIL_P(environment->txn))
395
+ if (!active_txn(self))
327
396
  return call_with_transaction(self, self, "database", argc, argv, 0);
328
397
 
329
- VALUE vname, vflags;
330
- rb_scan_args(argc, argv, "02", &vname, &vflags);
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(environment_need_txn(self), NIL_P(vname) ? 0 : StringValueCStr(vname), NIL_P(vflags) ? 0 : NUM2INT(vflags), &dbi));
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 (!environment_txn(database->env))
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(environment_need_txn(database->env), database->dbi, &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 (!environment_txn(database->env))
430
+ if (!active_txn(database->env))
358
431
  return call_with_transaction(database->env, self, "drop", 0, 0, 0);
359
- check(mdb_drop(environment_need_txn(database->env), database->dbi, 1));
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 (!environment_txn(database->env))
438
+ if (!active_txn(database->env))
366
439
  return call_with_transaction(database->env, self, "clear", 0, 0, 0);
367
- check(mdb_drop(environment_need_txn(database->env), database->dbi, 0));
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 (!environment_txn(database->env))
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(environment_need_txn(database->env), database->dbi, &key, &value);
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 (!environment_txn(database->env))
469
+ if (!active_txn(database->env))
391
470
  return call_with_transaction(database->env, self, "put", argc, argv, 0);
392
471
 
393
- VALUE vkey, vflags, vval;
394
- rb_scan_args(argc, argv, "21", &vkey, &vval, &vflags);
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(environment_need_txn(database->env), database->dbi, &key, &value, NIL_P(vflags) ? 0 : NUM2INT(vflags)));
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 (!environment_txn(database->env))
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(environment_need_txn(database->env), database->dbi, &key, 0));
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(environment_need_txn(database->env), database->dbi, &key, &value));
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 (!environment_txn(database->env))
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(environment_need_txn(database->env), database->dbi, &cur));
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 result = rb_protect(rb_yield, vcur, &exception);
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 result;
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, vflags, vval;
555
- rb_scan_args(argc, argv, "21", &vkey, &vval, &vflags);
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, NIL_P(vflags) ? 0 : NUM2INT(vflags)));
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
- VALUE vflags;
573
- rb_scan_args(argc, argv, "01", &vflags);
574
- check(mdb_cursor_del(cursor->cur, NIL_P(vflags) ? 0 : NUM2INT(vflags)));
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, "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);
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
- rb_undef_method(rb_singleton_class(cEnvironment), "new");
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, "flags=", environment_set_flags, 1);
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);
@@ -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 txn;
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 MDB_txn* environment_need_txn(VALUE self);
109
- static VALUE environment_open(int argc, VALUE *argv, VALUE klass);
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 VALUE environment_set_flags(VALUE self, VALUE vflags);
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* environment_txn(VALUE self);
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,5 @@
1
+ FLAG(NOOVERWRITE, nooverwrite)
2
+ FLAG(NODUPDATA, nodupdata)
3
+ FLAG(CURRENT, current)
4
+ FLAG(APPEND, append)
5
+ FLAG(APPENDDUP, appenddup)
@@ -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
@@ -0,0 +1,3 @@
1
+ module LMDB
2
+ VERSION = '0.3.0'
3
+ end
data/lib/lmdb.rb CHANGED
@@ -1,29 +1,3 @@
1
1
  require 'lmdb_ext'
2
-
3
- module LMDB
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 = '0.2.0'
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.open(path) }
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::VERSION_MAJOR.should be_instance_of(Fixnum)
12
- LMDB::VERSION_MINOR.should be_instance_of(Fixnum)
13
- LMDB::VERSION_PATCH.should be_instance_of(Fixnum)
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
- its(:path) { should == path }
49
- its(:flags) { should == 0 }
21
+ it 'should return flags' do
22
+ subject.flags.should be_instance_of(Array)
23
+ end
50
24
 
51
- describe 'open' do
25
+ describe 'new' do
52
26
  it 'returns environment' do
53
- env = LMDB::Environment.open(path)
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.open(path) do |env|
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.open(path, :flags => LMDB::NOSYNC, :mode => 0777, :maxreaders => 777, :mapsize => 111111, :maxdbs => 666)
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
- (subject.flags = LMDB::NOSYNC).should == LMDB::NOSYNC
109
- subject.flags.should == LMDB::NOSYNC
87
+ subject.flags.should_not include(:nosync)
110
88
 
111
- (subject.flags = 0).should == 0
112
- subject.flags.should == 0
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
- txn.should be_instance_of(described_class::Transaction)
124
+ subject.active_txn.should == txn
135
125
  env.transaction do |ctxn|
136
- ctxn.should be_instance_of(described_class::Transaction)
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.2.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-07 00:00:00.000000000 Z
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.0
114
+ rubygems_version: 2.0.3
107
115
  signing_key:
108
116
  specification_version: 4
109
117
  summary: Ruby bindings to Lightning MDB