lmdb 0.3.1 → 0.4.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/.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
|