mdbx 0.1.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.
@@ -4,12 +4,23 @@
4
4
 
5
5
  #include "mdbx.h"
6
6
 
7
- #ifndef MDBX_EXT_0_9_3
8
- #define MDBX_EXT_0_9_3
7
+ #ifndef RBMDBX_EXT
8
+ #define RBMDBX_EXT
9
9
 
10
10
  #define RMDBX_TXN_ROLLBACK 0
11
11
  #define RMDBX_TXN_COMMIT 1
12
12
 
13
+ /* Shortcut for fetching wrapped data structure.
14
+ */
15
+ #define UNWRAP_DB( self, db ) \
16
+ rmdbx_db_t *db; \
17
+ TypedData_Get_Struct( self, rmdbx_db_t, &rmdbx_db_data, db )
18
+
19
+ /* Raise if current DB is not open. */
20
+ #define CHECK_HANDLE() \
21
+ if ( ! db->state.open ) rb_raise( rmdbx_eDatabaseError, "Closed database." )
22
+
23
+
13
24
  /*
14
25
  * A struct encapsulating an instance's DB
15
26
  * state and settings.
@@ -21,7 +32,8 @@ struct rmdbx_db {
21
32
  MDBX_cursor *cursor;
22
33
 
23
34
  struct {
24
- int env_flags;
35
+ unsigned int env_flags;
36
+ unsigned int db_flags;
25
37
  int mode;
26
38
  int open;
27
39
  int max_collections;
@@ -40,12 +52,11 @@ struct rmdbx_db {
40
52
  typedef struct rmdbx_db rmdbx_db_t;
41
53
 
42
54
  static const rb_data_type_t rmdbx_db_data;
43
- extern void rmdbx_free( void *db ); /* forward declaration for the allocator */
55
+
44
56
 
45
57
  /* ------------------------------------------------------------
46
58
  * Globals
47
59
  * ------------------------------------------------------------ */
48
-
49
60
  extern VALUE rmdbx_mMDBX;
50
61
  extern VALUE rmdbx_cDatabase;
51
62
  extern VALUE rmdbx_eDatabaseError;
@@ -55,13 +66,15 @@ extern VALUE rmdbx_eRollback;
55
66
  /* ------------------------------------------------------------
56
67
  * Functions
57
68
  * ------------------------------------------------------------ */
69
+ extern void rmdbx_free( void *db ); /* forward declaration for the allocator */
58
70
  extern void Init_rmdbx ( void );
59
71
  extern void rmdbx_init_database ( void );
72
+ extern void rmdbx_close_all( rmdbx_db_t* );
60
73
  extern void rmdbx_open_txn( rmdbx_db_t*, int );
61
74
  extern void rmdbx_close_txn( rmdbx_db_t*, int );
62
-
75
+ extern void rmdbx_open_cursor( rmdbx_db_t* );
63
76
  extern VALUE rmdbx_gather_stats( rmdbx_db_t* );
64
77
 
65
78
 
66
- #endif /* define MDBX_EXT_0_9_3 */
79
+ #endif /* define RBMDBX_EXT */
67
80
 
data/ext/mdbx_ext/stats.c CHANGED
@@ -3,8 +3,6 @@
3
3
  * Expose a bunch of mdbx internals to ruby.
4
4
  * This is all largely stolen from mdbx_stat.c.
5
5
  *
6
- * Entry point is rmdbx_stats() in database.c.
7
- *
8
6
  */
9
7
 
10
8
  #include "mdbx_ext.h"
@@ -28,6 +26,32 @@ rmdbx_gather_build_stats( VALUE stat )
28
26
  }
29
27
 
30
28
 
29
+ /*
30
+ * Grab current memory usage. (Available since MDBX 0.10.0).
31
+ */
32
+ void
33
+ rmdbx_gather_memory_stats( VALUE stat )
34
+ {
35
+ if (! ( MDBX_VERSION_MAJOR >= 0 && MDBX_VERSION_MINOR >= 10 ) )
36
+ return;
37
+
38
+ VALUE mem = rb_hash_new();
39
+ rb_hash_aset( stat, ID2SYM(rb_intern("system_memory")), mem );
40
+
41
+ intptr_t page_size;
42
+ intptr_t total_pages;
43
+ intptr_t avail_pages;
44
+
45
+ mdbx_get_sysraminfo( &page_size, &total_pages, &avail_pages );
46
+
47
+ rb_hash_aset( mem, ID2SYM(rb_intern("pagesize")), LONG2FIX( page_size ) );
48
+ rb_hash_aset( mem, ID2SYM(rb_intern("total_pages")), LONG2FIX( total_pages ) );
49
+ rb_hash_aset( mem, ID2SYM(rb_intern("avail_pages")), LONG2FIX( avail_pages ) );
50
+
51
+ return;
52
+ }
53
+
54
+
31
55
  /*
32
56
  * Metadata for the database file.
33
57
  */
