mdbx 0.1.0.pre.20201217111933 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/History.md +5 -1
- data/README.md +305 -35
- data/ext/mdbx_ext/database.c +383 -138
- data/ext/mdbx_ext/mdbx_ext.c +8 -2
- data/ext/mdbx_ext/mdbx_ext.h +41 -3
- data/ext/mdbx_ext/stats.c +191 -0
- data/lib/mdbx.rb +1 -5
- data/lib/mdbx/database.rb +274 -9
- metadata +44 -29
- metadata.gz.sig +0 -0
- data/lib/mdbx_ext.so +0 -0
data/ext/mdbx_ext/mdbx_ext.c
CHANGED
@@ -14,12 +14,18 @@ Init_mdbx_ext()
|
|
14
14
|
{
|
15
15
|
rmdbx_mMDBX = rb_define_module( "MDBX" );
|
16
16
|
|
17
|
-
/* The backend library version. */
|
18
17
|
VALUE version = rb_str_new_cstr( mdbx_version.git.describe );
|
18
|
+
/* The backend MDBX library version. */
|
19
19
|
rb_define_const( rmdbx_mMDBX, "LIBRARY_VERSION", version );
|
20
20
|
|
21
|
+
/* A generic exception class for internal Database errors. */
|
21
22
|
rmdbx_eDatabaseError = rb_define_class_under( rmdbx_mMDBX, "DatabaseError", rb_eRuntimeError );
|
22
|
-
|
23
|
+
|
24
|
+
/*
|
25
|
+
* Raising an MDBX::Rollback exception from within a transaction
|
26
|
+
* discards all changes and closes the transaction.
|
27
|
+
*/
|
28
|
+
rmdbx_eRollback = rb_define_class_under( rmdbx_mMDBX, "Rollback", rb_eRuntimeError );
|
23
29
|
|
24
30
|
rmdbx_init_database();
|
25
31
|
}
|
data/ext/mdbx_ext/mdbx_ext.h
CHANGED
@@ -4,9 +4,43 @@
|
|
4
4
|
|
5
5
|
#include "mdbx.h"
|
6
6
|
|
7
|
-
#ifndef
|
8
|
-
#define
|
7
|
+
#ifndef MDBX_EXT_0_9_3
|
8
|
+
#define MDBX_EXT_0_9_3
|
9
9
|
|
10
|
+
#define RMDBX_TXN_ROLLBACK 0
|
11
|
+
#define RMDBX_TXN_COMMIT 1
|
12
|
+
|
13
|
+
/*
|
14
|
+
* A struct encapsulating an instance's DB
|
15
|
+
* state and settings.
|
16
|
+
*/
|
17
|
+
struct rmdbx_db {
|
18
|
+
MDBX_env *env;
|
19
|
+
MDBX_dbi dbi;
|
20
|
+
MDBX_txn *txn;
|
21
|
+
MDBX_cursor *cursor;
|
22
|
+
|
23
|
+
struct {
|
24
|
+
int env_flags;
|
25
|
+
int mode;
|
26
|
+
int open;
|
27
|
+
int max_collections;
|
28
|
+
int max_readers;
|
29
|
+
uint64_t max_size;
|
30
|
+
} settings;
|
31
|
+
|
32
|
+
struct {
|
33
|
+
int open;
|
34
|
+
int retain_txn;
|
35
|
+
} state;
|
36
|
+
|
37
|
+
char *path;
|
38
|
+
char *subdb;
|
39
|
+
};
|
40
|
+
typedef struct rmdbx_db rmdbx_db_t;
|
41
|
+
|
42
|
+
static const rb_data_type_t rmdbx_db_data;
|
43
|
+
extern void rmdbx_free( void *db ); /* forward declaration for the allocator */
|
10
44
|
|
11
45
|
/* ------------------------------------------------------------
|
12
46
|
* Globals
|
@@ -23,7 +57,11 @@ extern VALUE rmdbx_eRollback;
|
|
23
57
|
* ------------------------------------------------------------ */
|
24
58
|
extern void Init_rmdbx ( void );
|
25
59
|
extern void rmdbx_init_database ( void );
|
60
|
+
extern void rmdbx_open_txn( rmdbx_db_t*, int );
|
61
|
+
extern void rmdbx_close_txn( rmdbx_db_t*, int );
|
62
|
+
|
63
|
+
extern VALUE rmdbx_gather_stats( rmdbx_db_t* );
|
26
64
|
|
27
65
|
|
28
|
-
#endif /* define
|
66
|
+
#endif /* define MDBX_EXT_0_9_3 */
|
29
67
|
|
@@ -0,0 +1,191 @@
|
|
1
|
+
/* vim: set noet sta sw=4 ts=4 :
|
2
|
+
*
|
3
|
+
* Expose a bunch of mdbx internals to ruby.
|
4
|
+
* This is all largely stolen from mdbx_stat.c.
|
5
|
+
*
|
6
|
+
* Entry point is rmdbx_stats() in database.c.
|
7
|
+
*
|
8
|
+
*/
|
9
|
+
|
10
|
+
#include "mdbx_ext.h"
|
11
|
+
|
12
|
+
|
13
|
+
/*
|
14
|
+
* Metadata specific to the mdbx build.
|
15
|
+
*/
|
16
|
+
void
|
17
|
+
rmdbx_gather_build_stats( VALUE stat )
|
18
|
+
{
|
19
|
+
rb_hash_aset( stat, ID2SYM(rb_intern("build_compiler")),
|
20
|
+
rb_str_new_cstr(mdbx_build.compiler) );
|
21
|
+
rb_hash_aset( stat, ID2SYM(rb_intern("build_flags")),
|
22
|
+
rb_str_new_cstr(mdbx_build.flags) );
|
23
|
+
rb_hash_aset( stat, ID2SYM(rb_intern("build_options")),
|
24
|
+
rb_str_new_cstr(mdbx_build.options) );
|
25
|
+
rb_hash_aset( stat, ID2SYM(rb_intern("build_target")),
|
26
|
+
rb_str_new_cstr(mdbx_build.target) );
|
27
|
+
return;
|
28
|
+
}
|
29
|
+
|
30
|
+
|
31
|
+
/*
|
32
|
+
* Metadata for the database file.
|
33
|
+
*/
|
34
|
+
void
|
35
|
+
rmdbx_gather_datafile_stats(
|
36
|
+
VALUE environ,
|
37
|
+
MDBX_stat mstat,
|
38
|
+
MDBX_envinfo menvinfo )
|
39
|
+
{
|
40
|
+
VALUE datafile = rb_hash_new();
|
41
|
+
rb_hash_aset( environ, ID2SYM(rb_intern("datafile")), datafile );
|
42
|
+
|
43
|
+
rb_hash_aset( datafile, ID2SYM(rb_intern("size_current")),
|
44
|
+
INT2NUM(menvinfo.mi_geo.current) );
|
45
|
+
rb_hash_aset( datafile, ID2SYM(rb_intern("pages")),
|
46
|
+
INT2NUM(menvinfo.mi_geo.current / mstat.ms_psize) );
|
47
|
+
|
48
|
+
if ( menvinfo.mi_geo.lower != menvinfo.mi_geo.upper ) {
|
49
|
+
rb_hash_aset( datafile, ID2SYM(rb_intern("type")),
|
50
|
+
rb_str_new_cstr("dynamic") );
|
51
|
+
rb_hash_aset( datafile, ID2SYM(rb_intern("size_lower")),
|
52
|
+
INT2NUM( menvinfo.mi_geo.lower ) );
|
53
|
+
rb_hash_aset( datafile, ID2SYM(rb_intern("size_upper")),
|
54
|
+
LONG2FIX( menvinfo.mi_geo.upper ) );
|
55
|
+
rb_hash_aset( datafile, ID2SYM(rb_intern("growth_step")),
|
56
|
+
INT2NUM( menvinfo.mi_geo.grow ) );
|
57
|
+
rb_hash_aset( datafile, ID2SYM(rb_intern("shrink_threshold")),
|
58
|
+
INT2NUM( menvinfo.mi_geo.shrink ) );
|
59
|
+
}
|
60
|
+
else {
|
61
|
+
rb_hash_aset( datafile, ID2SYM(rb_intern("type")),
|
62
|
+
rb_str_new_cstr("fixed") );
|
63
|
+
}
|
64
|
+
|
65
|
+
return;
|
66
|
+
}
|
67
|
+
|
68
|
+
|
69
|
+
/*
|
70
|
+
* Metadata for the database environment.
|
71
|
+
*/
|
72
|
+
void
|
73
|
+
rmdbx_gather_environment_stats(
|
74
|
+
VALUE stat,
|
75
|
+
MDBX_stat mstat,
|
76
|
+
MDBX_envinfo menvinfo )
|
77
|
+
{
|
78
|
+
VALUE environ = rb_hash_new();
|
79
|
+
rb_hash_aset( stat, ID2SYM(rb_intern("environment")), environ );
|
80
|
+
|
81
|
+
rb_hash_aset( environ, ID2SYM(rb_intern("pagesize")),
|
82
|
+
INT2NUM(mstat.ms_psize) );
|
83
|
+
rb_hash_aset( environ, ID2SYM(rb_intern("last_txnid")),
|
84
|
+
INT2NUM(menvinfo.mi_recent_txnid) );
|
85
|
+
rb_hash_aset( environ, ID2SYM(rb_intern("last_reader_txnid")),
|
86
|
+
INT2NUM(menvinfo.mi_latter_reader_txnid) );
|
87
|
+
rb_hash_aset( environ, ID2SYM(rb_intern("max_readers")),
|
88
|
+
INT2NUM(menvinfo.mi_maxreaders) );
|
89
|
+
rb_hash_aset( environ, ID2SYM(rb_intern("readers_in_use")),
|
90
|
+
INT2NUM(menvinfo.mi_numreaders) );
|
91
|
+
|
92
|
+
rmdbx_gather_datafile_stats( environ, mstat, menvinfo );
|
93
|
+
|
94
|
+
return;
|
95
|
+
}
|
96
|
+
|
97
|
+
|
98
|
+
/*
|
99
|
+
* Callback iterator for pulling each reader's current state.
|
100
|
+
* See: https://erthink.github.io/libmdbx/group__c__statinfo.html#gad1ab5cf54d4a9f7d4c2999078920e8b0
|
101
|
+
*
|
102
|
+
*/
|
103
|
+
int
|
104
|
+
reader_list_callback(
|
105
|
+
void *ctx,
|
106
|
+
int num,
|
107
|
+
int slot,
|
108
|
+
mdbx_pid_t pid,
|
109
|
+
mdbx_tid_t thread,
|
110
|
+
uint64_t txnid,
|
111
|
+
uint64_t lag,
|
112
|
+
size_t bytes_used,
|
113
|
+
size_t bytes_retired )
|
114
|
+
{
|
115
|
+
VALUE reader = rb_hash_new();
|
116
|
+
|
117
|
+
rb_hash_aset( reader, ID2SYM(rb_intern("slot")),
|
118
|
+
INT2NUM( slot ) );
|
119
|
+
rb_hash_aset( reader, ID2SYM(rb_intern("pid")),
|
120
|
+
LONG2FIX( pid ) );
|
121
|
+
rb_hash_aset( reader, ID2SYM(rb_intern("thread")),
|
122
|
+
LONG2FIX( thread ) );
|
123
|
+
rb_hash_aset( reader, ID2SYM(rb_intern("txnid")),
|
124
|
+
LONG2FIX( txnid ) );
|
125
|
+
rb_hash_aset( reader, ID2SYM(rb_intern("lag")),
|
126
|
+
LONG2FIX( lag ) );
|
127
|
+
rb_hash_aset( reader, ID2SYM(rb_intern("bytes_used")),
|
128
|
+
LONG2FIX( bytes_used ) );
|
129
|
+
rb_hash_aset( reader, ID2SYM(rb_intern("bytes_retired")),
|
130
|
+
LONG2FIX( bytes_retired ) );
|
131
|
+
|
132
|
+
rb_ary_push( (VALUE)ctx, reader );
|
133
|
+
|
134
|
+
return 0;
|
135
|
+
}
|
136
|
+
|
137
|
+
|
138
|
+
/*
|
139
|
+
* Metadata for current reader slots.
|
140
|
+
* Initialize an array and populate it with each reader's statistics.
|
141
|
+
*/
|
142
|
+
void
|
143
|
+
rmdbx_gather_reader_stats(
|
144
|
+
rmdbx_db_t *db,
|
145
|
+
VALUE stat,
|
146
|
+
MDBX_stat mstat,
|
147
|
+
MDBX_envinfo menvinfo )
|
148
|
+
{
|
149
|
+
VALUE readers = rb_ary_new();
|
150
|
+
|
151
|
+
mdbx_reader_list( db->env, reader_list_callback, (void*)readers );
|
152
|
+
rb_hash_aset( stat, ID2SYM(rb_intern("readers")), readers );
|
153
|
+
|
154
|
+
return;
|
155
|
+
}
|
156
|
+
|
157
|
+
|
158
|
+
/*
|
159
|
+
* Build and return a hash of various statistic/metadata
|
160
|
+
* for the open +db+ handle.
|
161
|
+
*/
|
162
|
+
VALUE
|
163
|
+
rmdbx_gather_stats( rmdbx_db_t *db )
|
164
|
+
{
|
165
|
+
VALUE stat = rb_hash_new();
|
166
|
+
|
167
|
+
int rc;
|
168
|
+
MDBX_stat mstat;
|
169
|
+
MDBX_envinfo menvinfo;
|
170
|
+
|
171
|
+
rmdbx_gather_build_stats( stat );
|
172
|
+
|
173
|
+
rmdbx_open_txn( db, MDBX_TXN_RDONLY );
|
174
|
+
rc = mdbx_env_info_ex( db->env, db->txn, &menvinfo, sizeof(menvinfo) );
|
175
|
+
if ( rc != MDBX_SUCCESS )
|
176
|
+
rb_raise( rmdbx_eDatabaseError, "mdbx_env_info_ex: (%d) %s", rc, mdbx_strerror(rc) );
|
177
|
+
|
178
|
+
rc = mdbx_env_stat_ex( db->env, db->txn, &mstat, sizeof(mstat) );
|
179
|
+
if ( rc != MDBX_SUCCESS )
|
180
|
+
rb_raise( rmdbx_eDatabaseError, "mdbx_env_stat_ex: (%d) %s", rc, mdbx_strerror(rc) );
|
181
|
+
rmdbx_close_txn( db, RMDBX_TXN_ROLLBACK );
|
182
|
+
|
183
|
+
rmdbx_gather_environment_stats( stat, mstat, menvinfo );
|
184
|
+
rmdbx_gather_reader_stats( db, stat, mstat, menvinfo );
|
185
|
+
|
186
|
+
/* TODO: database and subdatabase stats */
|
187
|
+
|
188
|
+
return stat;
|
189
|
+
}
|
190
|
+
|
191
|
+
|
data/lib/mdbx.rb
CHANGED
@@ -10,11 +10,7 @@ require 'mdbx_ext'
|
|
10
10
|
module MDBX
|
11
11
|
|
12
12
|
# The version of this gem.
|
13
|
-
|
14
|
-
# Note: the MDBX library version this gem was built
|
15
|
-
# against can be found in the 'LIBRARY_VERSION' constant.
|
16
|
-
#
|
17
|
-
VERSION = '0.0.1'
|
13
|
+
VERSION = '0.1.0'
|
18
14
|
|
19
15
|
end # module MDBX
|
20
16
|
|
data/lib/mdbx/database.rb
CHANGED
@@ -5,20 +5,91 @@
|
|
5
5
|
require 'mdbx' unless defined?( MDBX )
|
6
6
|
|
7
7
|
|
8
|
-
#
|
8
|
+
# The primary class for interacting with an MDBX database.
|
9
9
|
#
|
10
10
|
class MDBX::Database
|
11
11
|
|
12
|
+
### call-seq:
|
13
|
+
### MDBX::Database.open( path ) => db
|
14
|
+
### MDBX::Database.open( path, options ) => db
|
15
|
+
###
|
12
16
|
### Open an existing (or create a new) mdbx database at filesystem
|
13
|
-
### +path+. In block form, the database is automatically closed
|
17
|
+
### +path+. In block form, the database is automatically closed
|
18
|
+
### when the block exits.
|
14
19
|
###
|
15
|
-
### MDBX::Database.open( path ) -> db
|
16
|
-
### MDBX::Database.open( path, options ) -> db
|
17
20
|
### MDBX::Database.open( path, options ) do |db|
|
18
|
-
### db[ 'key' ]
|
19
|
-
### end
|
21
|
+
### db[ 'key' ] = value
|
22
|
+
### end # closed!
|
23
|
+
###
|
24
|
+
### Passing options modify various database behaviors. See the libmdbx
|
25
|
+
### documentation for detailed information.
|
26
|
+
###
|
27
|
+
### ==== Options
|
28
|
+
###
|
29
|
+
### Unless otherwise mentioned, option keys are symbols, and values
|
30
|
+
### are boolean.
|
31
|
+
###
|
32
|
+
### [:mode]
|
33
|
+
### Whe creating a new database, set permissions to this 4 digit
|
34
|
+
### octal number. Defaults to `0644`. Set to `0` to never automatically
|
35
|
+
### create a new file, only opening existing databases.
|
36
|
+
###
|
37
|
+
### [:max_collections]
|
38
|
+
### Set the maximum number of "subdatabase" collections allowed. By
|
39
|
+
### default, collection support is disabled.
|
40
|
+
###
|
41
|
+
### [:max_readers]
|
42
|
+
### Set the maximum number of allocated simultaneous reader slots.
|
43
|
+
###
|
44
|
+
### [:max_size]
|
45
|
+
### Set an upper boundary (in bytes) for the database map size.
|
46
|
+
### The default is 10485760 bytes.
|
47
|
+
###
|
48
|
+
### [:nosubdir]
|
49
|
+
### When creating a new database, don't put the data and lock file
|
50
|
+
### under a dedicated subdirectory.
|
51
|
+
###
|
52
|
+
### [:readonly]
|
53
|
+
### Reject any write attempts while using this database handle.
|
54
|
+
###
|
55
|
+
### [:exclusive]
|
56
|
+
### Access is restricted to the first opening process. Other attempts
|
57
|
+
### to use this database (even in readonly mode) are denied.
|
58
|
+
###
|
59
|
+
### [:compat]
|
60
|
+
### Skip compatibility checks when opening an in-use database with
|
61
|
+
### unknown or mismatched flag values.
|
62
|
+
###
|
63
|
+
### [:writemap]
|
64
|
+
### Trade safety for speed for databases that fit within available
|
65
|
+
### memory. (See MDBX documentation for details.)
|
20
66
|
###
|
21
|
-
###
|
67
|
+
### [:no_threadlocal]
|
68
|
+
### Parallelize read-only transactions across threads. Writes are
|
69
|
+
### always thread local. (See MDBX documentatoin for details.)
|
70
|
+
###
|
71
|
+
### [:no_readahead]
|
72
|
+
### Disable all use of OS readahead. Potentially useful for
|
73
|
+
### random reads wunder low memory conditions. Default behavior
|
74
|
+
### is to dynamically choose when to use or omit readahead.
|
75
|
+
###
|
76
|
+
### [:no_memory_init]
|
77
|
+
### Skip initializing malloc'ed memory to zeroes before writing.
|
78
|
+
###
|
79
|
+
### [:coalesce]
|
80
|
+
### Attempt to coalesce items for the garbage collector,
|
81
|
+
### potentialy increasing the chance of unallocating storage
|
82
|
+
### earlier.
|
83
|
+
###
|
84
|
+
### [:lifo_reclaim]
|
85
|
+
### Recycle garbage collected items via LIFO, instead of FIFO.
|
86
|
+
### Depending on underlying hardware (disk write-back cache), this
|
87
|
+
### could increase write performance.
|
88
|
+
###
|
89
|
+
### [:no_metasync]
|
90
|
+
### A system crash may sacrifice the last commit for a potentially
|
91
|
+
### large write performance increase. Database integrity is
|
92
|
+
### maintained.
|
22
93
|
###
|
23
94
|
def self::open( *args, &block )
|
24
95
|
db = new( *args )
|
@@ -42,16 +113,18 @@ class MDBX::Database
|
|
42
113
|
private_class_method :new
|
43
114
|
|
44
115
|
|
45
|
-
#
|
116
|
+
# Options used when instantiating this database handle.
|
46
117
|
attr_reader :options
|
47
118
|
|
48
119
|
# The path on disk of the database.
|
49
120
|
attr_reader :path
|
50
121
|
|
51
122
|
# A Proc for automatically serializing values.
|
123
|
+
# Defaults to +Marshal.dump+.
|
52
124
|
attr_accessor :serializer
|
53
125
|
|
54
126
|
# A Proc for automatically deserializing values.
|
127
|
+
# Defaults to +Marshal.load+.
|
55
128
|
attr_accessor :deserializer
|
56
129
|
|
57
130
|
|
@@ -61,8 +134,200 @@ class MDBX::Database
|
|
61
134
|
return self.collection( nil )
|
62
135
|
end
|
63
136
|
|
64
|
-
# Allow for some common nomenclature.
|
65
137
|
alias_method :namespace, :collection
|
138
|
+
alias_method :size, :length
|
139
|
+
alias_method :each, :each_pair
|
140
|
+
|
141
|
+
|
142
|
+
#
|
143
|
+
# Transaction methods
|
144
|
+
#
|
145
|
+
|
146
|
+
### Open a new mdbx read/write transaction. In block form,
|
147
|
+
### the transaction is automatically committed when the block ends.
|
148
|
+
###
|
149
|
+
### Raising a MDBX::Rollback exception from within the block
|
150
|
+
### automatically rolls the transaction back.
|
151
|
+
###
|
152
|
+
def transaction( commit: true, &block )
|
153
|
+
self.open_transaction( commit )
|
154
|
+
yield self if block_given?
|
155
|
+
|
156
|
+
return self
|
157
|
+
|
158
|
+
rescue MDBX::Rollback
|
159
|
+
commit = false
|
160
|
+
self.rollback
|
161
|
+
rescue
|
162
|
+
commit = false
|
163
|
+
self.rollback
|
164
|
+
raise
|
165
|
+
ensure
|
166
|
+
if block_given?
|
167
|
+
commit ? self.commit : self.rollback
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
|
172
|
+
### Open a new mdbx read only snapshot. In block form,
|
173
|
+
### the snapshot is automatically closed when the block ends.
|
174
|
+
###
|
175
|
+
def snapshot( &block )
|
176
|
+
self.transaction( commit: false, &block )
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
### Close any open transaction, abandoning all changes.
|
181
|
+
###
|
182
|
+
def rollback
|
183
|
+
return self.close_transaction( false )
|
184
|
+
end
|
185
|
+
alias_method :abort, :rollback
|
186
|
+
|
187
|
+
|
188
|
+
### Close any open transaction, writing all changes.
|
189
|
+
###
|
190
|
+
def commit
|
191
|
+
return self.close_transaction( true )
|
192
|
+
end
|
193
|
+
alias_method :save, :commit
|
194
|
+
|
195
|
+
|
196
|
+
#
|
197
|
+
# Hash-alike methods
|
198
|
+
#
|
199
|
+
|
200
|
+
### Return the entirety of database contents as an Array of array
|
201
|
+
### pairs.
|
202
|
+
###
|
203
|
+
def to_a
|
204
|
+
self.snapshot do
|
205
|
+
return self.each_pair.to_a
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
### Return the entirety of database contents as a Hash.
|
211
|
+
###
|
212
|
+
def to_h
|
213
|
+
self.snapshot do
|
214
|
+
return self.each_pair.to_h
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
|
219
|
+
### Returns +true+ if the current collection has no data.
|
220
|
+
###
|
221
|
+
def empty?
|
222
|
+
return self.size.zero?
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
### Returns the value for the given key, if found.
|
227
|
+
### If key is not found and no block was given, returns nil.
|
228
|
+
### If key is not found and a block was given, yields key to the
|
229
|
+
### block and returns the block's return value.
|
230
|
+
###
|
231
|
+
def fetch( key, &block )
|
232
|
+
val = self[ key ]
|
233
|
+
if block_given?
|
234
|
+
return block.call( key ) if val.nil?
|
235
|
+
else
|
236
|
+
return val if val
|
237
|
+
raise KeyError, "key not found: %p" % [ key ]
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
|
242
|
+
### Deletes the entry for the given key and returns its associated
|
243
|
+
### value. If no block is given and key is found, deletes the entry
|
244
|
+
### and returns the associated value. If no block given and key is
|
245
|
+
### not found, returns nil.
|
246
|
+
###
|
247
|
+
### If a block is given and key is found, ignores the block, deletes
|
248
|
+
### the entry, and returns the associated value. If a block is given
|
249
|
+
### and key is not found, calls the block and returns the block's
|
250
|
+
### return value.
|
251
|
+
###
|
252
|
+
def delete( key, &block )
|
253
|
+
val = self[ key ]
|
254
|
+
return block.call( key ) if block_given? && val.nil?
|
255
|
+
|
256
|
+
self[ key ] = nil
|
257
|
+
return val
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
### Returns a new Array containing all keys in the collection.
|
262
|
+
###
|
263
|
+
def keys
|
264
|
+
self.snapshot do
|
265
|
+
return self.each_key.to_a
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
### Returns a new Hash object containing the entries for the given
|
271
|
+
### keys. Any given keys that are not found are ignored.
|
272
|
+
###
|
273
|
+
def slice( *keys )
|
274
|
+
self.snapshot do
|
275
|
+
return keys.each_with_object( {} ) do |key, acc|
|
276
|
+
val = self[ key ]
|
277
|
+
acc[ key ] = val if val
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
|
283
|
+
### Returns a new Array containing all values in the collection.
|
284
|
+
###
|
285
|
+
def values
|
286
|
+
self.snapshot do
|
287
|
+
return self.each_value.to_a
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
|
292
|
+
### Returns a new Array containing values for the given +keys+.
|
293
|
+
###
|
294
|
+
def values_at( *keys )
|
295
|
+
self.snapshot do
|
296
|
+
return keys.each_with_object( [] ) do |key, acc|
|
297
|
+
acc << self[ key ]
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
|
303
|
+
#
|
304
|
+
# Utility methods
|
305
|
+
#
|
306
|
+
|
307
|
+
### Return a hash of various metadata for the current database.
|
308
|
+
###
|
309
|
+
def statistics
|
310
|
+
raw = self.raw_stats
|
311
|
+
|
312
|
+
# Place build options in their own hash.
|
313
|
+
#
|
314
|
+
build_opts = raw.delete( :build_options ).split.each_with_object( {} ) do |opt, acc|
|
315
|
+
key, val = opt.split( '=' )
|
316
|
+
acc[ key.to_sym ] = Integer( val ) rescue val
|
317
|
+
end
|
318
|
+
|
319
|
+
stats = {
|
320
|
+
build: {
|
321
|
+
compiler: raw.delete( :build_compiler ),
|
322
|
+
flags: raw.delete( :build_flags ),
|
323
|
+
options: build_opts,
|
324
|
+
target: raw.delete( :build_target )
|
325
|
+
}
|
326
|
+
}
|
327
|
+
stats.merge!( raw )
|
328
|
+
|
329
|
+
return stats
|
330
|
+
end
|
66
331
|
|
67
332
|
end # class MDBX::Database
|
68
333
|
|