Skip to content

Replace node_size with memory_limit - #7965

Draft
dangell7 wants to merge 5 commits into
developfrom
dangell7/memory-fix
Draft

Replace node_size with memory_limit#7965
dangell7 wants to merge 5 commits into
developfrom
dangell7/memory-fix

Conversation

@dangell7

@dangell7 dangell7 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

High Level Overview of Change

Replaces [node_size] with [memory_limit]: the memory budget, in gigabytes, that the server sizes its caches within. When it is not set, the budget defaults to detected physical RAM, and on Linux the detection respects the container or service cgroup limit. Setting 0 selects minimal sizes with no enforcement. [node_size] still parses as a deprecated alias (tiny/small/medium/large/huge map to 4/8/32/64/128 GB) and warns at startup, so existing configs keep working.

Context of Change

node_size has served for a long time, but its five presets are entry counts, which are hard to reason about in bytes, and the targets are advisory. During capacity testing our 64 GB nodes ran out of memory at about 2.5M accounts on the "huge" preset, while the same nodes on "large" carried the same load at 2.3 GiB RSS. That test is the calibration for this change: a 64 GB budget produces the "large" sizing that held up, and 128 GB produces the old "huge". The model is the one Redis uses with maxmemory, a byte budget the process keeps.

The change:

  1. Every sized value derives from the budget. The tree cache gets half of it at an estimated 8 KiB per entry, the db caches scale between their old floors and ceilings, and the time and policy values become fixed defaults with their own override sections (tree_cache_age, ledger_cache_age, ledger_fetch_size).
  2. The tree cache target is enforced. TaggedCache gains an opt-in hard cap that demotes the approximately oldest entry whenever growth would exceed it, on fresh inserts and weak-to-strong revivals, with bounded work per call. The sweep remains the primary evictor, and saturation is logged.
  3. Thread counts derive from the core count alone; [workers] and [io_workers] still override.
  4. [node_db] cache_size and cache_age now default to the documented 16384 records and 5 minutes. They previously inherited the tree cache values, and the age was read in the wrong unit, which gave a "huge" node a second 8.4M-entry cache with 15-hour retention.
  5. Admin server_info reports memory_limit in GB instead of node_size (API-CHANGELOG updated), and the unused SizedItem::OpenFinalLimit and RamSizeGb entries are removed.

API Impact

  • libxrpl change: new defaulted TaggedCache constructor parameter; Config::getValueFor loses its node-size override parameter; two dead SizedItem entries removed.
  • Public API: admin server_info drops node_size, adds memory_limit (see API-CHANGELOG.md).

Test Plan

Config tests cover parsing (gigabytes, 0, garbage and values over 1024 rejected), the budget-derived values, standalone behavior, and the alias forms (names, the legacy 0-4 index, and [memory_limit] winning when both are set). GTest covers the hard cap holding through a 1000-insert burst with the sweep unable to fire, and cap 0 disabling it. The full unit test suite passes.

Future Tasks

@xrplf-ai-reviewer xrplf-ai-reviewer Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two budget-aware cache sizing issues flagged inline.

Comment thread src/xrpld/app/misc/SHAMapStoreImp.cpp Outdated
}

if (!section.exists(Keys::kFilterBits) && (config.nodeSize >= 2))
if (!section.exists(Keys::kFilterBits))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bloom filter unconditionally enabled for minimal-budget configs. Re-gate on budget:

