mdbx 0.2.0 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,6 +6,60 @@ VALUE rmdbx_mMDBX;
6
6
  VALUE rmdbx_eDatabaseError;
7
7
  VALUE rmdbx_eRollback;
8
8
 
9
+ /*
10
+ * Log a message to the given +context+ object's logger.
11
+ */
12
+ void
13
+ #ifdef HAVE_STDARG_PROTOTYPES
14
+ rmdbx_log_obj( VALUE context, const char *level, const char *fmt, ... )
15
+ #else
16
+ rmdbx_log_obj( VALUE context, const char *level, const char *fmt, va_dcl )
17
+ #endif
18
+ {
19
+ char buf[BUFSIZ];
20
+ va_list args;
21
+ VALUE logger = Qnil;
22
+ VALUE message = Qnil;
23
+
24
+ va_init_list( args, fmt );
25
+ vsnprintf( buf, BUFSIZ, fmt, args );
26
+ message = rb_str_new2( buf );
27
+
28
+ logger = rb_funcall( context, rb_intern("log"), 0 );
29
+ rb_funcall( logger, rb_intern(level), 1, message );
30
+
31
+ va_end( args );
32
+ }
33
+
34
+
35
+ /*
36
+ * Log a message to the global logger.
37
+ */
38
+ void
39
+ #ifdef HAVE_STDARG_PROTOTYPES
40
+ rmdbx_log( const char *level, const char *fmt, ... )
41
+ #else
42
+ rmdbx_log( const char *level, const char *fmt, va_dcl )
43
+ #endif
44
+ {
45
+ char buf[BUFSIZ];
46
+ va_list args;
47
+ VALUE logger = Qnil;
48
+ VALUE message = Qnil;
49
+
50
+ va_init_list( args, fmt );
51
+ vsnprintf( buf, BUFSIZ, fmt, args );
52
+ message = rb_str_new2( buf );
53
+
54
+ logger = rb_funcall( rmdbx_mMDBX, rb_intern("logger"), 0 );
55
+ rb_funcall( logger, rb_intern(level), 1, message );
56
+
57
+ va_end( args );
58
+ }
59
+
60
+
61
+
62
+
9
63
  /*
10
64
  * MDBX initialization
11
65
  */
@@ -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,27 @@ 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
- * Globals
58
+ * Logging
47
59
  * ------------------------------------------------------------ */
60
+ #ifdef HAVE_STDARG_PROTOTYPES
61
+ #include <stdarg.h>
62
+ #define va_init_list(a,b) va_start(a,b)
63
+ void rmdbx_log_obj( VALUE, const char *, const char *, ... );
64
+ void rmdbx_log( const char *, const char *, ... );
65
+ #else
66
+ #include <varargs.h>
67
+ #define va_init_list(a,b) va_start(a)
68
+ void rmdbx_log_obj( VALUE, const char *, const char *, va_dcl );
69
+ void rmdbx_log( const char *, const char *, va_dcl );
70
+ #endif
48
71
 
72
+
73
+ /* ------------------------------------------------------------
74
+ * Globals
75
+ * ------------------------------------------------------------ */
49
76
  extern VALUE rmdbx_mMDBX;
50
77
  extern VALUE rmdbx_cDatabase;
51
78
  extern VALUE rmdbx_eDatabaseError;
@@ -55,13 +82,15 @@ extern VALUE rmdbx_eRollback;
55
82
  /* ------------------------------------------------------------
56
83
  * Functions
57
84
  * ------------------------------------------------------------ */
85
+ extern void rmdbx_free( void *db ); /* forward declaration for the allocator */
58
86
  extern void Init_rmdbx ( void );
59
87
  extern void rmdbx_init_database ( void );
88
+ extern void rmdbx_close_all( rmdbx_db_t* );
60
89
  extern void rmdbx_open_txn( rmdbx_db_t*, int );
61
90
  extern void rmdbx_close_txn( rmdbx_db_t*, int );
62
-
91
+ extern void rmdbx_open_cursor( rmdbx_db_t* );
63
92
  extern VALUE rmdbx_gather_stats( rmdbx_db_t* );
64
93
 
65
94
 
66
- #endif /* define MDBX_EXT_0_9_3 */
95
+ #endif /* define RBMDBX_EXT */
67
96
 
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/database.rb CHANGED
@@ -8,6 +8,9 @@ require 'mdbx' unless defined?( MDBX )
8
8
  # The primary class for interacting with an MDBX database.
9
9
  #
10
10
  class MDBX::Database
11
+ extend Loggability
12
+
13
+ log_to :mdbx
11
14
 
12
15
  ### call-seq:
13
16
  ### MDBX::Database.open( path ) => db
@@ -29,10 +32,23 @@ class MDBX::Database
29
32
  ### Unless otherwise mentioned, option keys are symbols, and values
30
33
  ### are boolean.
31
34
  ###
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.
35
+ ### [:coalesce]
36
+ ### Attempt to coalesce items for the garbage collector,
37
+ ### potentialy increasing the chance of unallocating storage
38
+ ### earlier.
39
+ ###
40
+ ### [:compatible]
41
+ ### Skip compatibility checks when opening an in-use database with
42
+ ### unknown or mismatched flag values.
43
+ ###
44
+ ### [:exclusive]
45
+ ### Access is restricted to the first opening process. Other attempts
46
+ ### to use this database (even in readonly mode) are denied.
47
+ ###
48
+ ### [:lifo_reclaim]
49
+ ### Recycle garbage collected items via LIFO, instead of FIFO.
50
+ ### Depending on underlying hardware (disk write-back cache), this
51
+ ### could increase write performance.
36
52
  ###
37
53
  ### [:max_collections]
38
54
  ### Set the maximum number of "subdatabase" collections allowed. By
@@ -45,51 +61,38 @@ class MDBX::Database
45
61
  ### Set an upper boundary (in bytes) for the database map size.
46
62
  ### The default is 10485760 bytes.
47
63
  ###
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.
64
+ ### [:mode]
65
+ ### Whe creating a new database, set permissions to this 4 digit
66
+ ### octal number. Defaults to `0644`. Set to `0` to never automatically
67
+ ### create a new file, only opening existing databases.
58
68
  ###
59
- ### [:compat]
60
- ### Skip compatibility checks when opening an in-use database with
61
- ### unknown or mismatched flag values.
69
+ ### [:no_memory_init]
70
+ ### Skip initializing malloc'ed memory to zeroes before writing.
62
71
  ###
63
- ### [:writemap]
64
- ### Trade safety for speed for databases that fit within available
65
- ### memory. (See MDBX documentation for details.)
72
+ ### [:no_metasync]
73
+ ### A system crash may sacrifice the last commit for a potentially
74
+ ### large write performance increase. Database integrity is
75
+ ### maintained.
66
76
  ###
67
- ### [:no_threadlocal]
68
- ### Parallelize read-only transactions across threads. Writes are
69
- ### always thread local. (See MDBX documentatoin for details.)
77
+ ### [:no_subdir]
78
+ ### When creating a new database, don't put the data and lock file
79
+ ### under a dedicated subdirectory.
70
80
  ###
71
81
  ### [:no_readahead]
72
82
  ### Disable all use of OS readahead. Potentially useful for
73
83
  ### random reads wunder low memory conditions. Default behavior
74
84
  ### is to dynamically choose when to use or omit readahead.
75
85
  ###
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.
86
+ ### [:no_threadlocal]
87
+ ### Parallelize read-only transactions across threads. Writes are
88
+ ### always thread local. (See MDBX documentatoin for details.)
83
89
  ###
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.
90
+ ### [:readonly]
91
+ ### Reject any write attempts while using this database handle.
88
92
  ###
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.
93
+ ### [:writemap]
94
+ ### Trade safety for speed for databases that fit within available
95
+ ### memory. (See MDBX documentation for details.)
93
96
  ###
94
97
  def self::open( *args, &block )
95
98
  db = new( *args )
@@ -128,16 +131,43 @@ class MDBX::Database
128
131
  attr_accessor :deserializer
129
132
 
130
133
 
