Skip to content

Commit aed813c

Browse files
committed
Flush dbcache early if system is under memory pressure
No point forcing memory to get pushed out to swap just to cache db changes when we can write the db changes out instead
1 parent 55bd5d8 commit aed813c

File tree

4 files changed

+56
-2
lines changed

4 files changed

+56
-2
lines changed

configure.ac

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,21 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <malloc.h>]],
10051005
[ AC_MSG_RESULT([no])]
10061006
)
10071007

1008+
AC_MSG_CHECKING(for compatible sysinfo call)
1009+
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/sysinfo.h>]],
1010+
[[
1011+
struct sysinfo info;
1012+
int rv = sysinfo(&info);
1013+
unsigned long test = info.freeram + info.bufferram + info.mem_unit;
1014+
]])],
1015+
[
1016+
AC_MSG_RESULT(yes);
1017+
AC_DEFINE(HAVE_LINUX_SYSINFO, 1, [Define this symbol if you have a Linux-compatible sysinfo call])
1018+
],[
1019+
AC_MSG_RESULT(no)
1020+
]
1021+
)
1022+
10081023
dnl Check for posix_fallocate
10091024
AC_MSG_CHECKING([for posix_fallocate])
10101025
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[

src/common/system.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
#include <malloc.h>
2525
#endif
2626

27+
#ifdef HAVE_LINUX_SYSINFO
28+
#include <sys/sysinfo.h>
29+
#endif
30+
2731
#include <cstdlib>
2832
#include <locale>
2933
#include <stdexcept>
@@ -110,3 +114,28 @@ int64_t GetStartupTime()
110114
{
111115
return nStartupTime;
112116
}
117+
118+
bool SystemNeedsMemoryReleased()
119+
{
120+
constexpr size_t low_memory_threshold = 10 * 1024 * 1024 /* 10 MB */;
121+
#ifdef WIN32
122+
MEMORYSTATUSEX mem_status;
123+
mem_status.dwLength = sizeof(mem_status);
124+
if (GlobalMemoryStatusEx(&mem_status)) {
125+
if (mem_status.dwMemoryLoad >= 99) return true;
126+
if (mem_status.ullAvailPhys < low_memory_threshold) return true;
127+
if (mem_status.ullAvailVirtual < low_memory_threshold) return true;
128+
}
129+
#endif
130+
#ifdef HAVE_LINUX_SYSINFO
131+
struct sysinfo sys_info;
132+
if (!sysinfo(&sys_info)) {
133+
// Explicitly 64-bit in case of 32-bit userspace on 64-bit kernel
134+
const uint64_t free_ram = uint64_t(sys_info.freeram) * sys_info.mem_unit;
135+
const uint64_t buffer_ram = uint64_t(sys_info.bufferram) * sys_info.mem_unit;
136+
if (free_ram + buffer_ram < low_memory_threshold) return true;
137+
}
138+
#endif
139+
// NOTE: sysconf(_SC_AVPHYS_PAGES) doesn't account for caches on at least Linux, so not safe to use here
140+
return false;
141+
}

src/common/system.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ std::string ShellEscape(const std::string& arg);
2525
void runCommand(const std::string& strCommand);
2626
#endif
2727

28+
bool SystemNeedsMemoryReleased();
29+
2830
/**
2931
* Return the number of cores available on the current system.
3032
* @note This does count virtual cores, such as those provided by HyperThreading.

src/validation.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <chain.h>
1414
#include <checkqueue.h>
1515
#include <clientversion.h>
16+
#include <common/system.h>
1617
#include <consensus/amount.h>
1718
#include <consensus/consensus.h>
1819
#include <consensus/merkle.h>
@@ -2628,8 +2629,15 @@ bool Chainstate::FlushStateToDisk(
26282629
}
26292630
// The cache is large and we're within 10% and 10 MiB of the limit, but we have time now (not in the middle of a block processing).
26302631
bool fCacheLarge = mode == FlushStateMode::PERIODIC && cache_state >= CoinsCacheSizeState::LARGE;
2631-
// The cache is over the limit, we have to write now.
2632-
bool fCacheCritical = mode == FlushStateMode::IF_NEEDED && cache_state >= CoinsCacheSizeState::CRITICAL;
2632+
bool fCacheCritical = false;
2633+
if (mode == FlushStateMode::IF_NEEDED) {
2634+
if (cache_state >= CoinsCacheSizeState::CRITICAL) {
2635+
// The cache is over the limit, we have to write now.
2636+
fCacheCritical = true;
2637+
} else if (SystemNeedsMemoryReleased()) {
2638+
fCacheCritical = true;
2639+
}
2640+
}
26332641
// It's been a while since we wrote the block index to disk. Do this frequently, so we don't need to redownload after a crash.
26342642
bool fPeriodicWrite = mode == FlushStateMode::PERIODIC && nNow > m_last_write + DATABASE_WRITE_INTERVAL;
26352643
// It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage.

0 commit comments

Comments
 (0)