lmdb 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|