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