@@ -80,6 +104,16 @@ rmdbx_gather_environment_stats(
80
104
 
81
105
  rb_hash_aset( environ, ID2SYM(rb_intern("pagesize")),
82
106
  INT2NUM(mstat.ms_psize) );
107
+ rb_hash_aset( environ, ID2SYM(rb_intern("branch_pages")),
108
+ LONG2NUM(mstat.ms_branch_pages) );
109
+ rb_hash_aset( environ, ID2SYM(rb_intern("leaf_pages")),
110
+ LONG2NUM(mstat.ms_leaf_pages) );
111
+ rb_hash_aset( environ, ID2SYM(rb_intern("overflow_pages")),
112
+ LONG2NUM(mstat.ms_overflow_pages) );
113
+ rb_hash_aset( environ, ID2SYM(rb_intern("btree_depth")),
114
+ INT2NUM(mstat.ms_depth) );
115
+ rb_hash_aset( environ, ID2SYM(rb_intern("entries")),
116
+ LONG2NUM(mstat.ms_entries) );
83
117
  rb_hash_aset( environ, ID2SYM(rb_intern("last_txnid")),
84
118
  INT2NUM(menvinfo.mi_recent_txnid) );
85
119
  rb_hash_aset( environ, ID2SYM(rb_intern("last_reader_txnid")),
@@ -101,7 +135,7 @@ rmdbx_gather_environment_stats(
101
135
  *
102
136
  */
103
137
  int
104
- reader_list_callback(
138
+ rmdbx_reader_list_cb(
105
139
  void *ctx,
106
140
  int num,
107
141
  int slot,
@@ -148,7 +182,7 @@ rmdbx_gather_reader_stats(
148
182
  {
149
183
  VALUE readers = rb_ary_new();
150
184
 
151
- mdbx_reader_list( db->env, reader_list_callback, (void*)readers );
185
+ mdbx_reader_list( db->env, rmdbx_reader_list_cb, (void*)readers );
152
186
  rb_hash_aset( stat, ID2SYM(rb_intern("readers")), readers );
153
187
 
154
188
  return;
@@ -168,6 +202,7 @@ rmdbx_gather_stats( rmdbx_db_t *db )
168
202
  MDBX_stat mstat;
169
203
  MDBX_envinfo menvinfo;
170
204
 
205
+ rmdbx_gather_memory_stats( stat );
171
206
  rmdbx_gather_build_stats( stat );
172
207
 
173
208
  rmdbx_open_txn( db, MDBX_TXN_RDONLY );
@@ -183,9 +218,6 @@ rmdbx_gather_stats( rmdbx_db_t *db )
183
218
  rmdbx_gather_environment_stats( stat, mstat, menvinfo );
184
219
  rmdbx_gather_reader_stats( db, stat, mstat, menvinfo );
185
220
 
186
- /* TODO: database and subdatabase stats */
187
-
188
221
  return stat;
189
222
  }
190
223
 
191
-
data/lib/mdbx.rb CHANGED
@@ -10,7 +10,7 @@ require 'mdbx_ext'
10
10
  module MDBX
11
11
 
12
12
  # The version of this gem.
13
- VERSION = '0.1.1'
13
+ VERSION = '0.3.2'
14
14
 
15
15
  end # module MDBX
16
16
 
data/lib/mdbx/database.rb CHANGED
@@ -29,10 +29,23 @@ class MDBX::Database
29
29
  ### Unless otherwise mentioned, option keys are symbols, and values
30
30
  ### are boolean.
31
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.
32
+ ### [:coalesce]
33
+ ### Attempt to coalesce items for the garbage collector,
34
+ ### potentialy increasing the chance of unallocating storage
35
+ ### earlier.
36
+ ###
37
+ ### [:compatible]
38
+ ### Skip compatibility checks when opening an in-use database with
39
+ ### unknown or mismatched flag values.
40
+ ###
41
+ ### [:exclusive]
42
+ ### Access is restricted to the first opening process. Other attempts
43
+ ### to use this database (even in readonly mode) are denied.
44
+ ###
45
+ ### [:lifo_reclaim]
46
+ ### Recycle garbage collected items via LIFO, instead of FIFO.
47
+ ### Depending on underlying hardware (disk write-back cache), this
48
+ ### could increase write performance.
36
49
  ###
37
50
  ### [:max_collections]
38
51
  ### Set the maximum number of "subdatabase" collections allowed. By
@@ -45,51 +58,38 @@ class MDBX::Database
45
58
  ### Set an upper boundary (in bytes) for the database map size.
46
59
  ### The default is 10485760 bytes.
47
60
  ###
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.
61
+ ### [:mode]
62
+ ### Whe creating a new database, set permissions to this 4 digit
63
+ ### octal number. Defaults to `0644`. Set to `0` to never automatically
64
+ ### create a new file, only opening existing databases.
58
65
  ###
59
- ### [:compat]
60
- ### Skip compatibility checks when opening an in-use database with
61
- ### unknown or mismatched flag values.
66
+ ### [:no_memory_init]
67
+ ### Skip initializing malloc'ed memory to zeroes before writing.
62
68
  ###
63
- ### [:writemap]
64
- ### Trade safety for speed for databases that fit within available
65
- ### memory. (See MDBX documentation for details.)
69
+ ### [:no_metasync]
70
+ ### A system crash may sacrifice the last commit for a potentially
71
+ ### large write performance increase. Database integrity is
72
+ ### maintained.
66
73
  ###
67
- ### [:no_threadlocal]
68
- ### Parallelize read-only transactions across threads. Writes are
69
- ### always thread local. (See MDBX documentatoin for details.)
74
+ ### [:no_subdir]
75
+ ### When creating a new database, don't put the data and lock file
76
+ ### under a dedicated subdirectory.
70
77
  ###
71
78
  ### [:no_readahead]
72
79
  ### Disable all use of OS readahead. Potentially useful for
73
80
  ### random reads wunder low memory conditions. Default behavior
74
81
  ### is to dynamically choose when to use or omit readahead.
75
82
  ###
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
+ ### [:no_threadlocal]
84
+ ### Parallelize read-only transactions across threads. Writes are
85
+ ### always thread local. (See MDBX documentatoin for details.)
83
86
  ###
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.
87
+ ### [:readonly]
88
+ ### Reject any write attempts while using this database handle.
88
89
  ###
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.
90
+ ### [:writemap]
91
+ ### Trade safety for speed for databases that fit within available
92
+ ### memory. (See MDBX documentation for details.)
93
93
  ###
94
94
  def self::open( *args, &block )
95
95
  db = new( *args )
@@ -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.collection( nil )
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,24 +228,18 @@ class MDBX::Database
201
228
  ### pairs.
202
229
  ###
203
230
  def to_a
204
- in_txn = self.in_transaction?
205
- self.snapshot unless in_txn
206
-
207
- return self.each_pair.to_a
208
- ensure
209
- self.abort unless in_txn
231
+ return self.conditional_snapshot do
232
+ self.each_pair.to_a
233
+ end
210
234
  end
211
235
 
212
236
 
213
237
  ### Return the entirety of database contents as a Hash.
214
238
  ###
215
239
  def to_h
216
- in_txn = self.in_transaction?
217
- self.snapshot unless in_txn
218
-
219
- return self.each_pair.to_h
220
- ensure
221
- self.abort unless in_txn
240
+ return self.conditional_snapshot do
241
+ self.each_pair.to_h
242
+ end
222
243
  end
223
244
 
224
245
 
@@ -267,12 +288,9 @@ class MDBX::Database
267
288
  ### Returns a new Array containing all keys in the collection.
268
289
  ###
269
290
  def keys
270
- in_txn = self.in_transaction?
271
- self.snapshot unless in_txn
272
-
273
- return self.each_key.to_a
274
- ensure
275
- self.abort unless in_txn
291
+ return self.conditional_snapshot do
292
+ self.each_key.to_a
293
+ end
276
294
  end
277
295
 
278
296
 
@@ -280,41 +298,32 @@ class MDBX::Database
280
298
  ### keys. Any given keys that are not found are ignored.
281
299
  ###
282
300
  def slice( *keys )
283
- in_txn = self.in_transaction?
284
- self.snapshot unless in_txn
285
-
286
- return keys.each_with_object( {} ) do |key, acc|
287
- val = self[ key ]
288
- acc[ key ] = val if val
301
+ return self.conditional_snapshot do
302
+ keys.each_with_object( {} ) do |key, acc|
303
+ val = self[ key ]
304
+ acc[ key ] = val if val
305
+ end
289
306
  end
290
- ensure
291
- self.abort unless in_txn
292
307
  end
293
308
 
294
309
 
295
310
  ### Returns a new Array containing all values in the collection.
296
311
  ###
297
312
  def values
298
- in_txn = self.in_transaction?
299
- self.snapshot unless in_txn
300
-
301
- return self.each_value.to_a
302
- ensure
303
- self.abort unless in_txn
313
+ return self.conditional_snapshot do
314
+ self.each_value.to_a
315
+ end
304
316
  end
305
317
 
306
318
 
307
319
  ### Returns a new Array containing values for the given +keys+.
308
320
  ###
309
321
  def values_at( *keys )
310
- in_txn = self.in_transaction?
311
- self.snapshot unless in_txn
312
-
313
- return keys.each_with_object( [] ) do |key, acc|
314
- acc << self[ key ]
322
+ return self.conditional_snapshot do
323
+ keys.each_with_object( [] ) do |key, acc|
324
+ acc << self[ key ]
325
+ end
315
326
  end
316
- ensure
317
- self.abort unless in_txn
318
327
  end
319
328
 
320
329
 
@@ -347,5 +356,23 @@ class MDBX::Database
347
356
  return stats
348
357
  end
349
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
+
350
377
  end # class MDBX::Database
351
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.1
4
+ version: 0.3.2
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-03-14 00:00:00.000000000 Z
37
+ date: 2021-07-13 00:00:00.000000000 Z
38
38
  dependencies:
39
39
  - !ruby/object:Gem::Dependency
40
40
  name: pry