dncurrency/nano/node/lmdb/lmdb_env.cpp
cryptocode 695dc5f5dc
LMDB sync options and new config settings (#2588)
* LMDB sync options and new config settings

* Force sync always for wallet store
2020-03-04 19:41:49 +01:00

109 lines
3.6 KiB
C++

#include <nano/node/lmdb/lmdb_env.hpp>
#include <boost/filesystem/operations.hpp>
nano::mdb_env::mdb_env (bool & error_a, boost::filesystem::path const & path_a, nano::mdb_env::options options_a)
{
init (error_a, path_a, options_a);
}
void nano::mdb_env::init (bool & error_a, boost::filesystem::path const & path_a, nano::mdb_env::options options_a)
{
boost::system::error_code error_mkdir, error_chmod;
if (path_a.has_parent_path ())
{
boost::filesystem::create_directories (path_a.parent_path (), error_mkdir);
nano::set_secure_perm_directory (path_a.parent_path (), error_chmod);
if (!error_mkdir)
{
auto status1 (mdb_env_create (&environment));
release_assert (status1 == 0);
auto status2 (mdb_env_set_maxdbs (environment, options_a.config.max_databases));
release_assert (status2 == 0);
auto map_size = options_a.config.map_size;
auto max_valgrind_map_size = 16 * 1024 * 1024;
if (running_within_valgrind () && map_size > max_valgrind_map_size)
{
// In order to run LMDB under Valgrind, the maximum map size must be smaller than half your available RAM
map_size = max_valgrind_map_size;
}
auto status3 (mdb_env_set_mapsize (environment, map_size));
release_assert (status3 == 0);
// It seems if there's ever more threads than mdb_env_set_maxreaders has read slots available, we get failures on transaction creation unless MDB_NOTLS is specified
// This can happen if something like 256 io_threads are specified in the node config
// MDB_NORDAHEAD will allow platforms that support it to load the DB in memory as needed.
// MDB_NOMEMINIT prevents zeroing malloc'ed pages. Can provide improvement for non-sensitive data but may make memory checkers noisy (e.g valgrind).
auto environment_flags = MDB_NOSUBDIR | MDB_NOTLS | MDB_NORDAHEAD;
if (options_a.config.sync == nano::lmdb_config::sync_strategy::nosync_safe)
{
environment_flags |= MDB_NOMETASYNC;
}
else if (options_a.config.sync == nano::lmdb_config::sync_strategy::nosync_unsafe)
{
environment_flags |= MDB_NOSYNC;
}
else if (options_a.config.sync == nano::lmdb_config::sync_strategy::nosync_unsafe_large_memory)
{
environment_flags |= MDB_NOSYNC | MDB_WRITEMAP | MDB_MAPASYNC;
}
if (!running_within_valgrind () && options_a.use_no_mem_init)
{
environment_flags |= MDB_NOMEMINIT;
}
auto status4 (mdb_env_open (environment, path_a.string ().c_str (), environment_flags, 00600));
if (status4 != 0)
{
std::cerr << "Could not open lmdb environment: " << status4;
char * error_str (mdb_strerror (status4));
if (error_str)
{
std::cerr << ", " << error_str;
}
std::cerr << std::endl;
}
release_assert (status4 == 0);
error_a = status4 != 0;
}
else
{
error_a = true;
environment = nullptr;
}
}
else
{
error_a = true;
environment = nullptr;
}
}
nano::mdb_env::~mdb_env ()
{
if (environment != nullptr)
{
// Make sure the commits are flushed. This is a no-op unless MDB_NOSYNC is used.
mdb_env_sync (environment, true);
mdb_env_close (environment);
}
}
nano::mdb_env::operator MDB_env * () const
{
return environment;
}
nano::read_transaction nano::mdb_env::tx_begin_read (mdb_txn_callbacks mdb_txn_callbacks) const
{
return nano::read_transaction{ std::make_unique<nano::read_mdb_txn> (*this, mdb_txn_callbacks) };
}
nano::write_transaction nano::mdb_env::tx_begin_write (mdb_txn_callbacks mdb_txn_callbacks) const
{
return nano::write_transaction{ std::make_unique<nano::write_mdb_txn> (*this, mdb_txn_callbacks) };
}
MDB_txn * nano::mdb_env::tx (nano::transaction const & transaction_a) const
{
return static_cast<MDB_txn *> (transaction_a.get_handle ());
}