Skip to content

Commit

Permalink
Merge pull request #40 from AntelopeIO/reset_dirty
Browse files Browse the repository at this point in the history
[leap5 -> main] clear the DB dirty bit if `pinnable_mapped_file` fails to fully start
  • Loading branch information
spoonincode authored Jan 24, 2024
2 parents 1c48351 + d68dd7a commit 1c55886
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 39 deletions.
26 changes: 26 additions & 0 deletions include/chainbase/scope_exit.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once
#include <utility>
#include <exception>

namespace chainbase {
template<typename F>
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<typename F>
struct scope_fail {
scope_fail(F&& f) : _f{static_cast<F&&>(f)}, _exception_count{std::uncaught_exceptions()} {}
~scope_fail() {
if(_exception_count != std::uncaught_exceptions()) _f();
}
F _f;
int _exception_count;
};
}
14 changes: 1 addition & 13 deletions include/chainbase/undo_index.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <chainbase/scope_exit.hpp>
#include <boost/multi_index_container_fwd.hpp>
#include <boost/intrusive/set.hpp>
#include <boost/intrusive/avltree.hpp>
Expand All @@ -21,19 +22,6 @@
namespace chainbase {
struct constructor_tag {};

template<typename F>
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<typename KeyExtractor, typename T>
struct get_key {
Expand Down
36 changes: 20 additions & 16 deletions src/pinnable_mapped_file.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <chainbase/pinnable_mapped_file.hpp>
#include <chainbase/environment.hpp>
#include <chainbase/pagemap_accessor.hpp>
#include <chainbase/scope_exit.hpp>
#include <boost/asio/signal_set.hpp>
#include <iostream>
#include <fstream>
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<segment_manager*>((char*)_non_file_mapped_mapping+header_size);
}
Expand Down
17 changes: 17 additions & 0 deletions test/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
12 changes: 2 additions & 10 deletions test/undo_index.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,9 @@ class test_allocator : public test_allocator_base<T> {
return base::allocate(count);
}
};


template<typename F>
struct scope_fail {
scope_fail(F&& f) : _f{static_cast<F&&>(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<typename C>
Expand Down

0 comments on commit 1c55886

Please sign in to comment.