mdbx 0.3.1 → 0.3.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
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/History.md +23 -0
- data/README.md +0 -7
- data/ext/mdbx_ext/database.c +423 -398
- data/ext/mdbx_ext/mdbx_ext.h +20 -7
- data/ext/mdbx_ext/stats.c +39 -7
- data/lib/mdbx.rb +1 -1
- data/lib/mdbx/database.rb +38 -38
- metadata +2 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 678369c278e65d4faf56eb814e2cb7eba22da57fb5c07c6e4f9dc4e6edd7f09f
|
4
|
+
data.tar.gz: 0fc4b455b4556bb932f867fa40e7c240f555a5a6bbb7d09cb55c68ed7745bfd0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9844be65fc6e46df8dbaee242ce9bf185c4330559d2a5d8c803eca43f4d09a783276c3d2a20258ef84be099a133031acf0f0b36ff0c2af1f69d0882a0dd4335
|
7
|
+
data.tar.gz: 22fd3c418db16d2a58100ad6bd8f3ae7b7ddce2172075713a798065440e59f6a2fd4cea47bd37d3585781dbeaebc0421f483e20375a5e652fe3a81ee76e0da2f
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/History.md
CHANGED
@@ -1,5 +1,28 @@
|
|
1
1
|
# Release History for MDBX
|
2
2
|
|
3
|
+
---
|
4
|
+
## v0.3.2 [2021-07-13] Mahlon E. Smith <mahlon@martini.nu>
|
5
|
+
|
6
|
+
Bugfixes:
|
7
|
+
|
8
|
+
- Fix double memory allocation during initialization.
|
9
|
+
- Make various ruby->c string allocations safe with the garbage collector.
|
10
|
+
|
11
|
+
|
12
|
+
Minutiae:
|
13
|
+
|
14
|
+
- Raise exception if instantiating with invalid options.
|
15
|
+
|
16
|
+
|
17
|
+
---
|
18
|
+
## v0.3.1 [2021-05-16] Mahlon E. Smith <mahlon@martini.nu>
|
19
|
+
|
20
|
+
Bugfix:
|
21
|
+
|
22
|
+
- #drop could potentially remove unintended data. Yanked version
|
23
|
+
v0.3.0.
|
24
|
+
|
25
|
+
|
3
26
|
---
|
4
27
|
## v0.3.0 [2021-04-09] Mahlon E. Smith <mahlon@martini.nu>
|
5
28
|
|
data/README.md
CHANGED
@@ -340,13 +340,6 @@ information about the build environment, the database environment, and
|
|
340
340
|
the currently connected clients.
|
341
341
|
|
342
342
|
|
343
|
-
## TODO
|
344
|
-
|
345
|
-
- Expose more database/collection information to statistics
|
346
|
-
- Support libmdbx multiple values per key DUPSORT via `put`, `get`
|
347
|
-
Enumerators, and a 'value' argument for `delete`.
|
348
|
-
|
349
|
-
|
350
343
|
## Contributing
|
351
344
|
|
352
345
|
You can check out the current development source with Mercurial via its
|
data/ext/mdbx_ext/database.c
CHANGED
@@ -1,21 +1,16 @@
|
|
1
|
-
/* vim: set noet sta sw=4 ts=4 : */
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
/* Shortcut for fetching current DB variables.
|
1
|
+
/* vim: set noet sta sw=4 ts=4 fdm=marker: */
|
2
|
+
/*
|
3
|
+
* Primary database handle functions.
|
4
|
+
*
|
6
5
|
*/
|
7
|
-
#define UNWRAP_DB( val, db ) \
|
8
|
-
rmdbx_db_t *db; \
|
9
|
-
TypedData_Get_Struct( val, rmdbx_db_t, &rmdbx_db_data, db )
|
10
|
-
|
11
|
-
#define CHECK_HANDLE \
|
12
|
-
if ( ! db->state.open ) rb_raise( rmdbx_eDatabaseError, "Closed database." )
|
13
6
|
|
7
|
+
#include "mdbx_ext.h"
|
14
8
|
|
15
9
|
VALUE rmdbx_cDatabase;
|
16
10
|
|
11
|
+
|
17
12
|
/*
|
18
|
-
* Ruby allocation
|
13
|
+
* Ruby data allocation wrapper.
|
19
14
|
*/
|
20
15
|
static const rb_data_type_t rmdbx_db_data = {
|
21
16
|
.wrap_struct_name = "MDBX::Database::Data",
|
@@ -30,11 +25,24 @@ static const rb_data_type_t rmdbx_db_data = {
|
|
30
25
|
VALUE
|
31
26
|
rmdbx_alloc( VALUE klass )
|
32
27
|
{
|
33
|
-
rmdbx_db_t *new
|
28
|
+
rmdbx_db_t *new;
|
34
29
|
return TypedData_Make_Struct( klass, rmdbx_db_t, &rmdbx_db_data, new );
|
35
30
|
}
|
36
31
|
|
37
32
|
|
33
|
+
/*
|
34
|
+
* Cleanup a previously allocated DB environment.
|
35
|
+
*/
|
36
|
+
void
|
37
|
+
rmdbx_free( void *db )
|
38
|
+
{
|
39
|
+
if ( db ) {
|
40
|
+
rmdbx_close_all( db );
|
41
|
+
xfree( db );
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
|
38
46
|
/*
|
39
47
|
* Ensure all database file descriptors are collected and
|
40
48
|
* removed.
|
@@ -65,19 +73,9 @@ rmdbx_close_dbi( rmdbx_db_t *db )
|
|
65
73
|
|
66
74
|
|
67
75
|
/*
|
68
|
-
*
|
69
|
-
|
70
|
-
|
71
|
-
rmdbx_free( void *db )
|
72
|
-
{
|
73
|
-
if ( db ) {
|
74
|
-
rmdbx_close_all( db );
|
75
|
-
xfree( db );
|
76
|
-
}
|
77
|
-
}
|
78
|
-
|
79
|
-
|
80
|
-
/*
|
76
|
+
* call-seq:
|
77
|
+
* db.close => true
|
78
|
+
*
|
81
79
|
* Cleanly close an opened database.
|
82
80
|
*/
|
83
81
|
VALUE
|
@@ -104,17 +102,63 @@ rmdbx_closed_p( VALUE self )
|
|
104
102
|
|
105
103
|
|
106
104
|
/*
|
107
|
-
*
|
108
|
-
|
105
|
+
* Check if a given +flag+ is enabled for flag +val+.
|
106
|
+
*/
|
107
|
+
int
|
108
|
+
rmdbx_flag_enabled( val, flag )
|
109
|
+
{
|
110
|
+
return ( val & flag ) == flag;
|
111
|
+
}
|
112
|
+
|
113
|
+
|
114
|
+
/*
|
115
|
+
* Given a ruby string +key+ and a pointer to an MDBX_val, prepare the
|
116
|
+
* key for usage within mdbx. All keys are explicitly converted to
|
117
|
+
* strings.
|
109
118
|
*
|
110
|
-
|
111
|
-
|
119
|
+
*/
|
120
|
+
void
|
121
|
+
rmdbx_key_for( VALUE key, MDBX_val *ckey )
|
122
|
+
{
|
123
|
+
VALUE key_str = rb_funcall( key, rb_intern("to_s"), 0 );
|
124
|
+
ckey->iov_len = RSTRING_LEN( key_str );
|
125
|
+
ckey->iov_base = malloc( ckey->iov_len );
|
126
|
+
strlcpy( ckey->iov_base, StringValuePtr(key_str), ckey->iov_len + 1 );
|
127
|
+
}
|
128
|
+
|
129
|
+
|
130
|
+
/*
|
131
|
+
* Given a ruby +value+ and a pointer to an MDBX_val, prepare
|
132
|
+
* the value for usage within mdbx. Values are potentially serialized.
|
133
|
+
*
|
134
|
+
*/
|
135
|
+
void
|
136
|
+
rmdbx_val_for( VALUE self, VALUE val, MDBX_val *data )
|
137
|
+
{
|
138
|
+
VALUE serialize_proc = rb_iv_get( self, "@serializer" );
|
139
|
+
|
140
|
+
if ( ! NIL_P( serialize_proc ) )
|
141
|
+
val = rb_funcall( serialize_proc, rb_intern("call"), 1, val );
|
142
|
+
|
143
|
+
Check_Type( val, T_STRING );
|
144
|
+
|
145
|
+
data->iov_len = RSTRING_LEN( val );
|
146
|
+
data->iov_base = malloc( data->iov_len );
|
147
|
+
strlcpy( data->iov_base, StringValuePtr(val), data->iov_len + 1 );
|
148
|
+
}
|
149
|
+
|
150
|
+
|
151
|
+
/*
|
152
|
+
* Deserialize and return a value.
|
112
153
|
*/
|
113
154
|
VALUE
|
114
|
-
|
155
|
+
rmdbx_deserialize( VALUE self, VALUE val )
|
115
156
|
{
|
116
|
-
|
117
|
-
|
157
|
+
VALUE deserialize_proc = rb_iv_get( self, "@deserializer" );
|
158
|
+
if ( ! NIL_P( deserialize_proc ) )
|
159
|
+
val = rb_funcall( deserialize_proc, rb_intern("call"), 1, val );
|
160
|
+
|
161
|
+
return val;
|
118
162
|
}
|
119
163
|
|
120
164
|
|
@@ -151,245 +195,395 @@ rmdbx_open_env( VALUE self )
|
|
151
195
|
rmdbx_close_all( db );
|
152
196
|
rb_raise( rmdbx_eDatabaseError, "mdbx_env_open: (%d) %s", rc, mdbx_strerror(rc) );
|
153
197
|
}
|
154
|
-
db->state.open = 1;
|
155
198
|
|
199
|
+
db->state.open = 1;
|
156
200
|
return Qtrue;
|
157
201
|
}
|
158
202
|
|
159
203
|
|
160
204
|
/*
|
161
|
-
*
|
205
|
+
* call-seq:
|
206
|
+
* db.clear
|
207
|
+
*
|
208
|
+
* Empty the current collection on disk. If collections are not enabled
|
209
|
+
* or the database handle is set to the top-level (main) db - this
|
210
|
+
* deletes *all records* from the database.
|
162
211
|
*/
|
163
|
-
|
164
|
-
|
212
|
+
VALUE
|
213
|
+
rmdbx_clear( VALUE self )
|
165
214
|
{
|
166
|
-
|
167
|
-
if ( ! db->txn ) rb_raise( rmdbx_eDatabaseError, "No snapshot or transaction currently open." );
|
215
|
+
UNWRAP_DB( self, db );
|
168
216
|
|
169
|
-
|
170
|
-
|
171
|
-
rmdbx_close_all( db );
|
172
|
-
rb_raise( rmdbx_eDatabaseError, "Unable to open cursor: (%d) %s", rc, mdbx_strerror(rc) );
|
173
|
-
}
|
217
|
+
rmdbx_open_txn( db, MDBX_TXN_READWRITE );
|
218
|
+
int rc = mdbx_drop( db->txn, db->dbi, false );
|
174
219
|
|
175
|
-
|
220
|
+
if ( rc != MDBX_SUCCESS )
|
221
|
+
rb_raise( rmdbx_eDatabaseError, "mdbx_drop: (%d) %s", rc, mdbx_strerror(rc) );
|
222
|
+
|
223
|
+
rmdbx_close_txn( db, RMDBX_TXN_COMMIT );
|
224
|
+
|
225
|
+
return Qnil;
|
176
226
|
}
|
177
227
|
|
178
228
|
|
179
229
|
/*
|
180
|
-
*
|
181
|
-
*
|
230
|
+
* call-seq:
|
231
|
+
* db.drop( collection ) -> db
|
182
232
|
*
|
183
|
-
*
|
233
|
+
* Destroy a collection. You must be in the top level database to call
|
234
|
+
* this method.
|
184
235
|
*/
|
185
|
-
|
186
|
-
|
236
|
+
VALUE
|
237
|
+
rmdbx_drop( VALUE self, VALUE name )
|
187
238
|
{
|
188
|
-
|
239
|
+
UNWRAP_DB( self, db );
|
189
240
|
|
190
|
-
|
191
|
-
if (
|
192
|
-
|
193
|
-
rb_raise( rmdbx_eDatabaseError, "mdbx_txn_begin: (%d) %s", rc, mdbx_strerror(rc) );
|
194
|
-
}
|
241
|
+
/* Provide a friendlier error message if max_collections is 0. */
|
242
|
+
if ( db->settings.max_collections == 0 )
|
243
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to drop collection: collections are not enabled." );
|
195
244
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
if ( rc != MDBX_SUCCESS ) {
|
200
|
-
rmdbx_close_all( db );
|
201
|
-
rb_raise( rmdbx_eDatabaseError, "mdbx_dbi_open: (%d) %s", rc, mdbx_strerror(rc) );
|
202
|
-
}
|
203
|
-
}
|
245
|
+
/* All transactions must be closed when dropping a database. */
|
246
|
+
if ( db->txn )
|
247
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to drop collection: transaction open" );
|
204
248
|
|
205
|
-
|
249
|
+
/* A drop can only be performed from the top-level database. */
|
250
|
+
if ( db->subdb != NULL )
|
251
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to drop collection: switch to top-level db first" );
|
252
|
+
|
253
|
+
name = rb_funcall( name, rb_intern("to_s"), 0 );
|
254
|
+
db->subdb = StringValueCStr( name );
|
255
|
+
|
256
|
+
rmdbx_close_dbi( db ); /* ensure we're reopening within the new subdb */
|
257
|
+
rmdbx_open_txn( db, MDBX_TXN_READWRITE );
|
258
|
+
int rc = mdbx_drop( db->txn, db->dbi, true );
|
259
|
+
|
260
|
+
if ( rc != MDBX_SUCCESS )
|
261
|
+
rb_raise( rmdbx_eDatabaseError, "mdbx_drop: (%d) %s", rc, mdbx_strerror(rc) );
|
262
|
+
|
263
|
+
rmdbx_close_txn( db, RMDBX_TXN_COMMIT );
|
264
|
+
|
265
|
+
/* Reset the current collection to the top level. */
|
266
|
+
db->subdb = NULL;
|
267
|
+
rmdbx_close_dbi( db ); /* ensure next access is not in the defunct subdb */
|
268
|
+
|
269
|
+
return self;
|
206
270
|
}
|
207
271
|
|
208
272
|
|
209
|
-
/*
|
210
|
-
*
|
211
|
-
* active transaction, this is a no-op. If there is a long
|
212
|
-
* running transaction open, this is a no-op.
|
273
|
+
/* call-seq:
|
274
|
+
* db.length -> Integer
|
213
275
|
*
|
214
|
-
*
|
276
|
+
* Returns the count of keys in the currently selected collection.
|
215
277
|
*/
|
216
|
-
|
217
|
-
|
278
|
+
VALUE
|
279
|
+
rmdbx_length( VALUE self )
|
218
280
|
{
|
219
|
-
|
281
|
+
UNWRAP_DB( self, db );
|
282
|
+
MDBX_stat mstat;
|
220
283
|
|
221
|
-
|
222
|
-
|
223
|
-
}
|
224
|
-
else {
|
225
|
-
mdbx_txn_abort( db->txn );
|
226
|
-
}
|
284
|
+
CHECK_HANDLE();
|
285
|
+
rmdbx_open_txn( db, MDBX_TXN_RDONLY );
|
227
286
|
|
228
|
-
db->txn
|
229
|
-
|
287
|
+
int rc = mdbx_dbi_stat( db->txn, db->dbi, &mstat, sizeof(mstat) );
|
288
|
+
if ( rc != MDBX_SUCCESS )
|
289
|
+
rb_raise( rmdbx_eDatabaseError, "mdbx_dbi_stat: (%d) %s", rc, mdbx_strerror(rc) );
|
290
|
+
|
291
|
+
VALUE rv = LONG2FIX( mstat.ms_entries );
|
292
|
+
rmdbx_close_txn( db, RMDBX_TXN_ROLLBACK );
|
293
|
+
|
294
|
+
return rv;
|
230
295
|
}
|
231
296
|
|
232
297
|
|
233
|
-
/*
|
234
|
-
*
|
235
|
-
* db.open_transaction( mode )
|
236
|
-
*
|
237
|
-
* Open a new long-running transaction. If +mode+ is true,
|
238
|
-
* it is opened read/write.
|
298
|
+
/* call-seq:
|
299
|
+
* db.include?( 'key' ) => bool
|
239
300
|
*
|
301
|
+
* Returns true if the current collection contains +key+.
|
240
302
|
*/
|
241
303
|
VALUE
|
242
|
-
|
304
|
+
rmdbx_include( VALUE self, VALUE key )
|
243
305
|
{
|
244
306
|
UNWRAP_DB( self, db );
|
245
|
-
CHECK_HANDLE;
|
246
307
|
|
247
|
-
|
248
|
-
db
|
308
|
+
CHECK_HANDLE();
|
309
|
+
rmdbx_open_txn( db, MDBX_TXN_RDONLY );
|
249
310
|
|
250
|
-
|
311
|
+
MDBX_val ckey;
|
312
|
+
MDBX_val data;
|
313
|
+
rmdbx_key_for( key, &ckey );
|
314
|
+
|
315
|
+
int rc = mdbx_get( db->txn, db->dbi, &ckey, &data );
|
316
|
+
rmdbx_close_txn( db, RMDBX_TXN_ROLLBACK );
|
317
|
+
xfree( ckey.iov_base );
|
318
|
+
|
319
|
+
switch ( rc ) {
|
320
|
+
case MDBX_SUCCESS:
|
321
|
+
return Qtrue;
|
322
|
+
|
323
|
+
case MDBX_NOTFOUND:
|
324
|
+
return Qfalse;
|
325
|
+
|
326
|
+
default:
|
327
|
+
rmdbx_close( self );
|
328
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to fetch key: (%d) %s", rc, mdbx_strerror(rc) );
|
329
|
+
}
|
251
330
|
}
|
252
331
|
|
253
332
|
|
254
|
-
/*
|
255
|
-
*
|
256
|
-
* db.close_transaction( mode )
|
257
|
-
*
|
258
|
-
* Close a long-running transaction. If +write+ is true,
|
259
|
-
* the transaction is committed. Otherwise, rolled back.
|
333
|
+
/* call-seq:
|
334
|
+
* db[ 'key' ] => value
|
260
335
|
*
|
336
|
+
* Return a single value for +key+ immediately.
|
261
337
|
*/
|
262
338
|
VALUE
|
263
|
-
|
339
|
+
rmdbx_get_val( VALUE self, VALUE key )
|
264
340
|
{
|
265
341
|
UNWRAP_DB( self, db );
|
266
342
|
|
267
|
-
|
268
|
-
|
343
|
+
CHECK_HANDLE();
|
344
|
+
rmdbx_open_txn( db, MDBX_TXN_RDONLY );
|
269
345
|
|
270
|
-
|
346
|
+
MDBX_val ckey;
|
347
|
+
MDBX_val data;
|
348
|
+
|
349
|
+
rmdbx_key_for( key, &ckey );
|
350
|
+
int rc = mdbx_get( db->txn, db->dbi, &ckey, &data );
|
351
|
+
rmdbx_close_txn( db, RMDBX_TXN_ROLLBACK );
|
352
|
+
xfree( ckey.iov_base );
|
353
|
+
|
354
|
+
VALUE rv;
|
355
|
+
switch ( rc ) {
|
356
|
+
case MDBX_SUCCESS:
|
357
|
+
rv = rb_str_new( data.iov_base, data.iov_len );
|
358
|
+
return rmdbx_deserialize( self, rv );
|
359
|
+
|
360
|
+
case MDBX_NOTFOUND:
|
361
|
+
return Qnil;
|
362
|
+
|
363
|
+
default:
|
364
|
+
rmdbx_close( self );
|
365
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to fetch value: (%d) %s", rc, mdbx_strerror(rc) );
|
366
|
+
}
|
271
367
|
}
|
272
368
|
|
273
369
|
|
274
|
-
/*
|
275
|
-
*
|
276
|
-
* db.clear
|
370
|
+
/* call-seq:
|
371
|
+
* db[ 'key' ] = value
|
277
372
|
*
|
278
|
-
*
|
279
|
-
*
|
280
|
-
* deletes *all records* from the database.
|
373
|
+
* Set a single value for +key+. If the value is +nil+, the
|
374
|
+
* key is removed.
|
281
375
|
*/
|
282
376
|
VALUE
|
283
|
-
|
377
|
+
rmdbx_put_val( VALUE self, VALUE key, VALUE val )
|
284
378
|
{
|
379
|
+
int rc;
|
285
380
|
UNWRAP_DB( self, db );
|
286
381
|
|
382
|
+
CHECK_HANDLE();
|
287
383
|
rmdbx_open_txn( db, MDBX_TXN_READWRITE );
|
288
|
-
int rc = mdbx_drop( db->txn, db->dbi, false );
|
289
384
|
|
290
|
-
|
291
|
-
|
385
|
+
MDBX_val ckey;
|
386
|
+
rmdbx_key_for( key, &ckey );
|
387
|
+
|
388
|
+
if ( NIL_P(val) ) { /* remove if set to nil */
|
389
|
+
rc = mdbx_del( db->txn, db->dbi, &ckey, NULL );
|
390
|
+
}
|
391
|
+
else {
|
392
|
+
MDBX_val old;
|
393
|
+
MDBX_val data;
|
394
|
+
rmdbx_val_for( self, val, &data );
|
395
|
+
rc = mdbx_replace( db->txn, db->dbi, &ckey, &data, &old, 0 );
|
396
|
+
xfree( data.iov_base );
|
397
|
+
}
|
292
398
|
|
293
399
|
rmdbx_close_txn( db, RMDBX_TXN_COMMIT );
|
400
|
+
xfree( ckey.iov_base );
|
294
401
|
|
295
|
-
|
402
|
+
switch ( rc ) {
|
403
|
+
case MDBX_SUCCESS:
|
404
|
+
return val;
|
405
|
+
case MDBX_NOTFOUND:
|
406
|
+
return Qnil;
|
407
|
+
default:
|
408
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to update value: (%d) %s", rc, mdbx_strerror(rc) );
|
409
|
+
}
|
296
410
|
}
|
297
411
|
|
298
412
|
|
299
413
|
/*
|
300
|
-
*
|
301
|
-
*
|
414
|
+
* Return the currently selected collection, or +nil+ if at the
|
415
|
+
* top-level.
|
416
|
+
*/
|
417
|
+
VALUE
|
418
|
+
rmdbx_get_subdb( VALUE self )
|
419
|
+
{
|
420
|
+
UNWRAP_DB( self, db );
|
421
|
+
return ( db->subdb == NULL ) ? Qnil : rb_str_new_cstr( db->subdb );
|
422
|
+
}
|
423
|
+
|
424
|
+
|
425
|
+
/*
|
426
|
+
* Sets the current collection name for read/write operations.
|
302
427
|
*
|
303
|
-
* Destroy a collection. You must be in the top level database to call
|
304
|
-
* this method.
|
305
428
|
*/
|
306
429
|
VALUE
|
307
|
-
|
430
|
+
rmdbx_set_subdb( VALUE self, VALUE name )
|
308
431
|
{
|
309
432
|
UNWRAP_DB( self, db );
|
310
433
|
|
311
434
|
/* Provide a friendlier error message if max_collections is 0. */
|
312
435
|
if ( db->settings.max_collections == 0 )
|
313
|
-
rb_raise( rmdbx_eDatabaseError, "Unable to
|
436
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to change collection: collections are not enabled." );
|
314
437
|
|
315
|
-
/* All transactions must be closed when
|
438
|
+
/* All transactions must be closed when switching database handles. */
|
316
439
|
if ( db->txn )
|
317
|
-
rb_raise( rmdbx_eDatabaseError, "Unable to
|
440
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to change collection: transaction open" );
|
318
441
|
|
319
|
-
|
320
|
-
|
321
|
-
rb_raise( rmdbx_eDatabaseError, "Unable to drop collection: switch to top-level db first" );
|
442
|
+
xfree( db->subdb );
|
443
|
+
db->subdb = NULL;
|
322
444
|
|
323
|
-
|
324
|
-
|
445
|
+
if ( ! NIL_P(name) ) {
|
446
|
+
size_t len = RSTRING_LEN( name ) + 1;
|
447
|
+
db->subdb = malloc( len );
|
448
|
+
strlcpy( db->subdb, StringValuePtr(name), len );
|
449
|
+
}
|
325
450
|
|
326
|
-
|
451
|
+
/* Reset the db handle and issue a single transaction to reify
|
452
|
+
the collection.
|
453
|
+
*/
|
454
|
+
rmdbx_close_dbi( db );
|
327
455
|
rmdbx_open_txn( db, MDBX_TXN_READWRITE );
|
328
|
-
|
456
|
+
rmdbx_close_txn( db, RMDBX_TXN_COMMIT );
|
329
457
|
|
330
|
-
|
331
|
-
|
458
|
+
return self;
|
459
|
+
}
|
332
460
|
|
333
|
-
rmdbx_close_txn( db, RMDBX_TXN_COMMIT );
|
334
461
|
|
335
|
-
|
336
|
-
|
337
|
-
|
462
|
+
/*
|
463
|
+
* call-seq:
|
464
|
+
* db.in_transaction? => false
|
465
|
+
*
|
466
|
+
* Predicate: return true if a transaction (or snapshot)
|
467
|
+
* is currently open.
|
468
|
+
*/
|
469
|
+
VALUE
|
470
|
+
rmdbx_in_transaction_p( VALUE self )
|
471
|
+
{
|
472
|
+
UNWRAP_DB( self, db );
|
473
|
+
return db->txn ? Qtrue : Qfalse;
|
474
|
+
}
|
338
475
|
|
339
|
-
|
476
|
+
|
477
|
+
/*
|
478
|
+
* Open a new database transaction. If a transaction is already
|
479
|
+
* open, this is a no-op.
|
480
|
+
*
|
481
|
+
* +rwflag+ must be either MDBX_TXN_RDONLY or MDBX_TXN_READWRITE.
|
482
|
+
*/
|
483
|
+
void
|
484
|
+
rmdbx_open_txn( rmdbx_db_t *db, int rwflag )
|
485
|
+
{
|
486
|
+
if ( db->txn ) return;
|
487
|
+
|
488
|
+
int rc = mdbx_txn_begin( db->env, NULL, rwflag, &db->txn );
|
489
|
+
if ( rc != MDBX_SUCCESS ) {
|
490
|
+
rmdbx_close_all( db );
|
491
|
+
rb_raise( rmdbx_eDatabaseError, "mdbx_txn_begin: (%d) %s", rc, mdbx_strerror(rc) );
|
492
|
+
}
|
493
|
+
|
494
|
+
if ( db->dbi == 0 ) {
|
495
|
+
rc = mdbx_dbi_open( db->txn, db->subdb, db->settings.db_flags, &db->dbi );
|
496
|
+
if ( rc != MDBX_SUCCESS ) {
|
497
|
+
rmdbx_close_all( db );
|
498
|
+
rb_raise( rmdbx_eDatabaseError, "mdbx_dbi_open: (%d) %s", rc, mdbx_strerror(rc) );
|
499
|
+
}
|
500
|
+
}
|
501
|
+
|
502
|
+
return;
|
340
503
|
}
|
341
504
|
|
342
505
|
|
343
506
|
/*
|
344
|
-
*
|
345
|
-
*
|
346
|
-
*
|
507
|
+
* Close any existing database transaction. If there is no
|
508
|
+
* active transaction, this is a no-op. If there is a long
|
509
|
+
* running transaction open, this is a no-op.
|
510
|
+
*
|
511
|
+
* +txnflag must either be RMDBX_TXN_ROLLBACK or RMDBX_TXN_COMMIT.
|
347
512
|
*/
|
348
|
-
|
349
|
-
|
513
|
+
void
|
514
|
+
rmdbx_close_txn( rmdbx_db_t *db, int txnflag )
|
350
515
|
{
|
351
|
-
|
516
|
+
if ( ! db->txn || db->state.retain_txn > -1 ) return;
|
352
517
|
|
353
|
-
|
354
|
-
|
355
|
-
|
518
|
+
if ( txnflag == RMDBX_TXN_COMMIT ) {
|
519
|
+
mdbx_txn_commit( db->txn );
|
520
|
+
}
|
521
|
+
else {
|
522
|
+
mdbx_txn_abort( db->txn );
|
523
|
+
}
|
356
524
|
|
357
|
-
|
525
|
+
db->txn = 0;
|
526
|
+
return;
|
358
527
|
}
|
359
528
|
|
360
529
|
|
361
530
|
/*
|
362
|
-
*
|
363
|
-
*
|
531
|
+
* call-seq:
|
532
|
+
* db.open_transaction( mode )
|
533
|
+
*
|
534
|
+
* Open a new long-running transaction. If +mode+ is true,
|
535
|
+
* it is opened read/write.
|
536
|
+
*
|
364
537
|
*/
|
365
|
-
|
366
|
-
|
538
|
+
VALUE
|
539
|
+
rmdbx_rb_opentxn( VALUE self, VALUE mode )
|
367
540
|
{
|
368
|
-
|
369
|
-
|
541
|
+
UNWRAP_DB( self, db );
|
542
|
+
CHECK_HANDLE();
|
370
543
|
|
371
|
-
|
372
|
-
|
373
|
-
|
544
|
+
rmdbx_open_txn( db, RTEST(mode) ? MDBX_TXN_READWRITE : MDBX_TXN_RDONLY );
|
545
|
+
db->state.retain_txn = RTEST(mode) ? 1 : 0;
|
546
|
+
|
547
|
+
return Qtrue;
|
548
|
+
}
|
549
|
+
|
550
|
+
|
551
|
+
/*
|
552
|
+
* call-seq:
|
553
|
+
* db.close_transaction( mode )
|
554
|
+
*
|
555
|
+
* Close a long-running transaction. If +write+ is true,
|
556
|
+
* the transaction is committed. Otherwise, rolled back.
|
557
|
+
*
|
558
|
+
*/
|
559
|
+
VALUE
|
560
|
+
rmdbx_rb_closetxn( VALUE self, VALUE write )
|
561
|
+
{
|
562
|
+
UNWRAP_DB( self, db );
|
374
563
|
|
375
|
-
|
376
|
-
|
564
|
+
db->state.retain_txn = -1;
|
565
|
+
rmdbx_close_txn( db, RTEST(write) ? RMDBX_TXN_COMMIT : RMDBX_TXN_ROLLBACK );
|
377
566
|
|
378
|
-
return
|
567
|
+
return Qtrue;
|
379
568
|
}
|
380
569
|
|
381
570
|
|
382
571
|
/*
|
383
|
-
*
|
572
|
+
* Open a cursor for iteration.
|
384
573
|
*/
|
385
|
-
|
386
|
-
|
574
|
+
void
|
575
|
+
rmdbx_open_cursor( rmdbx_db_t *db )
|
387
576
|
{
|
388
|
-
|
389
|
-
if ( !
|
390
|
-
val = rb_funcall( deserialize_proc, rb_intern("call"), 1, val );
|
577
|
+
CHECK_HANDLE();
|
578
|
+
if ( ! db->txn ) rb_raise( rmdbx_eDatabaseError, "No snapshot or transaction currently open." );
|
391
579
|
|
392
|
-
|
580
|
+
int rc = mdbx_cursor_open( db->txn, db->dbi, &db->cursor );
|
581
|
+
if ( rc != MDBX_SUCCESS ) {
|
582
|
+
rmdbx_close_all( db );
|
583
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to open cursor: (%d) %s", rc, mdbx_strerror(rc) );
|
584
|
+
}
|
585
|
+
|
586
|
+
return;
|
393
587
|
}
|
394
588
|
|
395
589
|
|
@@ -425,7 +619,7 @@ rmdbx_each_key( VALUE self )
|
|
425
619
|
UNWRAP_DB( self, db );
|
426
620
|
int state;
|
427
621
|
|
428
|
-
CHECK_HANDLE;
|
622
|
+
CHECK_HANDLE();
|
429
623
|
rmdbx_open_cursor( db );
|
430
624
|
RETURN_ENUMERATOR( self, 0, 0 );
|
431
625
|
|
@@ -474,7 +668,7 @@ rmdbx_each_value( VALUE self )
|
|
474
668
|
UNWRAP_DB( self, db );
|
475
669
|
int state;
|
476
670
|
|
477
|
-
CHECK_HANDLE;
|
671
|
+
CHECK_HANDLE();
|
478
672
|
rmdbx_open_cursor( db );
|
479
673
|
RETURN_ENUMERATOR( self, 0, 0 );
|
480
674
|
|
@@ -525,7 +719,7 @@ rmdbx_each_pair( VALUE self )
|
|
525
719
|
UNWRAP_DB( self, db );
|
526
720
|
int state;
|
527
721
|
|
528
|
-
CHECK_HANDLE;
|
722
|
+
CHECK_HANDLE();
|
529
723
|
rmdbx_open_cursor( db );
|
530
724
|
RETURN_ENUMERATOR( self, 0, 0 );
|
531
725
|
|
@@ -540,201 +734,6 @@ rmdbx_each_pair( VALUE self )
|
|
540
734
|
}
|
541
735
|
|
542
736
|
|
543
|
-
|
544
|
-
/* call-seq:
|
545
|
-
* db.length -> Integer
|
546
|
-
*
|
547
|
-
* Returns the count of keys in the currently selected collection.
|
548
|
-
*/
|
549
|
-
VALUE
|
550
|
-
rmdbx_length( VALUE self )
|
551
|
-
{
|
552
|
-
UNWRAP_DB( self, db );
|
553
|
-
MDBX_stat mstat;
|
554
|
-
|
555
|
-
CHECK_HANDLE;
|
556
|
-
rmdbx_open_txn( db, MDBX_TXN_RDONLY );
|
557
|
-
|
558
|
-
int rc = mdbx_dbi_stat( db->txn, db->dbi, &mstat, sizeof(mstat) );
|
559
|
-
if ( rc != MDBX_SUCCESS )
|
560
|
-
rb_raise( rmdbx_eDatabaseError, "mdbx_dbi_stat: (%d) %s", rc, mdbx_strerror(rc) );
|
561
|
-
|
562
|
-
VALUE rv = LONG2FIX( mstat.ms_entries );
|
563
|
-
rmdbx_close_txn( db, RMDBX_TXN_ROLLBACK );
|
564
|
-
|
565
|
-
return rv;
|
566
|
-
}
|
567
|
-
|
568
|
-
|
569
|
-
/* call-seq:
|
570
|
-
* db.include?( 'key' ) => bool
|
571
|
-
*
|
572
|
-
* Returns true if the current collection contains +key+.
|
573
|
-
*/
|
574
|
-
VALUE
|
575
|
-
rmdbx_include( VALUE self, VALUE key )
|
576
|
-
{
|
577
|
-
int rc;
|
578
|
-
UNWRAP_DB( self, db );
|
579
|
-
|
580
|
-
CHECK_HANDLE;
|
581
|
-
rmdbx_open_txn( db, MDBX_TXN_RDONLY );
|
582
|
-
|
583
|
-
MDBX_val ckey = rmdbx_key_for( key );
|
584
|
-
MDBX_val data;
|
585
|
-
rc = mdbx_get( db->txn, db->dbi, &ckey, &data );
|
586
|
-
rmdbx_close_txn( db, RMDBX_TXN_ROLLBACK );
|
587
|
-
|
588
|
-
switch ( rc ) {
|
589
|
-
case MDBX_SUCCESS:
|
590
|
-
return Qtrue;
|
591
|
-
|
592
|
-
case MDBX_NOTFOUND:
|
593
|
-
return Qfalse;
|
594
|
-
|
595
|
-
default:
|
596
|
-
rmdbx_close( self );
|
597
|
-
rb_raise( rmdbx_eDatabaseError, "Unable to fetch key: (%d) %s", rc, mdbx_strerror(rc) );
|
598
|
-
}
|
599
|
-
}
|
600
|
-
|
601
|
-
|
602
|
-
/* call-seq:
|
603
|
-
* db[ 'key' ] => value
|
604
|
-
*
|
605
|
-
* Return a single value for +key+ immediately.
|
606
|
-
*/
|
607
|
-
VALUE
|
608
|
-
rmdbx_get_val( VALUE self, VALUE key )
|
609
|
-
{
|
610
|
-
int rc;
|
611
|
-
UNWRAP_DB( self, db );
|
612
|
-
|
613
|
-
CHECK_HANDLE;
|
614
|
-
rmdbx_open_txn( db, MDBX_TXN_RDONLY );
|
615
|
-
|
616
|
-
MDBX_val ckey = rmdbx_key_for( key );
|
617
|
-
MDBX_val data;
|
618
|
-
VALUE rv;
|
619
|
-
rc = mdbx_get( db->txn, db->dbi, &ckey, &data );
|
620
|
-
rmdbx_close_txn( db, RMDBX_TXN_ROLLBACK );
|
621
|
-
|
622
|
-
switch ( rc ) {
|
623
|
-
case MDBX_SUCCESS:
|
624
|
-
rv = rb_str_new( data.iov_base, data.iov_len );
|
625
|
-
return rmdbx_deserialize( self, rv );
|
626
|
-
|
627
|
-
case MDBX_NOTFOUND:
|
628
|
-
return Qnil;
|
629
|
-
|
630
|
-
default:
|
631
|
-
rmdbx_close( self );
|
632
|
-
rb_raise( rmdbx_eDatabaseError, "Unable to fetch value: (%d) %s", rc, mdbx_strerror(rc) );
|
633
|
-
}
|
634
|
-
}
|
635
|
-
|
636
|
-
|
637
|
-
/* call-seq:
|
638
|
-
* db[ 'key' ] = value
|
639
|
-
*
|
640
|
-
* Set a single value for +key+. If the value is +nil+, the
|
641
|
-
* key is removed.
|
642
|
-
*/
|
643
|
-
VALUE
|
644
|
-
rmdbx_put_val( VALUE self, VALUE key, VALUE val )
|
645
|
-
{
|
646
|
-
int rc;
|
647
|
-
UNWRAP_DB( self, db );
|
648
|
-
|
649
|
-
CHECK_HANDLE;
|
650
|
-
rmdbx_open_txn( db, MDBX_TXN_READWRITE );
|
651
|
-
|
652
|
-
MDBX_val ckey = rmdbx_key_for( key );
|
653
|
-
|
654
|
-
// FIXME: DUPSORT is enabled -- different api?
|
655
|
-
// See: MDBX_NODUPDATA / MDBX_NOOVERWRITE
|
656
|
-
if ( NIL_P(val) ) { /* remove if set to nil */
|
657
|
-
rc = mdbx_del( db->txn, db->dbi, &ckey, NULL );
|
658
|
-
}
|
659
|
-
else {
|
660
|
-
MDBX_val old;
|
661
|
-
MDBX_val data = rmdbx_val_for( self, val );
|
662
|
-
rc = mdbx_replace( db->txn, db->dbi, &ckey, &data, &old, 0 );
|
663
|
-
}
|
664
|
-
|
665
|
-
rmdbx_close_txn( db, RMDBX_TXN_COMMIT );
|
666
|
-
|
667
|
-
switch ( rc ) {
|
668
|
-
case MDBX_SUCCESS:
|
669
|
-
return val;
|
670
|
-
case MDBX_NOTFOUND:
|
671
|
-
return Qnil;
|
672
|
-
default:
|
673
|
-
rb_raise( rmdbx_eDatabaseError, "Unable to store value: (%d) %s", rc, mdbx_strerror(rc) );
|
674
|
-
}
|
675
|
-
}
|
676
|
-
|
677
|
-
|
678
|
-
/*
|
679
|
-
* call-seq:
|
680
|
-
* db.statistics => (hash of stats)
|
681
|
-
*
|
682
|
-
* Returns a hash populated with various metadata for the opened
|
683
|
-
* database.
|
684
|
-
*
|
685
|
-
*/
|
686
|
-
VALUE
|
687
|
-
rmdbx_stats( VALUE self )
|
688
|
-
{
|
689
|
-
UNWRAP_DB( self, db );
|
690
|
-
CHECK_HANDLE;
|
691
|
-
|
692
|
-
return rmdbx_gather_stats( db );
|
693
|
-
}
|
694
|
-
|
695
|
-
|
696
|
-
/*
|
697
|
-
* Return the currently selected collection, or +nil+ if at the
|
698
|
-
* top-level.
|
699
|
-
*/
|
700
|
-
VALUE
|
701
|
-
rmdbx_get_subdb( VALUE self )
|
702
|
-
{
|
703
|
-
UNWRAP_DB( self, db );
|
704
|
-
return ( db->subdb == NULL ) ? Qnil : rb_str_new_cstr( db->subdb );
|
705
|
-
}
|
706
|
-
|
707
|
-
|
708
|
-
/*
|
709
|
-
* Sets the current collection name for read/write operations.
|
710
|
-
*
|
711
|
-
*/
|
712
|
-
VALUE
|
713
|
-
rmdbx_set_subdb( VALUE self, VALUE name )
|
714
|
-
{
|
715
|
-
UNWRAP_DB( self, db );
|
716
|
-
|
717
|
-
/* Provide a friendlier error message if max_collections is 0. */
|
718
|
-
if ( db->settings.max_collections == 0 )
|
719
|
-
rb_raise( rmdbx_eDatabaseError, "Unable to change collection: collections are not enabled." );
|
720
|
-
|
721
|
-
/* All transactions must be closed when switching database handles. */
|
722
|
-
if ( db->txn )
|
723
|
-
rb_raise( rmdbx_eDatabaseError, "Unable to change collection: transaction open" );
|
724
|
-
|
725
|
-
db->subdb = NIL_P( name ) ? NULL : StringValueCStr( name );
|
726
|
-
|
727
|
-
/* Reset the db handle and issue a single transaction to reify
|
728
|
-
the collection.
|
729
|
-
*/
|
730
|
-
rmdbx_close_dbi( db );
|
731
|
-
rmdbx_open_txn( db, MDBX_TXN_READWRITE );
|
732
|
-
rmdbx_close_txn( db, RMDBX_TXN_COMMIT );
|
733
|
-
|
734
|
-
return self;
|
735
|
-
}
|
736
|
-
|
737
|
-
|
738
737
|
/*
|
739
738
|
* Open an existing (or create a new) mdbx database at filesystem
|
740
739
|
* +path+. In block form, the database is automatically closed.
|
@@ -774,57 +773,80 @@ rmdbx_database_initialize( int argc, VALUE *argv, VALUE self )
|
|
774
773
|
db->state.open = 0;
|
775
774
|
db->state.retain_txn = -1;
|
776
775
|
db->settings.env_flags = MDBX_ENV_DEFAULTS;
|
776
|
+
db->settings.db_flags = MDBX_DB_DEFAULTS | MDBX_CREATE;
|
777
777
|
db->settings.mode = 0644;
|
778
778
|
db->settings.max_collections = 0;
|
779
779
|
db->settings.max_readers = 0;
|
780
780
|
db->settings.max_size = 0;
|
781
781
|
|
782
|
-
/*
|
782
|
+
/* Set instance variables.
|
783
|
+
*/
|
784
|
+
rb_iv_set( self, "@path", path );
|
785
|
+
rb_iv_set( self, "@options", rb_hash_dup( opts ) );
|
786
|
+
|
787
|
+
/* Environment and database options setup, overrides.
|
783
788
|
*/
|
784
|
-
opt =
|
785
|
-
if (
|
786
|
-
opt =
|
789
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("coalesce") ) );
|
790
|
+
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_COALESCE;
|
791
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("compatible") ) );
|
792
|
+
if ( RTEST(opt) ) {
|
793
|
+
db->settings.db_flags = db->settings.db_flags | MDBX_DB_ACCEDE;
|
794
|
+
db->settings.env_flags = db->settings.env_flags | MDBX_ACCEDE;
|
795
|
+
}
|
796
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("exclusive") ) );
|
797
|
+
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_EXCLUSIVE;
|
798
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("lifo_reclaim") ) );
|
799
|
+
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_LIFORECLAIM;
|
800
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("max_collections") ) );
|
787
801
|
if ( ! NIL_P(opt) ) db->settings.max_collections = FIX2INT( opt );
|
788
|
-
opt =
|
802
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("max_readers") ) );
|
789
803
|
if ( ! NIL_P(opt) ) db->settings.max_readers = FIX2INT( opt );
|
790
|
-
opt =
|
804
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("max_size") ) );
|
791
805
|
if ( ! NIL_P(opt) ) db->settings.max_size = NUM2LONG( opt );
|
792
|
-
opt =
|
806
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("mode") ) );
|
807
|
+
if ( ! NIL_P(opt) ) db->settings.mode = FIX2INT( opt );
|
808
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("no_memory_init") ) );
|
809
|
+
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NOMEMINIT;
|
810
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("no_metasync") ) );
|
811
|
+
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NOMETASYNC;
|
812
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("no_subdir") ) );
|
793
813
|
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NOSUBDIR;
|
794
|
-
opt =
|
814
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("no_readahead") ) );
|
815
|
+
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NORDAHEAD;
|
816
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("no_threadlocal") ) );
|
817
|
+
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NOTLS;
|
818
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("readonly") ) );
|
795
819
|
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_RDONLY;
|
796
|
-
opt =
|
797
|
-
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_EXCLUSIVE;
|
798
|
-
opt = rb_hash_aref( opts, ID2SYM( rb_intern("compat") ) );
|
799
|
-
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_ACCEDE;
|
800
|
-
opt = rb_hash_aref( opts, ID2SYM( rb_intern("writemap") ) );
|
820
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("writemap") ) );
|
801
821
|
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_WRITEMAP;
|
802
|
-
opt = rb_hash_aref( opts, ID2SYM( rb_intern("no_threadlocal") ) );
|
803
|
-
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NOTLS;
|
804
|
-
opt = rb_hash_aref( opts, ID2SYM( rb_intern("no_readahead") ) );
|
805
|
-
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NORDAHEAD;
|
806
|
-
opt = rb_hash_aref( opts, ID2SYM( rb_intern("no_memory_init") ) );
|
807
|
-
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NOMEMINIT;
|
808
|
-
opt = rb_hash_aref( opts, ID2SYM( rb_intern("coalesce") ) );
|
809
|
-
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_COALESCE;
|
810
|
-
opt = rb_hash_aref( opts, ID2SYM( rb_intern("lifo_reclaim") ) );
|
811
|
-
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_LIFORECLAIM;
|
812
|
-
opt = rb_hash_aref( opts, ID2SYM( rb_intern("no_metasync") ) );
|
813
|
-
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NOMETASYNC;
|
814
822
|
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
/* Set instance variables.
|
819
|
-
*/
|
820
|
-
rb_iv_set( self, "@path", path );
|
821
|
-
rb_iv_set( self, "@options", opts );
|
823
|
+
if ( rb_hash_size_num(opts) > 0 ) {
|
824
|
+
rb_raise( rb_eArgError, "Unknown option(s): %"PRIsVALUE, opts );
|
825
|
+
}
|
822
826
|
|
823
827
|
rmdbx_open_env( self );
|
824
828
|
return self;
|
825
829
|
}
|
826
830
|
|
827
831
|
|
832
|
+
/*
|
833
|
+
* call-seq:
|
834
|
+
* db.statistics => (hash of stats)
|
835
|
+
*
|
836
|
+
* Returns a hash populated with various metadata for the opened
|
837
|
+
* database.
|
838
|
+
*
|
839
|
+
*/
|
840
|
+
VALUE
|
841
|
+
rmdbx_stats( VALUE self )
|
842
|
+
{
|
843
|
+
UNWRAP_DB( self, db );
|
844
|
+
CHECK_HANDLE();
|
845
|
+
|
846
|
+
return rmdbx_gather_stats( db );
|
847
|
+
}
|
848
|
+
|
849
|
+
|
828
850
|
/*
|
829
851
|
* call-seq:
|
830
852
|
* db.clone => [copy of db]
|
@@ -874,17 +896,19 @@ rmdbx_init_database()
|
|
874
896
|
rb_define_method( rmdbx_cDatabase, "close", rmdbx_close, 0 );
|
875
897
|
rb_define_method( rmdbx_cDatabase, "closed?", rmdbx_closed_p, 0 );
|
876
898
|
rb_define_method( rmdbx_cDatabase, "drop", rmdbx_drop, 1 );
|
877
|
-
rb_define_method( rmdbx_cDatabase, "each_key", rmdbx_each_key, 0 );
|
878
|
-
rb_define_method( rmdbx_cDatabase, "each_pair", rmdbx_each_pair, 0 );
|
879
|
-
rb_define_method( rmdbx_cDatabase, "each_value", rmdbx_each_value, 0 );
|
880
|
-
rb_define_method( rmdbx_cDatabase, "in_transaction?", rmdbx_in_transaction_p, 0 );
|
881
899
|
rb_define_method( rmdbx_cDatabase, "include?", rmdbx_include, 1 );
|
882
900
|
rb_define_method( rmdbx_cDatabase, "length", rmdbx_length, 0 );
|
883
901
|
rb_define_method( rmdbx_cDatabase, "reopen", rmdbx_open_env, 0 );
|
884
902
|
rb_define_method( rmdbx_cDatabase, "[]", rmdbx_get_val, 1 );
|
885
903
|
rb_define_method( rmdbx_cDatabase, "[]=", rmdbx_put_val, 2 );
|
886
904
|
|
905
|
+
/* Enumerables */
|
906
|
+
rb_define_method( rmdbx_cDatabase, "each_key", rmdbx_each_key, 0 );
|
907
|
+
rb_define_method( rmdbx_cDatabase, "each_pair", rmdbx_each_pair, 0 );
|
908
|
+
rb_define_method( rmdbx_cDatabase, "each_value", rmdbx_each_value, 0 );
|
909
|
+
|
887
910
|
/* Manually open/close transactions from ruby. */
|
911
|
+
rb_define_method( rmdbx_cDatabase, "in_transaction?", rmdbx_in_transaction_p, 0 );
|
888
912
|
rb_define_protected_method( rmdbx_cDatabase, "open_transaction", rmdbx_rb_opentxn, 1 );
|
889
913
|
rb_define_protected_method( rmdbx_cDatabase, "close_transaction", rmdbx_rb_closetxn, 1 );
|
890
914
|
|
@@ -897,3 +921,4 @@ rmdbx_init_database()
|
|
897
921
|
rb_require( "mdbx/database" );
|
898
922
|
}
|
899
923
|
|
924
|
+
|