1#include <xrpl/basics/Log.h>
2#include <xrpl/basics/base_uint.h>
3#include <xrpl/basics/contract.h>
4#include <xrpl/beast/core/LexicalCast.h>
5#include <xrpl/beast/utility/Journal.h>
6#include <xrpl/beast/utility/instrumentation.h>
7#include <xrpl/config/BasicConfig.h>
8#include <xrpl/config/Constants.h>
9#include <xrpl/nodestore/Backend.h>
10#include <xrpl/nodestore/Factory.h>
11#include <xrpl/nodestore/Manager.h>
12#include <xrpl/nodestore/NodeObject.h>
13#include <xrpl/nodestore/Scheduler.h>
14#include <xrpl/nodestore/Types.h>
15#include <xrpl/nodestore/detail/DecodedBlob.h>
16#include <xrpl/nodestore/detail/EncodedBlob.h>
17#include <xrpl/nodestore/detail/codec.h>
19#include <boost/filesystem/operations.hpp>
20#include <boost/filesystem/path.hpp>
21#include <boost/system/detail/errc.hpp>
23#include <nudb/context.hpp>
24#include <nudb/create.hpp>
25#include <nudb/detail/buffer.hpp>
26#include <nudb/error.hpp>
27#include <nudb/file.hpp>
28#include <nudb/progress.hpp>
29#include <nudb/store.hpp>
30#include <nudb/verify.hpp>
31#include <nudb/visit.hpp>
32#include <nudb/xxhasher.hpp>
90 nudb::context& context,
112 catch (nudb::system_error
const&)
132 open(
bool createIfMissing, uint64_t appType, uint64_t uid, uint64_t salt)
override
134 using namespace boost::filesystem;
139 "xrpl::NodeStore::NuDBBackend::open : database is already "
141 JLOG(
j.error()) <<
"database is already open";
146 auto const dp = (folder /
"nudb.dat").
string();
147 auto const kp = (folder /
"nudb.key").
string();
148 auto const lp = (folder /
"nudb.log").
string();
152 create_directories(folder);
153 nudb::create<nudb::xxhasher>(
155 if (ec == nudb::errc::file_exists)
160 db.open(dp, kp, lp, ec);
176 open(
bool createIfMissing)
override
178 open(createIfMissing,
kAppNum, nudb::make_uid(), nudb::make_salt());
191 JLOG(
j.fatal()) <<
"NuBD close() failed: " << ec.message();
197 boost::filesystem::remove_all(
name, ec);
201 <<
"Filesystem remove_all of " <<
name <<
" failed with: " << ec.message();
215 [&hash, pno, &status](
void const* data,
std::size_t size) {
216 nudb::detail::buffer bf;
217 auto const result = nodeobjectDecompress(data, size, bf);
218 DecodedBlob decoded(hash.data(), result.first, result.second);
219 if (!decoded.wasOk())
221 status = Status::DataCorrupt;
224 *pno = decoded.createObject();
228 if (ec == nudb::error::key_not_found)
240 nudb::detail::buffer bf;
242 db.insert(e.
getKey(), result.first, result.second, ec);
243 if (ec && ec != nudb::error::key_exists)
265 for (
auto const& e : batch)
280 auto const dp =
db.dat_path();
281 auto const kp =
db.key_path();
282 auto const lp =
db.log_path();
295 nudb::detail::buffer bf;
297 DecodedBlob decoded(key, result.first, result.second);
298 if (!decoded.
wasOk())
309 db.open(dp, kp, lp, ec);
329 auto const dp =
db.dat_path();
330 auto const kp =
db.key_path();
331 auto const lp =
db.log_path();
336 nudb::verify_info vi;
337 nudb::verify<nudb::xxhasher>(vi, dp, kp, 0, nudb::no_progress{}, ec);
340 db.open(dp, kp, lp, ec);
355 using namespace boost::filesystem;
357 auto const kp = (folder /
"nudb.key").
string();
359 std::size_t const defaultSize = nudb::block_size(kp);
373 if (parsedBlockSize < 4096 || parsedBlockSize > 32768 ||
374 (parsedBlockSize & (parsedBlockSize - 1)) != 0)
377 s <<
"Invalid nudb_block_size: " << parsedBlockSize
378 <<
". Must be power of 2 between 4096 and 32768.";
382 JLOG(journal.
info()) <<
"Using custom NuDB block size: " << parsedBlockSize <<
" bytes";
383 return parsedBlockSize;
388 s <<
"Invalid nudb_block_size value: " << blockSizeStr <<
". Error: " << e.
what();
430 nudb::context& context,
434 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.
NuDBBackend(size_t keyBytes, Section const &keyValues, std::size_t burstSize, Scheduler &scheduler, beast::Journal journal)
void verify() override
Perform consistency checks on database.
Status fetch(uint256 const &hash, std::shared_ptr< NodeObject > *pno) override
Fetch a single object.
void storeBatch(Batch const &batch) override
Store a group of objects.
int getWriteLoad() override
Estimate the number of write operations pending.
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)
std::size_t const blockSize
std::size_t const burstSize
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.
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.
void doInsert(std::shared_ptr< NodeObject > const &no)
void open(bool createIfMissing) override
Open the backend.
std::atomic< bool > deletePath
void open(bool createIfMissing, uint64_t appType, uint64_t uid, uint64_t salt) override
Open the backend.
static constexpr std::uint64_t kAppNum
void close() override
Close the backend.
void setDeletePath() override
Remove contents on disk upon destruction.
void forEach(std::function< void(std::shared_ptr< NodeObject >)> f) override
Visit every object in the database This is usually called during import.
bool isOpen() override
Returns true is the database is open.
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.
Holds a collection of configuration values.
T duration_cast(T... args)
Out lexicalCastThrow(In in)
Convert from one type to another, throw on error.
void registerNuDBFactory(Manager &manager)
std::pair< void const *, std::size_t > nodeobjectCompress(void const *in, std::size_t inSize, BufferFactory &&bf)
Status
Return codes from Backend operations.
std::pair< void const *, std::size_t > nodeobjectDecompress(void const *in, std::size_t inSize, BufferFactory &&bf)
std::vector< std::shared_ptr< NodeObject > > Batch
A batch of NodeObjects to write at once.
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.
bool getIfExists(Section const §ion, std::string const &name, T &v)
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
static constexpr auto kNudbBlockSize
Contains information about a batch write operation.
std::chrono::milliseconds elapsed