/* * Copyright (c) 2015, Cryptonomex, Inc. * All rights reserved. * * This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and * the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification, * are permitted until September 8, 2015, provided that the following conditions are met: * * 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include #include #include #include #include namespace graphene { namespace db { /** * @class object_database * @brief maintains a set of indexed objects that can be modified with multi-level rollback support */ class object_database { public: object_database(); ~object_database(); void reset_indexes() { _index.clear(); _index.resize(255); } void open(const fc::path& data_dir ); /** * Saves the complete state of the object_database to disk, this could take a while */ void flush(); void wipe(const fc::path& data_dir); // remove from disk void close(); template const T& create( F&& constructor ) { auto& idx = get_mutable_index(); return static_cast( idx.create( [&](object& o) { assert( dynamic_cast(&o) ); constructor( static_cast(o) ); } )); } ///These methods are used to retrieve indexes on the object_database. All public index accessors are const-access only. /// @{ template const IndexType& get_index_type()const { static_assert( std::is_base_of::value, "Type must be an index type" ); return static_cast( get_index( IndexType::object_type::space_id, IndexType::object_type::type_id ) ); } template const index& get_index()const { return get_index(T::space_id,T::type_id); } const index& get_index(uint8_t space_id, uint8_t type_id)const; const index& get_index(object_id_type id)const { return get_index(id.space(),id.type()); } /// @} const object& get_object( object_id_type id )const; const object* find_object( object_id_type id )const; /// These methods are mutators of the object_database. You must use these methods to make changes to the object_database, /// in order to maintain proper undo history. ///@{ const object& insert( object&& obj ) { return get_mutable_index(obj.id).insert( std::move(obj) ); } void remove( const object& obj ) { get_mutable_index(obj.id).remove( obj ); } template void modify( const T& obj, const Lambda& m ) { get_mutable_index(obj.id).modify(obj,m); } ///@} template static const T& cast( const object& obj ) { assert( nullptr != dynamic_cast(&obj) ); return static_cast(obj); } template static T& cast( object& obj ) { assert( nullptr != dynamic_cast(&obj) ); return static_cast(obj); } template const T& get( object_id_type id )const { const object& obj = get_object( id ); assert( nullptr != dynamic_cast(&obj) ); return static_cast(obj); } template const T* find( object_id_type id )const { const object* obj = find_object( id ); assert( !obj || nullptr != dynamic_cast(obj) ); return static_cast(obj); } template const T* find( object_id id )const { return find(id); } template const T& get( object_id id )const { return get(id); } template IndexType* add_index() { typedef typename IndexType::object_type ObjectType; if( _index[ObjectType::space_id].size() <= ObjectType::type_id ) _index[ObjectType::space_id].resize( 255 ); assert(!_index[ObjectType::space_id][ObjectType::type_id]); unique_ptr indexptr( new IndexType(*this) ); _index[ObjectType::space_id][ObjectType::type_id] = std::move(indexptr); return static_cast(_index[ObjectType::space_id][ObjectType::type_id].get()); } void pop_undo(); fc::path get_data_dir()const { return _data_dir; } /** public for testing purposes only... should be private in practice. */ undo_database _undo_db; protected: template IndexType& get_mutable_index_type() { static_assert( std::is_base_of::value, "Type must be an index type" ); return static_cast( get_mutable_index( IndexType::object_type::space_id, IndexType::object_type::type_id ) ); } template index& get_mutable_index() { return get_mutable_index(T::space_id,T::type_id); } index& get_mutable_index(object_id_type id) { return get_mutable_index(id.space(),id.type()); } index& get_mutable_index(uint8_t space_id, uint8_t type_id); private: friend class base_primary_index; friend class undo_database; void save_undo( const object& obj ); void save_undo_add( const object& obj ); void save_undo_remove( const object& obj ); fc::path _data_dir; vector< vector< unique_ptr > > _index; }; } } // graphene::db