3#include <boost/interprocess/managed_mapped_file.hpp>
4#include <boost/interprocess/containers/map.hpp>
5#include <boost/interprocess/containers/set.hpp>
6#include <boost/interprocess/containers/flat_map.hpp>
7#include <boost/interprocess/containers/deque.hpp>
8#include <boost/interprocess/containers/string.hpp>
9#include <boost/interprocess/allocators/allocator.hpp>
10#include <boost/interprocess/sync/interprocess_sharable_mutex.hpp>
11#include <boost/interprocess/sync/sharable_lock.hpp>
12#include <boost/core/demangle.hpp>
14#include <boost/multi_index_container.hpp>
16#include <boost/chrono.hpp>
17#include <boost/config.hpp>
18#include <boost/filesystem.hpp>
19#include <boost/lexical_cast.hpp>
20#include <boost/throw_exception.hpp>
36#ifndef CHAINBASE_NUM_RW_LOCKS
37 #define CHAINBASE_NUM_RW_LOCKS 10
40#ifdef CHAINBASE_CHECK_LOCKING
41 #define CHAINBASE_REQUIRE_READ_LOCK(m, t) require_read_lock(m, typeid(t).name())
42 #define CHAINBASE_REQUIRE_WRITE_LOCK(m, t) require_write_lock(m, typeid(t).name())
44 #define CHAINBASE_REQUIRE_READ_LOCK(m, t)
45 #define CHAINBASE_REQUIRE_WRITE_LOCK(m, t)
52 using std::unique_ptr;
56 using allocator = bip::allocator<T, pinnable_mapped_file::segment_manager>;
64 typedef boost::interprocess::sharable_lock< read_write_mutex >
read_lock;
83 s << boost::core::demangle(
typeid(
oid<T>).
name()) <<
'(' <<
id._id <<
')';
return s;
89 template<u
int16_t TypeNumber,
typename Derived>
105 #define CHAINBASE_SET_INDEX_TYPE( OBJECT_TYPE, INDEX_TYPE ) \
106 namespace chainbase { template<> struct get_index_type<OBJECT_TYPE> { typedef INDEX_TYPE type; }; }
108 #define CHAINBASE_DEFAULT_CONSTRUCTOR( OBJECT_TYPE ) \
109 template<typename Constructor, typename Allocator> \
110 OBJECT_TYPE( Constructor&& c, Allocator&& ) { c(*this); }
135 template<
typename MultiIndexType>
146 template<
typename SessionType>
152 virtual void push()
override { _session.push(); }
153 virtual void squash()
override{ _session.squash(); }
154 virtual void undo()
override { _session.undo(); }
156 SessionType _session;
179 void*
get()
const {
return _idx_ptr; }
184 template<
typename BaseIndex>
195 virtual void undo()
const override { _base.undo(); }
196 virtual void squash()
const override { _base.squash(); }
198 virtual void undo_all()
const override {_base.undo_all(); }
201 virtual const std::string&
type_name()
const override {
return BaseIndex_name; }
207 std::string BaseIndex_name = boost::core::demangle(
typeid(
typename BaseIndex::value_type ).
name() );
210 template<
typename IndexType>
240 return _current_lock;
244 std::array< read_write_mutex, CHAINBASE_NUM_RW_LOCKS > _locks;
245 std::atomic< uint32_t > _current_lock;
271#ifdef CHAINBASE_CHECK_LOCKING
272 void require_lock_fail(
const char* method,
const char* lock_type,
const char* tname )
const;
274 void require_read_lock(
const char* method,
const char* tname )
const
276 if( BOOST_UNLIKELY( _enable_require_locking & _read_only & (_read_lock_count <= 0) ) )
277 require_lock_fail(method,
"read", tname);
280 void require_write_lock(
const char* method,
const char* tname )
282 if( BOOST_UNLIKELY( _enable_require_locking & (_write_lock_count <= 0) ) )
283 require_lock_fail(method,
"write", tname);
290 session( vector<std::unique_ptr<abstract_session>>&&
s ):_index_sessions(
std::move(
s) )
300 for(
auto& i : _index_sessions ) i->push();
301 _index_sessions.clear();
306 for(
auto& i : _index_sessions ) i->squash();
307 _index_sessions.clear();
312 for(
auto& i : _index_sessions ) i->undo();
313 _index_sessions.clear();
320 vector< std::unique_ptr<abstract_session> > _index_sessions;
326 if( _index_list.size() == 0 )
return -1;
327 return _index_list[0]->revision();
339 for(
auto i : _index_list ) i->set_revision(
revision );
343 template<
typename MultiIndexType>
347 typedef typename index_type::allocator_type index_alloc;
349 std::string type_name = boost::core::demangle(
typeid(
typename index_type::value_type ).
name() );
351 if( !( _index_map.size() <= type_id || _index_map[ type_id ] ==
nullptr ) ) {
352 BOOST_THROW_EXCEPTION( std::logic_error( type_name +
"::type_id is already in use" ) );
355 index_type* idx_ptr =
nullptr;
357 idx_ptr = _db_file.
get_segment_manager()->find_no_lock< index_type >( type_name.c_str() ).first;
360 bool first_time_adding =
false;
363 BOOST_THROW_EXCEPTION( std::runtime_error(
"unable to find index for " + type_name +
" in read only database" ) );
365 first_time_adding =
true;
372 if( _index_list.size() > 0 ) {
373 auto expected_revision_range = _index_list.front()->undo_stack_revision_range();
374 auto added_index_revision_range = idx_ptr->undo_stack_revision_range();
376 if( added_index_revision_range.first != expected_revision_range.first ||
377 added_index_revision_range.second != expected_revision_range.second ) {
379 if( !first_time_adding ) {
380 BOOST_THROW_EXCEPTION( std::logic_error(
381 "existing index for " + type_name +
" has an undo stack (revision range [" +
382 std::to_string(added_index_revision_range.first) +
", " + std::to_string(added_index_revision_range.second) +
383 "]) that is inconsistent with other indices in the database (revision range [" +
384 std::to_string(expected_revision_range.first) +
", " + std::to_string(expected_revision_range.second) +
385 "]); corrupted database?"
390 BOOST_THROW_EXCEPTION( std::logic_error(
391 "new index for " + type_name +
392 " requires an undo stack that is consistent with other indices in the database; cannot fix in read-only mode"
396 idx_ptr->set_revision(
static_cast<uint64_t>(expected_revision_range.first) );
397 while( idx_ptr->revision() < expected_revision_range.second ) {
398 idx_ptr->start_undo_session(
true).push();
403 if( type_id >= _index_map.size() )
404 _index_map.resize( type_id + 1 );
407 _index_map[ type_id ].reset( new_index );
408 _index_list.push_back( new_index );
424 template<
typename MultiIndexType>
429 typedef index_type* index_type_ptr;
430 assert( _index_map.size() > index_type::value_type::type_id );
431 assert( _index_map[index_type::value_type::type_id] );
432 return *index_type_ptr( _index_map[index_type::value_type::type_id]->
get() );
435 template<
typename MultiIndexType,
typename ByIndex>
440 typedef index_type* index_type_ptr;
441 assert( _index_map.size() > index_type::value_type::type_id );
442 assert( _index_map[index_type::value_type::type_id] );
443 return index_type_ptr( _index_map[index_type::value_type::type_id]->
get() )->indices().template
get<ByIndex>();
446 template<
typename MultiIndexType>
451 typedef index_type* index_type_ptr;
452 assert( _index_map.size() > index_type::value_type::type_id );
453 assert( _index_map[index_type::value_type::type_id] );
454 return *index_type_ptr( _index_map[index_type::value_type::type_id]->
get() );
457 template<
typename ObjectType,
typename IndexedByType,
typename CompatibleKey >
458 const ObjectType*
find( CompatibleKey&& key )
const
463 auto itr = idx.find( std::forward< CompatibleKey >( key ) );
464 if( itr == idx.end() )
return nullptr;
468 template<
typename ObjectType >
476 template<
typename ObjectType,
typename IndexedByType,
typename CompatibleKey >
477 const ObjectType&
get( CompatibleKey&& key )
const
482 std::stringstream ss;
483 ss <<
"unknown key (" << boost::core::demangle(
typeid( key ).
name() ) <<
"): " <<
key;
484 BOOST_THROW_EXCEPTION( std::out_of_range( ss.str().c_str() ) );
489 template<
typename ObjectType >
495 std::stringstream ss;
496 ss <<
"unknown key (" << boost::core::demangle(
typeid( key ).
name() ) <<
"): " << key._id;
497 BOOST_THROW_EXCEPTION( std::out_of_range( ss.str().c_str() ) );
502 template<
typename ObjectType,
typename Modifier>
503 void modify(
const ObjectType& obj, Modifier&& m )
510 template<
typename ObjectType>
518 template<
typename ObjectType,
typename Constructor>
519 const ObjectType&
create( Constructor&& con )
528 for(
const auto& ai_ptr : _index_map) {
531 ret.emplace(make_pair(ai_ptr->row_count(), ai_ptr->type_name()));
538 bool _read_only =
false;
543 vector<abstract_index*> _index_list;
548 vector<unique_ptr<abstract_index>> _index_map;
550#ifdef CHAINBASE_CHECK_LOCKING
553 bool _enable_require_locking =
false;
557 template<
typename Object,
typename... Args>
#define CHAINBASE_REQUIRE_WRITE_LOCK(m, t)
#define CHAINBASE_NUM_RW_LOCKS
#define CHAINBASE_REQUIRE_READ_LOCK(m, t)
virtual unique_ptr< abstract_session > start_undo_session(bool enabled)=0
virtual void commit(int64_t revision) const =0
virtual void undo_all() const =0
virtual ~abstract_index()
virtual int64_t revision() const =0
virtual void undo() const =0
virtual void squash() const =0
virtual void remove_object(int64_t id)=0
virtual std::pair< int64_t, int64_t > undo_stack_revision_range() const =0
virtual uint64_t row_count() const =0
virtual const std::string & type_name() const =0
virtual uint32_t type_id() const =0
virtual void set_revision(uint64_t revision)=0
virtual ~abstract_session()
const ObjectType * find(oid< ObjectType > key=oid< ObjectType >()) const
void set_revision(uint64_t revision)
database & operator=(database &&)=default
const ObjectType & get(const oid< ObjectType > &key=oid< ObjectType >()) const
database(const bfs::path &dir, open_flags write=read_only, uint64_t shared_file_size=0, bool allow_dirty=false, pinnable_mapped_file::map_mode=pinnable_mapped_file::map_mode::mapped)
const generic_index< MultiIndexType > & get_index() const
const pinnable_mapped_file::segment_manager * get_segment_manager() const
size_t get_free_memory() const
pinnable_mapped_file::segment_manager * get_segment_manager()
std::multiset< std::pair< unsigned, std::string > > database_index_row_count_multiset
void modify(const ObjectType &obj, Modifier &&m)
const ObjectType * find(CompatibleKey &&key) const
session start_undo_session(bool enabled)
database(database &&)=default
bool is_read_only() const
void remove(const ObjectType &obj)
void commit(int64_t revision)
void set_require_locking(bool enable_require_locking)
const ObjectType & create(Constructor &&con)
database_index_row_count_multiset row_count_per_index() const
auto get_index() const -> decltype(((generic_index< MultiIndexType > *)(nullptr)) ->indices().template get< ByIndex >())
generic_index< MultiIndexType > & get_mutable_index()
const ObjectType & get(CompatibleKey &&key) const
virtual const std::string & type_name() const override
virtual void undo() const override
virtual uint32_t type_id() const override
virtual unique_ptr< abstract_session > start_undo_session(bool enabled) override
virtual int64_t revision() const override
virtual void commit(int64_t revision) const override
virtual std::pair< int64_t, int64_t > undo_stack_revision_range() const override
virtual void squash() const override
virtual void remove_object(int64_t id) override
virtual void undo_all() const override
index_impl(BaseIndex &base)
virtual uint64_t row_count() const override
virtual void set_revision(uint64_t revision) override
int_incrementer(int32_t &target)
friend bool operator>=(const oid &a, const oid &b)
friend bool operator!=(const oid &a, const oid &b)
friend bool operator==(const oid &a, const oid &b)
friend bool operator<(const oid &a, const oid &b)
friend bool operator<=(const oid &a, const oid &b)
friend std::ostream & operator<<(std::ostream &s, const oid &id)
friend bool operator>(const oid &a, const oid &b)
segment_manager * get_segment_manager() const
bip::managed_mapped_file::segment_manager segment_manager
uint32_t current_lock_num()
~read_write_mutex_manager()
read_write_mutex & current_lock()
read_write_mutex_manager()
session_impl(SessionType &&s)
virtual void push() override
virtual void squash() override
virtual void undo() override
CK_SESSION_HANDLE session
multi_index_to_undo_index< MultiIndexType > generic_index
typename multi_index_to_undo_index_impl< MultiIndexContainer >::type multi_index_to_undo_index
boost::interprocess::interprocess_sharable_mutex read_write_mutex
boost::multi_index_container< Object, Args..., chainbase::node_allocator< Object > > shared_multi_index_container
bip::allocator< T, pinnable_mapped_file::segment_manager > allocator
boost::interprocess::sharable_lock< read_write_mutex > read_lock
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
unsigned __int64 uint64_t
session(vector< std::unique_ptr< abstract_session > > &&s)
static const uint16_t type_id
yubihsm_pkcs11_object_template template