134
+ alias_method :size, :length
135
+ alias_method :each, :each_pair
136
+ alias_method :has_key?, :include?
137
+
138
+
139
+ ### Gets or sets the sub-database "collection" that read/write
140
+ ### operations apply to. If a block is passed, the collection
141
+ ### automatically reverts to the prior collection when it exits.
142
+ ###
143
+ ### db.collection #=> (collection name, or nil if in main)
144
+ ### db.collection( 'collection_name' ) #=> db
145
+ ###
146
+ ### db.collection( 'collection_name' ) do
147
+ ### [ ... ]
148
+ ### end # reverts to the previous collection name
149
+ ###
150
+ def collection( name=nil )
151
+ current = self.get_subdb
152
+ return current unless name
153
+
154
+ self.set_subdb( name.to_s )
155
+ yield( self ) if block_given?
156
+
157
+ return self
158
+
159
+ ensure
160
+ self.set_subdb( current ) if name && block_given?
161
+ end
162
+ alias_method :namespace, :collection
163
+
164
+
131
165
  ### Switch to the top-level collection.
132
166
  ###
133
167
  def main
134
- return self.collection( nil )
168
+ return self.set_subdb( nil )
135
169
  end
136
170
 
137
- alias_method :namespace, :collection
138
- alias_method :size, :length
139
- alias_method :each, :each_pair
140
-
141
171
 
142
172
  #
143
173
  # Transaction methods
@@ -334,6 +364,34 @@ class MDBX::Database
334
364
  protected
335
365
  #########
336
366
 
367
+
368
+ ### Safely serialize a value, closing any open transaction and re-raising
369
+ ### if necessary.
370
+ ###
371
+ def serialize( val )
372
+ return val unless self.serializer
373
+ return self.serializer.call( val )
374
+
375
+ rescue => err
376
+ self.close_transaction( false )
377
+ raise err
378
+ end
379
+
380
+
381
+ ### Safely deserialize a value, closing any open transaction and re-raising
382
+ ### if necessary.
383
+ ###
384
+ def deserialize( val )
385
+ return val unless self.deserializer
386
+ return self.deserializer.call( val )
387
+
388
+ rescue => err
389
+ self.close_transaction( false )
390
+ raise err
391
+ end
392
+
393
+
394
+
337
395
  ### Yield and return the block, opening a snapshot first if
338
396
  ### there isn't already a transaction in progress. Closes
339
397
  ### the snapshot if this method opened it.
data/lib/mdbx.rb CHANGED
@@ -2,15 +2,22 @@
2
2
  # vim: set nosta noet ts=4 sw=4 ft=ruby:
3
3
  # encoding: utf-8
4
4
 
5
+ require 'loggability'
6
+
5
7
  require 'mdbx_ext'
6
8
 
7
9
 
8
10
  # Top level namespace for MDBX.
9
11
  #
10
12
  module MDBX
13
+ extend Loggability
11
14
 
12
15
  # The version of this gem.
13
- VERSION = '0.2.0'
16
+ VERSION = '0.3.3'
17
+
18
+
19
+ log_as :mdbx
20
+
14
21
 
15
22
  end # module MDBX
16
23
 
data.tar.gz.sig CHANGED
Binary file
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.2.0
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mahlon E. Smith
@@ -34,8 +34,22 @@ cert_chain:
34
34
  49pOzX5KHZLTS9DKeaP/xcGPz6C8MiwQdYrZarr2SHRASX1zFa79rkItO8kE6RDr
35
35
  b6WDF79UvZ55ajtE00TiwqjQL/ZPEtbd
36
36
  -----END CERTIFICATE-----
37
- date: 2021-03-19 00:00:00.000000000 Z
37
+ date: 2021-10-22 00:00:00.000000000 Z
38
38
  dependencies:
39
+ - !ruby/object:Gem::Dependency
40
+ name: loggability
41
+ requirement: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - "~>"
44
+ - !ruby/object:Gem::Version
45
+ version: '0.17'
46
+ type: :runtime
47
+ prerelease: false
48
+ version_requirements: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - "~>"
51
+ - !ruby/object:Gem::Version
52
+ version: '0.17'
39
53
  - !ruby/object:Gem::Dependency
40
54
  name: pry
41
55
  requirement: !ruby/object:Gem::Requirement
metadata.gz.sig CHANGED
Binary file