20#include <xrpld/nodestore/Factory.h>
21#include <xrpld/nodestore/Manager.h>
22#include <xrpld/nodestore/detail/DecodedBlob.h>
23#include <xrpld/nodestore/detail/EncodedBlob.h>
24#include <xrpld/nodestore/detail/codec.h>
26#include <xrpl/basics/contract.h>
27#include <xrpl/beast/core/LexicalCast.h>
28#include <xrpl/beast/utility/instrumentation.h>
30#include <boost/filesystem.hpp>
32#include <nudb/nudb.hpp>
76 Throw<std::runtime_error>(
77 "nodestore: Missing path in NuDB backend");
85 nudb::context& context,
97 Throw<std::runtime_error>(
98 "nodestore: Missing path in NuDB backend");
108 catch (nudb::system_error
const&)
128 open(
bool createIfMissing, uint64_t appType, uint64_t uid, uint64_t salt)
131 using namespace boost::filesystem;
136 "ripple::NodeStore::NuDBBackend::open : database is already "
138 JLOG(
j_.
error()) <<
"database is already open";
142 auto const folder = path(
name_);
143 auto const dp = (folder /
"nudb.dat").
string();
144 auto const kp = (folder /
"nudb.key").
string();
145 auto const lp = (folder /
"nudb.log").
string();
149 create_directories(folder);
150 nudb::create<nudb::xxhasher>(
161 if (ec == nudb::errc::file_exists)
164 Throw<nudb::system_error>(ec);
166 db_.open(dp, kp, lp, ec);
168 Throw<nudb::system_error>(ec);
171 Throw<std::runtime_error>(
"nodestore: unknown appnum");
178 return db_.is_open();
182 open(
bool createIfMissing)
override
184 open(createIfMissing,
appnum, nudb::make_uid(), nudb::make_salt());
197 JLOG(
j_.
fatal()) <<
"NuBD close() failed: " << ec.message();
198 Throw<nudb::system_error>(ec);
203 boost::filesystem::remove_all(
name_, ec);
206 JLOG(
j_.
fatal()) <<
"Filesystem remove_all of " <<
name_
207 <<
" failed with: " << ec.message();
221 [key, pno, &status](
void const* data,
std::size_t size) {
222 nudb::detail::buffer bf;
224 DecodedBlob decoded(key, result.first, result.second);
225 if (!decoded.
wasOk())
234 if (ec == nudb::error::key_not_found)
237 Throw<nudb::system_error>(ec);
246 for (
auto const& h : hashes)
256 return {results,
ok};
264 nudb::detail::buffer bf;
266 db_.insert(e.
getKey(), result.first, result.second, ec);
267 if (ec && ec != nudb::error::key_exists)
268 Throw<nudb::system_error>(ec);
278 report.
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
289 for (
auto const& e :
batch)
291 report.
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
304 auto const dp =
db_.dat_path();
305 auto const kp =
db_.key_path();
306 auto const lp =
db_.log_path();
311 Throw<nudb::system_error>(ec);
319 nudb::detail::buffer bf;
321 DecodedBlob decoded(key, result.first, result.second);
322 if (!decoded.
wasOk())
332 Throw<nudb::system_error>(ec);
333 db_.open(dp, kp, lp, ec);
335 Throw<nudb::system_error>(ec);
353 auto const dp =
db_.dat_path();
354 auto const kp =
db_.key_path();
355 auto const lp =
db_.log_path();
359 Throw<nudb::system_error>(ec);
360 nudb::verify_info vi;
361 nudb::verify<nudb::xxhasher>(vi, dp, kp, 0, nudb::no_progress{}, ec);
363 Throw<nudb::system_error>(ec);
364 db_.open(dp, kp, lp, ec);
366 Throw<nudb::system_error>(ec);
382 using namespace boost::filesystem;
383 auto const folder = path(name);
384 auto const kp = (folder /
"nudb.key").
string();
387 nudb::block_size(kp);
391 if (!
get_if_exists(keyValues,
"nudb_block_size", blockSizeStr))
399 beast::lexicalCastThrow<std::size_t>(blockSizeStr);
402 if (parsedBlockSize < 4096 || parsedBlockSize > 32768 ||
403 (parsedBlockSize & (parsedBlockSize - 1)) != 0)
406 s <<
"Invalid nudb_block_size: " << parsedBlockSize
407 <<
". Must be power of 2 between 4096 and 32768.";
408 Throw<std::runtime_error>(s.
str());
412 <<
"Using custom NuDB block size: " << parsedBlockSize
414 return parsedBlockSize;
419 s <<
"Invalid nudb_block_size value: " << blockSizeStr
420 <<
". Error: " << e.
what();
421 Throw<std::runtime_error>(s.
str());
456 keyBytes, keyValues,
burstSize, scheduler, journal);
465 nudb::context& context,
469 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.
static Manager & instance()
Returns the instance of the manager singleton.
virtual void erase(Factory &factory)=0
Remove a factory.
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.
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.
static NuDBFactory nuDBFactory
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