diff --git a/include/chainbase/scope_exit.hpp b/include/chainbase/scope_exit.hpp new file mode 100644 index 0000000..5e4e1a6 --- /dev/null +++ b/include/chainbase/scope_exit.hpp @@ -0,0 +1,26 @@ +#pragma once +#include +#include + +namespace chainbase { + template + struct scope_exit { + [[nodiscard]] scope_exit(F&& f) : _f(std::move(f)) {} + scope_exit(const scope_exit&) = delete; + scope_exit& operator=(const scope_exit&) = delete; + ~scope_exit() { if(!_canceled) _f(); } + void cancel() { _canceled = true; } + F _f; + bool _canceled = false; + }; + + template + struct scope_fail { + scope_fail(F&& f) : _f{static_cast(f)}, _exception_count{std::uncaught_exceptions()} {} + ~scope_fail() { + if(_exception_count != std::uncaught_exceptions()) _f(); + } + F _f; + int _exception_count; + }; +} \ No newline at end of file diff --git a/include/chainbase/undo_index.hpp b/include/chainbase/undo_index.hpp index 0b07f21..b477cdb 100644 --- a/include/chainbase/undo_index.hpp +++ b/include/chainbase/undo_index.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -21,19 +22,6 @@ namespace chainbase { struct constructor_tag {}; - template - struct scope_exit { - public: - [[nodiscard]] scope_exit(F&& f) : _f(std::move(f)) {} - scope_exit(const scope_exit&) = delete; - scope_exit& operator=(const scope_exit&) = delete; - ~scope_exit() { if(!_canceled) _f(); } - void cancel() { _canceled = true; } - private: - F _f; - bool _canceled = false; - }; - // Adapts multi_index's idea of keys to intrusive template struct get_key { diff --git a/src/pinnable_mapped_file.cpp b/src/pinnable_mapped_file.cpp index 06a2ea1..2b1fac6 100644 --- a/src/pinnable_mapped_file.cpp +++ b/src/pinnable_mapped_file.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -164,6 +165,16 @@ pinnable_mapped_file::pinnable_mapped_file(const std::filesystem::path& dir, boo set_mapped_file_db_dirty(true); } + auto reset_on_ctor_fail = scope_fail([&]() { + _file_mapped_region = bip::mapped_region(); + if(_non_file_mapped_mapping && _non_file_mapped_mapping != MAP_FAILED) + munmap(_non_file_mapped_mapping, _non_file_mapped_mapping_size); + + if(_writable) + set_mapped_file_db_dirty(false); + std::erase(_instance_tracker, this); + }); + if(mode == mapped || mode == mapped_private) { if (_writable && !_sharable) { // First make sure the db file is not on a ram-based tempfs, as it would be an @@ -199,26 +210,19 @@ pinnable_mapped_file::pinnable_mapped_file(const std::filesystem::path& dir, boo BOOST_THROW_EXCEPTION(std::system_error(make_error_code(db_error_code::aborted))); }); - try { - setup_non_file_mapping(); - _file_mapped_region = bip::mapped_region(); - load_database_file(sig_ios); + setup_non_file_mapping(); + _file_mapped_region = bip::mapped_region(); + load_database_file(sig_ios); #ifndef _WIN32 - if(mode == locked) { - if(mlock(_non_file_mapped_mapping, _non_file_mapped_mapping_size)) { - std::string what_str("Failed to mlock database \"" + _database_name + "\""); - BOOST_THROW_EXCEPTION(std::system_error(make_error_code(db_error_code::no_mlock), what_str)); - } - std::cerr << "CHAINBASE: Database \"" << _database_name << "\" has been successfully locked in memory" << '\n'; + if(mode == locked) { + if(mlock(_non_file_mapped_mapping, _non_file_mapped_mapping_size)) { + std::string what_str("Failed to mlock database \"" + _database_name + "\""); + BOOST_THROW_EXCEPTION(std::system_error(make_error_code(db_error_code::no_mlock), what_str)); } -#endif - } - catch(...) { - if(_writable) - set_mapped_file_db_dirty(false); - throw; + std::cerr << "CHAINBASE: Database \"" << _database_name << "\" has been successfully locked in memory" << '\n'; } +#endif _segment_manager = reinterpret_cast((char*)_non_file_mapped_mapping+header_size); } diff --git a/test/test.cpp b/test/test.cpp index 36b37b8..7e97a85 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -659,4 +659,21 @@ BOOST_AUTO_TEST_CASE( shared_string_object ) { } +BOOST_AUTO_TEST_CASE( mapped_big_boy ) { + temp_directory temp_dir; + const auto& temp = temp_dir.path(); + + BOOST_REQUIRE_THROW(chainbase::database(temp, database::read_write, 1024ull*1024*1024*1024*4, false, pinnable_mapped_file::map_mode::mapped_private), boost::interprocess::interprocess_exception); + chainbase::database(temp, database::read_write, 0, false); +} + +BOOST_AUTO_TEST_CASE( mapped_big_boy_extra ) { + temp_directory temp_dir; + const auto& temp = temp_dir.path(); + + chainbase::database(temp, database::read_write, 1024ull*1024*1024*1024*4, false); + BOOST_REQUIRE_THROW(chainbase::database(temp, database::read_write, 0, false, pinnable_mapped_file::map_mode::mapped_private), boost::interprocess::interprocess_exception); + chainbase::database(temp, database::read_write, 0, false); +} + // BOOST_AUTO_TEST_SUITE_END() diff --git a/test/undo_index.cpp b/test/undo_index.cpp index 9fe5a45..6351a0b 100644 --- a/test/undo_index.cpp +++ b/test/undo_index.cpp @@ -72,17 +72,9 @@ class test_allocator : public test_allocator_base { return base::allocate(count); } }; - -template -struct scope_fail { - scope_fail(F&& f) : _f{static_cast(f)}, _exception_count{std::uncaught_exceptions()} {} - ~scope_fail() { - if(_exception_count != std::uncaught_exceptions()) _f(); - } - F _f; - int _exception_count; -}; + +using chainbase::scope_fail; struct basic_element_t { template