Move de/serialization to ruby for easier error detection.

Closes open transactions if de/serialization fails for any reason,
avoiding the object to be in a potentially confused state.

Thanks to Michael Granger (ged@faeriemud.org) for the heads up and test case.

FossilOrigin-Name: e6e52675510533da8a26b0e2f0b2f73505a3b4ee0c94b123c37089489ed7745a
This commit is contained in:
Mahlon E. Smith 2021-10-06 20:43:13 +00:00
parent 6cc96d8fae
commit 25655d0554
4 changed files with 56 additions and 29 deletions

View file

@ -135,11 +135,7 @@ rmdbx_key_for( VALUE key, MDBX_val *ckey )
void
rmdbx_val_for( VALUE self, VALUE val, MDBX_val *data )
{
VALUE serialize_proc = rb_iv_get( self, "@serializer" );
if ( ! NIL_P( serialize_proc ) )
val = rb_funcall( serialize_proc, rb_intern("call"), 1, val );
val = rb_funcall( self, rb_intern("serialize"), 1, val );
Check_Type( val, T_STRING );
data->iov_len = RSTRING_LEN( val );
@ -148,20 +144,6 @@ rmdbx_val_for( VALUE self, VALUE val, MDBX_val *data )
}
/*
* Deserialize and return a value.
*/
VALUE
rmdbx_deserialize( VALUE self, VALUE val )
{
VALUE deserialize_proc = rb_iv_get( self, "@deserializer" );
if ( ! NIL_P( deserialize_proc ) )
val = rb_funcall( deserialize_proc, rb_intern("call"), 1, val );
return val;
}
/*
* Open the DB environment handle.
*
@ -355,7 +337,7 @@ rmdbx_get_val( VALUE self, VALUE key )
switch ( rc ) {
case MDBX_SUCCESS:
rv = rb_str_new( data.iov_base, data.iov_len );
return rmdbx_deserialize( self, rv );
return rb_funcall( self, rb_intern("deserialize"), 1, rv );
case MDBX_NOTFOUND:
return Qnil;
@ -439,13 +421,17 @@ rmdbx_set_subdb( VALUE self, VALUE name )
if ( db->txn )
rb_raise( rmdbx_eDatabaseError, "Unable to change collection: transaction open" );
xfree( db->subdb );
xfree( db->subdb );
db->subdb = NULL;
if ( ! NIL_P(name) ) {
size_t len = RSTRING_LEN( name ) + 1;
db->subdb = malloc( len );
strlcpy( db->subdb, StringValuePtr(name), len );
rmdbx_log_obj( self, "debug", "setting subdb: %s", RSTRING_PTR(name) );
}
else {
rmdbx_log_obj( self, "debug", "clearing subdb" );
}
/* Reset the db handle and issue a single transaction to reify
@ -644,11 +630,11 @@ rmdbx_each_value_i( VALUE self )
if ( mdbx_cursor_get( db->cursor, &key, &data, MDBX_FIRST ) == MDBX_SUCCESS ) {
VALUE rv = rb_str_new( data.iov_base, data.iov_len );
rb_yield( rmdbx_deserialize( self, rv ) );
rb_yield( rb_funcall( self, rb_intern("deserialize"), 1, rv ) );
while ( mdbx_cursor_get( db->cursor, &key, &data, MDBX_NEXT ) == MDBX_SUCCESS ) {
rv = rb_str_new( data.iov_base, data.iov_len );
rb_yield( rmdbx_deserialize( self, rv ) );
rb_yield( rb_funcall( self, rb_intern("deserialize"), 1, rv ) );
}
}
@ -694,12 +680,15 @@ rmdbx_each_pair_i( VALUE self )
if ( mdbx_cursor_get( db->cursor, &key, &data, MDBX_FIRST ) == MDBX_SUCCESS ) {
VALUE rkey = rb_str_new( key.iov_base, key.iov_len );
VALUE rval = rb_str_new( data.iov_base, data.iov_len );
rb_yield( rb_assoc_new( rkey, rmdbx_deserialize( self, rval ) ) );
rval = rb_funcall( self, rb_intern("deserialize"), 1, rval );
rb_yield( rb_assoc_new( rkey, rval ) );
while ( mdbx_cursor_get( db->cursor, &key, &data, MDBX_NEXT ) == MDBX_SUCCESS ) {
rkey = rb_str_new( key.iov_base, key.iov_len );
rval = rb_str_new( data.iov_base, data.iov_len );
rb_yield( rb_assoc_new( rkey, rmdbx_deserialize( self, rval ) ) );
rval = rb_funcall( self, rb_intern("deserialize"), 1, rval );
rb_yield( rb_assoc_new( rkey, rval ) );
}
}