mdbx 0.1.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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