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 "ripple::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.
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