Skip to content
Snippets Groups Projects
Commit 859c9912 authored by theoreticalbts's avatar theoreticalbts
Browse files

Force calling code to correctly lock database

parent f1d4734e
No related branches found
No related tags found
No related merge requests found
......@@ -133,6 +133,29 @@ namespace chainbase {
int64_t revision = 0;
};
/**
* The code we want to implement is this:
*
* ++target; try { ... } finally { --target }
*
* In C++ the only way to implement finally is to create a class
* with a destructor, so that's what we do here.
*/
class int_incrementer
{
public:
int_incrementer( int32_t& target ) : _target(target)
{ ++_target; }
~int_incrementer()
{ --_target; }
int32_t get()const
{ return _target; }
private:
int32_t& _target;
};
/**
* The value_type stored in the multiindex container must have a integer field with the name 'id'. This will
* be the primary key and it will be assigned and managed by generic_index.
......@@ -616,6 +639,20 @@ namespace chainbase {
void flush();
void wipe( const bfs::path& dir );
void require_lock_fail( const char* lock_type )const;
void require_read_lock()const
{
if( _read_lock_count <= 0 )
require_lock_fail("read");
}
void require_write_lock()
{
if( _write_lock_count <= 0 )
require_lock_fail("write");
}
struct session {
public:
session( session&& s ):_index_sessions( std::move(s._index_sessions) ),_revision( s._revision ){}
......@@ -672,6 +709,7 @@ namespace chainbase {
void set_revision( uint64_t revision )
{
require_write_lock();
for( auto i : _index_list ) i->set_revision( revision );
}
......@@ -716,7 +754,9 @@ namespace chainbase {
}
template<typename MultiIndexType>
const generic_index<MultiIndexType>& get_index()const {
const generic_index<MultiIndexType>& get_index()const
{
require_read_lock();
typedef generic_index<MultiIndexType> index_type;
typedef index_type* index_type_ptr;
assert( _index_map.size() > index_type::value_type::type_id );
......@@ -725,7 +765,9 @@ namespace chainbase {
}
template<typename MultiIndexType, typename ByIndex>
auto get_index()const -> decltype( ((generic_index<MultiIndexType>*)( nullptr ))->indicies().template get<ByIndex>() ) {
auto get_index()const -> decltype( ((generic_index<MultiIndexType>*)( nullptr ))->indicies().template get<ByIndex>() )
{
require_read_lock();
typedef generic_index<MultiIndexType> index_type;
typedef index_type* index_type_ptr;
assert( _index_map.size() > index_type::value_type::type_id );
......@@ -734,7 +776,9 @@ namespace chainbase {
}
template<typename MultiIndexType>
generic_index<MultiIndexType>& get_mutable_index() {
generic_index<MultiIndexType>& get_mutable_index()
{
require_write_lock();
typedef generic_index<MultiIndexType> index_type;
typedef index_type* index_type_ptr;
assert( _index_map.size() > index_type::value_type::type_id );
......@@ -745,6 +789,7 @@ namespace chainbase {
template< typename ObjectType, typename IndexedByType, typename CompatibleKey >
const ObjectType* find( CompatibleKey&& key )const
{
require_read_lock();
typedef typename get_index_type< ObjectType >::type index_type;
const auto& idx = get_index< index_type >().indicies().template get< IndexedByType >();
auto itr = idx.find( std::forward< CompatibleKey >( key ) );
......@@ -755,6 +800,7 @@ namespace chainbase {
template< typename ObjectType >
const ObjectType* find( oid< ObjectType > key = oid< ObjectType >() ) const
{
require_read_lock();
typedef typename get_index_type< ObjectType >::type index_type;
const auto& idx = get_index< index_type >().indices();
auto itr = idx.find( key );
......@@ -765,6 +811,7 @@ namespace chainbase {
template< typename ObjectType, typename IndexedByType, typename CompatibleKey >
const ObjectType& get( CompatibleKey&& key )const
{
require_read_lock();
auto obj = find< ObjectType, IndexedByType >( std::forward< CompatibleKey >( key ) );
if( !obj ) BOOST_THROW_EXCEPTION( std::out_of_range( "unknown key" ) );
return *obj;
......@@ -773,6 +820,7 @@ namespace chainbase {
template< typename ObjectType >
const ObjectType& get( const oid< ObjectType >& key = oid< ObjectType >() )const
{
require_read_lock();
auto obj = find< ObjectType >( key );
if( !obj ) BOOST_THROW_EXCEPTION( std::out_of_range( "unknown key") );
return *obj;
......@@ -781,6 +829,7 @@ namespace chainbase {
template<typename ObjectType, typename Modifier>
void modify( const ObjectType& obj, Modifier&& m )
{
require_write_lock();
typedef typename get_index_type<ObjectType>::type index_type;
get_mutable_index<index_type>().modify( obj, m );
}
......@@ -788,6 +837,7 @@ namespace chainbase {
template<typename ObjectType>
void remove( const ObjectType& obj )
{
require_write_lock();
typedef typename get_index_type<ObjectType>::type index_type;
return get_mutable_index<index_type>().remove( obj );
}
......@@ -795,6 +845,7 @@ namespace chainbase {
template<typename ObjectType, typename Constructor>
const ObjectType& create( Constructor&& con )
{
require_write_lock();
typedef typename get_index_type<ObjectType>::type index_type;
return get_mutable_index<index_type>().emplace( std::forward<Constructor>(con) );
}
......@@ -803,6 +854,8 @@ namespace chainbase {
auto with_read_lock( Lambda&& callback, uint64_t wait_micro = 1000000 ) -> decltype( (*(Lambda*)nullptr)() )
{
read_lock lock( _rw_manager->current_lock(), bip::defer_lock_type() );
int_incrementer ii( _read_lock_count );
ii.get(); // prevent unused variable warning
if( !wait_micro )
{
......@@ -825,6 +878,8 @@ namespace chainbase {
BOOST_THROW_EXCEPTION( std::logic_error( "cannot acquire write lock on read-only process" ) );
write_lock lock( _rw_manager->current_lock(), boost::defer_lock_t() );
int_incrementer ii( _write_lock_count );
ii.get(); // prevent unused variable warning
if( !wait_micro )
{
......@@ -860,6 +915,9 @@ namespace chainbase {
vector<unique_ptr<abstract_index>> _index_map;
bfs::path _data_dir;
int32_t _read_lock_count = 0;
int32_t _write_lock_count = 0;
};
template<typename Object, typename... Args>
......
......@@ -130,6 +130,13 @@ namespace chainbase {
_index_map.clear();
}
void database::require_lock_fail( const char* lock_type )const
{
std::string err_msg = "require_" + std::string( lock_type ) + "_lock() failed";
std::cerr << err_msg << std::endl;
BOOST_THROW_EXCEPTION( std::runtime_error( err_msg ) );
}
void database::undo()
{
for( auto& item : _index_list )
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment