lmdb 0.5.3 → 0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/CONTRIBUTORS +1 -0
- data/Rakefile +9 -0
- data/behaviour.org +35 -0
- data/ext/lmdb_ext/extconf.rb +1 -0
- data/ext/lmdb_ext/lmdb_ext.c +197 -93
- data/ext/lmdb_ext/lmdb_ext.h +19 -3
- data/lib/lmdb/database.rb +9 -8
- data/lib/lmdb/version.rb +1 -1
- data/lmdb.gemspec +1 -0
- data/spec/helper.rb +3 -0
- metadata +21 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2eac165bb0261c0af6813f16df9b725b2ca2a63f4c5de98734473d9976930735
|
4
|
+
data.tar.gz: 3aa0562060e4586dd7c7a44e795adc1449f489f57634787ef5e6480abbd49a48
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 22cc9f78002a05aa25fba212e4d3e3e97566ed7a9bd2e0c84996297398131b5afd57da0e1510a27086ac4b1938401d1369393f9b0515bdd044856109510c6432
|
7
|
+
data.tar.gz: eea983ccb0638bed2dbcfcd3e2ea76271072ea91d259b95e392d505c26f184c351f89ae6076025b93f47bfec3e42add3ec41055e5edb67bee5bfec2e8e341a80
|
data/.gitignore
CHANGED
data/CONTRIBUTORS
CHANGED
data/Rakefile
CHANGED
@@ -7,12 +7,21 @@ PRJ = File.basename(GEMSPEC, ".gemspec")
|
|
7
7
|
require 'bundler/setup'
|
8
8
|
require 'rspec/core/rake_task'
|
9
9
|
require 'rake/extensiontask'
|
10
|
+
require 'ruby_memcheck'
|
11
|
+
require 'ruby_memcheck/rspec/rake_task'
|
12
|
+
|
13
|
+
RubyMemcheck.config(binary_name: 'lmdb_ext')
|
10
14
|
|
11
15
|
RSpec::Core::RakeTask.new :spec
|
12
16
|
Rake::ExtensionTask.new :lmdb_ext
|
13
17
|
|
18
|
+
|
14
19
|
task :default => [:compile, :spec]
|
15
20
|
|
21
|
+
namespace :spec do
|
22
|
+
RubyMemcheck::RSpec::RakeTask.new(valgrind: :compile)
|
23
|
+
end
|
24
|
+
|
16
25
|
def version
|
17
26
|
@version ||= begin
|
18
27
|
require "#{PRJ}/version"
|
data/behaviour.org
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#+STARTUP: showall hidestars
|
2
|
+
* the situtation
|
3
|
+
- lmdb has two kinds of transaction: read-write and read-only
|
4
|
+
- there are two properties associated with transactions:
|
5
|
+
- nesting
|
6
|
+
- multiplicity
|
7
|
+
- *read-write* transactions can nest, but there can only be one stack of read-write transactions per *database*, that is, amongst /all/ threads and all processes attached to the persitent storage.
|
8
|
+
- *read-only* transactions /cannot/ nest (because it's not meaningful for a read-only transaction to nest), but there can be a read-only transaction per thread (and of course multiple threads per process).
|
9
|
+
- (i can't remember if you can have a thread with a read-write *and* read-only transaction going but we can probably assume not)
|
10
|
+
- so therefore we need a way to distinguish between read-write and read-only as well as identify the thread /across processes/ that has the one read-write transaction open.
|
11
|
+
* undocumented behaviour
|
12
|
+
** ~mdb_txn_begin~
|
13
|
+
- if the environment is read-only and the transaction is read-write, returns ~EACCES~
|
14
|
+
- if there is a parent transaction and the current transaction's flags are ~MDB_RDONLY~ or ~MDB_WRITEMAP~ (?) or ~TXN_BLOCKED~
|
15
|
+
- if the *parent's* transaction is ~MDB_TXN_RDONLY~ (which is the same as ~MDB_RDONLY~), return ~EINVAL~
|
16
|
+
- that's saying "read-only transactions can't be nested"
|
17
|
+
- otherwise, return ~MDB_BAD_TXN~
|
18
|
+
- this is saying "read-only transactions can't be children of read-write parents"
|
19
|
+
- otherwise a few boring scenarios where the function may return ~ENOMEM~
|
20
|
+
- otherwise check ~mdb_cursor_shadow~ or ~mdb_txn_renew0~
|
21
|
+
- XXX does ~mdb_txn_begin~ block when waiting for the read-write??
|
22
|
+
* desired behaviour
|
23
|
+
** ruby interface
|
24
|
+
- when the ruby programmer opens a read-only transaction within a read-only transaction, this should be a noop
|
25
|
+
- don't push any stack, don't allocate any resources, just do nothing
|
26
|
+
- when the ruby programmer opens a read-only transaction within a read-/write/ transaction, this should raise an exception
|
27
|
+
- in practice there's no harm except that this is more about communicating the right thing to the ruby programmer
|
28
|
+
- do we warn?
|
29
|
+
- problem: there's no way to know (via the lmdb api) if another process has a read-write transaction open
|
30
|
+
- poll?
|
31
|
+
- actually no it probably doesn't matter (the mdb api blocks anyway?)
|
32
|
+
- /actually/ actually, the cursed-ass goto pseudo-loop containing the ~CALL_WITHOUT_GVL~ deals with that
|
33
|
+
** internal implementation
|
34
|
+
- a successfully-created read-write transaction has to set ~rw_txn_thread~ to the current thread (unless it is a sub-transaction in which case noop)
|
35
|
+
- when a read-write transaction is committed or aborted, ~rw_txn_thread~ has to be set back to null (unless the transaction has a parent)
|
data/ext/lmdb_ext/extconf.rb
CHANGED
data/ext/lmdb_ext/lmdb_ext.c
CHANGED
@@ -26,6 +26,7 @@ static void check(int code) {
|
|
26
26
|
|
27
27
|
const char* err = mdb_strerror(code);
|
28
28
|
const char* sep = strchr(err, ':');
|
29
|
+
// increment the offset by two in case there is a colon (plus space)
|
29
30
|
if (sep)
|
30
31
|
err = sep + 2;
|
31
32
|
|
@@ -37,7 +38,7 @@ static void check(int code) {
|
|
37
38
|
}
|
38
39
|
|
39
40
|
static void transaction_free(Transaction* transaction) {
|
40
|
-
if (transaction->txn) {
|
41
|
+
if (transaction->txn && !NIL_P(transaction->txn)) {
|
41
42
|
//int id = (int)mdb_txn_id(transaction->txn);
|
42
43
|
//rb_warn(sprintf("Memory leak: Garbage collecting active transaction %d", id));
|
43
44
|
rb_warn("Memory leak: Garbage collecting active transaction");
|
@@ -49,6 +50,7 @@ static void transaction_free(Transaction* transaction) {
|
|
49
50
|
|
50
51
|
static void transaction_mark(Transaction* transaction) {
|
51
52
|
rb_gc_mark(transaction->parent);
|
53
|
+
rb_gc_mark(transaction->child);
|
52
54
|
rb_gc_mark(transaction->env);
|
53
55
|
rb_gc_mark(transaction->cursors);
|
54
56
|
}
|
@@ -130,55 +132,79 @@ static VALUE transaction_env(VALUE self) {
|
|
130
132
|
* @return [false,true] whether the transaction is read-only.
|
131
133
|
*/
|
132
134
|
static VALUE transaction_is_readonly(VALUE self) {
|
133
|
-
|
134
|
-
|
135
|
-
|
135
|
+
TRANSACTION(self, transaction);
|
136
|
+
//MDB_txn* txn = transaction->txn;
|
137
|
+
return (transaction->flags & MDB_RDONLY) ? Qtrue : Qfalse;
|
136
138
|
}
|
137
139
|
|
138
140
|
|
139
141
|
static void transaction_finish(VALUE self, int commit) {
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
142
|
+
TRANSACTION(self, transaction);
|
143
|
+
|
144
|
+
if (!transaction->txn)
|
145
|
+
rb_raise(cError, "Transaction is already terminated");
|
146
|
+
|
147
|
+
if (transaction->thread != rb_thread_current())
|
148
|
+
rb_raise(cError, "The thread closing the transaction "
|
149
|
+
"is not the one that opened it");
|
150
|
+
|
151
|
+
// ensure the transaction being closed is the active one
|
152
|
+
VALUE p = environment_active_txn(transaction->env);
|
153
|
+
while (!NIL_P(p) && p != self) {
|
154
|
+
TRANSACTION(p, txn);
|
155
|
+
p = txn->parent;
|
156
|
+
}
|
157
|
+
// bail out if the transaction `self` is not the active one
|
158
|
+
if (p != self)
|
159
|
+
rb_raise(cError, "Transaction is not active");
|
160
|
+
|
161
|
+
// now eliminate the cursors
|
162
|
+
long i;
|
163
|
+
for (i=0; i<RARRAY_LEN(transaction->cursors); i++) {
|
164
|
+
VALUE cursor = RARRAY_AREF(transaction->cursors, i);
|
165
|
+
cursor_close(cursor);
|
166
|
+
}
|
167
|
+
rb_ary_clear(transaction->cursors);
|
168
|
+
|
169
|
+
// now actually finish the internal transaction
|
170
|
+
int ret = 0;
|
171
|
+
if (commit)
|
172
|
+
ret = mdb_txn_commit(transaction->txn);
|
173
|
+
else
|
174
|
+
mdb_txn_abort(transaction->txn);
|
175
|
+
|
176
|
+
// eliminate child transactions
|
177
|
+
if (transaction->child) {
|
178
|
+
p = self; // again this is a VALUE
|
179
|
+
Transaction* txn = transaction; // and this is the struct
|
180
|
+
|
181
|
+
// descend into deepest child transaction
|
182
|
+
do {
|
183
|
+
p = txn->child;
|
184
|
+
// this is TRANSACTION minus the declaration
|
185
|
+
Data_Get_Struct(txn->child, Transaction, txn);
|
186
|
+
} while (txn->child);
|
187
|
+
|
188
|
+
// now we ascend back up
|
172
189
|
while (p != self) {
|
173
|
-
|
174
|
-
|
175
|
-
|
190
|
+
TRANSACTION(p, txn);
|
191
|
+
txn->txn = 0;
|
192
|
+
p = txn->parent;
|
176
193
|
}
|
177
|
-
|
194
|
+
}
|
195
|
+
transaction->txn = 0;
|
178
196
|
|
179
|
-
|
197
|
+
// no more active read-write transaction; unset the registry
|
198
|
+
if (!(transaction->flags & MDB_RDONLY) && !transaction->parent) {
|
199
|
+
ENVIRONMENT(transaction->env, env);
|
200
|
+
env->rw_txn_thread = NULL;
|
201
|
+
}
|
180
202
|
|
181
|
-
|
203
|
+
// now set the active transaction to the parent, if there is one
|
204
|
+
environment_set_active_txn(transaction->env, transaction->thread,
|
205
|
+
transaction->parent);
|
206
|
+
|
207
|
+
check(ret);
|
182
208
|
}
|
183
209
|
|
184
210
|
// Ruby 1.8.7 compatibility
|
@@ -219,65 +245,143 @@ static void stop_txn_begin(void *arg)
|
|
219
245
|
txn_args->stop = 1;
|
220
246
|
}
|
221
247
|
|
248
|
+
/**
|
249
|
+
* This is the code that opens transactions. Read-write transactions
|
250
|
+
* have to be called outside the GVL because they will block without
|
251
|
+
*
|
252
|
+
*
|
253
|
+
* Here is the basic problem with LMDB transactions:
|
254
|
+
*
|
255
|
+
* - There can only be one read-write transaction per LMDB
|
256
|
+
* ENVIRONMENT, not process, not thread.
|
257
|
+
*
|
258
|
+
* - Read-write transactions can nest.
|
259
|
+
*
|
260
|
+
* - There can only be one active transaction per thread.
|
261
|
+
*
|
262
|
+
* - Every thread can have an active read-ONLY transaction, but only one.
|
263
|
+
*
|
264
|
+
* - This is because read-only transactions canNOT nest (it is
|
265
|
+
* meaningless to have a nested read-only transaction)
|
266
|
+
*
|
267
|
+
* - Furthermore it is an error to open a read-only transaction under
|
268
|
+
* a read-write transaction.
|
269
|
+
*
|
270
|
+
* - Same goes for opening a read-write transaction in the same thread
|
271
|
+
* as an active read-only transaction.
|
272
|
+
*
|
273
|
+
* Nevertheless, the downstream Ruby user may not be able to
|
274
|
+
* completely control calls to env.transaction (e.g. if they are
|
275
|
+
* wrapping a transaction around a proc or lambda that happens to
|
276
|
+
* contain its own transaction), plus every call in LMDB needs to be
|
277
|
+
* implicitly wrapped in a transaction anyway.
|
278
|
+
*
|
279
|
+
* What this means is that we will, first, have to keep explicit track
|
280
|
+
* of the read-write transaction, if one exists. Second, we will have
|
281
|
+
* to simulate nesting for read-only transactions, so the behaviour in
|
282
|
+
* Ruby is the same as a read-write transaction.
|
283
|
+
*
|
284
|
+
*/
|
285
|
+
|
222
286
|
static VALUE with_transaction(VALUE venv, VALUE(*fn)(VALUE), VALUE arg, int flags) {
|
223
|
-
|
287
|
+
ENVIRONMENT(venv, environment);
|
224
288
|
|
225
|
-
|
226
|
-
|
289
|
+
MDB_txn* txn;
|
290
|
+
TxnArgs txn_args;
|
227
291
|
|
228
|
-
|
229
|
-
|
292
|
+
VALUE thread = rb_thread_current();
|
293
|
+
VALUE vparent = environment_active_txn(venv);
|
230
294
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
txn_args.htxn = &txn;
|
235
|
-
txn_args.result = 0;
|
236
|
-
txn_args.stop = 0;
|
295
|
+
Transaction* tparent = NULL;
|
296
|
+
if (vparent && !NIL_P(vparent))
|
297
|
+
Data_Get_Struct(vparent, Transaction, tparent);
|
237
298
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
299
|
+
// rb_warn("fart lol");
|
300
|
+
|
301
|
+
// XXX note this is a cursed goto loop that could almost certainly
|
302
|
+
// be rewritten as a do-while
|
303
|
+
retry:
|
304
|
+
txn = NULL;
|
305
|
+
|
306
|
+
txn_args.env = environment->env;
|
307
|
+
txn_args.parent = active_txn(venv);
|
308
|
+
txn_args.flags = flags;
|
309
|
+
txn_args.htxn = &txn;
|
310
|
+
txn_args.result = 0;
|
311
|
+
txn_args.stop = 0;
|
312
|
+
|
313
|
+
if (flags & MDB_RDONLY) {
|
314
|
+
if (tparent && tparent->flags & MDB_RDONLY)
|
315
|
+
// this is a no-op: put the same actual transaction in a
|
316
|
+
// different wrapper struct
|
317
|
+
txn = txn_args.parent;
|
318
|
+
else
|
319
|
+
// this will return an error if the parent transaction is
|
320
|
+
// read-write, so we don't need to handle the case explicitly
|
321
|
+
call_txn_begin(&txn_args);
|
322
|
+
}
|
323
|
+
else {
|
324
|
+
if (tparent) {
|
325
|
+
// first we have to determine if we're on the same thread
|
326
|
+
// as the parent, which in turn must be the same as the
|
327
|
+
// environment's registry for which thread has the
|
328
|
+
// read-write transaction
|
329
|
+
if (thread != tparent->thread ||
|
330
|
+
thread != environment->rw_txn_thread)
|
331
|
+
rb_raise(cError,
|
332
|
+
"Attempt to nest transaction on a different thread");
|
255
333
|
}
|
256
334
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
VALUE ret = rb_protect(fn, NIL_P(arg) ? vtxn : arg, &exception);
|
271
|
-
|
272
|
-
if (exception) {
|
273
|
-
//rb_warn("lol got exception");
|
274
|
-
if (vtxn == environment_active_txn(venv))
|
275
|
-
transaction_abort(vtxn);
|
276
|
-
rb_jump_tag(exception);
|
335
|
+
CALL_WITHOUT_GVL(call_txn_begin, &txn_args, stop_txn_begin, &txn_args);
|
336
|
+
|
337
|
+
if (txn_args.stop || !txn) {
|
338
|
+
// !txn is when rb_thread_call_without_gvl2
|
339
|
+
// returns before calling txn_begin
|
340
|
+
if (txn) {
|
341
|
+
mdb_txn_abort(txn);
|
342
|
+
txn_args.result = 0;
|
343
|
+
}
|
344
|
+
|
345
|
+
//rb_warn("got here lol");
|
346
|
+
rb_thread_check_ints();
|
347
|
+
goto retry; // in what cases do we get here?
|
277
348
|
}
|
349
|
+
|
350
|
+
// set the thread
|
351
|
+
environment->rw_txn_thread = thread;
|
352
|
+
}
|
353
|
+
|
354
|
+
// this will raise unless result is zero
|
355
|
+
check(txn_args.result);
|
356
|
+
|
357
|
+
Transaction* transaction;
|
358
|
+
VALUE vtxn = Data_Make_Struct(cTransaction, Transaction, transaction_mark,
|
359
|
+
transaction_free, transaction);
|
360
|
+
transaction->parent = vparent;
|
361
|
+
transaction->env = venv;
|
362
|
+
transaction->txn = txn;
|
363
|
+
transaction->flags = flags;
|
364
|
+
transaction->thread = rb_thread_current();
|
365
|
+
transaction->cursors = rb_ary_new();
|
366
|
+
|
367
|
+
// set the parent's child to self
|
368
|
+
if (tparent) tparent->child = vtxn;
|
369
|
+
|
370
|
+
environment_set_active_txn(venv, transaction->thread, vtxn);
|
371
|
+
|
372
|
+
// now we run the function in the transaction
|
373
|
+
int exception;
|
374
|
+
VALUE ret = rb_protect(fn, NIL_P(arg) ? vtxn : arg, &exception);
|
375
|
+
|
376
|
+
if (exception) {
|
377
|
+
// rb_warn("lol got exception");
|
278
378
|
if (vtxn == environment_active_txn(venv))
|
279
|
-
|
280
|
-
|
379
|
+
transaction_abort(vtxn);
|
380
|
+
rb_jump_tag(exception);
|
381
|
+
}
|
382
|
+
if (vtxn == environment_active_txn(venv))
|
383
|
+
transaction_commit(vtxn);
|
384
|
+
return ret;
|
281
385
|
}
|
282
386
|
|
283
387
|
static void environment_check(Environment* environment) {
|
@@ -674,7 +778,7 @@ static MDB_txn* active_txn(VALUE self) {
|
|
674
778
|
return 0;
|
675
779
|
TRANSACTION(vtxn, transaction);
|
676
780
|
if (!transaction->txn)
|
677
|
-
rb_raise(cError, "Transaction is terminated");
|
781
|
+
rb_raise(cError, "Transaction is already terminated");
|
678
782
|
if (transaction->thread != rb_thread_current())
|
679
783
|
rb_raise(cError, "Wrong thread");
|
680
784
|
return transaction->txn;
|
data/ext/lmdb_ext/lmdb_ext.h
CHANGED
@@ -47,19 +47,35 @@
|
|
47
47
|
Data_Get_Struct(var, Cursor, var_cur); \
|
48
48
|
cursor_check(var_cur)
|
49
49
|
|
50
|
+
/*
|
51
|
+
hey yo if you can convince hyc to add a function like
|
52
|
+
mdb_txn_get_flags or even mdb_txn_is_rdonly, you could probably get
|
53
|
+
rid of these wrapper structs and a lot of complexity, cause that is
|
54
|
+
literally the only reason why they're needed
|
55
|
+
|
56
|
+
actually no we would also need to know when a txn has a child and
|
57
|
+
there is also no mdb_txn_get_child or whatever
|
58
|
+
*/
|
59
|
+
|
50
60
|
typedef struct {
|
51
61
|
VALUE env;
|
52
|
-
VALUE parent;
|
62
|
+
VALUE parent; // ignored for ro threads
|
63
|
+
VALUE child; // ditto
|
53
64
|
VALUE thread;
|
54
65
|
VALUE cursors;
|
55
66
|
MDB_txn* txn;
|
56
67
|
unsigned int flags;
|
57
68
|
} Transaction;
|
58
69
|
|
70
|
+
// we have an extra field `rw_txn_thread` here that acts as the
|
71
|
+
// registry for the single read-write transaction. if it's populated,
|
72
|
+
// that's the one
|
73
|
+
|
59
74
|
typedef struct {
|
60
75
|
MDB_env* env;
|
61
|
-
VALUE thread_txn_hash;
|
62
|
-
VALUE txn_thread_hash;
|
76
|
+
VALUE thread_txn_hash; /* transaction -> thread */
|
77
|
+
VALUE txn_thread_hash; /* thread -> transaction */
|
78
|
+
VALUE rw_txn_thread; /* the thread with the rw transaction */
|
63
79
|
} Environment;
|
64
80
|
|
65
81
|
typedef struct {
|
data/lib/lmdb/database.rb
CHANGED
@@ -11,8 +11,8 @@ module LMDB
|
|
11
11
|
# puts "at #{key}: #{value}"
|
12
12
|
# end
|
13
13
|
def each
|
14
|
-
|
15
|
-
env.transaction do
|
14
|
+
maybe_txn true do
|
15
|
+
# env.transaction do
|
16
16
|
cursor do |c|
|
17
17
|
while i = c.next
|
18
18
|
yield(i)
|
@@ -56,8 +56,8 @@ module LMDB
|
|
56
56
|
# @return [Enumerator] in lieu of a block.
|
57
57
|
def each_key(&block)
|
58
58
|
return enum_for :each_key unless block_given?
|
59
|
-
|
60
|
-
env.transaction do
|
59
|
+
maybe_txn true do
|
60
|
+
#env.transaction do
|
61
61
|
cursor do |c|
|
62
62
|
while (rec = c.next true)
|
63
63
|
yield rec.first
|
@@ -81,8 +81,8 @@ module LMDB
|
|
81
81
|
return
|
82
82
|
end
|
83
83
|
|
84
|
-
|
85
|
-
env.transaction do
|
84
|
+
maybe_txn true do
|
85
|
+
# env.transaction do
|
86
86
|
cursor do |c|
|
87
87
|
method = :set
|
88
88
|
while rec = c.send(method, key)
|
@@ -124,8 +124,9 @@ module LMDB
|
|
124
124
|
|
125
125
|
ret = false
|
126
126
|
# read-only txn was having trouble being nested inside a read-write
|
127
|
-
|
128
|
-
env.transaction do
|
127
|
+
maybe_txn true do
|
128
|
+
# env.transaction true do
|
129
|
+
# env.transaction do
|
129
130
|
cursor { |c| ret = !!c.set(key, value) }
|
130
131
|
end
|
131
132
|
ret
|
data/lib/lmdb/version.rb
CHANGED
data/lmdb.gemspec
CHANGED
data/spec/helper.rb
CHANGED
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.6'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Mendler
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-05-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: ruby_memcheck
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
55
69
|
description: lmdb is a Ruby binding to OpenLDAP Lightning MDB.
|
56
70
|
email: mail@daniel-mendler.de
|
57
71
|
executables: []
|
@@ -66,6 +80,7 @@ files:
|
|
66
80
|
- Gemfile
|
67
81
|
- README.md
|
68
82
|
- Rakefile
|
83
|
+
- behaviour.org
|
69
84
|
- ext/lmdb_ext/cursor_delete_flags.h
|
70
85
|
- ext/lmdb_ext/cursor_put_flags.h
|
71
86
|
- ext/lmdb_ext/dbi_flags.h
|
@@ -95,7 +110,7 @@ homepage: https://github.com/minad/lmdb
|
|
95
110
|
licenses:
|
96
111
|
- MIT
|
97
112
|
metadata: {}
|
98
|
-
post_install_message:
|
113
|
+
post_install_message:
|
99
114
|
rdoc_options: []
|
100
115
|
require_paths:
|
101
116
|
- lib
|
@@ -110,8 +125,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
125
|
- !ruby/object:Gem::Version
|
111
126
|
version: '0'
|
112
127
|
requirements: []
|
113
|
-
rubygems_version: 3.
|
114
|
-
signing_key:
|
128
|
+
rubygems_version: 3.3.11
|
129
|
+
signing_key:
|
115
130
|
specification_version: 4
|
116
131
|
summary: Ruby bindings to Lightning MDB
|
117
132
|
test_files:
|