diff --git a/flatdata-cpp/include/flatdata/ArchiveBuilder.h b/flatdata-cpp/include/flatdata/ArchiveBuilder.h index c84ba3df..b7fea5bc 100644 --- a/flatdata-cpp/include/flatdata/ArchiveBuilder.h +++ b/flatdata-cpp/include/flatdata/ArchiveBuilder.h @@ -52,6 +52,7 @@ class ArchiveBuilder const flatdata::ResourceStorage& storage( ) const; bool is_created( ) const; void check_created( ) const; + void clean_up_signature( flatdata::ResourceStorage& storage ); private: std::shared_ptr< flatdata::ResourceStorage > m_storage; diff --git a/flatdata-cpp/include/flatdata/FileResourceStorage.h b/flatdata-cpp/include/flatdata/FileResourceStorage.h index 699541d5..b08021dc 100644 --- a/flatdata-cpp/include/flatdata/FileResourceStorage.h +++ b/flatdata-cpp/include/flatdata/FileResourceStorage.h @@ -42,6 +42,11 @@ class FileResourceStorage : public ResourceStorage bool exists( const char* key ) override; + void remove_resource( const char* resource_name, const char* expected_schema ) override; + + void remove_multivector_index_resource( const char* resource_name, + const char* expected_schema ) override; + protected: std::shared_ptr< std::ostream > create_output_stream( const char* key ) override; MemoryDescriptor read_resource( const char* key ) override; @@ -150,4 +155,76 @@ FileResourceStorage::exists( const char* key ) return !ec; } +inline void +logger( const std::string& msg ) +{ + static std::mutex m; + std::lock_guard< std::mutex > lock( m ); + printf( "%s\n", msg.c_str( ) ); +} + +inline void +FileResourceStorage::remove_resource( const char* resource_name, const char* expected_schema ) +{ + const std::string schema_name = std::string( resource_name ) + ".schema"; + const bool resource_exists = exists( resource_name ); + const bool schema_exists = exists( schema_name.c_str( ) ); + + if ( !resource_exists && !schema_exists ) + { + logger( "[INFO] resource " + std::string( resource_name ) + ": does not exist" ); + return; + } + + if ( resource_exists ^ schema_exists ) + { + // [CJ-TODO] + // remove what's left or simply return? + // can happen when crashes during writting + logger( "[ERR] resource " + std::string( resource_name ) + ": no schema or resource" ); + } + + auto schema = read_resource( ( schema_name.c_str( ) ) ); + std::string stored_schema( reinterpret_cast< const char* >( schema.data( ) ), + schema.size_in_bytes( ) ); + + if ( stored_schema != expected_schema ) + { + // [CJ-TODO] + // What if the schema change is intended? + logger( "[ERR] resource " + std::string( resource_name ) + ": unexpected schema" ); + return; + } + + boost::system::error_code ec_resource, ec_schema; + boost::filesystem::remove( get_path( resource_name ), ec_resource ); + boost::filesystem::remove( get_path( schema_name.c_str( ) ), ec_schema ); + if ( ec_resource.failed( ) ) + { + logger( "[ERR] resource " + std::string( resource_name ) + ": failed to remove resource" ); + } + else + { + logger( "[INFO] resource " + std::string( resource_name ) + ": removed resource" ); + } + if ( ec_schema.failed( ) ) + { + logger( "[ERR] resource " + std::string( resource_name ) + ": failed to remove schema" ); + } + else + { + logger( "[INFO] resource " + std::string( resource_name ) + ": removed schema" ); + } +} + +inline void +FileResourceStorage::remove_multivector_index_resource( const char* resource_name, + const char* expected_schema ) +{ + std::string index_name = std::string( resource_name ) + internal::INDEX_SUFFIX; + std::string index_schema = internal::multivector_index_schema( expected_schema ); + + remove_resource( index_name.c_str( ), index_schema.c_str( ) ); +} + } // namespace flatdata diff --git a/flatdata-cpp/include/flatdata/ResourceStorage.h b/flatdata-cpp/include/flatdata/ResourceStorage.h index 2085167f..c47f8a52 100644 --- a/flatdata-cpp/include/flatdata/ResourceStorage.h +++ b/flatdata-cpp/include/flatdata/ResourceStorage.h @@ -96,6 +96,21 @@ class ResourceStorage : private boost::noncopyable */ virtual bool exists( const char* key ) = 0; + virtual void + remove_resource( const char* /* resource_name */, const char* /* expected_schema */ ) + { + // [CJ-TODO] make it pure virtual + return; + } + + virtual void + remove_multivector_index_resource( const char* /* resource_name */, + const char* /* expected_schema */ ) + { + // [CJ-TODO] make it pure virtual + return; + } + protected: /** * @brief Creates output stream for given key diff --git a/flatdata-cpp/src/ArchiveBuilder.cpp b/flatdata-cpp/src/ArchiveBuilder.cpp index 4333b5d9..cbd3f9d3 100644 --- a/flatdata-cpp/src/ArchiveBuilder.cpp +++ b/flatdata-cpp/src/ArchiveBuilder.cpp @@ -67,4 +67,11 @@ ArchiveBuilder::initialize( ) return static_cast< bool >( signature ); } +void +ArchiveBuilder::clean_up_signature( flatdata::ResourceStorage& storage ) +{ + const auto signature_name = internal::signature_name( name( ) ); + storage.remove_resource( signature_name.c_str( ), schema( ) ); +} + } // namespace flatdata diff --git a/flatdata-generator/flatdata/generator/templates/cpp/archive.jinja2 b/flatdata-generator/flatdata/generator/templates/cpp/archive.jinja2 index 97b5e7de..cf7c6322 100644 --- a/flatdata-generator/flatdata/generator/templates/cpp/archive.jinja2 +++ b/flatdata-generator/flatdata/generator/templates/cpp/archive.jinja2 @@ -51,7 +51,7 @@ class {{ builder_name }} : public flatdata::ArchiveBuilder { public: /// Creates Archive builder - static {{ builder_name }} open( std::shared_ptr< flatdata::ResourceStorage > storage ); + static {{ builder_name }} open( std::shared_ptr< flatdata::ResourceStorage > storage, bool force_overwrite = false ); /// Archive schema static const char* schema_definition( ); @@ -65,19 +65,22 @@ public: /// Resources using {{ r|typedef_name }} = {{ resource.writer_type(r) }}; using {{ r|typedef_name("Reader") }} = {{ resource.reader_type(r) }}; {% if r|resource_provides_incremental_builder %} - {{ r|typedef_name }} start_{{ r.name }}( ); + {{ r|typedef_name }} start_{{ r.name }}( bool force_overwrite = false ); {% endif %} {% if r|provides_setter %} - bool set_{{ r.name }}( {{ r|typedef_name("Reader") }} data ); + bool set_{{ r.name }}( {{ r|typedef_name("Reader") }} data, bool force_overwrite = false ); {% endif %} + void clean_up_{{ r.name }}( flatdata::ResourceStorage& storage ); {% endfor %} {% for r in archive.resources|archive_resources %} using {{ r|typedef_name }} = {{ resource.writer_type(r) }}; - {{ r|typedef_name }}& {{ r.name }}( ); + {{ r|typedef_name }}& {{ r.name }}( bool force_overwrite = false ); {% endfor %} + void clean_up( flatdata::ResourceStorage& storage ); + private: {{ builder_name }}( std::shared_ptr< flatdata::ResourceStorage > storage ); @@ -205,9 +208,13 @@ inline inline {{ builder_name }} -{{ builder_name }}::open(std::shared_ptr< flatdata::ResourceStorage > storage ) +{{ builder_name }}::open(std::shared_ptr< flatdata::ResourceStorage > storage, bool force_overwrite ) { {{ builder_name }} result( storage ); + if ( force_overwrite ) + { + result.clean_up( *storage ); + } if ( !result.initialize( ) ) { return {{ builder_name }}( ); @@ -217,31 +224,69 @@ inline {{ builder_name }} {% for r in archive.resources|simple_resources %} {% if r|resource_provides_incremental_builder %} -inline auto {{ builder_name }}::start_{{ r.name }}( ) -> {{ r|typedef_name }} +inline auto {{ builder_name }}::start_{{ r.name }}( bool force_overwrite ) -> {{ r|typedef_name }} { - check_created( ); + if ( force_overwrite ) + { + clean_up_{{ r.name }}( storage( ) ); + } + else + { + check_created( ); + } return storage( ).{{ resource.incremental_write_call(r) }}( "{{ r.name }}", internal::{{ archive.name }}__{{ r.name }}__schema__ ); } {% endif %} {% if r|provides_setter %} inline bool -{{ builder_name }}::set_{{ r.name }}( {{ r|typedef_name("Reader") }} data ) +{{ builder_name }}::set_{{ r.name }}( {{ r|typedef_name("Reader") }} data, bool force_overwrite ) { - check_created( ); + if ( force_overwrite ) + { + clean_up_{{ r.name }}( storage( ) ); + } + else + { + check_created( ); + } return storage( ).write< {{ r|typedef_name("Reader") }} >( "{{ r.name }}", internal::{{ archive.name }}__{{ r.name }}__schema__, data ); } {% endif %} +inline void +{{ builder_name }}::clean_up_{{ r.name }}( flatdata::ResourceStorage& storage ) +{ + storage.remove_resource( "{{ r.name }}", internal::{{ archive.name }}__{{ r.name }}__schema__ ); + {% if r|is_multivector %} + storage.remove_multivector_index_resource( "{{ r.name }}", internal::{{ archive.name }}__{{ r.name }}__schema__ ); + {% endif %} +} {% endfor %} {% for r in archive.resources|archive_resources %} inline auto -{{ builder_name }}::{{ r.name }}( ) -> {{ r|typedef_name }}& +{{ builder_name }}::{{ r.name }}( bool force_overwrite ) -> {{ r|typedef_name }}& { if ( !m_{{ r.name }}.is_open( ) ) { - m_{{ r.name }} = {{ r|typedef_name }}::open( this->storage( ).create_directory( "{{ r.name }}" ) ); + m_{{ r.name }} = {{ r|typedef_name }}::open( this->storage( ).create_directory( "{{ r.name }}" ), force_overwrite ); } return m_{{ r.name }}; } {% endfor %} + +inline void +{{ builder_name }}::clean_up( flatdata::ResourceStorage& storage ) +{ +{% for r in archive.resources|simple_resources %} + clean_up_{{ r.name }}( storage ); +{% endfor %} +{% for r in archive.resources|archive_resources %} + if ( auto subarchive_storage = storage.directory( "{{ r.name }}" ) ) + { + m_{{ r.name }}.clean_up( *subarchive_storage ); + } +{% endfor %} + clean_up_signature( storage ); +} + {% endmacro %}