Suggested change
if (!section.exists(Keys::kFilterBits))
if (!section.exists(Keys::kFilterBits) && config.cacheMemoryBudget() != 0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto-resolved: the latest review no longer flags this issue, so it appears to have been addressed. If that is not correct, reopen this thread and it will be re-checked on the next review.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto-resolved: the latest review no longer flags this issue, so it appears to have been addressed. If that is not correct, reopen this thread and it will be re-checked on the next review.

return std::clamp(gb * 2, 4, 128);
case SizedItem::BurstSize:
return std::clamp(gb, 4, 48);
case SizedItem::AccountIdCacheSize:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AccountIdCacheSize hardcoded to 300007 ignores new budget. Scale like other caches:

Suggested change
case SizedItem::AccountIdCacheSize:
return std::clamp(gb * 2344, 20047, 300007);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto-resolved: the latest review no longer flags this issue, so it appears to have been addressed. If that is not correct, reopen this thread and it will be re-checked on the next review.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto-resolved: the latest review no longer flags this issue, so it appears to have been addressed. If that is not correct, reopen this thread and it will be re-checked on the next review.

@xrplf-ai-reviewer xrplf-ai-reviewer Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AccountIdCacheSize scaling inconsistency—see inline.

return std::clamp(gb * 2, 4, 128);
case SizedItem::BurstSize:
return std::clamp(gb, 4, 48);
case SizedItem::AccountIdCacheSize:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AccountIdCacheSize hardcoded to 300007 while other db caches scale with budget—document why or scale it:

        case SizedItem::AccountIdCacheSize:
            // Fixed regardless of budget: account ID cache is not
            // memory-significant and uses a documented policy value.
            return 300007;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto-resolved: the latest review no longer flags this issue, so it appears to have been addressed. If that is not correct, reopen this thread and it will be re-checked on the next review.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, kept it fixed with the comment. It's ~22 MB at most and the value stays prime for hash distribution. resolved: f80e72c6f7

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto-resolved: the latest review no longer flags this issue, so it appears to have been addressed. If that is not correct, reopen this thread and it will be re-checked on the next review.

@xrplf-ai-reviewer xrplf-ai-reviewer Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bloom filter config and log-level issues flagged inline.

Comment thread src/xrpld/app/misc/SHAMapStoreImp.cpp Outdated
}

if (!section.exists(Keys::kFilterBits) && (config.nodeSize >= 2))
if (!section.exists(Keys::kFilterBits))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bloom filter now enabled unconditionally for all configs, increasing memory in minimal deployments. Gate on cacheMemoryBudget():

Suggested change
if (!section.exists(Keys::kFilterBits))
if (!section.exists(Keys::kFilterBits) && config.cacheMemoryBudget() != 0)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, gated on a nonzero budget. resolved: f80e72c6f7

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto-resolved: the latest review no longer flags this issue, so it appears to have been addressed. If that is not correct, reopen this thread and it will be re-checked on the next review.

Comment thread src/xrpld/shamap/NodeFamily.cpp Outdated
: 0))
{
auto const budget = app.config().cacheMemoryBudget();
JLOG(j_.warn()) << "TreeNodeCache sizing: target="

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normal startup log at warn level will trigger monitoring alerts. Use j_.info() for routine messages:

Suggested change
JLOG(j_.warn()) << "TreeNodeCache sizing: target="
JLOG(j_.info()) << "TreeNodeCache sizing: target="

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, moved to info. resolved: f80e72c6f7

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto-resolved: the latest review no longer flags this issue, so it appears to have been addressed. If that is not correct, reopen this thread and it will be re-checked on the next review.

@codecov

codecov Bot commented Aug 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 71.92118% with 57 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/xrpld/core/detail/Config.cpp 66.1% 43 Missing ⚠️
include/xrpl/basics/TaggedCache.ipp 80.4% 11 Missing ⚠️
src/xrpld/app/main/Application.cpp 50.0% 2 Missing ⚠️
src/xrpld/app/misc/SHAMapStoreImp.cpp 80.0% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@xrplf-ai-reviewer xrplf-ai-reviewer Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bloom filter scope expanded — see inline.

}

if (!section.exists(Keys::kFilterBits) && (config.nodeSize >= 2))
if (!section.exists(Keys::kFilterBits) && config.cacheMemoryBudget() != 0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bloom filter bits enabled for all budgets (was medium+ tiers only). Likely unintended scope expansion for a memory-reduction PR — gate on threshold:

Suggested change
if (!section.exists(Keys::kFilterBits) && config.cacheMemoryBudget() != 0)
if (!section.exists(Keys::kFilterBits) && config.cacheMemoryBudget() >= (16ull << 30))

@dangell7
dangell7 marked this pull request as draft August 7, 2026 05:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant