20#include <xrpl/basics/contract.h>
21#include <xrpl/beast/core/LexicalCast.h>
22#include <xrpl/beast/utility/instrumentation.h>
23#include <xrpl/nodestore/Factory.h>
24#include <xrpl/nodestore/Manager.h>
25#include <xrpl/nodestore/detail/DecodedBlob.h>
26#include <xrpl/nodestore/detail/EncodedBlob.h>
27#include <xrpl/nodestore/detail/codec.h>
29#include <boost/filesystem.hpp>
31#include <nudb/nudb.hpp>
75 Throw<std::runtime_error>(
76 "nodestore: Missing path in NuDB backend");
84 nudb::context& context,
96 Throw<std::runtime_error>(
97 "nodestore: Missing path in NuDB backend");
107 catch (nudb::system_error
const&)
127 open(
bool createIfMissing, uint64_t appType, uint64_t uid, uint64_t salt)
130 using namespace boost::filesystem;
135 "ripple::NodeStore::NuDBBackend::open : database is already "
137 JLOG(
j_.
error()) <<
"database is already open";
141 auto const folder = path(
name_);
142 auto const dp = (folder /
"nudb.dat").
string();
143 auto const kp = (folder /
"nudb.key").
string();
144 auto const lp = (folder /
"nudb.log").
string();
148 create_directories(folder);
149 nudb::create<nudb::xxhasher>(
160 if (ec == nudb::errc::file_exists)
163 Throw<nudb::system_error>(ec);
165 db_.open(dp, kp, lp, ec);
167 Throw<nudb::system_error>(ec);
170 Throw<std::runtime_error>(
"nodestore: unknown appnum");
177 return db_.is_open();
181 open(
bool createIfMissing)
override
183 open(createIfMissing,
appnum, nudb::make_uid(), nudb::make_salt());
196 JLOG(
j_.
fatal()) <<
"NuBD close() failed: " << ec.message();
197 Throw<nudb::system_error>(ec);
202 boost::filesystem::remove_all(
name_, ec);
205 JLOG(
j_.
fatal()) <<
"Filesystem remove_all of " <<
name_
206 <<
" failed with: " << ec.message();
220 [key, pno, &status](
void const* data,
std::size_t size) {
221 nudb::detail::buffer bf;
223 DecodedBlob decoded(key, result.first, result.second);
224 if (!decoded.
wasOk())
233 if (ec == nudb::error::key_not_found)
236 Throw<nudb::system_error>(ec);
245 for (
auto const& h : hashes)
255 return {results,
ok};
263 nudb::detail::buffer bf;
265 db_.insert(e.
getKey(), result.first, result.second, ec);
266 if (ec && ec != nudb::error::key_exists)
267 Throw<nudb::system_error>(ec);
277 report.
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
288 for (
auto const& e :
batch)
290 report.
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
303 auto const dp =
db_.dat_path();
304 auto const kp =
db_.key_path();
305 auto const lp =
db_.log_path();
310 Throw<nudb::system_error>(ec);
318 nudb::detail::buffer bf;
320 DecodedBlob decoded(key, result.first, result.second);
321 if (!decoded.
wasOk())
331 Throw<nudb::system_error>(ec);
332 db_.open(dp, kp, lp, ec);
334 Throw<nudb::system_error>(ec);
352 auto const dp =
db_.dat_path();
353 auto const kp =
db_.key_path();
354 auto const lp =
db_.log_path();
358 Throw<nudb::system_error>(ec);
359 nudb::verify_info vi;
360 nudb::verify<nudb::xxhasher>(vi, dp, kp, 0, nudb::no_progress{}, ec);
362 Throw<nudb::system_error>(ec);
363 db_.open(dp, kp, lp, ec);
365 Throw<nudb::system_error>(ec);
381 using namespace boost::filesystem;
382 auto const folder = path(name);
383 auto const kp = (folder /
"nudb.key").
string();
386 nudb::block_size(kp);
390 if (!
get_if_exists(keyValues,
"nudb_block_size", blockSizeStr))
398 beast::lexicalCastThrow<std::size_t>(blockSizeStr);
401 if (parsedBlockSize < 4096 || parsedBlockSize > 32768 ||
402 (parsedBlockSize & (parsedBlockSize - 1)) != 0)
405 s <<
"Invalid nudb_block_size: " << parsedBlockSize
406 <<
". Must be power of 2 between 4096 and 32768.";
407 Throw<std::runtime_error>(s.
str());
411 <<
"Using custom NuDB block size: " << parsedBlockSize
413 return parsedBlockSize;
418 s <<
"Invalid nudb_block_size value: " << blockSizeStr
419 <<
". Error: " << e.
what();
420 Throw<std::runtime_error>(s.
str());
453 keyBytes, keyValues,
burstSize, scheduler, journal);
462 nudb::context& context,
466 keyBytes, keyValues,
burstSize, scheduler, context, journal);
A generic endpoint for log messages.
A backend used for the NodeStore.
Parsed key/value blob into NodeObject components.
std::shared_ptr< NodeObject > createObject()
Create a NodeObject from this data.
bool wasOk() const noexcept
Determine if the decoding was successful.
Convert a NodeObject from in-memory to database format.
void const * getKey() const noexcept
std::size_t getSize() const noexcept
void const * getData() const noexcept
Base class for backend factories.
Singleton for managing NodeStore factories and back ends.
virtual void insert(Factory &factory)=0
Add a factory.
void store(std::shared_ptr< NodeObject > const &no) override
Store a single object.
NuDBBackend(size_t keyBytes, Section const &keyValues, std::size_t burstSize, Scheduler &scheduler, beast::Journal journal)
Status fetch(void const *key, std::shared_ptr< NodeObject > *pno) override
Fetch a single object.
void open(bool createIfMissing) override
Open the backend.
std::size_t const burstSize_
std::pair< std::vector< std::shared_ptr< NodeObject > >, Status > fetchBatch(std::vector< uint256 const * > const &hashes) override
Fetch a batch synchronously.
static std::size_t parseBlockSize(std::string const &name, Section const &keyValues, beast::Journal journal)
static constexpr std::uint64_t appnum
void close() override
Close the backend.
NuDBBackend(size_t keyBytes, Section const &keyValues, std::size_t burstSize, Scheduler &scheduler, nudb::context &context, beast::Journal journal)
void storeBatch(Batch const &batch) override
Store a group of objects.
void do_insert(std::shared_ptr< NodeObject > const &no)
std::optional< std::size_t > getBlockSize() const override
Get the block size for backends that support it.
int fdRequired() const override
Returns the number of file descriptors the backend expects to need.
std::string getName() override
Get the human-readable name of this backend.
void open(bool createIfMissing, uint64_t appType, uint64_t uid, uint64_t salt) override
Open the backend.
void verify() override
Perform consistency checks on database.
void for_each(std::function< void(std::shared_ptr< NodeObject >)> f) override
Visit every object in the database This is usually called during import.
std::atomic< bool > deletePath_
std::size_t const blockSize_
bool isOpen() override
Returns true is the database is open.
int getWriteLoad() override
Estimate the number of write operations pending.
void setDeletePath() override
Remove contents on disk upon destruction.
std::unique_ptr< Backend > createInstance(size_t keyBytes, Section const &keyValues, std::size_t burstSize, Scheduler &scheduler, nudb::context &context, beast::Journal journal) override
Create an instance of this factory's backend.
NuDBFactory(Manager &manager)
std::string getName() const override
Retrieve the name of this factory.
std::unique_ptr< Backend > createInstance(size_t keyBytes, Section const &keyValues, std::size_t burstSize, Scheduler &scheduler, beast::Journal journal) override
Create an instance of this factory's backend.
Scheduling for asynchronous backend activity.
virtual void onBatchWrite(BatchWriteReport const &report)=0
Reports the completion of a batch write Allows the scheduler to monitor the node store's performance.
Holds a collection of configuration values.
void registerNuDBFactory(Manager &manager)
std::pair< void const *, std::size_t > nodeobject_decompress(void const *in, std::size_t in_size, BufferFactory &&bf)
std::pair< void const *, std::size_t > nodeobject_compress(void const *in, std::size_t in_size, BufferFactory &&bf)
Status
Return codes from Backend operations.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool get_if_exists(Section const §ion, std::string const &name, T &v)
std::error_code make_error_code(ripple::TokenCodecErrc e)
@ open
We haven't closed our ledger yet, but others might have.
T get(Section const §ion, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
Contains information about a batch write operation.
std::chrono::milliseconds elapsed