mdbx 0.1.0 → 0.3.1
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 +46 -0
- data/ext/mdbx_ext/database.c +232 -89
- data/ext/mdbx_ext/stats.c +1 -1
- data/lib/mdbx.rb +1 -1
- data/lib/mdbx/database.rb +62 -17
- 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: 97a83bdd83e99ab3b58cf823a914c8a7b75b5b63e33e13cd00f135aa2c8988b4
|
4
|
+
data.tar.gz: aa6687110e91dfe083332fc93299c492ce5628ad41fe26cb36d9ee33531e1039
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 732ecf85ef600ae8edb433b18d67ecf26fbc1332fc673e7e01b20637dbcffff94735a8c1d79cc43c9d293cdda7b7532670f9a0c9f101234367b19aaac03149a9
|
7
|
+
data.tar.gz: 1623ff8c9d4b6e7752ef9faaf4075961119d812c7dfd78bb619fa74eaacb3e7fd1042b66b630e5638010478f61a0f3f232fa6cf2e1a37e40ef3d010a5c3257f6
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/History.md
CHANGED
@@ -1,6 +1,52 @@
|
|
1
1
|
# Release History for MDBX
|
2
2
|
|
3
3
|
---
|
4
|
+
## v0.3.0 [2021-04-09] Mahlon E. Smith <mahlon@martini.nu>
|
5
|
+
|
6
|
+
Enhancements:
|
7
|
+
|
8
|
+
- Alter the behavior of #clear, so it doesn't destroy collection
|
9
|
+
environments, but just empties them.
|
10
|
+
|
11
|
+
- Add #drop, which explictly -does- destroy a collection environment.
|
12
|
+
|
13
|
+
- Switching to a collection now automatically creates its environment.
|
14
|
+
|
15
|
+
- Add include? and has_key?, for presence checks without allocating
|
16
|
+
value memory or requiring deserialization.
|
17
|
+
|
18
|
+
|
19
|
+
Bugfixes:
|
20
|
+
|
21
|
+
- Run all cursor methods through rb_protect, to ensure proper
|
22
|
+
cursor cleanup in the event of an exception mid iteration.
|
23
|
+
|
24
|
+
- Fix the block form of collections to support multiple scopes.
|
25
|
+
|
26
|
+
|
27
|
+
## v0.2.1 [2021-04-06] Mahlon E. Smith <mahlon@martini.nu>
|
28
|
+
|
29
|
+
Enhancement:
|
30
|
+
|
31
|
+
- Automatically stringify any argument to the collection() method.
|
32
|
+
|
33
|
+
|
34
|
+
## v0.2.0 [2021-03-19] Mahlon E. Smith <mahlon@martini.nu>
|
35
|
+
|
36
|
+
Enhancement:
|
37
|
+
|
38
|
+
- Support dup/clone. This has limited use, as there can only
|
39
|
+
be one open handle per process, but implemented in the interests
|
40
|
+
of avoiding unexpected behavior.
|
41
|
+
|
42
|
+
|
43
|
+
## v0.1.1 [2021-03-14] Mahlon E. Smith <mahlon@martini.nu>
|
44
|
+
|
45
|
+
Bugfix:
|
46
|
+
|
47
|
+
- Don't inadvertantly close an open transaction while using hash convenience methods.
|
48
|
+
|
49
|
+
|
4
50
|
## v0.1.0 [2021-03-14] Mahlon E. Smith <mahlon@martini.nu>
|
5
51
|
|
6
52
|
Initial public release.
|
data/ext/mdbx_ext/database.c
CHANGED
@@ -6,7 +6,10 @@
|
|
6
6
|
*/
|
7
7
|
#define UNWRAP_DB( val, db ) \
|
8
8
|
rmdbx_db_t *db; \
|
9
|
-
TypedData_Get_Struct( val, rmdbx_db_t, &rmdbx_db_data, 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." )
|
10
13
|
|
11
14
|
|
12
15
|
VALUE rmdbx_cDatabase;
|
@@ -160,7 +163,7 @@ rmdbx_open_env( VALUE self )
|
|
160
163
|
void
|
161
164
|
rmdbx_open_cursor( rmdbx_db_t *db )
|
162
165
|
{
|
163
|
-
|
166
|
+
CHECK_HANDLE;
|
164
167
|
if ( ! db->txn ) rb_raise( rmdbx_eDatabaseError, "No snapshot or transaction currently open." );
|
165
168
|
|
166
169
|
int rc = mdbx_cursor_open( db->txn, db->dbi, &db->cursor );
|
@@ -215,11 +218,11 @@ rmdbx_close_txn( rmdbx_db_t *db, int txnflag )
|
|
215
218
|
{
|
216
219
|
if ( ! db->txn || db->state.retain_txn > -1 ) return;
|
217
220
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
221
|
+
if ( txnflag == RMDBX_TXN_COMMIT ) {
|
222
|
+
mdbx_txn_commit( db->txn );
|
223
|
+
}
|
224
|
+
else {
|
225
|
+
mdbx_txn_abort( db->txn );
|
223
226
|
}
|
224
227
|
|
225
228
|
db->txn = 0;
|
@@ -239,6 +242,7 @@ VALUE
|
|
239
242
|
rmdbx_rb_opentxn( VALUE self, VALUE mode )
|
240
243
|
{
|
241
244
|
UNWRAP_DB( self, db );
|
245
|
+
CHECK_HANDLE;
|
242
246
|
|
243
247
|
rmdbx_open_txn( db, RTEST(mode) ? MDBX_TXN_READWRITE : MDBX_TXN_RDONLY );
|
244
248
|
db->state.retain_txn = RTEST(mode) ? 1 : 0;
|
@@ -273,13 +277,53 @@ rmdbx_rb_closetxn( VALUE self, VALUE write )
|
|
273
277
|
*
|
274
278
|
* Empty the current collection on disk. If collections are not enabled
|
275
279
|
* or the database handle is set to the top-level (main) db - this
|
276
|
-
* deletes *all records* from the database.
|
280
|
+
* deletes *all records* from the database.
|
277
281
|
*/
|
278
282
|
VALUE
|
279
283
|
rmdbx_clear( VALUE self )
|
280
284
|
{
|
281
285
|
UNWRAP_DB( self, db );
|
282
286
|
|
287
|
+
rmdbx_open_txn( db, MDBX_TXN_READWRITE );
|
288
|
+
int rc = mdbx_drop( db->txn, db->dbi, false );
|
289
|
+
|
290
|
+
if ( rc != MDBX_SUCCESS )
|
291
|
+
rb_raise( rmdbx_eDatabaseError, "mdbx_drop: (%d) %s", rc, mdbx_strerror(rc) );
|
292
|
+
|
293
|
+
rmdbx_close_txn( db, RMDBX_TXN_COMMIT );
|
294
|
+
|
295
|
+
return Qnil;
|
296
|
+
}
|
297
|
+
|
298
|
+
|
299
|
+
/*
|
300
|
+
* call-seq:
|
301
|
+
* db.drop( collection ) -> db
|
302
|
+
*
|
303
|
+
* Destroy a collection. You must be in the top level database to call
|
304
|
+
* this method.
|
305
|
+
*/
|
306
|
+
VALUE
|
307
|
+
rmdbx_drop( VALUE self, VALUE name )
|
308
|
+
{
|
309
|
+
UNWRAP_DB( self, db );
|
310
|
+
|
311
|
+
/* Provide a friendlier error message if max_collections is 0. */
|
312
|
+
if ( db->settings.max_collections == 0 )
|
313
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to drop collection: collections are not enabled." );
|
314
|
+
|
315
|
+
/* All transactions must be closed when dropping a database. */
|
316
|
+
if ( db->txn )
|
317
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to drop collection: transaction open" );
|
318
|
+
|
319
|
+
/* A drop can only be performed from the top-level database. */
|
320
|
+
if ( db->subdb != NULL )
|
321
|
+
rb_raise( rmdbx_eDatabaseError, "Unable to drop collection: switch to top-level db first" );
|
322
|
+
|
323
|
+
name = rb_funcall( name, rb_intern("to_s"), 0 );
|
324
|
+
db->subdb = StringValueCStr( name );
|
325
|
+
|
326
|
+
rmdbx_close_dbi( db ); /* ensure we're reopening within the new subdb */
|
283
327
|
rmdbx_open_txn( db, MDBX_TXN_READWRITE );
|
284
328
|
int rc = mdbx_drop( db->txn, db->dbi, true );
|
285
329
|
|
@@ -288,10 +332,11 @@ rmdbx_clear( VALUE self )
|
|
288
332
|
|
289
333
|
rmdbx_close_txn( db, RMDBX_TXN_COMMIT );
|
290
334
|
|
291
|
-
/*
|
292
|
-
|
335
|
+
/* Reset the current collection to the top level. */
|
336
|
+
db->subdb = NULL;
|
337
|
+
rmdbx_close_dbi( db ); /* ensure next access is not in the defunct subdb */
|
293
338
|
|
294
|
-
return
|
339
|
+
return self;
|
295
340
|
}
|
296
341
|
|
297
342
|
|
@@ -348,21 +393,15 @@ rmdbx_deserialize( VALUE self, VALUE val )
|
|
348
393
|
}
|
349
394
|
|
350
395
|
|
351
|
-
/*
|
352
|
-
*
|
353
|
-
*
|
354
|
-
* Calls the block once for each key, returning self.
|
355
|
-
* A transaction must be opened prior to use.
|
396
|
+
/*
|
397
|
+
* Enumerate over keys for the current collection.
|
356
398
|
*/
|
357
399
|
VALUE
|
358
|
-
|
400
|
+
rmdbx_each_key_i( VALUE self )
|
359
401
|
{
|
360
402
|
UNWRAP_DB( self, db );
|
361
403
|
MDBX_val key, data;
|
362
404
|
|
363
|
-
rmdbx_open_cursor( db );
|
364
|
-
RETURN_ENUMERATOR( self, 0, 0 );
|
365
|
-
|
366
405
|
if ( mdbx_cursor_get( db->cursor, &key, &data, MDBX_FIRST ) == MDBX_SUCCESS ) {
|
367
406
|
rb_yield( rb_str_new( key.iov_base, key.iov_len ) );
|
368
407
|
while ( mdbx_cursor_get( db->cursor, &key, &data, MDBX_NEXT ) == MDBX_SUCCESS ) {
|
@@ -370,27 +409,45 @@ rmdbx_each_key( VALUE self )
|
|
370
409
|
}
|
371
410
|
}
|
372
411
|
|
373
|
-
mdbx_cursor_close( db->cursor );
|
374
|
-
db->cursor = NULL;
|
375
412
|
return self;
|
376
413
|
}
|
377
414
|
|
378
415
|
|
379
416
|
/* call-seq:
|
380
|
-
* db.
|
417
|
+
* db.each_key {|key| block } => self
|
381
418
|
*
|
382
|
-
* Calls the block once for each
|
419
|
+
* Calls the block once for each key, returning self.
|
383
420
|
* A transaction must be opened prior to use.
|
384
421
|
*/
|
385
422
|
VALUE
|
386
|
-
|
423
|
+
rmdbx_each_key( VALUE self )
|
387
424
|
{
|
388
425
|
UNWRAP_DB( self, db );
|
389
|
-
|
426
|
+
int state;
|
390
427
|
|
428
|
+
CHECK_HANDLE;
|
391
429
|
rmdbx_open_cursor( db );
|
392
430
|
RETURN_ENUMERATOR( self, 0, 0 );
|
393
431
|
|
432
|
+
rb_protect( rmdbx_each_key_i, self, &state );
|
433
|
+
|
434
|
+
mdbx_cursor_close( db->cursor );
|
435
|
+
db->cursor = NULL;
|
436
|
+
|
437
|
+
if ( state ) rb_jump_tag( state );
|
438
|
+
|
439
|
+
return self;
|
440
|
+
}
|
441
|
+
|
442
|
+
|
443
|
+
/* Enumerate over values for the current collection.
|
444
|
+
*/
|
445
|
+
VALUE
|
446
|
+
rmdbx_each_value_i( VALUE self )
|
447
|
+
{
|
448
|
+
UNWRAP_DB( self, db );
|
449
|
+
MDBX_val key, data;
|
450
|
+
|
394
451
|
if ( mdbx_cursor_get( db->cursor, &key, &data, MDBX_FIRST ) == MDBX_SUCCESS ) {
|
395
452
|
VALUE rv = rb_str_new( data.iov_base, data.iov_len );
|
396
453
|
rb_yield( rmdbx_deserialize( self, rv ) );
|
@@ -401,27 +458,45 @@ rmdbx_each_value( VALUE self )
|
|
401
458
|
}
|
402
459
|
}
|
403
460
|
|
404
|
-
mdbx_cursor_close( db->cursor );
|
405
|
-
db->cursor = NULL;
|
406
461
|
return self;
|
407
462
|
}
|
408
463
|
|
409
464
|
|
410
465
|
/* call-seq:
|
411
|
-
* db.
|
466
|
+
* db.each_value {|value| block } => self
|
412
467
|
*
|
413
|
-
* Calls the block once for each
|
468
|
+
* Calls the block once for each value, returning self.
|
414
469
|
* A transaction must be opened prior to use.
|
415
470
|
*/
|
416
471
|
VALUE
|
417
|
-
|
472
|
+
rmdbx_each_value( VALUE self )
|
418
473
|
{
|
419
474
|
UNWRAP_DB( self, db );
|
420
|
-
|
475
|
+
int state;
|
421
476
|
|
477
|
+
CHECK_HANDLE;
|
422
478
|
rmdbx_open_cursor( db );
|
423
479
|
RETURN_ENUMERATOR( self, 0, 0 );
|
424
480
|
|
481
|
+
rb_protect( rmdbx_each_value_i, self, &state );
|
482
|
+
|
483
|
+
mdbx_cursor_close( db->cursor );
|
484
|
+
db->cursor = NULL;
|
485
|
+
|
486
|
+
if ( state ) rb_jump_tag( state );
|
487
|
+
|
488
|
+
return self;
|
489
|
+
}
|
490
|
+
|
491
|
+
|
492
|
+
/* Enumerate over key and value pairs for the current collection.
|
493
|
+
*/
|
494
|
+
VALUE
|
495
|
+
rmdbx_each_pair_i( VALUE self )
|
496
|
+
{
|
497
|
+
UNWRAP_DB( self, db );
|
498
|
+
MDBX_val key, data;
|
499
|
+
|
425
500
|
if ( mdbx_cursor_get( db->cursor, &key, &data, MDBX_FIRST ) == MDBX_SUCCESS ) {
|
426
501
|
VALUE rkey = rb_str_new( key.iov_base, key.iov_len );
|
427
502
|
VALUE rval = rb_str_new( data.iov_base, data.iov_len );
|
@@ -434,12 +509,38 @@ rmdbx_each_pair( VALUE self )
|
|
434
509
|
}
|
435
510
|
}
|
436
511
|
|
512
|
+
return self;
|
513
|
+
}
|
514
|
+
|
515
|
+
|
516
|
+
/* call-seq:
|
517
|
+
* db.each_pair {|key, value| block } => self
|
518
|
+
*
|
519
|
+
* Calls the block once for each key and value, returning self.
|
520
|
+
* A transaction must be opened prior to use.
|
521
|
+
*/
|
522
|
+
VALUE
|
523
|
+
rmdbx_each_pair( VALUE self )
|
524
|
+
{
|
525
|
+
UNWRAP_DB( self, db );
|
526
|
+
int state;
|
527
|
+
|
528
|
+
CHECK_HANDLE;
|
529
|
+
rmdbx_open_cursor( db );
|
530
|
+
RETURN_ENUMERATOR( self, 0, 0 );
|
531
|
+
|
532
|
+
rb_protect( rmdbx_each_pair_i, self, &state );
|
533
|
+
|
437
534
|
mdbx_cursor_close( db->cursor );
|
438
535
|
db->cursor = NULL;
|
536
|
+
|
537
|
+
if ( state ) rb_jump_tag( state );
|
538
|
+
|
439
539
|
return self;
|
440
540
|
}
|
441
541
|
|
442
542
|
|
543
|
+
|
443
544
|
/* call-seq:
|
444
545
|
* db.length -> Integer
|
445
546
|
*
|
@@ -451,7 +552,7 @@ rmdbx_length( VALUE self )
|
|
451
552
|
UNWRAP_DB( self, db );
|
452
553
|
MDBX_stat mstat;
|
453
554
|
|
454
|
-
|
555
|
+
CHECK_HANDLE;
|
455
556
|
rmdbx_open_txn( db, MDBX_TXN_RDONLY );
|
456
557
|
|
457
558
|
int rc = mdbx_dbi_stat( db->txn, db->dbi, &mstat, sizeof(mstat) );
|
@@ -465,6 +566,39 @@ rmdbx_length( VALUE self )
|
|
465
566
|
}
|
466
567
|
|
467
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
|
+
|
468
602
|
/* call-seq:
|
469
603
|
* db[ 'key' ] => value
|
470
604
|
*
|
@@ -476,7 +610,7 @@ rmdbx_get_val( VALUE self, VALUE key )
|
|
476
610
|
int rc;
|
477
611
|
UNWRAP_DB( self, db );
|
478
612
|
|
479
|
-
|
613
|
+
CHECK_HANDLE;
|
480
614
|
rmdbx_open_txn( db, MDBX_TXN_RDONLY );
|
481
615
|
|
482
616
|
MDBX_val ckey = rmdbx_key_for( key );
|
@@ -503,7 +637,8 @@ rmdbx_get_val( VALUE self, VALUE key )
|
|
503
637
|
/* call-seq:
|
504
638
|
* db[ 'key' ] = value
|
505
639
|
*
|
506
|
-
* Set a single value for +key+.
|
640
|
+
* Set a single value for +key+. If the value is +nil+, the
|
641
|
+
* key is removed.
|
507
642
|
*/
|
508
643
|
VALUE
|
509
644
|
rmdbx_put_val( VALUE self, VALUE key, VALUE val )
|
@@ -511,7 +646,7 @@ rmdbx_put_val( VALUE self, VALUE key, VALUE val )
|
|
511
646
|
int rc;
|
512
647
|
UNWRAP_DB( self, db );
|
513
648
|
|
514
|
-
|
649
|
+
CHECK_HANDLE;
|
515
650
|
rmdbx_open_txn( db, MDBX_TXN_READWRITE );
|
516
651
|
|
517
652
|
MDBX_val ckey = rmdbx_key_for( key );
|
@@ -552,41 +687,32 @@ VALUE
|
|
552
687
|
rmdbx_stats( VALUE self )
|
553
688
|
{
|
554
689
|
UNWRAP_DB( self, db );
|
555
|
-
|
690
|
+
CHECK_HANDLE;
|
556
691
|
|
557
692
|
return rmdbx_gather_stats( db );
|
558
693
|
}
|
559
694
|
|
560
695
|
|
561
696
|
/*
|
562
|
-
*
|
563
|
-
*
|
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
|
576
|
-
*
|
697
|
+
* Return the currently selected collection, or +nil+ if at the
|
698
|
+
* top-level.
|
577
699
|
*/
|
578
700
|
VALUE
|
579
|
-
|
701
|
+
rmdbx_get_subdb( VALUE self )
|
580
702
|
{
|
581
703
|
UNWRAP_DB( self, db );
|
582
|
-
|
583
|
-
|
704
|
+
return ( db->subdb == NULL ) ? Qnil : rb_str_new_cstr( db->subdb );
|
705
|
+
}
|
584
706
|
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
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 );
|
590
716
|
|
591
717
|
/* Provide a friendlier error message if max_collections is 0. */
|
592
718
|
if ( db->settings.max_collections == 0 )
|
@@ -596,32 +722,14 @@ rmdbx_set_subdb( int argc, VALUE *argv, VALUE self )
|
|
596
722
|
if ( db->txn )
|
597
723
|
rb_raise( rmdbx_eDatabaseError, "Unable to change collection: transaction open" );
|
598
724
|
|
599
|
-
|
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
|
-
}
|
725
|
+
db->subdb = NIL_P( name ) ? NULL : StringValueCStr( name );
|
605
726
|
|
606
|
-
|
727
|
+
/* Reset the db handle and issue a single transaction to reify
|
728
|
+
the collection.
|
729
|
+
*/
|
607
730
|
rmdbx_close_dbi( db );
|
608
|
-
|
609
|
-
|
610
|
-
FIXME: Immediate transaction write to auto-create new env?
|
611
|
-
Fetching from here at the moment causes an error if you
|
612
|
-
haven't written anything to the new collection yet.
|
613
|
-
*/
|
614
|
-
|
615
|
-
/* Revert to the previous collection after the block is done.
|
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
|
-
}
|
731
|
+
rmdbx_open_txn( db, MDBX_TXN_READWRITE );
|
732
|
+
rmdbx_close_txn( db, RMDBX_TXN_COMMIT );
|
625
733
|
|
626
734
|
return self;
|
627
735
|
}
|
@@ -717,6 +825,34 @@ rmdbx_database_initialize( int argc, VALUE *argv, VALUE self )
|
|
717
825
|
}
|
718
826
|
|
719
827
|
|
828
|
+
/*
|
829
|
+
* call-seq:
|
830
|
+
* db.clone => [copy of db]
|
831
|
+
*
|
832
|
+
* Copy the object (clone/dup). The returned copy is closed and needs
|
833
|
+
* to be reopened before use. This function likely has limited use,
|
834
|
+
* considering you can't open two handles within the same process.
|
835
|
+
*/
|
836
|
+
static VALUE rmdbx_init_copy( VALUE copy, VALUE orig )
|
837
|
+
{
|
838
|
+
rmdbx_db_t *orig_db;
|
839
|
+
rmdbx_db_t *copy_db;
|
840
|
+
|
841
|
+
if ( copy == orig ) return copy;
|
842
|
+
|
843
|
+
TypedData_Get_Struct( orig, rmdbx_db_t, &rmdbx_db_data, orig_db );
|
844
|
+
TypedData_Get_Struct( copy, rmdbx_db_t, &rmdbx_db_data, copy_db );
|
845
|
+
|
846
|
+
/* Copy all fields from the original to the copy, and force-close
|
847
|
+
the copy.
|
848
|
+
*/
|
849
|
+
MEMCPY( copy_db, orig_db, rmdbx_db_t, 1 );
|
850
|
+
rmdbx_close_all( copy_db );
|
851
|
+
|
852
|
+
return copy;
|
853
|
+
}
|
854
|
+
|
855
|
+
|
720
856
|
/*
|
721
857
|
* Initialization for the MDBX::Database class.
|
722
858
|
*/
|
@@ -732,16 +868,19 @@ rmdbx_init_database()
|
|
732
868
|
rb_define_alloc_func( rmdbx_cDatabase, rmdbx_alloc );
|
733
869
|
|
734
870
|
rb_define_protected_method( rmdbx_cDatabase, "initialize", rmdbx_database_initialize, -1 );
|
735
|
-
|
871
|
+
rb_define_protected_method( rmdbx_cDatabase, "initialize_copy", rmdbx_init_copy, 1 );
|
872
|
+
|
873
|
+
rb_define_method( rmdbx_cDatabase, "clear", rmdbx_clear, 0 );
|
736
874
|
rb_define_method( rmdbx_cDatabase, "close", rmdbx_close, 0 );
|
737
|
-
rb_define_method( rmdbx_cDatabase, "reopen", rmdbx_open_env, 0 );
|
738
875
|
rb_define_method( rmdbx_cDatabase, "closed?", rmdbx_closed_p, 0 );
|
739
|
-
rb_define_method( rmdbx_cDatabase, "
|
740
|
-
rb_define_method( rmdbx_cDatabase, "clear", rmdbx_clear, 0 );
|
876
|
+
rb_define_method( rmdbx_cDatabase, "drop", rmdbx_drop, 1 );
|
741
877
|
rb_define_method( rmdbx_cDatabase, "each_key", rmdbx_each_key, 0 );
|
742
|
-
rb_define_method( rmdbx_cDatabase, "each_value", rmdbx_each_value, 0 );
|
743
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
|
+
rb_define_method( rmdbx_cDatabase, "include?", rmdbx_include, 1 );
|
744
882
|
rb_define_method( rmdbx_cDatabase, "length", rmdbx_length, 0 );
|
883
|
+
rb_define_method( rmdbx_cDatabase, "reopen", rmdbx_open_env, 0 );
|
745
884
|
rb_define_method( rmdbx_cDatabase, "[]", rmdbx_get_val, 1 );
|
746
885
|
rb_define_method( rmdbx_cDatabase, "[]=", rmdbx_put_val, 2 );
|
747
886
|
|
@@ -749,6 +888,10 @@ rmdbx_init_database()
|
|
749
888
|
rb_define_protected_method( rmdbx_cDatabase, "open_transaction", rmdbx_rb_opentxn, 1 );
|
750
889
|
rb_define_protected_method( rmdbx_cDatabase, "close_transaction", rmdbx_rb_closetxn, 1 );
|
751
890
|
|
891
|
+
/* Collection functions */
|
892
|
+
rb_define_protected_method( rmdbx_cDatabase, "get_subdb", rmdbx_get_subdb, 0 );
|
893
|
+
rb_define_protected_method( rmdbx_cDatabase, "set_subdb", rmdbx_set_subdb, 1 );
|
894
|
+
|
752
895
|
rb_define_protected_method( rmdbx_cDatabase, "raw_stats", rmdbx_stats, 0 );
|
753
896
|
|
754
897
|
rb_require( "mdbx/database" );
|
data/ext/mdbx_ext/stats.c
CHANGED
@@ -148,7 +148,7 @@ rmdbx_gather_reader_stats(
|
|
148
148
|
{
|
149
149
|
VALUE readers = rb_ary_new();
|
150
150
|
|
151
|
-
|
151
|
+
mdbx_reader_list( db->env, reader_list_callback, (void*)readers );
|
152
152
|
rb_hash_aset( stat, ID2SYM(rb_intern("readers")), readers );
|
153
153
|
|
154
154
|
return;
|
data/lib/mdbx.rb
CHANGED
data/lib/mdbx/database.rb
CHANGED
@@ -128,16 +128,43 @@ class MDBX::Database
|
|
128
128
|
attr_accessor :deserializer
|
129
129
|
|
130
130
|
|
131
|
+
alias_method :size, :length
|
132
|
+
alias_method :each, :each_pair
|
133
|
+
alias_method :has_key?, :include?
|
134
|
+
|
135
|
+
|
136
|
+
### Gets or sets the sub-database "collection" that read/write
|
137
|
+
### operations apply to. If a block is passed, the collection
|
138
|
+
### automatically reverts to the prior collection when it exits.
|
139
|
+
###
|
140
|
+
### db.collection #=> (collection name, or nil if in main)
|
141
|
+
### db.collection( 'collection_name' ) #=> db
|
142
|
+
###
|
143
|
+
### db.collection( 'collection_name' ) do
|
144
|
+
### [ ... ]
|
145
|
+
### end # reverts to the previous collection name
|
146
|
+
###
|
147
|
+
def collection( name=nil )
|
148
|
+
current = self.get_subdb
|
149
|
+
return current unless name
|
150
|
+
|
151
|
+
self.set_subdb( name.to_s )
|
152
|
+
yield( self ) if block_given?
|
153
|
+
|
154
|
+
return self
|
155
|
+
|
156
|
+
ensure
|
157
|
+
self.set_subdb( current ) if name && block_given?
|
158
|
+
end
|
159
|
+
alias_method :namespace, :collection
|
160
|
+
|
161
|
+
|
131
162
|
### Switch to the top-level collection.
|
132
163
|
###
|
133
164
|
def main
|
134
|
-
return self.
|
165
|
+
return self.set_subdb( nil )
|
135
166
|
end
|
136
167
|
|
137
|
-
alias_method :namespace, :collection
|
138
|
-
alias_method :size, :length
|
139
|
-
alias_method :each, :each_pair
|
140
|
-
|
141
168
|
|
142
169
|
#
|
143
170
|
# Transaction methods
|
@@ -201,8 +228,8 @@ class MDBX::Database
|
|
201
228
|
### pairs.
|
202
229
|
###
|
203
230
|
def to_a
|
204
|
-
self.
|
205
|
-
|
231
|
+
return self.conditional_snapshot do
|
232
|
+
self.each_pair.to_a
|
206
233
|
end
|
207
234
|
end
|
208
235
|
|
@@ -210,8 +237,8 @@ class MDBX::Database
|
|
210
237
|
### Return the entirety of database contents as a Hash.
|
211
238
|
###
|
212
239
|
def to_h
|
213
|
-
self.
|
214
|
-
|
240
|
+
return self.conditional_snapshot do
|
241
|
+
self.each_pair.to_h
|
215
242
|
end
|
216
243
|
end
|
217
244
|
|
@@ -261,8 +288,8 @@ class MDBX::Database
|
|
261
288
|
### Returns a new Array containing all keys in the collection.
|
262
289
|
###
|
263
290
|
def keys
|
264
|
-
self.
|
265
|
-
|
291
|
+
return self.conditional_snapshot do
|
292
|
+
self.each_key.to_a
|
266
293
|
end
|
267
294
|
end
|
268
295
|
|
@@ -271,8 +298,8 @@ class MDBX::Database
|
|
271
298
|
### keys. Any given keys that are not found are ignored.
|
272
299
|
###
|
273
300
|
def slice( *keys )
|
274
|
-
self.
|
275
|
-
|
301
|
+
return self.conditional_snapshot do
|
302
|
+
keys.each_with_object( {} ) do |key, acc|
|
276
303
|
val = self[ key ]
|
277
304
|
acc[ key ] = val if val
|
278
305
|
end
|
@@ -283,8 +310,8 @@ class MDBX::Database
|
|
283
310
|
### Returns a new Array containing all values in the collection.
|
284
311
|
###
|
285
312
|
def values
|
286
|
-
self.
|
287
|
-
|
313
|
+
return self.conditional_snapshot do
|
314
|
+
self.each_value.to_a
|
288
315
|
end
|
289
316
|
end
|
290
317
|
|
@@ -292,8 +319,8 @@ class MDBX::Database
|
|
292
319
|
### Returns a new Array containing values for the given +keys+.
|
293
320
|
###
|
294
321
|
def values_at( *keys )
|
295
|
-
self.
|
296
|
-
|
322
|
+
return self.conditional_snapshot do
|
323
|
+
keys.each_with_object( [] ) do |key, acc|
|
297
324
|
acc << self[ key ]
|
298
325
|
end
|
299
326
|
end
|
@@ -329,5 +356,23 @@ class MDBX::Database
|
|
329
356
|
return stats
|
330
357
|
end
|
331
358
|
|
359
|
+
|
360
|
+
#########
|
361
|
+
protected
|
362
|
+
#########
|
363
|
+
|
364
|
+
### Yield and return the block, opening a snapshot first if
|
365
|
+
### there isn't already a transaction in progress. Closes
|
366
|
+
### the snapshot if this method opened it.
|
367
|
+
###
|
368
|
+
def conditional_snapshot
|
369
|
+
in_txn = self.in_transaction?
|
370
|
+
self.snapshot unless in_txn
|
371
|
+
|
372
|
+
return yield
|
373
|
+
ensure
|
374
|
+
self.abort unless in_txn
|
375
|
+
end
|
376
|
+
|
332
377
|
end # class MDBX::Database
|
333
378
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mdbx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mahlon E. Smith
|
@@ -34,7 +34,7 @@ cert_chain:
|
|
34
34
|
49pOzX5KHZLTS9DKeaP/xcGPz6C8MiwQdYrZarr2SHRASX1zFa79rkItO8kE6RDr
|
35
35
|
b6WDF79UvZ55ajtE00TiwqjQL/ZPEtbd
|
36
36
|
-----END CERTIFICATE-----
|
37
|
-
date: 2021-
|
37
|
+
date: 2021-05-16 00:00:00.000000000 Z
|
38
38
|
dependencies:
|
39
39
|
- !ruby/object:Gem::Dependency
|
40
40
|
name: pry
|
metadata.gz.sig
CHANGED
Binary file
|