lmdb 0.6.6 → 0.7.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 +4 -4
- data/CHANGES +9 -0
- data/ext/lmdb_ext/lmdb_ext.c +84 -64
- data/ext/lmdb_ext/lmdb_ext.h +6 -6
- data/lib/lmdb/database.rb +12 -6
- data/lib/lmdb/version.rb +1 -1
- data/spec/lmdb_spec.rb +80 -76
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c098384d91381d0f7c66a4794f88ea55c1c8a1e54d60480a75a379704407252d
|
|
4
|
+
data.tar.gz: 11c4e5b74f9b552ad9f89d5a189bf812340ab409b43b54361cb84f7d47dfd906
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: da3b52d345951ad527b67ce32998c749b17267b7b0d075f695e841d1b2a0891df4e0064e021e7db9ac21f41c0b81a4fb590ff88a98250675e15ad14baf185680
|
|
7
|
+
data.tar.gz: 12ae851f60db43dec61730f8497a06bf952e56242bff2e8fe64153a852c34582441556320cb1627fa65b7c29dfe417ba312c929d242511c0ab9c3888b12075b4
|
data/CHANGES
CHANGED
data/ext/lmdb_ext/lmdb_ext.c
CHANGED
|
@@ -285,69 +285,87 @@ static void stop_txn_begin(void *arg)
|
|
|
285
285
|
*/
|
|
286
286
|
|
|
287
287
|
static VALUE with_transaction(VALUE venv, VALUE(*fn)(VALUE), VALUE arg, int flags) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
288
|
+
ENVIRONMENT(venv, environment);
|
|
289
|
+
|
|
290
|
+
MDB_txn* txn;
|
|
291
|
+
TxnArgs txn_args;
|
|
292
|
+
|
|
293
|
+
VALUE thread = rb_thread_current();
|
|
294
|
+
VALUE vparent = environment_active_txn(venv);
|
|
295
|
+
|
|
296
|
+
//
|
|
297
|
+
Transaction* tparent = NULL;
|
|
298
|
+
if (vparent && !NIL_P(vparent))
|
|
299
|
+
Data_Get_Struct(vparent, Transaction, tparent);
|
|
300
|
+
|
|
301
|
+
/*
|
|
302
|
+
* If the requested transaction is read-only and there is a parent
|
|
303
|
+
* transaction (whether read-only or not), we need to use the
|
|
304
|
+
* parent transaction.
|
|
305
|
+
*
|
|
306
|
+
* XXX except conceivably you could do a transaction (RO or RW)
|
|
307
|
+
* that spawns a thread that opens another transaction.
|
|
308
|
+
*
|
|
309
|
+
* note we do *NOT* re-begin the parent transaction, nor do we
|
|
310
|
+
* want to commit it
|
|
311
|
+
*
|
|
312
|
+
*/
|
|
313
|
+
|
|
314
|
+
if (tparent && flags & MDB_RDONLY) {
|
|
315
|
+
int exception;
|
|
316
|
+
VALUE ret = rb_protect(fn, NIL_P(arg) ? vparent : arg, &exception);
|
|
317
|
+
if (exception) {
|
|
318
|
+
if (vparent == environment_active_txn(venv))
|
|
319
|
+
transaction_abort(vparent);
|
|
320
|
+
rb_jump_tag(exception);
|
|
321
|
+
}
|
|
322
|
+
return ret;
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
300
325
|
// XXX note this is a cursed goto loop that could almost certainly
|
|
301
326
|
// be rewritten as a do-while
|
|
302
|
-
|
|
327
|
+
retry:
|
|
303
328
|
txn = NULL;
|
|
304
329
|
|
|
305
330
|
txn_args.env = environment->env;
|
|
306
|
-
txn_args.parent = active_txn(venv);
|
|
331
|
+
txn_args.parent = active_txn(venv); // this returns an MDB_txn
|
|
307
332
|
txn_args.flags = flags;
|
|
308
333
|
txn_args.htxn = &txn;
|
|
309
334
|
txn_args.result = 0;
|
|
310
335
|
txn_args.stop = 0;
|
|
311
336
|
|
|
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
|
-
}
|
|
337
|
+
if (flags & MDB_RDONLY)
|
|
338
|
+
call_txn_begin(&txn_args);
|
|
322
339
|
else {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
340
|
+
if (tparent) {
|
|
341
|
+
// first we have to determine if we're on the same thread
|
|
342
|
+
// as the parent, which in turn must be the same as the
|
|
343
|
+
// environment's registry for which thread has the
|
|
344
|
+
// read-write transaction
|
|
345
|
+
if (thread != tparent->thread ||
|
|
346
|
+
thread != environment->rw_txn_thread)
|
|
347
|
+
rb_raise(cError,
|
|
348
|
+
"Attempt to nest transaction on a different thread");
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// try to acquire the new transaction
|
|
352
|
+
CALL_WITHOUT_GVL(call_txn_begin, &txn_args, stop_txn_begin, &txn_args);
|
|
353
|
+
|
|
354
|
+
if (txn_args.stop || !txn) {
|
|
355
|
+
// !txn is when rb_thread_call_without_gvl2
|
|
356
|
+
// returns before calling txn_begin
|
|
357
|
+
if (txn) {
|
|
358
|
+
mdb_txn_abort(txn);
|
|
359
|
+
txn_args.result = 0;
|
|
332
360
|
}
|
|
333
361
|
|
|
334
|
-
|
|
362
|
+
//rb_warn("got here lol");
|
|
363
|
+
rb_thread_check_ints();
|
|
364
|
+
goto retry; // in what cases do we get here?
|
|
365
|
+
}
|
|
335
366
|
|
|
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;
|
|
367
|
+
// set the thread
|
|
368
|
+
environment->rw_txn_thread = thread;
|
|
351
369
|
}
|
|
352
370
|
|
|
353
371
|
// this will raise unless result is zero
|
|
@@ -373,14 +391,15 @@ static VALUE with_transaction(VALUE venv, VALUE(*fn)(VALUE), VALUE arg, int flag
|
|
|
373
391
|
VALUE ret = rb_protect(fn, NIL_P(arg) ? vtxn : arg, &exception);
|
|
374
392
|
|
|
375
393
|
if (exception) {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
394
|
+
// rb_warn("lol got exception");
|
|
395
|
+
if (vtxn == environment_active_txn(venv))
|
|
396
|
+
transaction_abort(vtxn);
|
|
397
|
+
rb_jump_tag(exception);
|
|
380
398
|
}
|
|
381
399
|
if (vtxn == environment_active_txn(venv))
|
|
382
|
-
|
|
400
|
+
transaction_commit(vtxn);
|
|
383
401
|
return ret;
|
|
402
|
+
}
|
|
384
403
|
}
|
|
385
404
|
|
|
386
405
|
static void environment_check(Environment* environment) {
|
|
@@ -773,23 +792,24 @@ static void environment_set_active_txn(VALUE self, VALUE thread, VALUE txn) {
|
|
|
773
792
|
}
|
|
774
793
|
}
|
|
775
794
|
|
|
795
|
+
static MDB_txn* extract_txn(VALUE vtxn) {
|
|
796
|
+
if (NIL_P(vtxn)) return NULL;
|
|
797
|
+
TRANSACTION(vtxn, transaction);
|
|
798
|
+
if (!transaction->txn) rb_raise(cError, "Transaction is already terminated");
|
|
799
|
+
if (transaction->thread != rb_thread_current())
|
|
800
|
+
rb_raise(cError, "Transaction is from another thread");
|
|
801
|
+
return transaction->txn;
|
|
802
|
+
}
|
|
776
803
|
|
|
777
804
|
static MDB_txn* active_txn(VALUE self) {
|
|
778
805
|
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;
|
|
806
|
+
return extract_txn(vtxn);
|
|
787
807
|
}
|
|
788
808
|
|
|
789
809
|
static MDB_txn* need_txn(VALUE self) {
|
|
790
810
|
MDB_txn* txn = active_txn(self);
|
|
791
|
-
|
|
792
|
-
|
|
811
|
+
|
|
812
|
+
if (!txn) rb_raise(cError, "No active transaction");
|
|
793
813
|
return txn;
|
|
794
814
|
}
|
|
795
815
|
|
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
|
@@ -136,16 +136,18 @@ module LMDB
|
|
|
136
136
|
|
|
137
137
|
# Conditionally put a value into the database.
|
|
138
138
|
#
|
|
139
|
-
# @param key [
|
|
140
|
-
# @param value [
|
|
139
|
+
# @param key [#to_s] The key of the record
|
|
140
|
+
# @param value [#to_s, nil] the (optional) value
|
|
141
141
|
# @param options [Hash] options
|
|
142
142
|
#
|
|
143
143
|
# @see #put
|
|
144
144
|
#
|
|
145
145
|
# @return [void]
|
|
146
|
+
#
|
|
146
147
|
def put?(key, value = nil, **options)
|
|
148
|
+
flags = { (dupsort? ? :nodupdata : :nooverwrite) => true }
|
|
147
149
|
begin
|
|
148
|
-
put key, value, **options
|
|
150
|
+
put key, value, **options.merge(flags)
|
|
149
151
|
rescue LMDB::Error::KEYEXIST
|
|
150
152
|
nil
|
|
151
153
|
end
|
|
@@ -154,15 +156,15 @@ module LMDB
|
|
|
154
156
|
# Delete the key (and optional value pair) if it exists; do not
|
|
155
157
|
# complain about missing keys.
|
|
156
158
|
# @param key [#to_s] The key of the record
|
|
157
|
-
# @param value [#to_s] The optional value
|
|
159
|
+
# @param value [#to_s, nil] The optional value
|
|
158
160
|
#
|
|
159
161
|
# @see #delete
|
|
160
162
|
#
|
|
161
163
|
# @return [void]
|
|
162
164
|
#
|
|
163
|
-
def delete?(key, value = nil
|
|
165
|
+
def delete?(key, value = nil)
|
|
164
166
|
begin
|
|
165
|
-
delete key, value
|
|
167
|
+
delete key, value
|
|
166
168
|
rescue LMDB::Error::NOTFOUND
|
|
167
169
|
nil
|
|
168
170
|
end
|
|
@@ -186,6 +188,10 @@ module LMDB
|
|
|
186
188
|
# having trouble with read-only transactions embedded in
|
|
187
189
|
# read-write for some reason; can't pin it down to test it yet so
|
|
188
190
|
# going to do this (djt; 2020-02-10)
|
|
191
|
+
#
|
|
192
|
+
# 2025-11-14: this miiiigght no longer be necessary?? like as of
|
|
193
|
+
# whenever i implemented that short-circuiting code
|
|
194
|
+
#
|
|
189
195
|
def maybe_txn(readonly, &block)
|
|
190
196
|
if t = env.active_txn
|
|
191
197
|
# warn "reusing #{t.readonly? ? 'read-only ' : ''}txn #{t.inspect}"
|
data/lib/lmdb/version.rb
CHANGED
data/spec/lmdb_spec.rb
CHANGED
|
@@ -40,8 +40,8 @@ describe LMDB do
|
|
|
40
40
|
env = LMDB::Environment.new(path, nosync: true, mode: 0777,
|
|
41
41
|
maxreaders: 777, mapsize: 111111, maxdbs: 666)
|
|
42
42
|
env.should be_instance_of(described_class)
|
|
43
|
-
env.info[:maxreaders].should
|
|
44
|
-
env.info[:mapsize].should
|
|
43
|
+
env.info[:maxreaders].should eq(777)
|
|
44
|
+
env.info[:mapsize].should eq(111111)
|
|
45
45
|
env.flags.should include(:nosync)
|
|
46
46
|
env.close
|
|
47
47
|
|
|
@@ -74,7 +74,7 @@ describe LMDB do
|
|
|
74
74
|
it 'should set mapsize' do
|
|
75
75
|
size_before = env.info[:mapsize]
|
|
76
76
|
env.mapsize = size_before * 2
|
|
77
|
-
env.info[:mapsize].should
|
|
77
|
+
env.info[:mapsize].should eq(size_before * 2)
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
it 'should copy' do
|
|
@@ -108,7 +108,7 @@ describe LMDB do
|
|
|
108
108
|
it 'returns list of named databases' do
|
|
109
109
|
db1 = subject.database 'db1', create: true
|
|
110
110
|
db2 = subject.database 'db2', create: true
|
|
111
|
-
subject.databases.should
|
|
111
|
+
subject.databases.should eq(['db1', 'db2'])
|
|
112
112
|
end
|
|
113
113
|
|
|
114
114
|
it 'returns list of named databases when there are non-database kes in the main db' do
|
|
@@ -117,7 +117,7 @@ describe LMDB do
|
|
|
117
117
|
subject.database 'db1', create: true
|
|
118
118
|
subject.database 'db2', create: true
|
|
119
119
|
|
|
120
|
-
subject.databases.should
|
|
120
|
+
subject.databases.should eq(['db1', 'db2'])
|
|
121
121
|
end
|
|
122
122
|
end
|
|
123
123
|
|
|
@@ -125,71 +125,71 @@ describe LMDB do
|
|
|
125
125
|
subject { env }
|
|
126
126
|
|
|
127
127
|
it 'should create transactions' do
|
|
128
|
-
subject.active_txn.should
|
|
128
|
+
subject.active_txn.should be_nil
|
|
129
129
|
subject.transaction do |txn|
|
|
130
|
-
subject.active_txn.should
|
|
130
|
+
subject.active_txn.should eq(txn)
|
|
131
131
|
txn.should be_instance_of(described_class)
|
|
132
132
|
txn.abort
|
|
133
|
-
subject.active_txn.should
|
|
133
|
+
subject.active_txn.should be_nil
|
|
134
134
|
end
|
|
135
|
-
subject.active_txn.should
|
|
135
|
+
subject.active_txn.should be_nil
|
|
136
136
|
end
|
|
137
137
|
|
|
138
138
|
it 'should create read-only transactions' do
|
|
139
|
-
subject.active_txn.should
|
|
139
|
+
subject.active_txn.should be_nil
|
|
140
140
|
subject.transaction(true) do |txn|
|
|
141
|
-
subject.active_txn.should
|
|
141
|
+
subject.active_txn.should eq(txn)
|
|
142
142
|
txn.should be_instance_of(described_class)
|
|
143
143
|
txn.abort
|
|
144
|
-
subject.active_txn.should
|
|
144
|
+
subject.active_txn.should be_nil
|
|
145
145
|
end
|
|
146
|
-
subject.active_txn.should
|
|
146
|
+
subject.active_txn.should be_nil
|
|
147
147
|
end
|
|
148
148
|
|
|
149
149
|
it 'can create child transactions' do
|
|
150
|
-
subject.active_txn.should
|
|
150
|
+
subject.active_txn.should be_nil
|
|
151
151
|
env.transaction do |txn|
|
|
152
|
-
subject.active_txn.should
|
|
152
|
+
subject.active_txn.should eq(txn)
|
|
153
153
|
env.transaction do |ctxn|
|
|
154
|
-
subject.active_txn.should
|
|
154
|
+
subject.active_txn.should eq(ctxn)
|
|
155
155
|
ctxn.abort
|
|
156
|
-
subject.active_txn.should
|
|
156
|
+
subject.active_txn.should eq(txn)
|
|
157
157
|
end
|
|
158
|
-
subject.active_txn.should
|
|
158
|
+
subject.active_txn.should eq(txn)
|
|
159
159
|
end
|
|
160
|
-
subject.active_txn.should
|
|
160
|
+
subject.active_txn.should be_nil
|
|
161
161
|
end
|
|
162
162
|
|
|
163
163
|
it 'should support aborting parent transaction' do
|
|
164
|
-
subject.active_txn.should
|
|
164
|
+
subject.active_txn.should be_nil
|
|
165
165
|
env.transaction do |txn|
|
|
166
|
-
subject.active_txn.should
|
|
166
|
+
subject.active_txn.should eq(txn)
|
|
167
167
|
env.transaction do |ctxn|
|
|
168
|
-
subject.active_txn.should
|
|
168
|
+
subject.active_txn.should eq(ctxn)
|
|
169
169
|
db['key'] = 'value'
|
|
170
170
|
txn.abort
|
|
171
|
-
subject.active_txn.should
|
|
171
|
+
subject.active_txn.should be_nil
|
|
172
172
|
end
|
|
173
|
-
subject.active_txn.should
|
|
173
|
+
subject.active_txn.should be_nil
|
|
174
174
|
end
|
|
175
|
-
db['key'].should
|
|
176
|
-
subject.active_txn.should
|
|
175
|
+
db['key'].should be_nil
|
|
176
|
+
subject.active_txn.should be_nil
|
|
177
177
|
end
|
|
178
178
|
|
|
179
179
|
it 'should support comitting parent transaction' do
|
|
180
|
-
subject.active_txn.should
|
|
180
|
+
subject.active_txn.should be_nil
|
|
181
181
|
env.transaction do |txn|
|
|
182
|
-
subject.active_txn.should
|
|
182
|
+
subject.active_txn.should eq(txn)
|
|
183
183
|
env.transaction do |ctxn|
|
|
184
|
-
subject.active_txn.should
|
|
184
|
+
subject.active_txn.should eq(ctxn)
|
|
185
185
|
db['key'] = 'value'
|
|
186
186
|
txn.commit
|
|
187
|
-
subject.active_txn.should
|
|
187
|
+
subject.active_txn.should be_nil
|
|
188
188
|
end
|
|
189
|
-
subject.active_txn.should
|
|
189
|
+
subject.active_txn.should be_nil
|
|
190
190
|
end
|
|
191
|
-
db['key'].should
|
|
192
|
-
subject.active_txn.should
|
|
191
|
+
db['key'].should eq('value')
|
|
192
|
+
subject.active_txn.should be_nil
|
|
193
193
|
end
|
|
194
194
|
|
|
195
195
|
it 'should get environment' do
|
|
@@ -197,7 +197,7 @@ describe LMDB do
|
|
|
197
197
|
env.transaction do |txn|
|
|
198
198
|
env2 = txn.env
|
|
199
199
|
end
|
|
200
|
-
env2.should
|
|
200
|
+
env2.should eq(env)
|
|
201
201
|
end
|
|
202
202
|
end
|
|
203
203
|
end
|
|
@@ -207,8 +207,8 @@ describe LMDB do
|
|
|
207
207
|
|
|
208
208
|
it 'should return flags' do
|
|
209
209
|
subject.flags.should be_instance_of(Hash)
|
|
210
|
-
subject.dupsort?.should
|
|
211
|
-
subject.dupfixed?.should
|
|
210
|
+
subject.dupsort?.should be_falsy
|
|
211
|
+
subject.dupfixed?.should be_falsy
|
|
212
212
|
end
|
|
213
213
|
|
|
214
214
|
it 'should support named databases' do
|
|
@@ -222,19 +222,22 @@ describe LMDB do
|
|
|
222
222
|
db1['key'] = '2'
|
|
223
223
|
db2['key'] = '3'
|
|
224
224
|
|
|
225
|
-
main['key'].should
|
|
226
|
-
db1['key'].should
|
|
227
|
-
db2['key'].should
|
|
225
|
+
main['key'].should eq(?1)
|
|
226
|
+
db1['key'].should eq(?2)
|
|
227
|
+
db2['key'].should eq(?3)
|
|
228
228
|
end
|
|
229
229
|
|
|
230
230
|
it 'should get/put data' do
|
|
231
231
|
subject.get('cat').should be_nil
|
|
232
232
|
subject.put('cat', 'garfield').should be_nil
|
|
233
|
-
subject.get('cat').should
|
|
233
|
+
subject.get('cat').should eq('garfield')
|
|
234
234
|
|
|
235
235
|
# check for key-value pairs on non-dupsort database
|
|
236
|
-
subject.has?('cat', 'garfield').should
|
|
237
|
-
subject.has?('cat', 'heathcliff').should
|
|
236
|
+
subject.has?('cat', 'garfield').should be_truthy
|
|
237
|
+
subject.has?('cat', 'heathcliff').should be_falsy
|
|
238
|
+
|
|
239
|
+
subject.put?('dog', 'odie')
|
|
240
|
+
subject.has?('dog', 'odie').should be_truthy
|
|
238
241
|
end
|
|
239
242
|
|
|
240
243
|
it 'should delete by key' do
|
|
@@ -255,7 +258,7 @@ describe LMDB do
|
|
|
255
258
|
|
|
256
259
|
it 'stores key/values in same transaction' do
|
|
257
260
|
db.put('key', 'value').should be_nil
|
|
258
|
-
db.get('key').should
|
|
261
|
+
db.get('key').should eq('value')
|
|
259
262
|
end
|
|
260
263
|
|
|
261
264
|
it 'stores key/values in different transactions' do
|
|
@@ -268,10 +271,10 @@ describe LMDB do
|
|
|
268
271
|
end
|
|
269
272
|
|
|
270
273
|
env.transaction do
|
|
271
|
-
db.get('key').should
|
|
272
|
-
db.get('key2').should
|
|
274
|
+
db.get('key').should eq('value')
|
|
275
|
+
db.get('key2').should eq('value2')
|
|
273
276
|
env.transaction do
|
|
274
|
-
db.get('key3').should
|
|
277
|
+
db.get('key3').should eq('value3')
|
|
275
278
|
end
|
|
276
279
|
end
|
|
277
280
|
end
|
|
@@ -281,22 +284,22 @@ describe LMDB do
|
|
|
281
284
|
end
|
|
282
285
|
|
|
283
286
|
it 'should return size' do
|
|
284
|
-
db.size.should
|
|
287
|
+
db.size.should eq(0)
|
|
285
288
|
db.put('key', 'value')
|
|
286
|
-
db.size.should
|
|
289
|
+
db.size.should eq(1)
|
|
287
290
|
db.put('key2', 'value2')
|
|
288
|
-
db.size.should
|
|
291
|
+
db.size.should eq(2)
|
|
289
292
|
end
|
|
290
293
|
|
|
291
294
|
it 'should be enumerable' do
|
|
292
295
|
db['k1'] = 'v1'
|
|
293
296
|
db['k2'] = 'v2'
|
|
294
|
-
db.to_a.should
|
|
297
|
+
db.to_a.should eq([['k1', 'v1'], ['k2', 'v2']])
|
|
295
298
|
end
|
|
296
299
|
|
|
297
300
|
it 'should have shortcuts' do
|
|
298
301
|
db['key'] = 'value'
|
|
299
|
-
db['key'].should
|
|
302
|
+
db['key'].should eq('value')
|
|
300
303
|
end
|
|
301
304
|
|
|
302
305
|
it 'should store binary' do
|
|
@@ -304,15 +307,15 @@ describe LMDB do
|
|
|
304
307
|
bin2 = "\xAAx\BB\xCC2"
|
|
305
308
|
db[bin1] = bin2
|
|
306
309
|
db['key'] = bin2
|
|
307
|
-
db[bin1].should
|
|
308
|
-
db['key'].should
|
|
310
|
+
db[bin1].should eq(bin2)
|
|
311
|
+
db['key'].should eq(bin2)
|
|
309
312
|
end
|
|
310
313
|
|
|
311
314
|
it 'should get environment' do
|
|
312
315
|
main = env.database
|
|
313
316
|
db1 = env.database('db1', create: true)
|
|
314
|
-
main.env.should
|
|
315
|
-
db1.env.should
|
|
317
|
+
main.env.should eq(env)
|
|
318
|
+
db1.env.should eq(env)
|
|
316
319
|
end
|
|
317
320
|
|
|
318
321
|
it 'should iterate over/list keys' do
|
|
@@ -330,38 +333,38 @@ describe LMDB do
|
|
|
330
333
|
|
|
331
334
|
it 'should get first key/value' do
|
|
332
335
|
db.cursor do |c|
|
|
333
|
-
c.first.should
|
|
336
|
+
c.first.should eq(['key1', 'value1'])
|
|
334
337
|
end
|
|
335
338
|
end
|
|
336
339
|
|
|
337
340
|
it 'should get last key/value' do
|
|
338
341
|
db.cursor do |c|
|
|
339
|
-
c.last.should
|
|
342
|
+
c.last.should eq(['key2', 'value2'])
|
|
340
343
|
end
|
|
341
344
|
end
|
|
342
345
|
|
|
343
346
|
it 'should get next key/value' do
|
|
344
347
|
db.cursor do |c|
|
|
345
348
|
c.first
|
|
346
|
-
c.next.should
|
|
349
|
+
c.next.should eq(['key2', 'value2'])
|
|
347
350
|
end
|
|
348
351
|
end
|
|
349
352
|
|
|
350
353
|
it 'should seek to key' do
|
|
351
354
|
db.cursor do |c|
|
|
352
|
-
c.set('key1').should
|
|
355
|
+
c.set('key1').should eq(['key1', 'value1'])
|
|
353
356
|
end
|
|
354
357
|
end
|
|
355
358
|
|
|
356
359
|
it 'should seek to closest key' do
|
|
357
360
|
db.cursor do |c|
|
|
358
|
-
c.set_range('key0').should
|
|
361
|
+
c.set_range('key0').should eq(['key1', 'value1'])
|
|
359
362
|
end
|
|
360
363
|
end
|
|
361
364
|
|
|
362
365
|
it 'should seek to key with nuls' do
|
|
363
366
|
db.cursor do |c|
|
|
364
|
-
c.set_range('\x00').should
|
|
367
|
+
c.set_range('\x00').should eq(['key1', 'value1'])
|
|
365
368
|
end
|
|
366
369
|
end
|
|
367
370
|
|
|
@@ -369,8 +372,8 @@ describe LMDB do
|
|
|
369
372
|
db.cursor do |c|
|
|
370
373
|
db.put('key0', 'value0')
|
|
371
374
|
c.first
|
|
372
|
-
c.next_range('key1').should
|
|
373
|
-
c.next_range('key1').should
|
|
375
|
+
c.next_range('key1').should eq(['key1', 'value1'])
|
|
376
|
+
c.next_range('key1').should be_nil
|
|
374
377
|
end
|
|
375
378
|
end
|
|
376
379
|
|
|
@@ -378,34 +381,35 @@ describe LMDB do
|
|
|
378
381
|
dupdb = env.database 'dupsort', create: true, dupsort: true
|
|
379
382
|
|
|
380
383
|
# check flag while we're at it
|
|
381
|
-
dupdb.flags[:dupsort].should
|
|
382
|
-
dupdb.dupsort?.should
|
|
383
|
-
dupdb.dupfixed?.should
|
|
384
|
+
dupdb.flags[:dupsort].should be_truthy
|
|
385
|
+
dupdb.dupsort?.should be_truthy
|
|
386
|
+
dupdb.dupfixed?.should be_falsy
|
|
384
387
|
|
|
385
388
|
# add the no-op keyword to trigger a complaint from ruby 2.7
|
|
386
389
|
dupdb.put 'key1', 'value1', nodupdata: false
|
|
387
390
|
dupdb.put 'key1', 'value2'
|
|
388
391
|
dupdb.put 'key2', 'value3'
|
|
389
392
|
dupdb.cursor do |c|
|
|
390
|
-
c.set('key1', 'value2').should
|
|
391
|
-
c.set('key1', 'value1').should
|
|
392
|
-
c.set('key1', 'value3').should
|
|
393
|
+
c.set('key1', 'value2').should eq(['key1', 'value2'])
|
|
394
|
+
c.set('key1', 'value1').should eq(['key1', 'value1'])
|
|
395
|
+
c.set('key1', 'value3').should be_nil
|
|
393
396
|
end
|
|
394
397
|
|
|
398
|
+
# this should do nothing
|
|
395
399
|
dupdb.put?('key1', 'value1', nodupdata: true).should be_nil
|
|
396
400
|
|
|
397
401
|
# this is basically an extended test of `cursor.set key, val`
|
|
398
|
-
dupdb.has?('key1', 'value1').should
|
|
399
|
-
dupdb.has?('key1', 'value2').should
|
|
400
|
-
dupdb.has?('key1', 'value0').should
|
|
402
|
+
dupdb.has?('key1', 'value1').should be_truthy
|
|
403
|
+
dupdb.has?('key1', 'value2').should be_truthy
|
|
404
|
+
dupdb.has?('key1', 'value0').should be_falsy
|
|
401
405
|
|
|
402
406
|
# match the contents of key1
|
|
403
|
-
dupdb.each_value('key1').to_a.sort.should
|
|
407
|
+
dupdb.each_value('key1').to_a.sort.should eq(['value1', 'value2'])
|
|
404
408
|
|
|
405
409
|
# we should have two entries for key1
|
|
406
|
-
dupdb.cardinality('key1').should
|
|
410
|
+
dupdb.cardinality('key1').should eq(2)
|
|
407
411
|
|
|
408
|
-
dupdb.each_key.to_a.sort.should
|
|
412
|
+
dupdb.each_key.to_a.sort.should eq(['key1', 'key2'])
|
|
409
413
|
|
|
410
414
|
# XXX move this or whatever
|
|
411
415
|
env.transaction do |t|
|
|
@@ -432,7 +436,7 @@ describe LMDB do
|
|
|
432
436
|
it 'should get database' do
|
|
433
437
|
db2 = nil
|
|
434
438
|
env.transaction { c = db.cursor; db2 = c.database }
|
|
435
|
-
db2.should
|
|
439
|
+
db2.should eq(db)
|
|
436
440
|
end
|
|
437
441
|
|
|
438
442
|
it 'should nest a read-only txn in a read-write' do
|
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.0
|
|
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: 2025-11-
|
|
11
|
+
date: 2025-11-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|