Skip to content
Snippets Groups Projects
Commit 4de0d495 authored by Daniel Larimer's avatar Daniel Larimer
Browse files

merge

parents d9204a25 67914006
No related branches found
No related tags found
No related merge requests found
......@@ -7,17 +7,27 @@
#include <boost/interprocess/containers/deque.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/sync/interprocess_sharable_mutex.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/chrono.hpp>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>
#include <boost/throw_exception.hpp>
#include <stdexcept>
#include <typeindex>
#include <array>
#include <atomic>
#include <fstream>
#include <stdexcept>
#include <typeindex>
#ifndef CHAINBASE_DEFAULT_NUM_RW_LOCKS
#define CHAINBASE_DEFAULT_NUM_RW_LOCKS 10
#endif
namespace chainbase {
......@@ -54,6 +64,9 @@ namespace chainbase {
}
};
typedef boost::interprocess::interprocess_sharable_mutex read_write_mutex;
typedef boost::interprocess::sharable_lock< read_write_mutex > read_lock;
typedef boost::unique_lock< read_write_mutex > write_lock;
class database;
......@@ -93,7 +106,7 @@ namespace chainbase {
* This macro must be used at global scope and OBJECT_TYPE and INDEX_TYPE must be fully qualified
*/
#define CHAINBASE_SET_INDEX_TYPE( OBJECT_TYPE, INDEX_TYPE ) \
namespace chainbase { template<> struct get_index_type<OBJECT_TYPE> { typedef INDEX_TYPE type; }; }
namespace chainbase { template<> struct get_index_type<OBJECT_TYPE> { typedef INDEX_TYPE type; }; }
#define CHAINBASE_DEFAULT_CONSTRUCTOR( OBJECT_TYPE ) \
template<typename Constructor, typename Allocator> \
......@@ -117,7 +130,7 @@ namespace chainbase {
:_stack(a),_indices( a ),_size_of_value_type( sizeof(typename MultiIndexType::node_type) ),_size_of_this(sizeof(*this)){}
void validate()const {
if( sizeof(typename MultiIndexType::node_type) != _size_of_value_type || sizeof(*this) != _size_of_this )
if( sizeof(typename MultiIndexType::node_type) != _size_of_value_type || sizeof(*this) != _size_of_this )
BOOST_THROW_EXCEPTION( std::runtime_error("content of memory does not match data expected by executable") );
}
......@@ -137,7 +150,7 @@ namespace chainbase {
auto insert_result = _indices.emplace( constructor, _indices.get_allocator() );
if( !insert_result.second ) {
throw std::logic_error("could not insert object, most likely a uniqueness constraint was violated");
BOOST_THROW_EXCEPTION( std::logic_error("could not insert object, most likely a uniqueness constraint was violated") );
}
++_next_id;
......@@ -559,6 +572,33 @@ namespace chainbase {
};
class read_write_mutex_manager
{
public:
read_write_mutex_manager()
{
_current_lock = 0;
}
~read_write_mutex_manager(){}
void next_lock()
{
_current_lock++;
new( &_locks[ _current_lock % 10 ] ) read_write_mutex();
}
read_write_mutex& current_lock()
{
return _locks[ _current_lock % 10 ];
}
private:
std::array< read_write_mutex, 10 > _locks;
std::atomic< uint32_t > _current_lock;
};
/**
* This class
*/
......@@ -570,7 +610,7 @@ namespace chainbase {
read_write = 1
};
void open( const bfs::path& dir, int write = read_only, uint64_t shared_file_size = 0 );
void open( const bfs::path& dir, uint32_t write = read_only, uint64_t shared_file_size = 0 );
void close();
void flush();
void wipe( const bfs::path& dir );
......@@ -663,7 +703,6 @@ namespace chainbase {
auto new_index = new index<index_type>( *idx_ptr );
_index_map[ type_id ].reset( new_index );
_index_list.push_back( new_index );
_type_name_to_id.emplace( type_name, type_id );
}
auto get_segment_manager() -> decltype( ((bip::managed_mapped_file*)nullptr)->get_segment_manager()) {
......@@ -674,6 +713,8 @@ namespace chainbase {
const generic_index<MultiIndexType>& get_index()const {
typedef generic_index<MultiIndexType> index_type;
typedef index_type* index_type_ptr;
assert( _index_map.size() > index_type::value_type::type_id );
assert( _index_map[index_type::value_type::type_id] );
return *index_type_ptr( _index_map[index_type::value_type::type_id]->get() );
}
......@@ -681,14 +722,18 @@ namespace chainbase {
auto get_index()const -> decltype( ((generic_index<MultiIndexType>*)( nullptr ))->indicies().template get<ByIndex>() ) {
typedef generic_index<MultiIndexType> index_type;
typedef index_type* index_type_ptr;
assert( _index_map.size() > index_type::value_type::type_id );
assert( _index_map[index_type::value_type::type_id] );
return index_type_ptr( _index_map[index_type::value_type::type_id]->get() )->indicies().template get<ByIndex>();
}
template<typename MultiIndexType>
generic_index<MultiIndexType>& get_mutable_index() {
typedef generic_index<MultiIndexType> index_type;
typedef index_type* index_type_ptr;
return *index_type_ptr( _index_map[index_type::value_type::type_id]->get() );
typedef generic_index<MultiIndexType> index_type;
typedef index_type* index_type_ptr;
assert( _index_map.size() > index_type::value_type::type_id );
assert( _index_map[index_type::value_type::type_id] );
return *index_type_ptr( _index_map[index_type::value_type::type_id]->get() );
}
template< typename ObjectType, typename IndexedByType, typename CompatibleKey >
......@@ -720,7 +765,7 @@ namespace chainbase {
}
template< typename ObjectType >
const ObjectType& get( oid< ObjectType > key = oid< ObjectType >() )const
const ObjectType& get( const oid< ObjectType >& key = oid< ObjectType >() )const
{
auto obj = find< ObjectType >( key );
if( !obj ) BOOST_THROW_EXCEPTION( std::out_of_range( "unknown key") );
......@@ -748,22 +793,67 @@ namespace chainbase {
return get_mutable_index<index_type>().emplace( std::forward<Constructor>(con) );
}
template< typename Lambda >
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() );
if( !wait_micro )
{
lock.lock();
}
else
{
if( !lock.timed_lock( boost::posix_time::microsec_clock::local_time() + boost::posix_time::microseconds( wait_micro ) ) )
BOOST_THROW_EXCEPTION( std::runtime_error( "unable to acquire lock" ) );
}
return callback();
}
template< typename Lambda >
auto with_write_lock( Lambda&& callback, uint64_t wait_micro = 1000000 ) -> decltype( (*(Lambda*)nullptr)() )
{
if( _read_only )
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() );
if( !wait_micro )
{
lock.lock();
}
else
{
while( !lock.timed_lock( boost::posix_time::microsec_clock::local_time() + boost::posix_time::microseconds( wait_micro ) ) )
{
_rw_manager->next_lock();
lock = write_lock( _rw_manager->current_lock(), boost::defer_lock_t() );
}
}
return callback();
}
private:
unique_ptr<bip::managed_mapped_file> _segment;
bool _read_only = false;
unique_ptr<bip::managed_mapped_file> _segment;
unique_ptr<bip::managed_mapped_file> _meta;
read_write_mutex_manager* _rw_manager = nullptr;
bool _read_only = false;
bip::file_lock _flock;
/**
* This is a sparse list of known indicies kept to accelerate creation of undo sessions
*/
vector<abstract_index*> _index_list;
vector<abstract_index*> _index_list;
/**
* This is a full map (size 2^16) of all possible index designed for constant time lookup
*/
vector<unique_ptr<abstract_index>> _index_map;
bfs::path _data_dir;
vector<unique_ptr<abstract_index>> _index_map;
boost::container::flat_map< std::string, uint16_t > _type_name_to_id;
bfs::path _data_dir;
};
......
#include <chainbase.hpp>
#include <chainbase/chainbase.hpp>
#include <boost/array.hpp>
#include <iostream>
......@@ -30,23 +30,31 @@ namespace chainbase {
bool windows = false;
};
void database::open( const bfs::path& dir, int flags, uint64_t shared_file_size ) {
void database::open( const bfs::path& dir, uint32_t flags, uint64_t shared_file_size ) {
bool write = flags & database::read_write;
if( !bfs::exists( dir ) ) {
if( !write ) BOOST_THROW_EXCEPTION( std::runtime_error( "database file not found at " + dir.native() ) );
}
bfs::create_directories( dir );
if( _data_dir != dir ) close();
_data_dir = dir;
auto abs_path = bfs::absolute( dir / "shared_memory" );
auto abs_path = bfs::absolute( dir / "shared_memory.bin" );
if( bfs::exists( abs_path ) )
{
if( write ) {
if( write )
{
auto existing_file_size = bfs::file_size( abs_path );
if( shared_file_size > existing_file_size )
{
if( !bip::managed_mapped_file::grow( abs_path.generic_string().c_str(), shared_file_size - existing_file_size ) )
BOOST_THROW_EXCEPTION( std::runtime_error( "could not grow database file to requested size." ) );
}
_segment.reset( new bip::managed_mapped_file( bip::open_only,
abs_path.generic_string().c_str()
) );
......@@ -67,24 +75,59 @@ namespace chainbase {
) );
_segment->find_or_construct< environment_check >( "environment" )();
}
abs_path = bfs::absolute( dir / "shared_memory.meta" );
if( bfs::exists( abs_path ) )
{
_meta.reset( new bip::managed_mapped_file( bip::open_only, abs_path.generic_string().c_str()
) );
_rw_manager = _meta->find< read_write_mutex_manager >( "rw_manager" ).first;
if( !_rw_manager )
BOOST_THROW_EXCEPTION( std::runtime_error( "could not find read write lock manager" ) );
}
else
{
_meta.reset( new bip::managed_mapped_file( bip::create_only,
abs_path.generic_string().c_str(), sizeof( read_write_mutex_manager ) * 2
) );
_rw_manager = _meta->find_or_construct< read_write_mutex_manager >( "rw_manager" )();
}
if( write )
{
_flock = bip::file_lock( abs_path.generic_string().c_str() );
if( !_flock.try_lock() )
BOOST_THROW_EXCEPTION( std::runtime_error( "could not gain write access to the shared memory file" ) );
}
}
void database::flush() {
if( _segment )
_segment->flush();
if( _meta )
_meta->flush();
}
void database::close()
{
_segment.reset();
_meta.reset();
_data_dir = bfs::path();
}
void database::wipe( const bfs::path& dir )
{
_segment.reset();
bfs::remove_all( dir / "shared_memory" );
_meta.reset();
bfs::remove_all( dir / "shared_memory.bin" );
bfs::remove_all( dir / "shared_memory.meta" );
_data_dir = bfs::path();
_index_list.clear();
_index_map.clear();
}
void database::undo()
......@@ -94,6 +137,7 @@ namespace chainbase {
item->undo();
}
}
void database::squash()
{
for( auto& item : _index_list )
......@@ -101,6 +145,7 @@ namespace chainbase {
item->squash();
}
}
void database::commit( int64_t revision )
{
for( auto& item : _index_list )
......
#define BOOST_TEST_MODULE chainbase test
#include <boost/test/unit_test.hpp>
#include <chainbase.hpp>
#include <chainbase/chainbase.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
......@@ -15,12 +15,12 @@ using namespace boost::multi_index;
//BOOST_TEST_SUITE( serialization_tests, clean_database_fixture )
struct book : public chainbase::object<0, book> {
template<typename Constructor, typename Allocator>
book( Constructor&& c, Allocator&& a ) {
c(*this);
}
id_type id;
int a = 0;
int b = 1;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment