diff --git a/.gitsubprojects b/.gitsubprojects index 6010312..3adc712 100644 --- a/.gitsubprojects +++ b/.gitsubprojects @@ -1,6 +1,6 @@ # -*- mode: cmake -*- git_subproject(Servus https://github.com/HBPVIS/Servus.git 85e715b) git_subproject(Lunchbox https://github.com/Eyescale/Lunchbox.git 3a1a704) -git_subproject(Keyv https://github.com/BlueBrain/Keyv.git 3e9fa2b) +git_subproject(Keyv https://github.com/BlueBrain/Keyv.git b6444a4) git_subproject(vmmlib https://github.com/Eyescale/vmmlib.git 8795629) git_subproject(MVDTool https://github.com/BlueBrain/MVDTool.git 4e2f0f4) diff --git a/apps/compartmentConverter.cpp b/apps/compartmentConverter.cpp index 39e1cbf..dbb5a87 100644 --- a/apps/compartmentConverter.cpp +++ b/apps/compartmentConverter.cpp @@ -89,6 +89,8 @@ int main( const int argc, char** argv ) #endif ( "output,o", po::value< std::string >()->default_value( "null://" ), uriHelp.c_str( )) + ( "erase,e", po::value< std::string >(), + "Erase the given report (map-based reports only)" ) ( "maxFrames,m", po::value< size_t >(), "Convert at most the given number of frames" ) ( "gids,g", po::value< std::vector< uint32_t >>()->multitoken(), @@ -122,6 +124,16 @@ int main( const int argc, char** argv ) return EXIT_SUCCESS; } + if( vm.count( "erase" )) + { + lunchbox::URI outURI( vm[ "erase" ].as< std::string >( )); + brion::CompartmentReport report( outURI, brion::MODE_READ ); + if( report.erase( )) + return EXIT_SUCCESS; + std::cerr << "Could not erase " << outURI << std::endl; + return EXIT_FAILURE; + } + std::string input; if( vm.count( "input" )) input = vm["input"].as< std::string >(); diff --git a/brion/compartmentReport.cpp b/brion/compartmentReport.cpp index 10995f6..d8feaea 100644 --- a/brion/compartmentReport.cpp +++ b/brion/compartmentReport.cpp @@ -181,4 +181,8 @@ bool CompartmentReport::flush() return _impl->plugin->flush(); } +bool CompartmentReport::erase() +{ + return _impl->plugin->erase(); +} } diff --git a/brion/compartmentReport.h b/brion/compartmentReport.h index d218641..634036a 100644 --- a/brion/compartmentReport.h +++ b/brion/compartmentReport.h @@ -153,6 +153,8 @@ class CompartmentReport : public boost::noncopyable /** Load report values for the given neuron. * + * May not be implemented by all backends (e.g. HDF5). + * * @param gid the neuron identifier * @return the report values if neuron is found, nullptr otherwise * @version 1.10 @@ -178,7 +180,6 @@ class CompartmentReport : public boost::noncopyable BRION_API void clearBuffer(); //@} - /** @name Write API */ //@{ /** Write the header information of this report. @@ -191,8 +192,8 @@ class CompartmentReport : public boost::noncopyable * @throw std::invalid_argument if any passed argument is invalid * @version 1.0 */ - BRION_API void writeHeader( float startTime, float endTime, - float timestep, const std::string& dunit, + BRION_API void writeHeader( float startTime, float endTime, float timestep, + const std::string& dunit, const std::string& tunit ); /** Write the compartment counts for each section for one cell. @@ -204,8 +205,7 @@ class CompartmentReport : public boost::noncopyable * @return false if saving was not successful, true otherwise * @version 1.0 */ - BRION_API bool writeCompartments( uint32_t gid, - const uint16_ts& counts ); + BRION_API bool writeCompartments( uint32_t gid, const uint16_ts& counts ); /** Write the voltages for one cell at a point in time. * @@ -223,12 +223,20 @@ class CompartmentReport : public boost::noncopyable /** Flush data to output. @return true on success. @version 1.0 */ BRION_API bool flush(); + + /** + * Remove all data of the report from storage. + * + * May not be implemented by all backends, such as file-based reports. + * @return true if data was removed. + * @version 1.10 + */ + BRION_API bool erase(); //@} private: detail::CompartmentReport* _impl; }; - } #endif diff --git a/brion/compartmentReportPlugin.h b/brion/compartmentReportPlugin.h index b617f38..e8c18fd 100644 --- a/brion/compartmentReportPlugin.h +++ b/brion/compartmentReportPlugin.h @@ -20,11 +20,11 @@ #pragma once #include -#include #include +#include -#include #include +#include namespace brion { @@ -145,8 +145,8 @@ class CompartmentReportPlugin : public boost::noncopyable virtual size_t getBufferSize() const { return 0; } /** @copydoc brion::CompartmentReport::writeHeader */ - virtual void writeHeader( float startTime, float endTime, - float timestep, const std::string& dunit, + virtual void writeHeader( float startTime, float endTime, float timestep, + const std::string& dunit, const std::string& tunit ) = 0; /** @copydoc brion::CompartmentReport::writeCompartments */ @@ -158,6 +158,9 @@ class CompartmentReportPlugin : public boost::noncopyable /** @copydoc brion::CompartmentReport::flush */ virtual bool flush() = 0; + + /** @copydoc brion::CompartmentReport::erase */ + virtual bool erase() { return false; } //@} /** @copydoc brion::CompartmentReport::getIndex */ diff --git a/brion/plugin/compartmentReportMap.cpp b/brion/plugin/compartmentReportMap.cpp index f908ca0..80ec6b6 100644 --- a/brion/plugin/compartmentReportMap.cpp +++ b/brion/plugin/compartmentReportMap.cpp @@ -199,6 +199,34 @@ bool CompartmentReportMap::flush() return true; } +bool CompartmentReportMap::erase() +{ + if( !_readable ) + { + LBINFO << "Can't remove report, missing header information in store" + << std::endl; + return false; + } + + auto& store = _stores.front(); + for( const uint32_t gid : _gids ) + { + const size_t nFrames = + ( _header.endTime - _header.startTime ) / _header.timestep; + for( size_t i = 0; i < nFrames; ++i ) + store.erase( _getValueKey( gid, i ) ); + + store.erase( _getCountsKey( gid ) ); + } + store.erase( _getHeaderKey() ); + store.erase( _getGidsKey() ); + store.erase( _getDunitKey() ); + store.erase( _getTunitKey() ); + + _clear(); + return true; +} + bool CompartmentReportMap::_flushHeader() { if( _readable ) @@ -363,7 +391,6 @@ floatsPtr CompartmentReportMap::loadFrame( const float time ) const if( !_readable ) return floatsPtr(); - OffsetMap offsetMap; size_t offset = 0; diff --git a/brion/plugin/compartmentReportMap.h b/brion/plugin/compartmentReportMap.h index bd0dce7..3754bab 100644 --- a/brion/plugin/compartmentReportMap.h +++ b/brion/plugin/compartmentReportMap.h @@ -78,6 +78,7 @@ class CompartmentReportMap : public CompartmentReportCommon bool writeFrame( uint32_t gid, const floats& voltages, float timestamp ) final; bool flush() final; + bool erase() final; struct Header { diff --git a/doc/Changelog.md b/doc/Changelog.md index 491afd9..c76962f 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -3,6 +3,8 @@ Changelog {#Changelog} # git master +* [126](https://github.com/BlueBrain/Brion/pull/126): + Add erase for map compartment reports * [122](https://github.com/BlueBrain/Brion/pull/122): Support loading of individual neurons for binary and map compartment reports * [121](https://github.com/BlueBrain/Brion/pull/121): diff --git a/tests/compartmentReport.cpp b/tests/compartmentReport.cpp index 9d88013..6b11b39 100644 --- a/tests/compartmentReport.cpp +++ b/tests/compartmentReport.cpp @@ -28,6 +28,7 @@ #include #include #include +#include using boost::lexical_cast; @@ -358,11 +359,12 @@ BOOST_AUTO_TEST_CASE( test_convert_and_compare ) test_compare( source, brion::URI( path.string() + "allCompartments.h5" )); const boost::filesystem::path& temp = createUniquePath(); + const std::string random = servus::make_UUID().getString(); std::vector< brion::URI > uris; uris.push_back( brion::URI( temp.string() + ".h5" )); - uris.push_back( brion::URI( "leveldb:///briontest" )); - uris.push_back( brion::URI( "memcached:///briontest" )); + uris.push_back( brion::URI( std::string( "leveldb:///" ) + random )); + uris.push_back( brion::URI( std::string( "memcached:///" ) + random )); while( !uris.empty( )) { @@ -387,6 +389,19 @@ BOOST_AUTO_TEST_CASE( test_convert_and_compare ) } } } + + for( const auto& uri : uris ) + { + try + { + brion::CompartmentReport report( uri, brion::MODE_READ ); + if( report.erase( )) + BOOST_CHECK_THROW( + brion::CompartmentReport( uri, brion::MODE_READ ), + std::runtime_error ); + } + catch( const std::runtime_error& ) { /* ignore */ } + } } BOOST_AUTO_TEST_CASE( test_read_soma_binary )