lmdb 0.4.1 → 0.4.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/.travis.yml +2 -4
- data/CHANGES +5 -0
- data/CONTRIBUTORS +1 -0
- data/Rakefile +59 -0
- data/ext/lmdb_ext/liblmdb/CHANGES +25 -1
- data/ext/lmdb_ext/liblmdb/COPYRIGHT +1 -1
- data/ext/lmdb_ext/liblmdb/lmdb.h +65 -21
- data/ext/lmdb_ext/liblmdb/mdb.c +626 -395
- data/ext/lmdb_ext/liblmdb/midl.c +1 -3
- data/ext/lmdb_ext/lmdb_ext.c +77 -4
- data/ext/lmdb_ext/lmdb_ext.h +15 -0
- data/lib/lmdb/version.rb +1 -1
- data/lmdb.gemspec +2 -2
- data/spec/helper.rb +3 -1
- data/spec/lmdb_spec.rb +16 -6
- metadata +11 -11
data/ext/lmdb_ext/liblmdb/midl.c
CHANGED
@@ -20,7 +20,6 @@
|
|
20
20
|
#include <stdlib.h>
|
21
21
|
#include <errno.h>
|
22
22
|
#include <sys/types.h>
|
23
|
-
#include <assert.h>
|
24
23
|
#include "midl.h"
|
25
24
|
|
26
25
|
/** @defgroup internal MDB Internals
|
@@ -150,7 +149,7 @@ int mdb_midl_need( MDB_IDL *idp, unsigned num )
|
|
150
149
|
num = (num + num/4 + (256 + 2)) & -256;
|
151
150
|
if (!(ids = realloc(ids-1, num * sizeof(MDB_ID))))
|
152
151
|
return ENOMEM;
|
153
|
-
*ids++ = num
|
152
|
+
*ids++ = num - 2;
|
154
153
|
*idp = ids;
|
155
154
|
}
|
156
155
|
return 0;
|
@@ -306,7 +305,6 @@ int mdb_mid2l_insert( MDB_ID2L ids, MDB_ID2 *id )
|
|
306
305
|
unsigned x, i;
|
307
306
|
|
308
307
|
x = mdb_mid2l_search( ids, id->mid );
|
309
|
-
assert( x > 0 );
|
310
308
|
|
311
309
|
if( x < 1 ) {
|
312
310
|
/* internal error */
|
data/ext/lmdb_ext/lmdb_ext.c
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#include "lmdb_ext.h"
|
2
|
+
#include "ruby/thread.h"
|
2
3
|
|
3
4
|
static void check(int code) {
|
4
5
|
if (!code)
|
@@ -110,6 +111,13 @@ static void transaction_finish(VALUE self, int commit) {
|
|
110
111
|
else
|
111
112
|
mdb_txn_abort(transaction->txn);
|
112
113
|
|
114
|
+
long i;
|
115
|
+
for (i=0; i<RARRAY_LEN(transaction->cursors); i++) {
|
116
|
+
VALUE cursor = RARRAY_AREF(transaction->cursors, i);
|
117
|
+
cursor_close(cursor);
|
118
|
+
}
|
119
|
+
rb_ary_clear(transaction->cursors);
|
120
|
+
|
113
121
|
// Mark child transactions as closed
|
114
122
|
p = environment_active_txn(transaction->env);
|
115
123
|
while (p != self) {
|
@@ -141,11 +149,58 @@ static VALUE call_with_transaction(VALUE venv, VALUE self, const char* name, int
|
|
141
149
|
return with_transaction(venv, call_with_transaction_helper, (VALUE)&arg, flags);
|
142
150
|
}
|
143
151
|
|
152
|
+
static void *call_txn_begin(void *arg) {
|
153
|
+
TxnArgs *txn_args = arg;
|
154
|
+
txn_args->result = mdb_txn_begin(txn_args->env,
|
155
|
+
txn_args->parent, txn_args->flags, txn_args->htxn);
|
156
|
+
return (void *)NULL;
|
157
|
+
}
|
158
|
+
|
159
|
+
static void stop_txn_begin(void *arg)
|
160
|
+
{
|
161
|
+
TxnArgs *txn_args = arg;
|
162
|
+
// There's no way to stop waiting for mutex:
|
163
|
+
// http://www.cognitus.net/faq/pthread/pthreadSemiFAQ_6.html
|
164
|
+
// However, we can (and must) release the mutex as soon as we get it:
|
165
|
+
txn_args->stop = 1;
|
166
|
+
}
|
167
|
+
|
144
168
|
static VALUE with_transaction(VALUE venv, VALUE(*fn)(VALUE), VALUE arg, int flags) {
|
145
169
|
ENVIRONMENT(venv, environment);
|
146
170
|
|
147
171
|
MDB_txn* txn;
|
148
|
-
|
172
|
+
TxnArgs txn_args;
|
173
|
+
|
174
|
+
retry:
|
175
|
+
txn = NULL;
|
176
|
+
|
177
|
+
txn_args.env = environment->env;
|
178
|
+
txn_args.parent = active_txn(venv);
|
179
|
+
txn_args.flags = flags;
|
180
|
+
txn_args.htxn = &txn;
|
181
|
+
txn_args.result = 0;
|
182
|
+
txn_args.stop = 0;
|
183
|
+
|
184
|
+
if (flags & MDB_RDONLY) {
|
185
|
+
call_txn_begin(&txn_args);
|
186
|
+
}
|
187
|
+
else {
|
188
|
+
rb_thread_call_without_gvl2(
|
189
|
+
call_txn_begin, &txn_args,
|
190
|
+
stop_txn_begin, &txn_args);
|
191
|
+
|
192
|
+
if (txn_args.stop || !txn) {
|
193
|
+
// !txn is when rb_thread_call_without_gvl2
|
194
|
+
// returns before calling txn_begin
|
195
|
+
if (txn) {
|
196
|
+
mdb_txn_abort(txn);
|
197
|
+
}
|
198
|
+
rb_thread_check_ints();
|
199
|
+
goto retry; // in what cases do we get here?
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
check(txn_args.result);
|
149
204
|
|
150
205
|
Transaction* transaction;
|
151
206
|
VALUE vtxn = Data_Make_Struct(cTransaction, Transaction, transaction_mark, transaction_free, transaction);
|
@@ -153,6 +208,7 @@ static VALUE with_transaction(VALUE venv, VALUE(*fn)(VALUE), VALUE arg, int flag
|
|
153
208
|
transaction->env = venv;
|
154
209
|
transaction->txn = txn;
|
155
210
|
transaction->thread = rb_thread_current();
|
211
|
+
transaction->cursors = rb_ary_new();
|
156
212
|
environment_set_active_txn(venv, transaction->thread, vtxn);
|
157
213
|
|
158
214
|
int exception;
|
@@ -855,10 +911,13 @@ static VALUE cursor_close(VALUE self) {
|
|
855
911
|
|
856
912
|
/**
|
857
913
|
* @overload cursor
|
858
|
-
* Create a cursor to iterate through a database.
|
914
|
+
* Create a cursor to iterate through a database. Uses current
|
915
|
+
* transaction, if any. Otherwise, if called with a block,
|
916
|
+
* creates a new transaction for the scope of the block.
|
917
|
+
* Otherwise, fails.
|
859
918
|
*
|
860
919
|
* @see Cursor
|
861
|
-
* @yield [cursor] A block to be executed with the cursor
|
920
|
+
* @yield [cursor] A block to be executed with the cursor.
|
862
921
|
* @yieldparam cursor [Cursor] The cursor to be used to iterate
|
863
922
|
* @example
|
864
923
|
* db = env.database "abc"
|
@@ -869,8 +928,12 @@ static VALUE cursor_close(VALUE self) {
|
|
869
928
|
*/
|
870
929
|
static VALUE database_cursor(VALUE self) {
|
871
930
|
DATABASE(self, database);
|
872
|
-
if (!active_txn(database->env))
|
931
|
+
if (!active_txn(database->env)) {
|
932
|
+
if (!rb_block_given_p()) {
|
933
|
+
rb_raise(cError, "Must call with block or active transaction.");
|
934
|
+
}
|
873
935
|
return call_with_transaction(database->env, self, "cursor", 0, 0, 0);
|
936
|
+
}
|
874
937
|
|
875
938
|
MDB_cursor* cur;
|
876
939
|
check(mdb_cursor_open(need_txn(database->env), database->dbi, &cur));
|
@@ -890,6 +953,16 @@ static VALUE database_cursor(VALUE self) {
|
|
890
953
|
cursor_close(vcur);
|
891
954
|
return ret;
|
892
955
|
}
|
956
|
+
else {
|
957
|
+
VALUE vtxn = environment_active_txn(database->env);
|
958
|
+
if (NIL_P(vtxn)) {
|
959
|
+
rb_fatal("Internal error: transaction finished unexpectedly.");
|
960
|
+
}
|
961
|
+
else {
|
962
|
+
TRANSACTION(vtxn, txn);
|
963
|
+
rb_ary_push(txn->cursors, vcur);
|
964
|
+
}
|
965
|
+
}
|
893
966
|
|
894
967
|
return vcur;
|
895
968
|
}
|
data/ext/lmdb_ext/lmdb_ext.h
CHANGED
@@ -24,6 +24,11 @@
|
|
24
24
|
# endif
|
25
25
|
#endif
|
26
26
|
|
27
|
+
// Ruby 2.0 compatibility
|
28
|
+
#ifndef RARRAY_AREF
|
29
|
+
# define RARRAY_AREF(ary,n) (RARRAY_PTR(ary)[n])
|
30
|
+
#endif
|
31
|
+
|
27
32
|
#define ENVIRONMENT(var, var_env) \
|
28
33
|
Environment* var_env; \
|
29
34
|
Data_Get_Struct(var, Environment, var_env); \
|
@@ -46,6 +51,7 @@ typedef struct {
|
|
46
51
|
VALUE env;
|
47
52
|
VALUE parent;
|
48
53
|
VALUE thread;
|
54
|
+
VALUE cursors;
|
49
55
|
MDB_txn* txn;
|
50
56
|
} Transaction;
|
51
57
|
|
@@ -80,6 +86,15 @@ typedef struct {
|
|
80
86
|
size_t mapsize;
|
81
87
|
} EnvironmentOptions;
|
82
88
|
|
89
|
+
typedef struct {
|
90
|
+
MDB_env *env;
|
91
|
+
MDB_txn *parent;
|
92
|
+
unsigned int flags;
|
93
|
+
MDB_txn **htxn;
|
94
|
+
int result;
|
95
|
+
int stop;
|
96
|
+
} TxnArgs;
|
97
|
+
|
83
98
|
static VALUE cEnvironment, cDatabase, cTransaction, cCursor, cError;
|
84
99
|
|
85
100
|
#define ERROR(name) static VALUE cError_##name;
|
data/lib/lmdb/version.rb
CHANGED
data/lmdb.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.test_files = `git ls-files -- spec/*`.split("\n")
|
20
20
|
s.require_paths = ['lib']
|
21
21
|
|
22
|
-
s.add_development_dependency 'rake'
|
22
|
+
s.add_development_dependency 'rake', "~> 10.0"
|
23
23
|
s.add_development_dependency 'rake-compiler', '<=0.8.2'
|
24
|
-
s.add_development_dependency 'rspec'
|
24
|
+
s.add_development_dependency 'rspec', "~> 3.0"
|
25
25
|
end
|
data/spec/helper.rb
CHANGED
data/spec/lmdb_spec.rb
CHANGED
@@ -25,20 +25,20 @@ describe LMDB do
|
|
25
25
|
describe 'new' do
|
26
26
|
it 'returns environment' do
|
27
27
|
env = LMDB::Environment.new(path)
|
28
|
-
env.should be_instance_of(described_class
|
28
|
+
env.should be_instance_of(described_class)
|
29
29
|
env.close
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'accepts block' do
|
33
33
|
LMDB::Environment.new(path) do |env|
|
34
|
-
env.should be_instance_of(described_class
|
34
|
+
env.should be_instance_of(described_class)
|
35
35
|
42
|
36
36
|
end.should == 42
|
37
37
|
end
|
38
38
|
|
39
39
|
it 'accepts options' do
|
40
40
|
env = LMDB::Environment.new(path, :nosync => true, :mode => 0777, :maxreaders => 777, :mapsize => 111111, :maxdbs => 666)
|
41
|
-
env.should be_instance_of(described_class
|
41
|
+
env.should be_instance_of(described_class)
|
42
42
|
env.info[:maxreaders].should == 777
|
43
43
|
env.info[:mapsize].should == 111111
|
44
44
|
env.flags.should include(:nosync)
|
@@ -93,14 +93,14 @@ describe LMDB do
|
|
93
93
|
subject.flags.should_not include(:nosync)
|
94
94
|
end
|
95
95
|
|
96
|
-
describe
|
96
|
+
describe LMDB::Transaction do
|
97
97
|
subject { env}
|
98
98
|
|
99
99
|
it 'should create transactions' do
|
100
100
|
subject.active_txn.should == nil
|
101
101
|
subject.transaction do |txn|
|
102
102
|
subject.active_txn.should == txn
|
103
|
-
txn.should be_instance_of(described_class
|
103
|
+
txn.should be_instance_of(described_class)
|
104
104
|
txn.abort
|
105
105
|
subject.active_txn.should == nil
|
106
106
|
end
|
@@ -111,7 +111,7 @@ describe LMDB do
|
|
111
111
|
subject.active_txn.should == nil
|
112
112
|
subject.transaction(true) do |txn|
|
113
113
|
subject.active_txn.should == txn
|
114
|
-
txn.should be_instance_of(described_class
|
114
|
+
txn.should be_instance_of(described_class)
|
115
115
|
txn.abort
|
116
116
|
subject.active_txn.should == nil
|
117
117
|
end
|
@@ -287,5 +287,15 @@ describe LMDB do
|
|
287
287
|
c.set_range('\x00').should == ['key1', 'value1']
|
288
288
|
end
|
289
289
|
end
|
290
|
+
|
291
|
+
it 'should raise without block or txn' do
|
292
|
+
proc { db.cursor.next }.should raise_error(LMDB::Error)
|
293
|
+
end
|
294
|
+
|
295
|
+
it 'should raise outside txn' do
|
296
|
+
c = nil
|
297
|
+
env.transaction { c = db.cursor }
|
298
|
+
proc { c.next }.should raise_error(LMDB::Error)
|
299
|
+
end
|
290
300
|
end
|
291
301
|
end
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lmdb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Mendler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-07-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
19
|
+
version: '10.0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
26
|
+
version: '10.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake-compiler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -42,16 +42,16 @@ dependencies:
|
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
47
|
+
version: '3.0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
54
|
+
version: '3.0'
|
55
55
|
description: lmdb is a Ruby binding to OpenLDAP Lightning MDB.
|
56
56
|
email: mail@daniel-mendler.de
|
57
57
|
executables: []
|
@@ -111,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
111
|
version: '0'
|
112
112
|
requirements: []
|
113
113
|
rubyforge_project:
|
114
|
-
rubygems_version: 2.
|
114
|
+
rubygems_version: 2.4.1
|
115
115
|
signing_key:
|
116
116
|
specification_version: 4
|
117
117
|
summary: Ruby bindings to Lightning MDB
|