Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions include/bitcoin/database/impl/memory/mmap.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <shared_mutex>
#include <bitcoin/database/define.hpp>
#include <bitcoin/database/file/file.hpp>
#include <bitcoin/database/memory/utilities.hpp>

namespace libbitcoin {
namespace database {
Expand Down Expand Up @@ -112,6 +113,17 @@ size_t CLASS::to_capacity(size_t required) const NOEXCEPT
// this design exists to prevent, moved from create to first touch). Growth is
// chunked to bound slow path frequency, and clamped so that small tables do
// not over-commit (the provisioned file requires no memory until committed).
// The commit chunk is scaled to memory (bounded by commit_chunk), as the
// committed but unused overhang is otherwise up to one full chunk for every
// instance, an outsized share of a small system under memory pressure.
TEMPLATE
size_t CLASS::to_chunk() NOEXCEPT
{
static const auto chunk = std::min(commit_chunk,
system::possible_narrow_cast<size_t>(system_memory() / chunk_scale));
return chunk;
}

TEMPLATE
size_t CLASS::to_growth(size_t required) const NOEXCEPT
{
Expand All @@ -120,7 +132,7 @@ size_t CLASS::to_growth(size_t required) const NOEXCEPT
const auto expand = ceilinged_multiply(required, expansion_) / 100u;
const auto expanded = ceilinged_add(required, expand);
const auto chunked = std::max(expanded,
ceilinged_add(capacity_.load(), to_rows(commit_chunk)));
ceilinged_add(capacity_.load(), to_rows(to_chunk())));

return std::min(chunked, std::max(expanded, to_provision()));
#else
Expand Down Expand Up @@ -148,7 +160,7 @@ size_t CLASS::to_commitment() const NOEXCEPT
{
#if defined(MANAGE_STAGING)
const auto logical = logical_.load();
return std::min(to_provision(), std::max(logical, to_rows(commit_chunk)));
return std::min(to_provision(), std::max(logical, to_rows(to_chunk())));
#else
// The classic mapping is file-backed, so commitment is provisioning.
return to_provision();
Expand Down
6 changes: 5 additions & 1 deletion include/bitcoin/database/impl/memory/mmap_staging.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,11 @@ bool CLASS::sync_() NOEXCEPT
TEMPLATE
void CLASS::settler_start_() NOEXCEPT
{
limit_ = system_memory() / throttle_factor;
// Halve the staging debt allowance on small systems, as the debt is
// otherwise an outsized share of a small system under memory pressure.
const auto memory = system_memory();
const auto small = memory < system::power2(36u);
limit_ = memory / (small ? (2u * throttle_factor) : throttle_factor);
evicted_ = zero;
settling_.store(true);
settler_ = std::thread([this]() NOEXCEPT
Expand Down
2 changes: 2 additions & 0 deletions include/bitcoin/database/memory/mmap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ class mmap
return system::ceilinged_divide(bytes, row);
}

static size_t to_chunk() NOEXCEPT;
size_t to_capacity(size_t required) const NOEXCEPT;
size_t to_growth(size_t required) const NOEXCEPT;
size_t to_provision() const NOEXCEPT;
Expand All @@ -214,6 +215,7 @@ class mmap
static constexpr size_t settle_chunk = system::power2(28u);
static constexpr size_t advise_chunk = system::power2(30u);
static constexpr size_t commit_chunk = system::power2(28u);
static constexpr size_t chunk_scale = 256;
static constexpr size_t evict_chunk = system::power2(30u);
static constexpr size_t compress_factor = 32;
static constexpr size_t evict_factor = 32;
Expand Down
30 changes: 16 additions & 14 deletions src/file/utilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,10 @@
#include <ios>
#include <bitcoin/database/define.hpp>

#if defined(HAVE_MSC)
#define MSC_ONLY(name) name
#else
#define MSC_ONLY(name)
#endif

#if defined(HAVE_LINUX)
#define LINUX_ONLY(name) name
#if defined(HAVE_MSC) || defined(HAVE_LINUX)
#define ADVISED_ONLY(name) name
#else
#define LINUX_ONLY(name)
#define ADVISED_ONLY(name)
#endif

namespace libbitcoin {
Expand Down Expand Up @@ -299,18 +293,26 @@ code space_ex(size_t& out, const path& filename) NOEXCEPT
// File descriptor functions required for memory mapping.
// ----------------------------------------------------------------------------

int open(const path& filename, bool MSC_ONLY(random),
advice LINUX_ONLY(access)) NOEXCEPT
int open(const path& filename, bool,
advice ADVISED_ONLY(access)) NOEXCEPT
{
const auto path = system::extended_path(filename);
int file_descriptor{};

#if defined(HAVE_MSC)
// Advice is elective (unhinted is the cache manager default) and
// configured from the read pattern (see database::advice).
// Order follows the advice enumeration.
static constexpr std::array<int, 3> hints
{
0, _O_RANDOM, _O_SEQUENTIAL
};

// _wsopen_s and wstring do not throw (but are unannotated).
// sets file_descriptor = -1 and errno on error.
const auto access = (random ? _O_RANDOM : _O_SEQUENTIAL);
const auto hint = hints.at(to_value(access));
::_wsopen_s(&file_descriptor, path.c_str(),
O_RDWR | _O_BINARY | access, _SH_DENYWR, _S_IREAD | _S_IWRITE);
O_RDWR | _O_BINARY | hint, _SH_DENYWR, _S_IREAD | _S_IWRITE);
#elif defined(HAVE_LINUX)
// open sets errno on failure.
file_descriptor = ::open(path.c_str(), O_RDWR, S_IRUSR | S_IWUSR);
Expand All @@ -327,7 +329,7 @@ int open(const path& filename, bool MSC_ONLY(random),

// posix_fadvise returns error on failure.
const auto result = ::posix_fadvise(file_descriptor, 0, 0,
advices.at(static_cast<uint8_t>(access)));
advices.at(to_value(access)));
if (!is_zero(result))
{
close(file_descriptor);
Expand Down
Loading