1#include <xrpl/basics/contract.h>
2#include <xrpl/beast/core/LexicalCast.h>
3#include <xrpl/beast/utility/instrumentation.h>
4#include <xrpl/nodestore/Factory.h>
5#include <xrpl/nodestore/Manager.h>
6#include <xrpl/nodestore/detail/DecodedBlob.h>
7#include <xrpl/nodestore/detail/EncodedBlob.h>
8#include <xrpl/nodestore/detail/codec.h>
10#include <boost/filesystem.hpp>
12#include <nudb/nudb.hpp>
56 Throw<std::runtime_error>(
57 "nodestore: Missing path in NuDB backend");
65 nudb::context& context,
77 Throw<std::runtime_error>(
78 "nodestore: Missing path in NuDB backend");
88 catch (nudb::system_error
const&)
108 open(
bool createIfMissing, uint64_t appType, uint64_t uid, uint64_t salt)
111 using namespace boost::filesystem;
116 "xrpl::NodeStore::NuDBBackend::open : database is already "
118 JLOG(
j_.
error()) <<
"database is already open";
122 auto const folder = path(
name_);
123 auto const dp = (folder /
"nudb.dat").
string();
124 auto const kp = (folder /
"nudb.key").
string();
125 auto const lp = (folder /
"nudb.log").
string();
129 create_directories(folder);
130 nudb::create<nudb::xxhasher>(
141 if (ec == nudb::errc::file_exists)
144 Throw<nudb::system_error>(ec);
146 db_.open(dp, kp, lp, ec);
148 Throw<nudb::system_error>(ec);
151 Throw<std::runtime_error>(
"nodestore: unknown appnum");
158 return db_.is_open();
162 open(
bool createIfMissing)
override
164 open(createIfMissing,
appnum, nudb::make_uid(), nudb::make_salt());
177 JLOG(
j_.
fatal()) <<
"NuBD close() failed: " << ec.message();
178 Throw<nudb::system_error>(ec);
183 boost::filesystem::remove_all(
name_, ec);
186 JLOG(
j_.
fatal()) <<
"Filesystem remove_all of " <<
name_
187 <<
" failed with: " << ec.message();
201 [key, pno, &status](
void const* data,
std::size_t size) {
202 nudb::detail::buffer bf;
204 DecodedBlob decoded(key, result.first, result.second);
205 if (!decoded.
wasOk())
214 if (ec == nudb::error::key_not_found)
217 Throw<nudb::system_error>(ec);
226 for (
auto const& h : hashes)
236 return {results,
ok};
244 nudb::detail::buffer bf;
246 db_.insert(e.
getKey(), result.first, result.second, ec);
247 if (ec && ec != nudb::error::key_exists)
248 Throw<nudb::system_error>(ec);
258 report.
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
269 for (
auto const& e :
batch)
271 report.
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
284 auto const dp =
db_.dat_path();
285 auto const kp =
db_.key_path();
286 auto const lp =
db_.log_path();
291 Throw<nudb::system_error>(ec);
299 nudb::detail::buffer bf;
301 DecodedBlob decoded(key, result.first, result.second);
302 if (!decoded.
wasOk())
312 Throw<nudb::system_error>(ec);
313 db_.open(dp, kp, lp, ec);
315 Throw<nudb::system_error>(ec);
333 auto const dp =
db_.dat_path();
334 auto const kp =
db_.key_path();
335 auto const lp =
db_.log_path();
339 Throw<nudb::system_error>(ec);
340 nudb::verify_info vi;
341 nudb::verify<nudb::xxhasher>(vi, dp, kp, 0, nudb::no_progress{}, ec);
343 Throw<nudb::system_error>(ec);
344 db_.open(dp, kp, lp, ec);
346 Throw<nudb::system_error>(ec);
362 using namespace boost::filesystem;
363 auto const folder = path(name);
364 auto const kp = (folder /
"nudb.key").
string();
367 nudb::block_size(kp);
371 if (!
get_if_exists(keyValues,
"nudb_block_size", blockSizeStr))
379 beast::lexicalCastThrow<std::size_t>(blockSizeStr);
382 if (parsedBlockSize < 4096 || parsedBlockSize > 32768 ||
383 (parsedBlockSize & (parsedBlockSize - 1)) != 0)
386 s <<
"Invalid nudb_block_size: " << parsedBlockSize
387 <<
". Must be power of 2 between 4096 and 32768.";
388 Throw<std::runtime_error>(s.
str());
392 <<
"Using custom NuDB block size: " << parsedBlockSize
394 return parsedBlockSize;
399 s <<
"Invalid nudb_block_size value: " << blockSizeStr
400 <<
". Error: " << e.
what();
401 Throw<std::runtime_error>(s.
str());
434 keyBytes, keyValues,
burstSize, scheduler, journal);
443 nudb::context& context,
447 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.
NuDBBackend(size_t keyBytes, Section const &keyValues, std::size_t burstSize, Scheduler &scheduler, beast::Journal journal)
std::size_t const blockSize_
void verify() override
Perform consistency checks on database.
void storeBatch(Batch const &batch) override
Store a group of objects.
int getWriteLoad() override
Estimate the number of write operations pending.
std::pair< std::vector< std::shared_ptr< NodeObject > >, Status > fetchBatch(std::vector< uint256 const * > const &hashes) override
Fetch a batch synchronously.
std::optional< std::size_t > getBlockSize() const override
Get the block size for backends that support it.
static std::size_t parseBlockSize(std::string const &name, Section const &keyValues, beast::Journal journal)
int fdRequired() const override
Returns the number of file descriptors the backend expects to need.
void store(std::shared_ptr< NodeObject > const &no) override
Store a single object.
static constexpr std::uint64_t appnum
NuDBBackend(size_t keyBytes, Section const &keyValues, std::size_t burstSize, Scheduler &scheduler, nudb::context &context, beast::Journal journal)
std::string getName() override
Get the human-readable name of this backend.
Status fetch(void const *key, std::shared_ptr< NodeObject > *pno) override
Fetch a single object.
void do_insert(std::shared_ptr< NodeObject > const &no)
void open(bool createIfMissing) override
Open the backend.
void open(bool createIfMissing, uint64_t appType, uint64_t uid, uint64_t salt) override
Open the backend.
std::size_t const burstSize_
void close() override
Close the backend.
void setDeletePath() override
Remove contents on disk upon destruction.
bool isOpen() override
Returns true is the database is open.
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::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::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.
std::string getName() const override
Retrieve the name of this factory.
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_compress(void const *in, std::size_t in_size, BufferFactory &&bf)
Status
Return codes from Backend operations.
std::pair< void const *, std::size_t > nodeobject_decompress(void const *in, std::size_t in_size, BufferFactory &&bf)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::error_code make_error_code(xrpl::TokenCodecErrc e)
T get(Section const §ion, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
@ open
We haven't closed our ledger yet, but others might have.
bool get_if_exists(Section const §ion, std::string const &name, T &v)
Contains information about a batch write operation.
std::chrono::milliseconds elapsed