lmdb 0.6.7 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES +9 -0
- data/ext/lmdb_ext/lmdb_ext.c +110 -61
- data/ext/lmdb_ext/lmdb_ext.h +6 -6
- data/lib/lmdb/database.rb +22 -11
- data/lib/lmdb/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 27c33b768709ded58c1414c9102a0a4024219abb305e875279b705d6d784aa68
|
|
4
|
+
data.tar.gz: 6d9b3f61f5ec981329fe42b6c310aca2760d5569f72202cbbe590258d1693591
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8e1816c955d847948075046de78e382316ea599e56090bde14c669b4318cb12fc42d0c90cfed3089dded7be185c2589b99d756b343ae126c4e2c6f425e19451e
|
|
7
|
+
data.tar.gz: 2bab39420ba0d6243bf261239a1264694e8be367f2b221522b3e596acfc3697225190cd8b6ba41fc34596e73731cc7f870312e13b15f36ae66f9041186268eb0
|
data/CHANGES
CHANGED
data/ext/lmdb_ext/lmdb_ext.c
CHANGED
|
@@ -137,6 +137,28 @@ static VALUE transaction_is_readonly(VALUE self) {
|
|
|
137
137
|
return (transaction->flags & MDB_RDONLY) ? Qtrue : Qfalse;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
/**
|
|
141
|
+
* @overload finished?
|
|
142
|
+
* @note This predicate is considered *unstable*; do not get used to it.
|
|
143
|
+
* @return [false,true] whether the transaction is finished.
|
|
144
|
+
*/
|
|
145
|
+
static VALUE transaction_is_finished(VALUE self) {
|
|
146
|
+
TRANSACTION(self, transaction);
|
|
147
|
+
// MDB_TXN_FINISHED
|
|
148
|
+
return (transaction->flags & 0x01) ? Qtrue : Qfalse;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* @overload error?
|
|
153
|
+
* @note This predicate is considered *unstable*; do not get used to it.
|
|
154
|
+
* @return [false,true] whether the transaction incurred an error.
|
|
155
|
+
*/
|
|
156
|
+
static VALUE transaction_is_error(VALUE self) {
|
|
157
|
+
TRANSACTION(self, transaction);
|
|
158
|
+
// MDB_TXN_ERROR
|
|
159
|
+
return (transaction->flags & 0x02) ? Qtrue : Qfalse;
|
|
160
|
+
}
|
|
161
|
+
|
|
140
162
|
|
|
141
163
|
static void transaction_finish(VALUE self, int commit) {
|
|
142
164
|
TRANSACTION(self, transaction);
|
|
@@ -285,69 +307,92 @@ static void stop_txn_begin(void *arg)
|
|
|
285
307
|
*/
|
|
286
308
|
|
|
287
309
|
static VALUE with_transaction(VALUE venv, VALUE(*fn)(VALUE), VALUE arg, int flags) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
310
|
+
ENVIRONMENT(venv, environment);
|
|
311
|
+
|
|
312
|
+
MDB_txn* txn;
|
|
313
|
+
TxnArgs txn_args;
|
|
314
|
+
|
|
315
|
+
VALUE thread = rb_thread_current();
|
|
316
|
+
VALUE vparent = environment_active_txn(venv);
|
|
317
|
+
|
|
318
|
+
//
|
|
319
|
+
Transaction* tparent = NULL;
|
|
320
|
+
if (vparent && !NIL_P(vparent))
|
|
321
|
+
Data_Get_Struct(vparent, Transaction, tparent);
|
|
322
|
+
|
|
323
|
+
/*
|
|
324
|
+
* If the requested transaction is read-only and there is a parent
|
|
325
|
+
* transaction (whether read-only or not), we need to use the
|
|
326
|
+
* parent transaction.
|
|
327
|
+
*
|
|
328
|
+
* XXX except conceivably you could do a transaction (RO or RW)
|
|
329
|
+
* that spawns a thread that opens another transaction.
|
|
330
|
+
*
|
|
331
|
+
* note we do *NOT* re-begin the parent transaction, nor do we
|
|
332
|
+
* want to commit it
|
|
333
|
+
*
|
|
334
|
+
*/
|
|
335
|
+
|
|
336
|
+
if (tparent && flags & MDB_RDONLY) {
|
|
337
|
+
// We are reusing the parent transaction.
|
|
292
338
|
|
|
293
|
-
|
|
294
|
-
VALUE
|
|
339
|
+
int exception;
|
|
340
|
+
VALUE ret = rb_protect(fn, NIL_P(arg) ? vparent : arg, &exception);
|
|
295
341
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
342
|
+
if (exception) {
|
|
343
|
+
// this is a cargo cult; i just copied it from below
|
|
344
|
+
if (vparent == environment_active_txn(venv)) transaction_abort(vparent);
|
|
345
|
+
rb_jump_tag(exception);
|
|
346
|
+
}
|
|
347
|
+
return ret;
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
// We are creating a new transaction.
|
|
299
351
|
|
|
300
352
|
// XXX note this is a cursed goto loop that could almost certainly
|
|
301
353
|
// be rewritten as a do-while
|
|
302
|
-
|
|
354
|
+
retry:
|
|
303
355
|
txn = NULL;
|
|
304
356
|
|
|
305
357
|
txn_args.env = environment->env;
|
|
306
|
-
txn_args.parent = active_txn(venv);
|
|
358
|
+
txn_args.parent = active_txn(venv); // this returns an MDB_txn
|
|
307
359
|
txn_args.flags = flags;
|
|
308
360
|
txn_args.htxn = &txn;
|
|
309
361
|
txn_args.result = 0;
|
|
310
362
|
txn_args.stop = 0;
|
|
311
363
|
|
|
312
|
-
if (flags & MDB_RDONLY)
|
|
313
|
-
|
|
314
|
-
// this is a no-op: put the same actual transaction in a
|
|
315
|
-
// different wrapper struct
|
|
316
|
-
txn = txn_args.parent;
|
|
317
|
-
else
|
|
318
|
-
// this will return an error if the parent transaction is
|
|
319
|
-
// read-write, so we don't need to handle the case explicitly
|
|
320
|
-
call_txn_begin(&txn_args);
|
|
321
|
-
}
|
|
364
|
+
if (flags & MDB_RDONLY)
|
|
365
|
+
call_txn_begin(&txn_args);
|
|
322
366
|
else {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
367
|
+
if (tparent) {
|
|
368
|
+
// first we have to determine if we're on the same thread
|
|
369
|
+
// as the parent, which in turn must be the same as the
|
|
370
|
+
// environment's registry for which thread has the
|
|
371
|
+
// read-write transaction
|
|
372
|
+
if (thread != tparent->thread ||
|
|
373
|
+
thread != environment->rw_txn_thread)
|
|
374
|
+
rb_raise(cError,
|
|
375
|
+
"Attempt to nest transaction on a different thread");
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// try to acquire the new transaction
|
|
379
|
+
CALL_WITHOUT_GVL(call_txn_begin, &txn_args, stop_txn_begin, &txn_args);
|
|
380
|
+
|
|
381
|
+
if (txn_args.stop || !txn) {
|
|
382
|
+
// !txn is when rb_thread_call_without_gvl2
|
|
383
|
+
// returns before calling txn_begin
|
|
384
|
+
if (txn) {
|
|
385
|
+
mdb_txn_abort(txn);
|
|
386
|
+
txn_args.result = 0;
|
|
332
387
|
}
|
|
333
388
|
|
|
334
|
-
|
|
389
|
+
//rb_warn("got here lol");
|
|
390
|
+
rb_thread_check_ints();
|
|
391
|
+
goto retry; // in what cases do we get here?
|
|
392
|
+
}
|
|
335
393
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
// returns before calling txn_begin
|
|
339
|
-
if (txn) {
|
|
340
|
-
mdb_txn_abort(txn);
|
|
341
|
-
txn_args.result = 0;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
//rb_warn("got here lol");
|
|
345
|
-
rb_thread_check_ints();
|
|
346
|
-
goto retry; // in what cases do we get here?
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// set the thread
|
|
350
|
-
environment->rw_txn_thread = thread;
|
|
394
|
+
// set the thread
|
|
395
|
+
environment->rw_txn_thread = thread;
|
|
351
396
|
}
|
|
352
397
|
|
|
353
398
|
// this will raise unless result is zero
|
|
@@ -373,14 +418,15 @@ static VALUE with_transaction(VALUE venv, VALUE(*fn)(VALUE), VALUE arg, int flag
|
|
|
373
418
|
VALUE ret = rb_protect(fn, NIL_P(arg) ? vtxn : arg, &exception);
|
|
374
419
|
|
|
375
420
|
if (exception) {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
421
|
+
// rb_warn("lol got exception");
|
|
422
|
+
if (vtxn == environment_active_txn(venv))
|
|
423
|
+
transaction_abort(vtxn);
|
|
424
|
+
rb_jump_tag(exception);
|
|
380
425
|
}
|
|
381
426
|
if (vtxn == environment_active_txn(venv))
|
|
382
|
-
|
|
427
|
+
transaction_commit(vtxn);
|
|
383
428
|
return ret;
|
|
429
|
+
}
|
|
384
430
|
}
|
|
385
431
|
|
|
386
432
|
static void environment_check(Environment* environment) {
|
|
@@ -773,23 +819,24 @@ static void environment_set_active_txn(VALUE self, VALUE thread, VALUE txn) {
|
|
|
773
819
|
}
|
|
774
820
|
}
|
|
775
821
|
|
|
822
|
+
static MDB_txn* extract_txn(VALUE vtxn) {
|
|
823
|
+
if (NIL_P(vtxn)) return NULL;
|
|
824
|
+
TRANSACTION(vtxn, transaction);
|
|
825
|
+
if (!transaction->txn) rb_raise(cError, "Transaction is already terminated");
|
|
826
|
+
if (transaction->thread != rb_thread_current())
|
|
827
|
+
rb_raise(cError, "Transaction is from another thread");
|
|
828
|
+
return transaction->txn;
|
|
829
|
+
}
|
|
776
830
|
|
|
777
831
|
static MDB_txn* active_txn(VALUE self) {
|
|
778
832
|
VALUE vtxn = environment_active_txn(self);
|
|
779
|
-
|
|
780
|
-
return 0;
|
|
781
|
-
TRANSACTION(vtxn, transaction);
|
|
782
|
-
if (!transaction->txn)
|
|
783
|
-
rb_raise(cError, "Transaction is already terminated");
|
|
784
|
-
if (transaction->thread != rb_thread_current())
|
|
785
|
-
rb_raise(cError, "Wrong thread");
|
|
786
|
-
return transaction->txn;
|
|
833
|
+
return extract_txn(vtxn);
|
|
787
834
|
}
|
|
788
835
|
|
|
789
836
|
static MDB_txn* need_txn(VALUE self) {
|
|
790
837
|
MDB_txn* txn = active_txn(self);
|
|
791
|
-
|
|
792
|
-
|
|
838
|
+
|
|
839
|
+
if (!txn) rb_raise(cError, "No active transaction");
|
|
793
840
|
return txn;
|
|
794
841
|
}
|
|
795
842
|
|
|
@@ -1782,6 +1829,8 @@ void Init_lmdb_ext() {
|
|
|
1782
1829
|
rb_define_method(cTransaction, "abort", transaction_abort, 0);
|
|
1783
1830
|
rb_define_method(cTransaction, "env", transaction_env, 0);
|
|
1784
1831
|
rb_define_method(cTransaction, "readonly?", transaction_is_readonly, 0);
|
|
1832
|
+
rb_define_method(cTransaction, "finished?", transaction_is_finished, 0);
|
|
1833
|
+
rb_define_method(cTransaction, "error?", transaction_is_error, 0);
|
|
1785
1834
|
|
|
1786
1835
|
/**
|
|
1787
1836
|
* Document-class: LMDB::Cursor
|
data/ext/lmdb_ext/lmdb_ext.h
CHANGED
|
@@ -104,12 +104,12 @@ typedef struct {
|
|
|
104
104
|
} EnvironmentOptions;
|
|
105
105
|
|
|
106
106
|
typedef struct {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
107
|
+
MDB_env *env;
|
|
108
|
+
MDB_txn *parent;
|
|
109
|
+
unsigned int flags;
|
|
110
|
+
MDB_txn **htxn; // not sure why this is a pointer to a pointer
|
|
111
|
+
int result;
|
|
112
|
+
int stop;
|
|
113
113
|
} TxnArgs;
|
|
114
114
|
|
|
115
115
|
static VALUE cEnvironment, cDatabase, cTransaction, cCursor, cError;
|
data/lib/lmdb/database.rb
CHANGED
|
@@ -126,7 +126,7 @@ module LMDB
|
|
|
126
126
|
|
|
127
127
|
ret = false
|
|
128
128
|
# read-only txn was having trouble being nested inside a read-write
|
|
129
|
-
maybe_txn
|
|
129
|
+
maybe_txn(true) do
|
|
130
130
|
# env.transaction true do
|
|
131
131
|
# env.transaction do
|
|
132
132
|
cursor { |c| ret = !!c.set(key, value) }
|
|
@@ -145,12 +145,20 @@ module LMDB
|
|
|
145
145
|
# @return [void]
|
|
146
146
|
#
|
|
147
147
|
def put?(key, value = nil, **options)
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
148
|
+
# early bailout
|
|
149
|
+
return if value.nil?
|
|
150
|
+
|
|
151
|
+
flags = { (dupsort? ? :nodupdata : :nooverwrite) => true }
|
|
152
|
+
|
|
153
|
+
env.transaction do |txn|
|
|
154
|
+
# begin
|
|
155
|
+
put(key, value, **options.merge(flags)) unless has?(key, value)
|
|
156
|
+
# rescue LMDB::Error::KEYEXIST
|
|
157
|
+
# # this should never be reached lol
|
|
158
|
+
# # warn 'lol'
|
|
159
|
+
# txn.abort
|
|
160
|
+
# nil
|
|
161
|
+
# end
|
|
154
162
|
end
|
|
155
163
|
end
|
|
156
164
|
|
|
@@ -164,10 +172,13 @@ module LMDB
|
|
|
164
172
|
# @return [void]
|
|
165
173
|
#
|
|
166
174
|
def delete?(key, value = nil)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
175
|
+
env.transaction do |txn|
|
|
176
|
+
begin
|
|
177
|
+
delete key, value
|
|
178
|
+
rescue LMDB::Error::NOTFOUND
|
|
179
|
+
txn.abort
|
|
180
|
+
nil
|
|
181
|
+
end
|
|
171
182
|
end
|
|
172
183
|
end
|
|
173
184
|
|
data/lib/lmdb/version.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.7.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel Mendler
|
|
8
8
|
- Dorian Taylor
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-05-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -143,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
143
143
|
- !ruby/object:Gem::Version
|
|
144
144
|
version: '0'
|
|
145
145
|
requirements: []
|
|
146
|
-
rubygems_version: 3.6.
|
|
146
|
+
rubygems_version: 3.6.7
|
|
147
147
|
specification_version: 4
|
|
148
148
|
summary: Ruby bindings to Lightning MDB
|
|
149
149
|
test_files:
|