Files
rippled/include/xrpl/nodestore/Backend.h
Pratik Mankawde 216d75e2e5 feat(nodestore): measure the NuDB write queue
NuDB serializes every insert behind one global mutex held for the whole
call, so a caller cannot see how long it waited. Record instead the
writer depth joined at and the wall time spent; with mean depth L and
mean insert time W, Little's Law gives service time W/L and queueing
W - W/L. That distinguishes a serialized write path from a saturated
disk: measured on a dev box the device sat 89 percent idle while
throughput stayed flat at 42k inserts per second.

The accounting runs from a ScopeExit guard because the insert can
allocate and therefore throw; leaking the depth would strand the gauge
above zero for the life of the process.

getWriteLoad also stops returning a hardcoded zero. It now reports
writer depth, which is bounded by the writing-thread count and so stays
far below the kMaxWriteLoadAcquire cutoff that gates history
acquisition, where returning bytes or microseconds would have silently
suppressed it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 18:37:00 +01:00

180 lines
4.7 KiB
C++

#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/contract.h>
#include <xrpl/nodestore/NodeObject.h>
#include <xrpl/nodestore/Types.h>
#include <xrpl/nodestore/WriteStats.h>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <optional>
#include <stdexcept>
#include <string>
namespace xrpl::node_store {
/**
* A backend used for the NodeStore.
*
* The NodeStore uses a swappable backend so that other database systems
* can be tried. Different databases may offer various features such
* as improved performance, fault tolerant or distributed storage, or
* all in-memory operation.
*
* A given instance of a backend is fixed to a particular key size.
*/
class Backend
{
public:
/**
* Destroy the backend.
*
* All open files are closed and flushed. If there are batched writes
* or other tasks scheduled, they will be completed before this call
* returns.
*/
virtual ~Backend() = default;
/**
* Get the human-readable name of this backend.
* This is used for diagnostic output.
*/
virtual std::string
getName() = 0;
/**
* Get the block size for backends that support it
*/
[[nodiscard]] virtual std::optional<std::size_t>
getBlockSize() const
{
return std::nullopt;
}
/**
* Get write-path statistics for backends that support it.
*
* Returns std::nullopt for backends that do not measure their writes.
* @see WriteStats for how to derive queuing time from the result.
*/
[[nodiscard]] virtual std::optional<WriteStats>
getWriteStats() const
{
return std::nullopt;
}
/**
* Open the backend.
* @param createIfMissing Create the database files if necessary.
* This allows the caller to catch exceptions.
*/
virtual void
open(bool createIfMissing = true) = 0;
/**
* Returns true is the database is open.
*/
virtual bool
isOpen() = 0;
/**
* Open the backend.
* @param createIfMissing Create the database files if necessary.
* @param appType Deterministic appType used to create a backend.
* @param uid Deterministic uid used to create a backend.
* @param salt Deterministic salt used to create a backend.
* @throws std::runtime_error is function is called not for NuDB backend.
*/
virtual void
open(bool createIfMissing, uint64_t appType, uint64_t uid, uint64_t salt)
{
Throw<std::runtime_error>(
"Deterministic appType/uid/salt not supported by backend " + getName());
}
/**
* Close the backend.
* This allows the caller to catch exceptions.
*/
virtual void
close() = 0;
/**
* Fetch a single object.
* If the object is not found or an error is encountered, the
* result will indicate the condition.
* @note This will be called concurrently.
* @param hash The hash of the object.
* @param pObject [out] The created object if successful.
* @return The result of the operation.
*/
virtual Status
fetch(uint256 const& hash, std::shared_ptr<NodeObject>* pObject) = 0;
/**
* Store a single object.
* Depending on the implementation this may happen immediately
* or deferred using a scheduled task.
* @note This will be called concurrently.
* @param object The object to store.
*/
virtual void
store(std::shared_ptr<NodeObject> const& object) = 0;
/**
* Store a group of objects.
* @note This function will not be called concurrently with
* itself or @ref store.
*/
virtual void
storeBatch(Batch const& batch) = 0;
virtual void
sync() = 0;
/**
* Visit every object in the database
* This is usually called during import.
* @note This routine will not be called concurrently with itself
* or other methods.
* @see import
*/
virtual void
forEach(std::function<void(std::shared_ptr<NodeObject>)> f) = 0;
/**
* Estimate the number of write operations pending.
*/
virtual int
getWriteLoad() = 0;
/**
* Remove contents on disk upon destruction.
*/
virtual void
setDeletePath() = 0;
/**
* Perform consistency checks on database.
*
* This method is implemented only by NuDBBackend. It is not yet called
* anywhere, but it might be a good idea to one day call it at startup to
* avert a crash.
*/
virtual void
verify()
{
}
/**
* Returns the number of file descriptors the backend expects to need.
*/
[[nodiscard]] virtual int
fdRequired() const = 0;
};
} // namespace xrpl::node_store