Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
8d31b17
TEST: Disable tagged cache to measure performance
bthomee Mar 28, 2025
d170384
Fully disable cache
bthomee Apr 1, 2025
d01851b
Only disable the database cache
bthomee Apr 1, 2025
61c9a19
Merge branch 'develop' into bthomee/disable-cache
bthomee May 7, 2025
39bfcaf
Merge branch 'develop' into bthomee/disable-cache
bthomee May 17, 2025
0777f7c
Merge branch 'develop' into bthomee/disable-cache
bthomee May 19, 2025
6e7537d
Remove cache from DatabaseNodeImp
bthomee May 19, 2025
a213127
Remove cache from SHAMapStoreImp
bthomee May 19, 2025
4650e7d
Removed unused caches from SHAMapStoreImp
bthomee May 20, 2025
2fa1c71
Removed unused config values
bthomee May 20, 2025
965fc75
Reserve vector size
bthomee May 20, 2025
d96c416
Merge branch 'develop' into bthomee/disable-cache
bthomee May 22, 2025
fca6a87
Merge branch 'develop' into bthomee/disable-cache
bthomee Jun 2, 2025
a4a1c4e
Merge branch 'develop' into bthomee/disable-cache
bthomee Jul 3, 2025
aad6edb
Merge branch 'develop' into bthomee/disable-cache
bthomee Aug 13, 2025
1a4d973
Merge branch 'develop' into bthomee/disable-cache
bthomee Sep 17, 2025
4306d9c
Restore freshening caches of tree node cache
bthomee Sep 17, 2025
f3ea3e9
Merge branch 'develop' into bthomee/disable-cache
bthomee Nov 22, 2025
eabd485
Merge branch 'develop' into bthomee/disable-cache
bthomee Jan 29, 2026
9639b79
Copilot feedback
bthomee Feb 2, 2026
aeb7934
Update src/libxrpl/nodestore/DatabaseNodeImp.cpp
bthomee Feb 3, 2026
735f9f4
Apply suggestions from code review
bthomee Feb 3, 2026
4bdba71
Remove unused sweep
bthomee Feb 3, 2026
96e645a
chore: Add cmake-format pre-commit hook (#6279)
mathbunnyru Jan 29, 2026
d7d84e8
chore: Format all cmake files without comments (#6294)
mathbunnyru Jan 29, 2026
a4bccb9
ci: Update hashes of XRPLF/actions (#6316)
mathbunnyru Feb 2, 2026
e5ce4f1
chore: Add upper-case match for ARM64 in CompilationEnv (#6315)
ximinez Feb 2, 2026
00e7a04
fix: Restore config changes that broke standalone mode (#6301)
bthomee Feb 3, 2026
9f6ec0a
docs: Update API changelog, add APIv2+APIv3 version documentation (#6…
mvadari Feb 3, 2026
6eb6df9
Remove const
bthomee Feb 3, 2026
606ffae
Merge branch 'develop' into bthomee/disable-cache
bthomee Feb 3, 2026
cd3feb9
Fix pointer access
bthomee Feb 3, 2026
4495952
Add assert
bthomee Feb 3, 2026
62d65c2
Initial plan
Copilot Feb 3, 2026
6b57c27
Remove incorrect assertion about result size matching input size
Copilot Feb 3, 2026
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
20 changes: 1 addition & 19 deletions cfg/xrpld-example.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -940,32 +940,14 @@
#
# path Location to store the database
#
# Optional keys
#
# cache_size Size of cache for database records. Default is 16384.
# Setting this value to 0 will use the default value.
#
# cache_age Length of time in minutes to keep database records
# cached. Default is 5 minutes. Setting this value to
# 0 will use the default value.
#
# Note: if neither cache_size nor cache_age is
# specified, the cache for database records will not
# be created. If only one of cache_size or cache_age
# is specified, the cache will be created using the
# default value for the unspecified parameter.
#
# Note: the cache will not be created if online_delete
# is specified.
# Optional keys for NuDB and RocksDB:
#
# fast_load Boolean. If set, load the last persisted ledger
# from disk upon process start before syncing to
# the network. This is likely to improve performance
# if sufficient IOPS capacity is available.
# Default 0.
#
# Optional keys for NuDB or RocksDB:
#
# earliest_seq The default is 32570 to match the XRP ledger
# network's earliest allowed sequence. Alternate
# networks may set this value. Minimum value of 1.
Expand Down
4 changes: 0 additions & 4 deletions include/xrpl/nodestore/Database.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,6 @@ class Database
std::uint32_t ledgerSeq,
std::function<void(std::shared_ptr<NodeObject> const&)>&& callback);

/** Remove expired entries from the positive and negative caches. */
virtual void
sweep() = 0;

/** Gather statistics pertaining to read and write activities.
*
* @param obj Json object reference into which to place counters.
Expand Down
32 changes: 0 additions & 32 deletions include/xrpl/nodestore/detail/DatabaseNodeImp.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,6 @@ class DatabaseNodeImp : public Database
beast::Journal j)
: Database(scheduler, readThreads, config, j), backend_(std::move(backend))
{
std::optional<int> cacheSize, cacheAge;

if (config.exists("cache_size"))
{
cacheSize = get<int>(config, "cache_size");
if (cacheSize.value() < 0)
{
Throw<std::runtime_error>("Specified negative value for cache_size");
}
}

if (config.exists("cache_age"))
{
cacheAge = get<int>(config, "cache_age");
if (cacheAge.value() < 0)
{
Throw<std::runtime_error>("Specified negative value for cache_age");
}
}

if (cacheSize != 0 || cacheAge != 0)
{
cache_ = std::make_shared<TaggedCache<uint256, NodeObject>>(
"DatabaseNodeImp", cacheSize.value_or(0), std::chrono::minutes(cacheAge.value_or(0)), stopwatch(), j);
}

XRPL_ASSERT(
backend_,
"xrpl::NodeStore::DatabaseNodeImp::DatabaseNodeImp : non-null "
Expand Down Expand Up @@ -104,13 +78,7 @@ class DatabaseNodeImp : public Database
std::uint32_t ledgerSeq,
std::function<void(std::shared_ptr<NodeObject> const&)>&& callback) override;

void
sweep() override;

private:
// Cache for database objects. This cache is not always initialized. Check
// for null before using.
std::shared_ptr<TaggedCache<uint256, NodeObject>> cache_;
// Persistent key/value storage
std::shared_ptr<Backend> backend_;

Expand Down
3 changes: 0 additions & 3 deletions include/xrpl/nodestore/detail/DatabaseRotatingImp.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ class DatabaseRotatingImp : public DatabaseRotating
void
sync() override;

void
sweep() override;

private:
std::shared_ptr<Backend> writableBackend_;
std::shared_ptr<Backend> archiveBackend_;
Expand Down
141 changes: 29 additions & 112 deletions src/libxrpl/nodestore/DatabaseNodeImp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ DatabaseNodeImp::store(NodeObjectType type, Blob&& data, uint256 const& hash, st

auto obj = NodeObject::createObject(type, std::move(data), hash);
backend_->store(obj);
if (cache_)
{
// After the store, replace a negative cache entry if there is one
cache_->canonicalize(hash, obj, [](std::shared_ptr<NodeObject> const& n) { return n->getType() == hotDUMMY; });
}
}

void
Expand All @@ -23,77 +18,36 @@ DatabaseNodeImp::asyncFetch(
std::uint32_t ledgerSeq,
std::function<void(std::shared_ptr<NodeObject> const&)>&& callback)
{
if (cache_)
{
std::shared_ptr<NodeObject> obj = cache_->fetch(hash);
if (obj)
{
callback(obj->getType() == hotDUMMY ? nullptr : obj);
return;
}
}
Database::asyncFetch(hash, ledgerSeq, std::move(callback));
}

void
DatabaseNodeImp::sweep()
{
if (cache_)
cache_->sweep();
}

std::shared_ptr<NodeObject>
DatabaseNodeImp::fetchNodeObject(uint256 const& hash, std::uint32_t, FetchReport& fetchReport, bool duplicate)
{
std::shared_ptr<NodeObject> nodeObject = cache_ ? cache_->fetch(hash) : nullptr;
std::shared_ptr<NodeObject> nodeObject = nullptr;
Status status;

if (!nodeObject)
try
{
JLOG(j_.trace()) << "fetchNodeObject " << hash << ": record not " << (cache_ ? "cached" : "found");

Status status;

try
{
status = backend_->fetch(hash.data(), &nodeObject);
}
catch (std::exception const& e)
{
JLOG(j_.fatal()) << "fetchNodeObject " << hash << ": Exception fetching from backend: " << e.what();
Rethrow();
}

switch (status)
{
case ok:
if (cache_)
{
if (nodeObject)
cache_->canonicalize_replace_client(hash, nodeObject);
else
{
auto notFound = NodeObject::createObject(hotDUMMY, {}, hash);
cache_->canonicalize_replace_client(hash, notFound);
if (notFound->getType() != hotDUMMY)
nodeObject = notFound;
}
}
break;
case notFound:
break;
case dataCorrupt:
JLOG(j_.fatal()) << "fetchNodeObject " << hash << ": nodestore data is corrupted";
break;
default:
JLOG(j_.warn()) << "fetchNodeObject " << hash << ": backend returns unknown result " << status;
break;
}
status = backend_->fetch(hash.data(), &nodeObject);
}
catch (std::exception const& e)
{
JLOG(j_.fatal()) << "fetchNodeObject " << hash << ": Exception fetching from backend: " << e.what();
Rethrow();
}
else

switch (status)
{
JLOG(j_.trace()) << "fetchNodeObject " << hash << ": record found in cache";
if (nodeObject->getType() == hotDUMMY)
nodeObject.reset();
case ok:
case notFound:
break;
case dataCorrupt:
JLOG(j_.fatal()) << "fetchNodeObject " << hash << ": nodestore data is corrupted";
break;
default:
JLOG(j_.warn()) << "fetchNodeObject " << hash << ": backend returns unknown result " << status;
break;
}

if (nodeObject)
Expand All @@ -105,66 +59,29 @@ DatabaseNodeImp::fetchNodeObject(uint256 const& hash, std::uint32_t, FetchReport
std::vector<std::shared_ptr<NodeObject>>
DatabaseNodeImp::fetchBatch(std::vector<uint256> const& hashes)
{
std::vector<std::shared_ptr<NodeObject>> results{hashes.size()};
using namespace std::chrono;
auto const before = steady_clock::now();
std::unordered_map<uint256 const*, size_t> indexMap;
std::vector<uint256 const*> cacheMisses;
uint64_t hits = 0;
uint64_t fetches = 0;

std::vector<uint256 const*> batch{};
batch.reserve(hashes.size());
for (size_t i = 0; i < hashes.size(); ++i)
{
auto const& hash = hashes[i];
// See if the object already exists in the cache
auto nObj = cache_ ? cache_->fetch(hash) : nullptr;
++fetches;
if (!nObj)
{
// Try the database
indexMap[&hash] = i;
cacheMisses.push_back(&hash);
}
else
{
results[i] = nObj->getType() == hotDUMMY ? nullptr : nObj;
// It was in the cache.
++hits;
}
batch.push_back(&hash);
}

JLOG(j_.debug()) << "fetchBatch - cache hits = " << (hashes.size() - cacheMisses.size())
<< " - cache misses = " << cacheMisses.size();
auto dbResults = backend_->fetchBatch(cacheMisses).first;

for (size_t i = 0; i < dbResults.size(); ++i)
auto results = backend_->fetchBatch(batch).first;
for (size_t i = 0; i < results.size(); ++i)
{
auto nObj = std::move(dbResults[i]);
size_t index = indexMap[cacheMisses[i]];
auto const& hash = hashes[index];

if (nObj)
{
// Ensure all threads get the same object
if (cache_)
cache_->canonicalize_replace_client(hash, nObj);
}
else
if (!results[i])
{
JLOG(j_.error()) << "fetchBatch - "
<< "record not found in db or cache. hash = " << strHex(hash);
if (cache_)
{
auto notFound = NodeObject::createObject(hotDUMMY, {}, hash);
cache_->canonicalize_replace_client(hash, notFound);
if (notFound->getType() != hotDUMMY)
nObj = std::move(notFound);
}
<< "record not found in db. hash = " << strHex(hashes[i]);
}
results[index] = std::move(nObj);
}

auto fetchDurationUs = std::chrono::duration_cast<std::chrono::microseconds>(steady_clock::now() - before).count();
updateFetchMetrics(fetches, hits, fetchDurationUs);
updateFetchMetrics(hashes.size(), 0, fetchDurationUs);
return results;
}

Expand Down
6 changes: 0 additions & 6 deletions src/libxrpl/nodestore/DatabaseRotatingImp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,6 @@ DatabaseRotatingImp::store(NodeObjectType type, Blob&& data, uint256 const& hash
storeStats(1, nObj->getData().size());
}

void
DatabaseRotatingImp::sweep()
{
// nothing to do
}

std::shared_ptr<NodeObject>
DatabaseRotatingImp::fetchNodeObject(uint256 const& hash, std::uint32_t, FetchReport& fetchReport, bool duplicate)
{
Expand Down
18 changes: 3 additions & 15 deletions src/test/app/SHAMapStore_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -490,29 +490,17 @@ class SHAMapStore_test : public beast::unit_test::suite
Env env(*this, envconfig(onlineDelete));

/////////////////////////////////////////////////////////////
// Create the backend. Normally, SHAMapStoreImp handles all these
// details
auto nscfg = env.app().config().section(ConfigSection::nodeDatabase());

// Provide default values:
if (!nscfg.exists("cache_size"))
nscfg.set(
"cache_size", std::to_string(env.app().config().getValueFor(SizedItem::treeCacheSize, std::nullopt)));

if (!nscfg.exists("cache_age"))
nscfg.set(
"cache_age", std::to_string(env.app().config().getValueFor(SizedItem::treeCacheAge, std::nullopt)));

// Create NodeStore with two backends to allow online deletion of data.
// Normally, SHAMapStoreImp handles all these details.
NodeStoreScheduler scheduler(env.app().getJobQueue());

std::string const writableDb = "write";
std::string const archiveDb = "archive";
auto writableBackend = makeBackendRotating(env, scheduler, writableDb);
auto archiveBackend = makeBackendRotating(env, scheduler, archiveDb);

// Create NodeStore with two backends to allow online deletion of
// data
constexpr int readThreads = 4;
auto nscfg = env.app().config().section(ConfigSection::nodeDatabase());
auto dbr = std::make_unique<NodeStore::DatabaseRotatingImp>(
scheduler,
readThreads,
Expand Down
4 changes: 0 additions & 4 deletions src/xrpld/app/main/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -908,10 +908,6 @@ class ApplicationImp : public Application, public BasicApp
JLOG(m_journal.debug()) << "MasterTransaction sweep. Size before: " << oldMasterTxSize
<< "; size after: " << masterTxCache.size();
}
{
// Does not appear to have an associated cache.
getNodeStore().sweep();
}
{
std::size_t const oldLedgerMasterCacheSize = getLedgerMaster().getFetchPackCacheSize();

Expand Down
21 changes: 7 additions & 14 deletions src/xrpld/app/misc/SHAMapStoreImp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,14 +130,6 @@ std::unique_ptr<NodeStore::Database>
SHAMapStoreImp::makeNodeStore(int readThreads)
{
auto nscfg = app_.config().section(ConfigSection::nodeDatabase());

// Provide default values:
if (!nscfg.exists("cache_size"))
nscfg.set("cache_size", std::to_string(app_.config().getValueFor(SizedItem::treeCacheSize, std::nullopt)));

if (!nscfg.exists("cache_age"))
nscfg.set("cache_age", std::to_string(app_.config().getValueFor(SizedItem::treeCacheAge, std::nullopt)));

std::unique_ptr<NodeStore::Database> db;

if (deleteInterval_)
Expand Down Expand Up @@ -226,8 +218,6 @@ SHAMapStoreImp::run()
LedgerIndex lastRotated = state_db_.getState().lastRotated;
netOPs_ = &app_.getOPs();
ledgerMaster_ = &app_.getLedgerMaster();
fullBelowCache_ = &(*app_.getNodeFamily().getFullBelowCache());
treeNodeCache_ = &(*app_.getNodeFamily().getTreeNodeCache());

if (advisoryDelete_)
canDelete_ = state_db_.getCanDelete();
Expand Down Expand Up @@ -490,16 +480,19 @@ void
SHAMapStoreImp::clearCaches(LedgerIndex validatedSeq)
{
ledgerMaster_->clearLedgerCachePrior(validatedSeq);
fullBelowCache_->clear();
// Also clear the FullBelowCache so its generation counter is bumped.
// This prevents stale "full below" markers from persisting across
// backend rotation/online deletion and interfering with SHAMap sync.
app_.getNodeFamily().getFullBelowCache()->clear();
}

void
SHAMapStoreImp::freshenCaches()
{
if (freshenCache(*treeNodeCache_))
return;
if (freshenCache(app_.getMasterTransaction().getCache()))
if (freshenCache(*app_.getNodeFamily().getTreeNodeCache()))
return;

freshenCache(app_.getMasterTransaction().getCache());
}

void
Expand Down
Loading