lmdb 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CHANGES +4 -0
- data/README.md +4 -1
- data/ext/lmdb_ext/liblmdb/CHANGES +26 -1
- data/ext/lmdb_ext/liblmdb/lmdb.h +80 -10
- data/ext/lmdb_ext/liblmdb/mdb.c +648 -616
- data/ext/lmdb_ext/liblmdb/midl.c +8 -8
- data/ext/lmdb_ext/liblmdb/midl.h +1 -1
- data/ext/lmdb_ext/lmdb_ext.c +28 -45
- data/ext/lmdb_ext/lmdb_ext.h +4 -7
- data/lib/lmdb/version.rb +1 -1
- data/spec/lmdb_spec.rb +7 -1
- metadata +3 -3
data/ext/lmdb_ext/liblmdb/midl.c
CHANGED
@@ -59,7 +59,7 @@ unsigned mdb_midl_search( MDB_IDL ids, MDB_ID id )
|
|
59
59
|
return cursor;
|
60
60
|
}
|
61
61
|
}
|
62
|
-
|
62
|
+
|
63
63
|
if( val > 0 ) {
|
64
64
|
++cursor;
|
65
65
|
}
|
@@ -89,7 +89,7 @@ int mdb_midl_insert( MDB_IDL ids, MDB_ID id )
|
|
89
89
|
/* no room */
|
90
90
|
--ids[0];
|
91
91
|
return -2;
|
92
|
-
|
92
|
+
|
93
93
|
} else {
|
94
94
|
/* insert id */
|
95
95
|
for (i=ids[0]; i>x; i--)
|
@@ -203,7 +203,7 @@ int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n )
|
|
203
203
|
/* Quicksort + Insertion sort for small arrays */
|
204
204
|
|
205
205
|
#define SMALL 8
|
206
|
-
#define
|
206
|
+
#define MIDL_SWAP(a,b) { itmp=(a); (a)=(b); (b)=itmp; }
|
207
207
|
|
208
208
|
void
|
209
209
|
mdb_midl_sort( MDB_IDL ids )
|
@@ -231,15 +231,15 @@ mdb_midl_sort( MDB_IDL ids )
|
|
231
231
|
l = istack[jstack--];
|
232
232
|
} else {
|
233
233
|
k = (l + ir) >> 1; /* Choose median of left, center, right */
|
234
|
-
|
234
|
+
MIDL_SWAP(ids[k], ids[l+1]);
|
235
235
|
if (ids[l] < ids[ir]) {
|
236
|
-
|
236
|
+
MIDL_SWAP(ids[l], ids[ir]);
|
237
237
|
}
|
238
238
|
if (ids[l+1] < ids[ir]) {
|
239
|
-
|
239
|
+
MIDL_SWAP(ids[l+1], ids[ir]);
|
240
240
|
}
|
241
241
|
if (ids[l] < ids[l+1]) {
|
242
|
-
|
242
|
+
MIDL_SWAP(ids[l], ids[l+1]);
|
243
243
|
}
|
244
244
|
i = l+1;
|
245
245
|
j = ir;
|
@@ -248,7 +248,7 @@ mdb_midl_sort( MDB_IDL ids )
|
|
248
248
|
do i++; while(ids[i] > a);
|
249
249
|
do j--; while(ids[j] < a);
|
250
250
|
if (j < i) break;
|
251
|
-
|
251
|
+
MIDL_SWAP(ids[i],ids[j]);
|
252
252
|
}
|
253
253
|
ids[l+1] = ids[j];
|
254
254
|
ids[j] = a;
|
data/ext/lmdb_ext/liblmdb/midl.h
CHANGED
@@ -39,7 +39,7 @@ extern "C" {
|
|
39
39
|
/** @defgroup idls ID List Management
|
40
40
|
* @{
|
41
41
|
*/
|
42
|
-
/** A generic ID number. These were entryIDs in back-bdb.
|
42
|
+
/** A generic unsigned ID number. These were entryIDs in back-bdb.
|
43
43
|
* Preferably it should have the same size as a pointer.
|
44
44
|
*/
|
45
45
|
typedef size_t MDB_ID;
|
data/ext/lmdb_ext/lmdb_ext.c
CHANGED
@@ -16,20 +16,12 @@ static void check(int code) {
|
|
16
16
|
rb_raise(cError, "%s", err); /* fallback */
|
17
17
|
}
|
18
18
|
|
19
|
-
static void
|
20
|
-
if (
|
21
|
-
|
22
|
-
|
23
|
-
if (!NIL_P(transaction->parent)) {
|
24
|
-
Transaction* parent = (Transaction*)DATA_PTR(transaction->parent);
|
25
|
-
transaction_deref(parent);
|
26
|
-
}
|
27
|
-
if (transaction->txn) {
|
28
|
-
rb_warn("Garbage collecting active transaction!");
|
29
|
-
mdb_txn_abort(transaction->txn);
|
30
|
-
}
|
31
|
-
free(transaction);
|
19
|
+
static void transaction_free(Transaction* transaction) {
|
20
|
+
if (transaction->txn) {
|
21
|
+
rb_warn("Memory leak - Garbage collecting active transaction");
|
22
|
+
//mdb_txn_abort(transaction->txn);
|
32
23
|
}
|
24
|
+
free(transaction);
|
33
25
|
}
|
34
26
|
|
35
27
|
static void transaction_mark(Transaction* transaction) {
|
@@ -71,6 +63,7 @@ static void transaction_finish(VALUE self, int commit) {
|
|
71
63
|
else
|
72
64
|
mdb_txn_abort(transaction->txn);
|
73
65
|
|
66
|
+
// Mark child transactions as closed
|
74
67
|
p = environment_active_txn(transaction->env);
|
75
68
|
while (p != self) {
|
76
69
|
TRANSACTION(p, txn);
|
@@ -108,21 +101,13 @@ static VALUE with_transaction(VALUE venv, VALUE(*fn)(VALUE), VALUE arg, int flag
|
|
108
101
|
check(mdb_txn_begin(environment->env, active_txn(venv), flags, &txn));
|
109
102
|
|
110
103
|
Transaction* transaction;
|
111
|
-
VALUE vtxn = Data_Make_Struct(cTransaction, Transaction, transaction_mark,
|
112
|
-
transaction->refcount = 1;
|
104
|
+
VALUE vtxn = Data_Make_Struct(cTransaction, Transaction, transaction_mark, transaction_free, transaction);
|
113
105
|
transaction->parent = environment_active_txn(venv);
|
114
106
|
transaction->env = venv;
|
115
107
|
transaction->txn = txn;
|
116
108
|
transaction->thread = rb_thread_current();
|
117
109
|
environment_set_active_txn(venv, transaction->thread, vtxn);
|
118
110
|
|
119
|
-
if (!NIL_P(transaction->parent)) {
|
120
|
-
TRANSACTION(transaction->parent, parent);
|
121
|
-
++parent->refcount;
|
122
|
-
}
|
123
|
-
|
124
|
-
++environment->refcount;
|
125
|
-
|
126
111
|
int exception;
|
127
112
|
VALUE ret = rb_protect(fn, NIL_P(arg) ? vtxn : arg, &exception);
|
128
113
|
|
@@ -141,12 +126,12 @@ static void environment_check(Environment* environment) {
|
|
141
126
|
rb_raise(cError, "Environment is closed");
|
142
127
|
}
|
143
128
|
|
144
|
-
static void
|
145
|
-
if (
|
146
|
-
|
147
|
-
|
148
|
-
free(environment);
|
129
|
+
static void environment_free(Environment *environment) {
|
130
|
+
if (environment->env) {
|
131
|
+
rb_warn("Memory leak - Garbage collecting open environment");
|
132
|
+
//mdb_env_close(environment->env);
|
149
133
|
}
|
134
|
+
free(environment);
|
150
135
|
}
|
151
136
|
|
152
137
|
|
@@ -262,9 +247,8 @@ static VALUE environment_new(int argc, VALUE *argv, VALUE klass) {
|
|
262
247
|
check(mdb_env_create(&env));
|
263
248
|
|
264
249
|
Environment* environment;
|
265
|
-
VALUE venv = Data_Make_Struct(cEnvironment, Environment, environment_mark,
|
250
|
+
VALUE venv = Data_Make_Struct(cEnvironment, Environment, environment_mark, environment_free, environment);
|
266
251
|
environment->env = env;
|
267
|
-
environment->refcount = 1;
|
268
252
|
environment->thread_txn_hash = rb_hash_new();
|
269
253
|
environment->txn_thread_hash = rb_hash_new();
|
270
254
|
|
@@ -379,14 +363,6 @@ static VALUE environment_transaction(int argc, VALUE *argv, VALUE self) {
|
|
379
363
|
return with_transaction(self, rb_yield, Qnil, flags);
|
380
364
|
}
|
381
365
|
|
382
|
-
static void database_deref(Database* database) {
|
383
|
-
if (--database->refcount == 0) {
|
384
|
-
Environment* env = (Environment*)DATA_PTR(database->env);
|
385
|
-
environment_deref(env);
|
386
|
-
free(database);
|
387
|
-
}
|
388
|
-
}
|
389
|
-
|
390
366
|
static void database_mark(Database* database) {
|
391
367
|
rb_gc_mark(database->env);
|
392
368
|
}
|
@@ -413,11 +389,9 @@ static VALUE environment_database(int argc, VALUE *argv, VALUE self) {
|
|
413
389
|
check(mdb_dbi_open(need_txn(self), NIL_P(name) ? 0 : StringValueCStr(name), flags, &dbi));
|
414
390
|
|
415
391
|
Database* database;
|
416
|
-
VALUE vdb = Data_Make_Struct(cDatabase, Database, database_mark,
|
392
|
+
VALUE vdb = Data_Make_Struct(cDatabase, Database, database_mark, free, database);
|
417
393
|
database->dbi = dbi;
|
418
394
|
database->env = self;
|
419
|
-
database->refcount = 1;
|
420
|
-
++environment->refcount;
|
421
395
|
|
422
396
|
return vdb;
|
423
397
|
}
|
@@ -524,10 +498,11 @@ static VALUE database_delete(int argc, VALUE *argv, VALUE self) {
|
|
524
498
|
}
|
525
499
|
|
526
500
|
static void cursor_free(Cursor* cursor) {
|
527
|
-
if (cursor->cur)
|
528
|
-
|
501
|
+
if (cursor->cur) {
|
502
|
+
rb_warn("Memory leak - Garbage collecting open cursor");
|
503
|
+
//mdb_cursor_close(cursor->cur);
|
504
|
+
}
|
529
505
|
|
530
|
-
database_deref((Database*)DATA_PTR(cursor->db));
|
531
506
|
free(cursor);
|
532
507
|
}
|
533
508
|
|
@@ -559,7 +534,6 @@ static VALUE database_cursor(VALUE self) {
|
|
559
534
|
VALUE vcur = Data_Make_Struct(cCursor, Cursor, cursor_mark, cursor_free, cursor);
|
560
535
|
cursor->cur = cur;
|
561
536
|
cursor->db = self;
|
562
|
-
++database->refcount;
|
563
537
|
|
564
538
|
if (rb_block_given_p()) {
|
565
539
|
int exception;
|
@@ -583,6 +557,14 @@ static VALUE cursor_first(VALUE self) {
|
|
583
557
|
return rb_assoc_new(rb_str_new(key.mv_data, key.mv_size), rb_str_new(value.mv_data, value.mv_size));
|
584
558
|
}
|
585
559
|
|
560
|
+
static VALUE cursor_last(VALUE self) {
|
561
|
+
CURSOR(self, cursor);
|
562
|
+
MDB_val key, value;
|
563
|
+
|
564
|
+
check(mdb_cursor_get(cursor->cur, &key, &value, MDB_LAST));
|
565
|
+
return rb_assoc_new(rb_str_new(key.mv_data, key.mv_size), rb_str_new(value.mv_data, value.mv_size));
|
566
|
+
}
|
567
|
+
|
586
568
|
static VALUE cursor_prev(VALUE self) {
|
587
569
|
CURSOR(self, cursor);
|
588
570
|
MDB_val key, value;
|
@@ -738,7 +720,7 @@ void Init_lmdb_ext() {
|
|
738
720
|
rb_define_method(cDatabase, "cursor", database_cursor, 0);
|
739
721
|
|
740
722
|
cTransaction = rb_define_class_under(mLMDB, "Transaction", rb_cObject);
|
741
|
-
rb_undef_method(rb_singleton_class(
|
723
|
+
rb_undef_method(rb_singleton_class(cTransaction), "new");
|
742
724
|
rb_define_method(cTransaction, "commit", transaction_commit, 0);
|
743
725
|
rb_define_method(cTransaction, "abort", transaction_abort, 0);
|
744
726
|
|
@@ -747,6 +729,7 @@ void Init_lmdb_ext() {
|
|
747
729
|
rb_define_method(cCursor, "close", cursor_close, 0);
|
748
730
|
rb_define_method(cCursor, "get", cursor_get, 0);
|
749
731
|
rb_define_method(cCursor, "first", cursor_first, 0);
|
732
|
+
rb_define_method(cCursor, "last", cursor_last, 0);
|
750
733
|
rb_define_method(cCursor, "next", cursor_next, 0);
|
751
734
|
rb_define_method(cCursor, "prev", cursor_prev, 0);
|
752
735
|
rb_define_method(cCursor, "set", cursor_set, 1);
|
data/ext/lmdb_ext/lmdb_ext.h
CHANGED
@@ -42,25 +42,22 @@
|
|
42
42
|
Data_Get_Struct(var, Cursor, var_cur); \
|
43
43
|
cursor_check(var_cur)
|
44
44
|
|
45
|
-
typedef struct
|
45
|
+
typedef struct {
|
46
46
|
VALUE env;
|
47
47
|
VALUE parent;
|
48
48
|
VALUE thread;
|
49
49
|
MDB_txn* txn;
|
50
|
-
int refcount;
|
51
50
|
} Transaction;
|
52
51
|
|
53
52
|
typedef struct {
|
54
53
|
MDB_env* env;
|
55
54
|
VALUE thread_txn_hash;
|
56
55
|
VALUE txn_thread_hash;
|
57
|
-
int refcount;
|
58
56
|
} Environment;
|
59
57
|
|
60
58
|
typedef struct {
|
61
59
|
VALUE env;
|
62
60
|
MDB_dbi dbi;
|
63
|
-
int refcount;
|
64
61
|
} Database;
|
65
62
|
|
66
63
|
typedef struct {
|
@@ -102,6 +99,7 @@ static VALUE cursor_delete(int argc, VALUE *argv, VALUE self);
|
|
102
99
|
static VALUE cursor_first(VALUE self);
|
103
100
|
static void cursor_free(Cursor* cursor);
|
104
101
|
static VALUE cursor_get(VALUE self);
|
102
|
+
static VALUE cursor_last(VALUE self);
|
105
103
|
static void cursor_mark(Cursor* cursor);
|
106
104
|
static VALUE cursor_next(VALUE self);
|
107
105
|
static VALUE cursor_prev(VALUE self);
|
@@ -111,7 +109,6 @@ static VALUE cursor_set_range(VALUE self, VALUE vkey);
|
|
111
109
|
static VALUE database_clear(VALUE self);
|
112
110
|
static VALUE database_cursor(VALUE self);
|
113
111
|
static VALUE database_delete(int argc, VALUE *argv, VALUE self);
|
114
|
-
static void database_deref(Database* database);
|
115
112
|
static VALUE database_drop(VALUE self);
|
116
113
|
static VALUE database_get(VALUE self, VALUE vkey);
|
117
114
|
static void database_mark(Database* database);
|
@@ -124,8 +121,8 @@ static VALUE environment_clear_flags(int argc, VALUE* argv, VALUE self);
|
|
124
121
|
static VALUE environment_close(VALUE self);
|
125
122
|
static VALUE environment_copy(VALUE self, VALUE path);
|
126
123
|
static VALUE environment_database(int argc, VALUE *argv, VALUE self);
|
127
|
-
static void environment_deref(Environment *environment);
|
128
124
|
static VALUE environment_flags(VALUE self);
|
125
|
+
static void environment_free(Environment *environment);
|
129
126
|
static VALUE environment_info(VALUE self);
|
130
127
|
static void environment_mark(Environment* environment);
|
131
128
|
static VALUE environment_new(int argc, VALUE *argv, VALUE klass);
|
@@ -140,8 +137,8 @@ static MDB_txn* need_txn(VALUE self);
|
|
140
137
|
static VALUE stat2hash(const MDB_stat* stat);
|
141
138
|
static VALUE transaction_abort(VALUE self);
|
142
139
|
static VALUE transaction_commit(VALUE self);
|
143
|
-
static void transaction_deref(Transaction* transaction);
|
144
140
|
static void transaction_finish(VALUE self, int commit);
|
141
|
+
static void transaction_free(Transaction* transaction);
|
145
142
|
static void transaction_mark(Transaction* transaction);
|
146
143
|
static VALUE with_transaction(VALUE venv, VALUE(*fn)(VALUE), VALUE arg, int flags);
|
147
144
|
// END PROTOTYPES
|
data/lib/lmdb/version.rb
CHANGED
data/spec/lmdb_spec.rb
CHANGED
@@ -251,12 +251,18 @@ describe LMDB do
|
|
251
251
|
db.put('key2', 'value2')
|
252
252
|
end
|
253
253
|
|
254
|
-
it 'should get
|
254
|
+
it 'should get first key/value' do
|
255
255
|
db.cursor do |c|
|
256
256
|
c.first.should == ['key1', 'value1']
|
257
257
|
end
|
258
258
|
end
|
259
259
|
|
260
|
+
it 'should get last key/value' do
|
261
|
+
db.cursor do |c|
|
262
|
+
c.last.should == ['key2', 'value2']
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
260
266
|
it 'should get next key/value' do
|
261
267
|
db.cursor do |c|
|
262
268
|
c.first
|
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.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Mendler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -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.0.
|
114
|
+
rubygems_version: 2.0.14
|
115
115
|
signing_key:
|
116
116
|
specification_version: 4
|
117
117
|
summary: Ruby bindings to Lightning MDB
|