mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-28 14:35:48 +00:00
feat: enforce online_delete requirement for RWDB to prevent OOM
RWDB (in-memory backend) now requires online_delete configuration to prevent unbounded memory growth. Exception: standalone mode (used by tests) bypasses this requirement since tests run for short durations. - Add enforcement check in SHAMapStoreImp constructor - Tests use Config::setupControl() to simulate non-standalone environment - Comprehensive test coverage for all enforcement scenarios
This commit is contained in:
@@ -118,16 +118,10 @@ SHAMapStoreImp::SHAMapStoreImp(
|
|||||||
|
|
||||||
get_if_exists(section, "online_delete", deleteInterval_);
|
get_if_exists(section, "online_delete", deleteInterval_);
|
||||||
|
|
||||||
auto actual_standalone = config.standalone();
|
|
||||||
auto effective_standalone =
|
|
||||||
get(section,
|
|
||||||
"_online_delete_standalone_override",
|
|
||||||
actual_standalone ? "true" : "false") != "false";
|
|
||||||
|
|
||||||
// RWDB (in-memory backend) requires online_delete to prevent OOM
|
// RWDB (in-memory backend) requires online_delete to prevent OOM
|
||||||
// Exception: standalone mode (used by tests) doesn't need online_delete
|
// Exception: standalone mode (used by tests) doesn't need online_delete
|
||||||
// since tests run for short durations
|
// since tests run for short durations
|
||||||
if (config.mem_backend() && !deleteInterval_ && !effective_standalone)
|
if (config.mem_backend() && !deleteInterval_ && !config.standalone())
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(
|
||||||
"RWDB (in-memory backend) requires online_delete to be configured. "
|
"RWDB (in-memory backend) requires online_delete to be configured. "
|
||||||
|
|||||||
@@ -522,40 +522,39 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<Config>
|
static std::unique_ptr<Config>
|
||||||
rwdbNoDelete()
|
rwdbNoDeleteDefaultConfig()
|
||||||
{
|
{
|
||||||
// RWDB without online_delete, but keep standalone override = true
|
// RWDB without online_delete, in standalone mode (default)
|
||||||
// (default)
|
|
||||||
auto cfg = test::jtx::envconfig();
|
auto cfg = test::jtx::envconfig();
|
||||||
cfg->section(ConfigSection::nodeDatabase()).set("type", "rwdb");
|
cfg->section(ConfigSection::nodeDatabase()).set("type", "rwdb");
|
||||||
cfg->section(ConfigSection::nodeDatabase()).set("path", "main");
|
cfg->section(ConfigSection::nodeDatabase()).set("path", "main");
|
||||||
// Keep the default standalone override value of "true" from
|
// Default is standalone = true from envconfig.cpp
|
||||||
// envconfig.cpp
|
|
||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<Config>
|
static std::unique_ptr<Config>
|
||||||
rwdbNoDeleteEnforced()
|
rwdbNoDeleteNotStandalone()
|
||||||
{
|
{
|
||||||
// RWDB without online_delete and force enforcement
|
// RWDB without online_delete and NOT in standalone mode
|
||||||
|
// This should trigger the enforcement
|
||||||
auto cfg = test::jtx::envconfig();
|
auto cfg = test::jtx::envconfig();
|
||||||
cfg->section(ConfigSection::nodeDatabase()).set("type", "rwdb");
|
cfg->section(ConfigSection::nodeDatabase()).set("type", "rwdb");
|
||||||
cfg->section(ConfigSection::nodeDatabase()).set("path", "main");
|
cfg->section(ConfigSection::nodeDatabase()).set("path", "main");
|
||||||
cfg->section(ConfigSection::nodeDatabase())
|
cfg->setupControl(
|
||||||
.set("_online_delete_standalone_override", "false");
|
true, true, false); // bQuiet, bSilent, bStandalone=false
|
||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<Config>
|
static std::unique_ptr<Config>
|
||||||
rwdbWithDeleteEnforced()
|
rwdbWithDeleteNotStandalone()
|
||||||
{
|
{
|
||||||
// RWDB with online_delete and force enforcement
|
// RWDB with online_delete and NOT in standalone mode
|
||||||
auto cfg = test::jtx::envconfig();
|
auto cfg = test::jtx::envconfig();
|
||||||
cfg->section(ConfigSection::nodeDatabase()).set("type", "rwdb");
|
cfg->section(ConfigSection::nodeDatabase()).set("type", "rwdb");
|
||||||
cfg->section(ConfigSection::nodeDatabase()).set("path", "main");
|
cfg->section(ConfigSection::nodeDatabase()).set("path", "main");
|
||||||
cfg->section(ConfigSection::nodeDatabase()).set("online_delete", "256");
|
cfg->section(ConfigSection::nodeDatabase()).set("online_delete", "256");
|
||||||
cfg->section(ConfigSection::nodeDatabase())
|
cfg->setupControl(
|
||||||
.set("_online_delete_standalone_override", "false");
|
true, true, false); // bQuiet, bSilent, bStandalone=false
|
||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -564,18 +563,18 @@ public:
|
|||||||
{
|
{
|
||||||
testcase("RWDB online_delete enforcement");
|
testcase("RWDB online_delete enforcement");
|
||||||
|
|
||||||
// Test 1: RWDB without online_delete but with standalone override =
|
// Test 1: RWDB without online_delete in standalone mode (should
|
||||||
// true (should succeed)
|
// succeed)
|
||||||
{
|
{
|
||||||
test::jtx::Env env{*this, rwdbNoDelete()};
|
jtx::Env env{*this, rwdbNoDeleteDefaultConfig()};
|
||||||
pass();
|
pass();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 2: RWDB without online_delete and standalone override = false
|
// Test 2: RWDB without online_delete NOT in standalone mode (should
|
||||||
// (should throw)
|
// throw)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
test::jtx::Env env{*this, rwdbNoDeleteEnforced()};
|
jtx::Env env{*this, rwdbNoDeleteNotStandalone()};
|
||||||
fail("Expected exception for RWDB without online_delete");
|
fail("Expected exception for RWDB without online_delete");
|
||||||
}
|
}
|
||||||
catch (std::runtime_error const& e)
|
catch (std::runtime_error const& e)
|
||||||
@@ -587,10 +586,20 @@ public:
|
|||||||
pass();
|
pass();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 3: RWDB with online_delete and standalone override = false
|
// Test 3: RWDB with online_delete NOT in standalone mode (should
|
||||||
// (should succeed)
|
// succeed) But should throw with another error message unrelated
|
||||||
|
try
|
||||||
{
|
{
|
||||||
test::jtx::Env env{*this, rwdbWithDeleteEnforced()};
|
jtx::Env env{*this, rwdbWithDeleteNotStandalone()};
|
||||||
|
// Currently throwing due to missing database_path
|
||||||
|
fail("Test relies upon throwing exception");
|
||||||
|
}
|
||||||
|
catch (std::runtime_error const& e)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(
|
||||||
|
std::string(e.what()).find(
|
||||||
|
"RWDB (in-memory backend) requires online_delete") ==
|
||||||
|
std::string::npos);
|
||||||
pass();
|
pass();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,10 +51,6 @@ setupConfigForUnitTests(Config& cfg)
|
|||||||
|
|
||||||
cfg.overwrite(ConfigSection::nodeDatabase(), "type", "rwdb");
|
cfg.overwrite(ConfigSection::nodeDatabase(), "type", "rwdb");
|
||||||
cfg.overwrite(ConfigSection::nodeDatabase(), "path", "main");
|
cfg.overwrite(ConfigSection::nodeDatabase(), "path", "main");
|
||||||
cfg.overwrite(
|
|
||||||
ConfigSection::nodeDatabase(),
|
|
||||||
"_online_delete_standalone_override",
|
|
||||||
"true");
|
|
||||||
cfg.overwrite(SECTION_RELATIONAL_DB, "backend", "rwdb");
|
cfg.overwrite(SECTION_RELATIONAL_DB, "backend", "rwdb");
|
||||||
cfg.deprecatedClearSection(ConfigSection::importNodeDatabase());
|
cfg.deprecatedClearSection(ConfigSection::importNodeDatabase());
|
||||||
cfg.legacy("database_path", "");
|
cfg.legacy("database_path", "");
|
||||||
|
|||||||
Reference in New Issue
Block a user