mdbx 0.2.0 → 0.3.3
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/History.md +67 -0
- data/README.md +0 -7
- data/ext/mdbx_ext/database.c +482 -354
- data/ext/mdbx_ext/mdbx_ext.c +54 -0
- data/ext/mdbx_ext/mdbx_ext.h +36 -7
- data/ext/mdbx_ext/stats.c +39 -7
- data/lib/mdbx/database.rb +101 -43
- data/lib/mdbx.rb +8 -1
- data.tar.gz.sig +0 -0
- metadata +16 -2
- metadata.gz.sig +0 -0
data/ext/mdbx_ext/database.c
CHANGED
@@ -1,18 +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
6
|
|
7
|
+
#include "mdbx_ext.h"
|
11
8
|
|
12
9
|
VALUE rmdbx_cDatabase;
|
13
10
|
|
11
|
+
|
14
12
|
/*
|
15
|
-
* Ruby allocation
|
13
|
+
* Ruby data allocation wrapper.
|
16
14
|
*/
|
17
15
|
static const rb_data_type_t rmdbx_db_data = {
|
18
16
|
.wrap_struct_name = "MDBX::Database::Data",
|
@@ -27,11 +25,24 @@ static const rb_data_type_t rmdbx_db_data = {
|
|
27
25
|
VALUE
|
28
26
|
rmdbx_alloc( VALUE klass )
|
29
27
|
{
|
30
|
-
rmdbx_db_t *new
|
28
|
+
rmdbx_db_t *new;
|
31
29
|
return TypedData_Make_Struct( klass, rmdbx_db_t, &rmdbx_db_data, new );
|
32
30
|
}
|
33
31
|
|
34
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
|
+
|
35
46
|
/*
|
36
47
|
* Ensure all database file descriptors are collected and
|
37
48
|
* removed.
|
@@ -62,19 +73,9 @@ rmdbx_close_dbi( rmdbx_db_t *db )
|
|
62
73
|
|
63
74
|
|
64
75
|
/*
|
65
|
-
*
|
66
|
-
|
67
|
-
|
68
|
-
rmdbx_free( void *db )
|
69
|
-
{
|
70
|
-
if ( db ) {
|
71
|
-
rmdbx_close_all( db );
|
72
|
-
xfree( db );
|
73
|
-
}
|
74
|
-
}
|
75
|
-
|
76
|
-
|
77
|
-
/*
|
76
|
+
* call-seq:
|
77
|
+
* db.close => true
|
78
|
+
*
|
78
79
|
* Cleanly close an opened database.
|
79
80
|
*/
|
80
81
|
VALUE
|
@@ -101,17 +102,45 @@ rmdbx_closed_p( VALUE self )
|
|
101
102
|
|
102
103
|
|
103
104
|
/*
|
104
|
-
*
|
105
|
-
|
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.
|
106
118
|
*
|
107
|
-
* Predicate: return true if a transaction (or snapshot)
|
108
|
-
* is currently open.
|
109
119
|
*/
|
110
|
-
|
111
|
-
|
120
|
+
void
|
121
|
+
rmdbx_key_for( VALUE key, MDBX_val *ckey )
|
112
122
|
{
|
113
|
-
|
114
|
-
|
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
|
+
memcpy( ckey->iov_base, StringValuePtr(key_str), ckey->iov_len );
|
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
|
+
val = rb_funcall( self, rb_intern("serialize"), 1, val );
|
139
|
+
Check_Type( val, T_STRING );
|
140
|
+
|
141
|
+
data->iov_len = RSTRING_LEN( val );
|
142
|
+
data->iov_base = malloc( data->iov_len );
|
143
|
+
memcpy( data->iov_base, StringValuePtr(val), data->iov_len );
|
115
144
|
}
|
116
145
|
|
117
146
|
|
@@ -148,28 +177,286 @@ rmdbx_open_env( VALUE self )
|
|
148
177
|
rmdbx_close_all( db );
|
149
178
|
rb_raise( rmdbx_eDatabaseError, "mdbx_env_open: (%d) %s", rc, mdbx_strerror(rc) );
|
150
179
|
}
|
151
|
-
db->state.open = 1;
|
152
180
|
|
181
|
+
db->state.open = 1;
|
153
182
|
return Qtrue;
|
154
183
|
}
|
155
184
|
|
156
185
|
|
157
186
|
/*
|
158
|
-
*
|
187
|
+
* call-seq:
|
188
|
+
* db.clear
|
189
|
+
*
|
190
|
+
* Empty the current collection on disk. If collections are not enabled
|
191
|
+
* or the database handle is set to the top-level (main) db - this
|
192
|
+
* deletes *all records* from the database.
|
159
193
|
*/
|
160
|
-
|
161
|
-
|
194
|
+
VALUE
|
195
|
+
rmdbx_clear( VALUE self )
|
162
196
|
{
|
163
|
-
|
164
|
-
if ( ! db->txn ) rb_raise( rmdbx_eDatabaseError, "No snapshot or transaction currently open." );
|
197
|
+
UNWRAP_DB( self, db );
|
165
198
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
199
|
+
rmdbx_open_txn( db, MDBX_TXN_READWRITE );
|
200
|
+
int rc = mdbx_drop( db->txn, db->dbi, false );
|
201
|
+
|
202
|
+
if ( rc != MDBX_SUCCESS )
|
203
|
+
rb_raise( rmdbx_eDatabaseError, "mdbx_drop: (%d) %s", rc, mdbx_strerror(rc) );
|
204
|
+
|
205
|
+
rmdbx_close_txn( db, RMDBX_TXN_COMMIT );
|
206
|
+
|
207
|
+
return Qnil;
|
208
|
+
}
|
209
|
+
|
210
|
+
|
211
|
+
/*
|
212
|
+
* call-seq:
|
213
|
+
* db.drop( collection ) -> db
|
214
|
+
*
|
215
|
+
* Destroy a collection. You must be in the top level database to call
|
216
|
+
* this method.
|
217
|
+
*/
|
218
|
+
VALUE
|
219
|
+
rmdbx_drop( VALUE self, VALUE name )
|
220
|
+
{
|
221
|
+
UNWRAP_DB( self, db );
|
222
|
+
|
223
|
+
/* Provide a friendlier error message if max_collections is 0. */
|
224
|
+
if ( db->settings.max_collections == 0 )
|
225
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to drop collection: collections are not enabled." );
|
226
|
+
|
227
|
+
/* All transactions must be closed when dropping a database. */
|
228
|
+
if ( db->txn )
|
229
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to drop collection: transaction open" );
|
230
|
+
|
231
|
+
/* A drop can only be performed from the top-level database. */
|
232
|
+
if ( db->subdb != NULL )
|
233
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to drop collection: switch to top-level db first" );
|
234
|
+
|
235
|
+
name = rb_funcall( name, rb_intern("to_s"), 0 );
|
236
|
+
db->subdb = StringValueCStr( name );
|
237
|
+
|
238
|
+
rmdbx_close_dbi( db ); /* ensure we're reopening within the new subdb */
|
239
|
+
rmdbx_open_txn( db, MDBX_TXN_READWRITE );
|
240
|
+
int rc = mdbx_drop( db->txn, db->dbi, true );
|
241
|
+
|
242
|
+
if ( rc != MDBX_SUCCESS )
|
243
|
+
rb_raise( rmdbx_eDatabaseError, "mdbx_drop: (%d) %s", rc, mdbx_strerror(rc) );
|
244
|
+
|
245
|
+
rmdbx_close_txn( db, RMDBX_TXN_COMMIT );
|
246
|
+
|
247
|
+
/* Reset the current collection to the top level. */
|
248
|
+
db->subdb = NULL;
|
249
|
+
rmdbx_close_dbi( db ); /* ensure next access is not in the defunct subdb */
|
250
|
+
|
251
|
+
return self;
|
252
|
+
}
|
253
|
+
|
254
|
+
|
255
|
+
/* call-seq:
|
256
|
+
* db.length -> Integer
|
257
|
+
*
|
258
|
+
* Returns the count of keys in the currently selected collection.
|
259
|
+
*/
|
260
|
+
VALUE
|
261
|
+
rmdbx_length( VALUE self )
|
262
|
+
{
|
263
|
+
UNWRAP_DB( self, db );
|
264
|
+
MDBX_stat mstat;
|
265
|
+
|
266
|
+
CHECK_HANDLE();
|
267
|
+
rmdbx_open_txn( db, MDBX_TXN_RDONLY );
|
268
|
+
|
269
|
+
int rc = mdbx_dbi_stat( db->txn, db->dbi, &mstat, sizeof(mstat) );
|
270
|
+
if ( rc != MDBX_SUCCESS )
|
271
|
+
rb_raise( rmdbx_eDatabaseError, "mdbx_dbi_stat: (%d) %s", rc, mdbx_strerror(rc) );
|
272
|
+
|
273
|
+
VALUE rv = LONG2FIX( mstat.ms_entries );
|
274
|
+
rmdbx_close_txn( db, RMDBX_TXN_ROLLBACK );
|
275
|
+
|
276
|
+
return rv;
|
277
|
+
}
|
278
|
+
|
279
|
+
|
280
|
+
/* call-seq:
|
281
|
+
* db.include?( 'key' ) => bool
|
282
|
+
*
|
283
|
+
* Returns true if the current collection contains +key+.
|
284
|
+
*/
|
285
|
+
VALUE
|
286
|
+
rmdbx_include( VALUE self, VALUE key )
|
287
|
+
{
|
288
|
+
UNWRAP_DB( self, db );
|
289
|
+
|
290
|
+
CHECK_HANDLE();
|
291
|
+
rmdbx_open_txn( db, MDBX_TXN_RDONLY );
|
292
|
+
|
293
|
+
MDBX_val ckey;
|
294
|
+
MDBX_val data;
|
295
|
+
rmdbx_key_for( key, &ckey );
|
296
|
+
|
297
|
+
int rc = mdbx_get( db->txn, db->dbi, &ckey, &data );
|
298
|
+
rmdbx_close_txn( db, RMDBX_TXN_ROLLBACK );
|
299
|
+
xfree( ckey.iov_base );
|
300
|
+
|
301
|
+
switch ( rc ) {
|
302
|
+
case MDBX_SUCCESS:
|
303
|
+
return Qtrue;
|
304
|
+
|
305
|
+
case MDBX_NOTFOUND:
|
306
|
+
return Qfalse;
|
307
|
+
|
308
|
+
default:
|
309
|
+
rmdbx_close( self );
|
310
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to fetch key: (%d) %s", rc, mdbx_strerror(rc) );
|
170
311
|
}
|
312
|
+
}
|
171
313
|
|
172
|
-
|
314
|
+
|
315
|
+
/* call-seq:
|
316
|
+
* db[ 'key' ] => value
|
317
|
+
*
|
318
|
+
* Return a single value for +key+ immediately.
|
319
|
+
*/
|
320
|
+
VALUE
|
321
|
+
rmdbx_get_val( VALUE self, VALUE key )
|
322
|
+
{
|
323
|
+
UNWRAP_DB( self, db );
|
324
|
+
|
325
|
+
CHECK_HANDLE();
|
326
|
+
rmdbx_open_txn( db, MDBX_TXN_RDONLY );
|
327
|
+
|
328
|
+
MDBX_val ckey;
|
329
|
+
MDBX_val data;
|
330
|
+
|
331
|
+
rmdbx_key_for( key, &ckey );
|
332
|
+
int rc = mdbx_get( db->txn, db->dbi, &ckey, &data );
|
333
|
+
rmdbx_close_txn( db, RMDBX_TXN_ROLLBACK );
|
334
|
+
xfree( ckey.iov_base );
|
335
|
+
|
336
|
+
VALUE rv;
|
337
|
+
switch ( rc ) {
|
338
|
+
case MDBX_SUCCESS:
|
339
|
+
rv = rb_str_new( data.iov_base, data.iov_len );
|
340
|
+
return rb_funcall( self, rb_intern("deserialize"), 1, rv );
|
341
|
+
|
342
|
+
case MDBX_NOTFOUND:
|
343
|
+
return Qnil;
|
344
|
+
|
345
|
+
default:
|
346
|
+
rmdbx_close( self );
|
347
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to fetch value: (%d) %s", rc, mdbx_strerror(rc) );
|
348
|
+
}
|
349
|
+
}
|
350
|
+
|
351
|
+
|
352
|
+
/* call-seq:
|
353
|
+
* db[ 'key' ] = value
|
354
|
+
*
|
355
|
+
* Set a single value for +key+. If the value is +nil+, the
|
356
|
+
* key is removed.
|
357
|
+
*/
|
358
|
+
VALUE
|
359
|
+
rmdbx_put_val( VALUE self, VALUE key, VALUE val )
|
360
|
+
{
|
361
|
+
int rc;
|
362
|
+
UNWRAP_DB( self, db );
|
363
|
+
|
364
|
+
CHECK_HANDLE();
|
365
|
+
rmdbx_open_txn( db, MDBX_TXN_READWRITE );
|
366
|
+
|
367
|
+
MDBX_val ckey;
|
368
|
+
rmdbx_key_for( key, &ckey );
|
369
|
+
|
370
|
+
if ( NIL_P(val) ) { /* remove if set to nil */
|
371
|
+
rc = mdbx_del( db->txn, db->dbi, &ckey, NULL );
|
372
|
+
}
|
373
|
+
else {
|
374
|
+
MDBX_val old;
|
375
|
+
MDBX_val data;
|
376
|
+
rmdbx_val_for( self, val, &data );
|
377
|
+
rc = mdbx_replace( db->txn, db->dbi, &ckey, &data, &old, 0 );
|
378
|
+
xfree( data.iov_base );
|
379
|
+
}
|
380
|
+
|
381
|
+
rmdbx_close_txn( db, RMDBX_TXN_COMMIT );
|
382
|
+
xfree( ckey.iov_base );
|
383
|
+
|
384
|
+
switch ( rc ) {
|
385
|
+
case MDBX_SUCCESS:
|
386
|
+
return val;
|
387
|
+
case MDBX_NOTFOUND:
|
388
|
+
return Qnil;
|
389
|
+
default:
|
390
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to update value: (%d) %s", rc, mdbx_strerror(rc) );
|
391
|
+
}
|
392
|
+
}
|
393
|
+
|
394
|
+
|
395
|
+
/*
|
396
|
+
* Return the currently selected collection, or +nil+ if at the
|
397
|
+
* top-level.
|
398
|
+
*/
|
399
|
+
VALUE
|
400
|
+
rmdbx_get_subdb( VALUE self )
|
401
|
+
{
|
402
|
+
UNWRAP_DB( self, db );
|
403
|
+
return ( db->subdb == NULL ) ? Qnil : rb_str_new_cstr( db->subdb );
|
404
|
+
}
|
405
|
+
|
406
|
+
|
407
|
+
/*
|
408
|
+
* Sets the current collection name for read/write operations.
|
409
|
+
*
|
410
|
+
*/
|
411
|
+
VALUE
|
412
|
+
rmdbx_set_subdb( VALUE self, VALUE name )
|
413
|
+
{
|
414
|
+
UNWRAP_DB( self, db );
|
415
|
+
|
416
|
+
/* Provide a friendlier error message if max_collections is 0. */
|
417
|
+
if ( db->settings.max_collections == 0 )
|
418
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to change collection: collections are not enabled." );
|
419
|
+
|
420
|
+
/* All transactions must be closed when switching database handles. */
|
421
|
+
if ( db->txn )
|
422
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to change collection: transaction open" );
|
423
|
+
|
424
|
+
xfree( db->subdb );
|
425
|
+
db->subdb = NULL;
|
426
|
+
|
427
|
+
if ( ! NIL_P(name) ) {
|
428
|
+
size_t len = RSTRING_LEN( name ) + 1;
|
429
|
+
db->subdb = malloc( len );
|
430
|
+
strlcpy( db->subdb, StringValuePtr(name), len );
|
431
|
+
rmdbx_log_obj( self, "debug", "setting subdb: %s", RSTRING_PTR(name) );
|
432
|
+
}
|
433
|
+
else {
|
434
|
+
rmdbx_log_obj( self, "debug", "clearing subdb" );
|
435
|
+
}
|
436
|
+
|
437
|
+
/* Reset the db handle and issue a single transaction to reify
|
438
|
+
the collection.
|
439
|
+
*/
|
440
|
+
rmdbx_close_dbi( db );
|
441
|
+
rmdbx_open_txn( db, MDBX_TXN_READWRITE );
|
442
|
+
rmdbx_close_txn( db, RMDBX_TXN_COMMIT );
|
443
|
+
|
444
|
+
return self;
|
445
|
+
}
|
446
|
+
|
447
|
+
|
448
|
+
/*
|
449
|
+
* call-seq:
|
450
|
+
* db.in_transaction? => false
|
451
|
+
*
|
452
|
+
* Predicate: return true if a transaction (or snapshot)
|
453
|
+
* is currently open.
|
454
|
+
*/
|
455
|
+
VALUE
|
456
|
+
rmdbx_in_transaction_p( VALUE self )
|
457
|
+
{
|
458
|
+
UNWRAP_DB( self, db );
|
459
|
+
return db->txn ? Qtrue : Qfalse;
|
173
460
|
}
|
174
461
|
|
175
462
|
|
@@ -191,8 +478,7 @@ rmdbx_open_txn( rmdbx_db_t *db, int rwflag )
|
|
191
478
|
}
|
192
479
|
|
193
480
|
if ( db->dbi == 0 ) {
|
194
|
-
|
195
|
-
rc = mdbx_dbi_open( db->txn, db->subdb, MDBX_CREATE, &db->dbi );
|
481
|
+
rc = mdbx_dbi_open( db->txn, db->subdb, db->settings.db_flags, &db->dbi );
|
196
482
|
if ( rc != MDBX_SUCCESS ) {
|
197
483
|
rmdbx_close_all( db );
|
198
484
|
rb_raise( rmdbx_eDatabaseError, "mdbx_dbi_open: (%d) %s", rc, mdbx_strerror(rc) );
|
@@ -215,11 +501,11 @@ rmdbx_close_txn( rmdbx_db_t *db, int txnflag )
|
|
215
501
|
{
|
216
502
|
if ( ! db->txn || db->state.retain_txn > -1 ) return;
|
217
503
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
504
|
+
if ( txnflag == RMDBX_TXN_COMMIT ) {
|
505
|
+
mdbx_txn_commit( db->txn );
|
506
|
+
}
|
507
|
+
else {
|
508
|
+
mdbx_txn_abort( db->txn );
|
223
509
|
}
|
224
510
|
|
225
511
|
db->txn = 0;
|
@@ -239,6 +525,7 @@ VALUE
|
|
239
525
|
rmdbx_rb_opentxn( VALUE self, VALUE mode )
|
240
526
|
{
|
241
527
|
UNWRAP_DB( self, db );
|
528
|
+
CHECK_HANDLE();
|
242
529
|
|
243
530
|
rmdbx_open_txn( db, RTEST(mode) ? MDBX_TXN_READWRITE : MDBX_TXN_RDONLY );
|
244
531
|
db->state.retain_txn = RTEST(mode) ? 1 : 0;
|
@@ -255,114 +542,46 @@ rmdbx_rb_opentxn( VALUE self, VALUE mode )
|
|
255
542
|
* the transaction is committed. Otherwise, rolled back.
|
256
543
|
*
|
257
544
|
*/
|
258
|
-
VALUE
|
259
|
-
rmdbx_rb_closetxn( VALUE self, VALUE write )
|
260
|
-
{
|
261
|
-
UNWRAP_DB( self, db );
|
262
|
-
|
263
|
-
db->state.retain_txn = -1;
|
264
|
-
rmdbx_close_txn( db, RTEST(write) ? RMDBX_TXN_COMMIT : RMDBX_TXN_ROLLBACK );
|
265
|
-
|
266
|
-
return Qtrue;
|
267
|
-
}
|
268
|
-
|
269
|
-
|
270
|
-
/*
|
271
|
-
* call-seq:
|
272
|
-
* db.clear
|
273
|
-
*
|
274
|
-
* Empty the current collection on disk. If collections are not enabled
|
275
|
-
* or the database handle is set to the top-level (main) db - this
|
276
|
-
* deletes *all records* from the database. This is not recoverable!
|
277
|
-
*/
|
278
|
-
VALUE
|
279
|
-
rmdbx_clear( VALUE self )
|
280
|
-
{
|
281
|
-
UNWRAP_DB( self, db );
|
282
|
-
|
283
|
-
rmdbx_open_txn( db, MDBX_TXN_READWRITE );
|
284
|
-
int rc = mdbx_drop( db->txn, db->dbi, true );
|
285
|
-
|
286
|
-
if ( rc != MDBX_SUCCESS )
|
287
|
-
rb_raise( rmdbx_eDatabaseError, "mdbx_drop: (%d) %s", rc, mdbx_strerror(rc) );
|
288
|
-
|
289
|
-
rmdbx_close_txn( db, RMDBX_TXN_COMMIT );
|
290
|
-
|
291
|
-
/* Refresh the environment handles. */
|
292
|
-
rmdbx_open_env( self );
|
293
|
-
|
294
|
-
return Qnil;
|
295
|
-
}
|
296
|
-
|
297
|
-
|
298
|
-
/*
|
299
|
-
* Given a ruby +arg+, convert and return a structure
|
300
|
-
* suitable for usage as a key for mdbx. All keys are explicitly
|
301
|
-
* converted to strings.
|
302
|
-
*/
|
303
|
-
MDBX_val
|
304
|
-
rmdbx_key_for( VALUE arg )
|
545
|
+
VALUE
|
546
|
+
rmdbx_rb_closetxn( VALUE self, VALUE write )
|
305
547
|
{
|
306
|
-
|
548
|
+
UNWRAP_DB( self, db );
|
307
549
|
|
308
|
-
|
309
|
-
|
310
|
-
rv.iov_base = StringValuePtr( arg );
|
550
|
+
db->state.retain_txn = -1;
|
551
|
+
rmdbx_close_txn( db, RTEST(write) ? RMDBX_TXN_COMMIT : RMDBX_TXN_ROLLBACK );
|
311
552
|
|
312
|
-
return
|
553
|
+
return Qtrue;
|
313
554
|
}
|
314
555
|
|
315
556
|
|
316
557
|
/*
|
317
|
-
*
|
318
|
-
* suitable for usage as a value for mdbx.
|
558
|
+
* Open a cursor for iteration.
|
319
559
|
*/
|
320
|
-
|
321
|
-
|
560
|
+
void
|
561
|
+
rmdbx_open_cursor( rmdbx_db_t *db )
|
322
562
|
{
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
serialize_proc = rb_iv_get( self, "@serializer" );
|
327
|
-
if ( ! NIL_P( serialize_proc ) )
|
328
|
-
arg = rb_funcall( serialize_proc, rb_intern("call"), 1, arg );
|
563
|
+
CHECK_HANDLE();
|
564
|
+
if ( ! db->txn ) rb_raise( rmdbx_eDatabaseError, "No snapshot or transaction currently open." );
|
329
565
|
|
330
|
-
|
331
|
-
|
566
|
+
int rc = mdbx_cursor_open( db->txn, db->dbi, &db->cursor );
|
567
|
+
if ( rc != MDBX_SUCCESS ) {
|
568
|
+
rmdbx_close_all( db );
|
569
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to open cursor: (%d) %s", rc, mdbx_strerror(rc) );
|
570
|
+
}
|
332
571
|
|
333
|
-
return
|
572
|
+
return;
|
334
573
|
}
|
335
574
|
|
336
575
|
|
337
576
|
/*
|
338
|
-
*
|
339
|
-
*/
|
340
|
-
VALUE
|
341
|
-
rmdbx_deserialize( VALUE self, VALUE val )
|
342
|
-
{
|
343
|
-
VALUE deserialize_proc = rb_iv_get( self, "@deserializer" );
|
344
|
-
if ( ! NIL_P( deserialize_proc ) )
|
345
|
-
val = rb_funcall( deserialize_proc, rb_intern("call"), 1, val );
|
346
|
-
|
347
|
-
return val;
|
348
|
-
}
|
349
|
-
|
350
|
-
|
351
|
-
/* call-seq:
|
352
|
-
* db.each_key {|key| block } => self
|
353
|
-
*
|
354
|
-
* Calls the block once for each key, returning self.
|
355
|
-
* A transaction must be opened prior to use.
|
577
|
+
* Enumerate over keys for the current collection.
|
356
578
|
*/
|
357
579
|
VALUE
|
358
|
-
|
580
|
+
rmdbx_each_key_i( VALUE self )
|
359
581
|
{
|
360
582
|
UNWRAP_DB( self, db );
|
361
583
|
MDBX_val key, data;
|
362
584
|
|
363
|
-
rmdbx_open_cursor( db );
|
364
|
-
RETURN_ENUMERATOR( self, 0, 0 );
|
365
|
-
|
366
585
|
if ( mdbx_cursor_get( db->cursor, &key, &data, MDBX_FIRST ) == MDBX_SUCCESS ) {
|
367
586
|
rb_yield( rb_str_new( key.iov_base, key.iov_len ) );
|
368
587
|
while ( mdbx_cursor_get( db->cursor, &key, &data, MDBX_NEXT ) == MDBX_SUCCESS ) {
|
@@ -370,258 +589,135 @@ rmdbx_each_key( VALUE self )
|
|
370
589
|
}
|
371
590
|
}
|
372
591
|
|
373
|
-
mdbx_cursor_close( db->cursor );
|
374
|
-
db->cursor = NULL;
|
375
592
|
return self;
|
376
593
|
}
|
377
594
|
|
378
595
|
|
379
596
|
/* call-seq:
|
380
|
-
* db.
|
597
|
+
* db.each_key {|key| block } => self
|
381
598
|
*
|
382
|
-
* Calls the block once for each
|
599
|
+
* Calls the block once for each key, returning self.
|
383
600
|
* A transaction must be opened prior to use.
|
384
601
|
*/
|
385
602
|
VALUE
|
386
|
-
|
603
|
+
rmdbx_each_key( VALUE self )
|
387
604
|
{
|
388
605
|
UNWRAP_DB( self, db );
|
389
|
-
|
606
|
+
int state;
|
390
607
|
|
608
|
+
CHECK_HANDLE();
|
391
609
|
rmdbx_open_cursor( db );
|
392
610
|
RETURN_ENUMERATOR( self, 0, 0 );
|
393
611
|
|
394
|
-
|
395
|
-
VALUE rv = rb_str_new( data.iov_base, data.iov_len );
|
396
|
-
rb_yield( rmdbx_deserialize( self, rv ) );
|
397
|
-
|
398
|
-
while ( mdbx_cursor_get( db->cursor, &key, &data, MDBX_NEXT ) == MDBX_SUCCESS ) {
|
399
|
-
rv = rb_str_new( data.iov_base, data.iov_len );
|
400
|
-
rb_yield( rmdbx_deserialize( self, rv ) );
|
401
|
-
}
|
402
|
-
}
|
612
|
+
rb_protect( rmdbx_each_key_i, self, &state );
|
403
613
|
|
404
614
|
mdbx_cursor_close( db->cursor );
|
405
615
|
db->cursor = NULL;
|
616
|
+
|
617
|
+
if ( state ) rb_jump_tag( state );
|
618
|
+
|
406
619
|
return self;
|
407
620
|
}
|
408
621
|
|
409
622
|
|
410
|
-
/*
|
411
|
-
* db.each_pair {|key, value| block } => self
|
412
|
-
*
|
413
|
-
* Calls the block once for each key and value, returning self.
|
414
|
-
* A transaction must be opened prior to use.
|
623
|
+
/* Enumerate over values for the current collection.
|
415
624
|
*/
|
416
625
|
VALUE
|
417
|
-
|
626
|
+
rmdbx_each_value_i( VALUE self )
|
418
627
|
{
|
419
628
|
UNWRAP_DB( self, db );
|
420
629
|
MDBX_val key, data;
|
421
630
|
|
422
|
-
rmdbx_open_cursor( db );
|
423
|
-
RETURN_ENUMERATOR( self, 0, 0 );
|
424
|
-
|
425
631
|
if ( mdbx_cursor_get( db->cursor, &key, &data, MDBX_FIRST ) == MDBX_SUCCESS ) {
|
426
|
-
VALUE
|
427
|
-
|
428
|
-
rb_yield( rb_assoc_new( rkey, rmdbx_deserialize( self, rval ) ) );
|
632
|
+
VALUE rv = rb_str_new( data.iov_base, data.iov_len );
|
633
|
+
rb_yield( rb_funcall( self, rb_intern("deserialize"), 1, rv ) );
|
429
634
|
|
430
635
|
while ( mdbx_cursor_get( db->cursor, &key, &data, MDBX_NEXT ) == MDBX_SUCCESS ) {
|
431
|
-
|
432
|
-
|
433
|
-
rb_yield( rb_assoc_new( rkey, rmdbx_deserialize( self, rval ) ) );
|
636
|
+
rv = rb_str_new( data.iov_base, data.iov_len );
|
637
|
+
rb_yield( rb_funcall( self, rb_intern("deserialize"), 1, rv ) );
|
434
638
|
}
|
435
639
|
}
|
436
640
|
|
437
|
-
mdbx_cursor_close( db->cursor );
|
438
|
-
db->cursor = NULL;
|
439
641
|
return self;
|
440
642
|
}
|
441
643
|
|
442
644
|
|
443
645
|
/* call-seq:
|
444
|
-
* db.
|
445
|
-
*
|
446
|
-
* Returns the count of keys in the currently selected collection.
|
447
|
-
*/
|
448
|
-
VALUE
|
449
|
-
rmdbx_length( VALUE self )
|
450
|
-
{
|
451
|
-
UNWRAP_DB( self, db );
|
452
|
-
MDBX_stat mstat;
|
453
|
-
|
454
|
-
if ( ! db->state.open ) rb_raise( rmdbx_eDatabaseError, "Closed database." );
|
455
|
-
rmdbx_open_txn( db, MDBX_TXN_RDONLY );
|
456
|
-
|
457
|
-
int rc = mdbx_dbi_stat( db->txn, db->dbi, &mstat, sizeof(mstat) );
|
458
|
-
if ( rc != MDBX_SUCCESS )
|
459
|
-
rb_raise( rmdbx_eDatabaseError, "mdbx_dbi_stat: (%d) %s", rc, mdbx_strerror(rc) );
|
460
|
-
|
461
|
-
VALUE rv = LONG2FIX( mstat.ms_entries );
|
462
|
-
rmdbx_close_txn( db, RMDBX_TXN_ROLLBACK );
|
463
|
-
|
464
|
-
return rv;
|
465
|
-
}
|
466
|
-
|
467
|
-
|
468
|
-
/* call-seq:
|
469
|
-
* db[ 'key' ] => value
|
646
|
+
* db.each_value {|value| block } => self
|
470
647
|
*
|
471
|
-
*
|
648
|
+
* Calls the block once for each value, returning self.
|
649
|
+
* A transaction must be opened prior to use.
|
472
650
|
*/
|
473
651
|
VALUE
|
474
|
-
|
652
|
+
rmdbx_each_value( VALUE self )
|
475
653
|
{
|
476
|
-
int rc;
|
477
654
|
UNWRAP_DB( self, db );
|
655
|
+
int state;
|
478
656
|
|
479
|
-
|
480
|
-
|
657
|
+
CHECK_HANDLE();
|
658
|
+
rmdbx_open_cursor( db );
|
659
|
+
RETURN_ENUMERATOR( self, 0, 0 );
|
481
660
|
|
482
|
-
|
483
|
-
MDBX_val data;
|
484
|
-
VALUE rv;
|
485
|
-
rc = mdbx_get( db->txn, db->dbi, &ckey, &data );
|
486
|
-
rmdbx_close_txn( db, RMDBX_TXN_ROLLBACK );
|
661
|
+
rb_protect( rmdbx_each_value_i, self, &state );
|
487
662
|
|
488
|
-
|
489
|
-
|
490
|
-
rv = rb_str_new( data.iov_base, data.iov_len );
|
491
|
-
return rmdbx_deserialize( self, rv );
|
663
|
+
mdbx_cursor_close( db->cursor );
|
664
|
+
db->cursor = NULL;
|
492
665
|
|
493
|
-
|
494
|
-
return Qnil;
|
666
|
+
if ( state ) rb_jump_tag( state );
|
495
667
|
|
496
|
-
|
497
|
-
rmdbx_close( self );
|
498
|
-
rb_raise( rmdbx_eDatabaseError, "Unable to fetch value: (%d) %s", rc, mdbx_strerror(rc) );
|
499
|
-
}
|
668
|
+
return self;
|
500
669
|
}
|
501
670
|
|
502
671
|
|
503
|
-
/*
|
504
|
-
* db[ 'key' ] = value
|
505
|
-
*
|
506
|
-
* Set a single value for +key+.
|
672
|
+
/* Enumerate over key and value pairs for the current collection.
|
507
673
|
*/
|
508
674
|
VALUE
|
509
|
-
|
675
|
+
rmdbx_each_pair_i( VALUE self )
|
510
676
|
{
|
511
|
-
int rc;
|
512
677
|
UNWRAP_DB( self, db );
|
678
|
+
MDBX_val key, data;
|
513
679
|
|
514
|
-
if (
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
// FIXME: DUPSORT is enabled -- different api?
|
520
|
-
// See: MDBX_NODUPDATA / MDBX_NOOVERWRITE
|
521
|
-
if ( NIL_P(val) ) { /* remove if set to nil */
|
522
|
-
rc = mdbx_del( db->txn, db->dbi, &ckey, NULL );
|
523
|
-
}
|
524
|
-
else {
|
525
|
-
MDBX_val old;
|
526
|
-
MDBX_val data = rmdbx_val_for( self, val );
|
527
|
-
rc = mdbx_replace( db->txn, db->dbi, &ckey, &data, &old, 0 );
|
528
|
-
}
|
680
|
+
if ( mdbx_cursor_get( db->cursor, &key, &data, MDBX_FIRST ) == MDBX_SUCCESS ) {
|
681
|
+
VALUE rkey = rb_str_new( key.iov_base, key.iov_len );
|
682
|
+
VALUE rval = rb_str_new( data.iov_base, data.iov_len );
|
683
|
+
rval = rb_funcall( self, rb_intern("deserialize"), 1, rval );
|
684
|
+
rb_yield( rb_assoc_new( rkey, rval ) );
|
529
685
|
|
530
|
-
|
686
|
+
while ( mdbx_cursor_get( db->cursor, &key, &data, MDBX_NEXT ) == MDBX_SUCCESS ) {
|
687
|
+
rkey = rb_str_new( key.iov_base, key.iov_len );
|
688
|
+
rval = rb_str_new( data.iov_base, data.iov_len );
|
689
|
+
rval = rb_funcall( self, rb_intern("deserialize"), 1, rval );
|
531
690
|
|
532
|
-
|
533
|
-
|
534
|
-
return val;
|
535
|
-
case MDBX_NOTFOUND:
|
536
|
-
return Qnil;
|
537
|
-
default:
|
538
|
-
rb_raise( rmdbx_eDatabaseError, "Unable to store value: (%d) %s", rc, mdbx_strerror(rc) );
|
691
|
+
rb_yield( rb_assoc_new( rkey, rval ) );
|
692
|
+
}
|
539
693
|
}
|
540
|
-
}
|
541
|
-
|
542
|
-
|
543
|
-
/*
|
544
|
-
* call-seq:
|
545
|
-
* db.statistics => (hash of stats)
|
546
|
-
*
|
547
|
-
* Returns a hash populated with various metadata for the opened
|
548
|
-
* database.
|
549
|
-
*
|
550
|
-
*/
|
551
|
-
VALUE
|
552
|
-
rmdbx_stats( VALUE self )
|
553
|
-
{
|
554
|
-
UNWRAP_DB( self, db );
|
555
|
-
if ( ! db->state.open ) rb_raise( rmdbx_eDatabaseError, "Closed database." );
|
556
694
|
|
557
|
-
return
|
695
|
+
return self;
|
558
696
|
}
|
559
697
|
|
560
698
|
|
561
|
-
/*
|
562
|
-
*
|
563
|
-
* db.collection -> (collection name, or nil if in main)
|
564
|
-
* db.collection( 'collection_name' ) -> db
|
565
|
-
* db.collection( nil ) -> db (main)
|
566
|
-
*
|
567
|
-
* Gets or sets the sub-database "collection" that read/write
|
568
|
-
* operations apply to.
|
569
|
-
* Passing +nil+ sets the database to the main, top-level namespace.
|
570
|
-
* If a block is passed, the collection automatically reverts to the
|
571
|
-
* prior collection when it exits.
|
572
|
-
*
|
573
|
-
* db.collection( 'collection_name' ) do
|
574
|
-
* [ ... ]
|
575
|
-
* end # reverts to the previous collection name
|
699
|
+
/* call-seq:
|
700
|
+
* db.each_pair {|key, value| block } => self
|
576
701
|
*
|
702
|
+
* Calls the block once for each key and value, returning self.
|
703
|
+
* A transaction must be opened prior to use.
|
577
704
|
*/
|
578
705
|
VALUE
|
579
|
-
|
706
|
+
rmdbx_each_pair( VALUE self )
|
580
707
|
{
|
581
708
|
UNWRAP_DB( self, db );
|
582
|
-
|
583
|
-
char *prev_db = NULL;
|
709
|
+
int state;
|
584
710
|
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
return rb_str_new_cstr( db->subdb );
|
589
|
-
}
|
590
|
-
|
591
|
-
/* Provide a friendlier error message if max_collections is 0. */
|
592
|
-
if ( db->settings.max_collections == 0 )
|
593
|
-
rb_raise( rmdbx_eDatabaseError, "Unable to change collection: collections are not enabled." );
|
594
|
-
|
595
|
-
/* All transactions must be closed when switching database handles. */
|
596
|
-
if ( db->txn )
|
597
|
-
rb_raise( rmdbx_eDatabaseError, "Unable to change collection: transaction open" );
|
598
|
-
|
599
|
-
/* Retain the prior database collection if a block was passed.
|
600
|
-
*/
|
601
|
-
if ( rb_block_given_p() && db->subdb != NULL ) {
|
602
|
-
prev_db = (char *) malloc( strlen(db->subdb) + 1 );
|
603
|
-
strcpy( prev_db, db->subdb );
|
604
|
-
}
|
711
|
+
CHECK_HANDLE();
|
712
|
+
rmdbx_open_cursor( db );
|
713
|
+
RETURN_ENUMERATOR( self, 0, 0 );
|
605
714
|
|
606
|
-
|
607
|
-
rmdbx_close_dbi( db );
|
715
|
+
rb_protect( rmdbx_each_pair_i, self, &state );
|
608
716
|
|
609
|
-
|
610
|
-
|
611
|
-
Fetching from here at the moment causes an error if you
|
612
|
-
haven't written anything to the new collection yet.
|
613
|
-
*/
|
717
|
+
mdbx_cursor_close( db->cursor );
|
718
|
+
db->cursor = NULL;
|
614
719
|
|
615
|
-
|
616
|
-
*/
|
617
|
-
if ( rb_block_given_p() ) {
|
618
|
-
rb_yield( self );
|
619
|
-
if ( db->subdb != prev_db ) {
|
620
|
-
db->subdb = prev_db;
|
621
|
-
rmdbx_close_dbi( db );
|
622
|
-
}
|
623
|
-
xfree( prev_db );
|
624
|
-
}
|
720
|
+
if ( state ) rb_jump_tag( state );
|
625
721
|
|
626
722
|
return self;
|
627
723
|
}
|
@@ -666,57 +762,80 @@ rmdbx_database_initialize( int argc, VALUE *argv, VALUE self )
|
|
666
762
|
db->state.open = 0;
|
667
763
|
db->state.retain_txn = -1;
|
668
764
|
db->settings.env_flags = MDBX_ENV_DEFAULTS;
|
765
|
+
db->settings.db_flags = MDBX_DB_DEFAULTS | MDBX_CREATE;
|
669
766
|
db->settings.mode = 0644;
|
670
767
|
db->settings.max_collections = 0;
|
671
768
|
db->settings.max_readers = 0;
|
672
769
|
db->settings.max_size = 0;
|
673
770
|
|
674
|
-
/*
|
771
|
+
/* Set instance variables.
|
675
772
|
*/
|
676
|
-
|
677
|
-
|
678
|
-
|
773
|
+
rb_iv_set( self, "@path", path );
|
774
|
+
rb_iv_set( self, "@options", rb_hash_dup( opts ) );
|
775
|
+
|
776
|
+
/* Environment and database options setup, overrides.
|
777
|
+
*/
|
778
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("coalesce") ) );
|
779
|
+
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_COALESCE;
|
780
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("compatible") ) );
|
781
|
+
if ( RTEST(opt) ) {
|
782
|
+
db->settings.db_flags = db->settings.db_flags | MDBX_DB_ACCEDE;
|
783
|
+
db->settings.env_flags = db->settings.env_flags | MDBX_ACCEDE;
|
784
|
+
}
|
785
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("exclusive") ) );
|
786
|
+
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_EXCLUSIVE;
|
787
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("lifo_reclaim") ) );
|
788
|
+
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_LIFORECLAIM;
|
789
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("max_collections") ) );
|
679
790
|
if ( ! NIL_P(opt) ) db->settings.max_collections = FIX2INT( opt );
|
680
|
-
opt =
|
791
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("max_readers") ) );
|
681
792
|
if ( ! NIL_P(opt) ) db->settings.max_readers = FIX2INT( opt );
|
682
|
-
opt =
|
793
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("max_size") ) );
|
683
794
|
if ( ! NIL_P(opt) ) db->settings.max_size = NUM2LONG( opt );
|
684
|
-
opt =
|
795
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("mode") ) );
|
796
|
+
if ( ! NIL_P(opt) ) db->settings.mode = FIX2INT( opt );
|
797
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("no_memory_init") ) );
|
798
|
+
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NOMEMINIT;
|
799
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("no_metasync") ) );
|
800
|
+
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NOMETASYNC;
|
801
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("no_subdir") ) );
|
685
802
|
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NOSUBDIR;
|
686
|
-
opt =
|
803
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("no_readahead") ) );
|
804
|
+
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NORDAHEAD;
|
805
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("no_threadlocal") ) );
|
806
|
+
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NOTLS;
|
807
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("readonly") ) );
|
687
808
|
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_RDONLY;
|
688
|
-
opt =
|
689
|
-
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_EXCLUSIVE;
|
690
|
-
opt = rb_hash_aref( opts, ID2SYM( rb_intern("compat") ) );
|
691
|
-
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_ACCEDE;
|
692
|
-
opt = rb_hash_aref( opts, ID2SYM( rb_intern("writemap") ) );
|
809
|
+
opt = rb_hash_delete( opts, ID2SYM( rb_intern("writemap") ) );
|
693
810
|
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_WRITEMAP;
|
694
|
-
opt = rb_hash_aref( opts, ID2SYM( rb_intern("no_threadlocal") ) );
|
695
|
-
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NOTLS;
|
696
|
-
opt = rb_hash_aref( opts, ID2SYM( rb_intern("no_readahead") ) );
|
697
|
-
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NORDAHEAD;
|
698
|
-
opt = rb_hash_aref( opts, ID2SYM( rb_intern("no_memory_init") ) );
|
699
|
-
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NOMEMINIT;
|
700
|
-
opt = rb_hash_aref( opts, ID2SYM( rb_intern("coalesce") ) );
|
701
|
-
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_COALESCE;
|
702
|
-
opt = rb_hash_aref( opts, ID2SYM( rb_intern("lifo_reclaim") ) );
|
703
|
-
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_LIFORECLAIM;
|
704
|
-
opt = rb_hash_aref( opts, ID2SYM( rb_intern("no_metasync") ) );
|
705
|
-
if ( RTEST(opt) ) db->settings.env_flags = db->settings.env_flags | MDBX_NOMETASYNC;
|
706
811
|
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
/* Set instance variables.
|
711
|
-
*/
|
712
|
-
rb_iv_set( self, "@path", path );
|
713
|
-
rb_iv_set( self, "@options", opts );
|
812
|
+
if ( rb_hash_size_num(opts) > 0 ) {
|
813
|
+
rb_raise( rb_eArgError, "Unknown option(s): %"PRIsVALUE, opts );
|
814
|
+
}
|
714
815
|
|
715
816
|
rmdbx_open_env( self );
|
716
817
|
return self;
|
717
818
|
}
|
718
819
|
|
719
820
|
|
821
|
+
/*
|
822
|
+
* call-seq:
|
823
|
+
* db.statistics => (hash of stats)
|
824
|
+
*
|
825
|
+
* Returns a hash populated with various metadata for the opened
|
826
|
+
* database.
|
827
|
+
*
|
828
|
+
*/
|
829
|
+
VALUE
|
830
|
+
rmdbx_stats( VALUE self )
|
831
|
+
{
|
832
|
+
UNWRAP_DB( self, db );
|
833
|
+
CHECK_HANDLE();
|
834
|
+
|
835
|
+
return rmdbx_gather_stats( db );
|
836
|
+
}
|
837
|
+
|
838
|
+
|
720
839
|
/*
|
721
840
|
* call-seq:
|
722
841
|
* db.clone => [copy of db]
|
@@ -761,25 +880,34 @@ rmdbx_init_database()
|
|
761
880
|
|
762
881
|
rb_define_protected_method( rmdbx_cDatabase, "initialize", rmdbx_database_initialize, -1 );
|
763
882
|
rb_define_protected_method( rmdbx_cDatabase, "initialize_copy", rmdbx_init_copy, 1 );
|
764
|
-
|
883
|
+
|
884
|
+
rb_define_method( rmdbx_cDatabase, "clear", rmdbx_clear, 0 );
|
765
885
|
rb_define_method( rmdbx_cDatabase, "close", rmdbx_close, 0 );
|
766
|
-
rb_define_method( rmdbx_cDatabase, "reopen", rmdbx_open_env, 0 );
|
767
886
|
rb_define_method( rmdbx_cDatabase, "closed?", rmdbx_closed_p, 0 );
|
768
|
-
rb_define_method( rmdbx_cDatabase, "
|
769
|
-
rb_define_method( rmdbx_cDatabase, "
|
770
|
-
rb_define_method( rmdbx_cDatabase, "each_key", rmdbx_each_key, 0 );
|
771
|
-
rb_define_method( rmdbx_cDatabase, "each_value", rmdbx_each_value, 0 );
|
772
|
-
rb_define_method( rmdbx_cDatabase, "each_pair", rmdbx_each_pair, 0 );
|
887
|
+
rb_define_method( rmdbx_cDatabase, "drop", rmdbx_drop, 1 );
|
888
|
+
rb_define_method( rmdbx_cDatabase, "include?", rmdbx_include, 1 );
|
773
889
|
rb_define_method( rmdbx_cDatabase, "length", rmdbx_length, 0 );
|
890
|
+
rb_define_method( rmdbx_cDatabase, "reopen", rmdbx_open_env, 0 );
|
774
891
|
rb_define_method( rmdbx_cDatabase, "[]", rmdbx_get_val, 1 );
|
775
892
|
rb_define_method( rmdbx_cDatabase, "[]=", rmdbx_put_val, 2 );
|
776
893
|
|
894
|
+
/* Enumerables */
|
895
|
+
rb_define_method( rmdbx_cDatabase, "each_key", rmdbx_each_key, 0 );
|
896
|
+
rb_define_method( rmdbx_cDatabase, "each_pair", rmdbx_each_pair, 0 );
|
897
|
+
rb_define_method( rmdbx_cDatabase, "each_value", rmdbx_each_value, 0 );
|
898
|
+
|
777
899
|
/* Manually open/close transactions from ruby. */
|
900
|
+
rb_define_method( rmdbx_cDatabase, "in_transaction?", rmdbx_in_transaction_p, 0 );
|
778
901
|
rb_define_protected_method( rmdbx_cDatabase, "open_transaction", rmdbx_rb_opentxn, 1 );
|
779
902
|
rb_define_protected_method( rmdbx_cDatabase, "close_transaction", rmdbx_rb_closetxn, 1 );
|
780
903
|
|
904
|
+
/* Collection functions */
|
905
|
+
rb_define_protected_method( rmdbx_cDatabase, "get_subdb", rmdbx_get_subdb, 0 );
|
906
|
+
rb_define_protected_method( rmdbx_cDatabase, "set_subdb", rmdbx_set_subdb, 1 );
|
907
|
+
|
781
908
|
rb_define_protected_method( rmdbx_cDatabase, "raw_stats", rmdbx_stats, 0 );
|
782
909
|
|
783
910
|
rb_require( "mdbx/database" );
|
784
911
|
}
|
785
912
|
|
913
|
+
|