1#include <test/nodestore/TestBase.h>
2#include <test/unit_test/SuiteJournal.h>
4#include <xrpl/basics/BasicConfig.h>
5#include <xrpl/basics/ByteUtilities.h>
6#include <xrpl/basics/safe_cast.h>
7#include <xrpl/beast/unit_test.h>
8#include <xrpl/beast/unit_test/thread.h>
9#include <xrpl/beast/utility/temp_dir.h>
10#include <xrpl/beast/xor_shift_engine.h>
11#include <xrpl/nodestore/DummyScheduler.h>
12#include <xrpl/nodestore/Manager.h>
14#include <boost/algorithm/string.hpp>
27#ifndef NODESTORE_TIMING_DO_VERIFY
28#define NODESTORE_TIMING_DO_VERIFY 0
41template <
class Generator>
45 using result_type =
typename Generator::result_type;
46 while (bytes >=
sizeof(result_type))
49 memcpy(buffer, &v,
sizeof(v));
50 buffer =
reinterpret_cast<std::uint8_t*
>(buffer) +
sizeof(v);
57 memcpy(buffer, &v, bytes);
114 while ((size--) != 0u)
149 for (
auto iter = config.
begin(); iter != config.
end(); ++iter)
150 s += (iter != config.
begin() ?
"," :
"") + iter->first +
"=" + iter->second;
167 boost::split(v, s, boost::algorithm::is_any_of(
","));
176 template <
class Body>
188 template <
class... Args>
209 template <
class Body,
class... Args>
216 for (
std::size_t id = 0;
id < number_of_threads; ++id)
222 template <
class Body,
class... Args>
229 for (
std::size_t id = 0;
id < number_of_threads; ++id)
242 auto backend =
make_Backend(config, scheduler, journal);
243 BEAST_EXPECT(backend !=
nullptr);
254 explicit Body(suite& s,
Backend& backend) : suite_(s), backend_(backend), seq_(1)
267 suite_.fail(e.
what());
278#if NODESTORE_TIMING_DO_VERIFY
291 auto backend =
make_Backend(config, scheduler, journal);
292 BEAST_EXPECT(backend !=
nullptr);
306 : suite_(s), backend_(backend), seq1_(1), gen_(
id + 1), dist_(0, params.
items - 1)
317 obj = seq1_.
obj(dist_(gen_));
318 backend_.
fetch(obj->getHash(), &result);
319 suite_.expect(result &&
isSame(result, obj));
323 suite_.fail(e.
what());
329 parallel_for_id<Body>(
338#if NODESTORE_TIMING_DO_VERIFY
351 auto backend =
make_Backend(config, scheduler, journal);
352 BEAST_EXPECT(backend !=
nullptr);
372 , dist_(0, params.
items - 1)
381 auto const hash = seq2_.
key(i);
383 backend_.
fetch(hash, &result);
384 suite_.expect(!result);
388 suite_.fail(e.
what());
395 parallel_for_id<Body>(
404#if NODESTORE_TIMING_DO_VERIFY
417 auto backend =
make_Backend(config, scheduler, journal);
418 BEAST_EXPECT(backend !=
nullptr);
442 , dist_(0, params.
items - 1)
451 if (rand_(gen_) < missingNodePercent)
453 auto const hash = seq2_.
key(dist_(gen_));
455 backend_.
fetch(hash, &result);
456 suite_.expect(!result);
462 obj = seq1_.
obj(dist_(gen_));
463 backend_.
fetch(obj->getHash(), &result);
464 suite_.expect(result &&
isSame(result, obj));
469 suite_.fail(e.
what());
476 parallel_for_id<Body>(
485#if NODESTORE_TIMING_DO_VERIFY
502 auto backend =
make_Backend(config, scheduler, journal);
503 BEAST_EXPECT(backend !=
nullptr);
504 backend->setDeletePath();
527 , recent_(params.
items, (params.
items * 2) - 1)
528 , older_(0, params.
items - 1)
537 if (rand_(gen_) < 200)
542 auto const j = older_(gen_);
544 backend_.
fetch(obj->getHash(), &result);
545 suite_.expect(result !=
nullptr);
546 suite_.expect(
isSame(result, obj));
550 p[0] = rand_(gen_) < 50 ? 0 : 1;
552 for (
int q = 0; q < 2; ++q)
561 auto const j = recent_(gen_);
563 backend_.
fetch(obj->getHash(), &result);
564 suite_.expect(!result ||
isSame(result, obj));
570 auto const j = i + params_.
items;
579 suite_.fail(e.
what());
586 parallel_for_id<Body>(
595#if NODESTORE_TIMING_DO_VERIFY
612 (this->*f)(config, params, journal);
613 return std::chrono::duration_cast<duration_type>(
clock_type::now() - start);
624 for (
auto const& test : tests)
628 log << threads <<
" Thread" << (threads > 1 ?
"s" :
"") <<
", " <<
default_items
633 for (
auto const& test : tests)
634 ss <<
" " << setw(w) << test.first;
641 for (
auto const& config_string : config_strings)
645 params.threads = threads;
650 config.
set(
"path", tempDir.
path());
653 for (
auto const& test : tests)
677#if XRPL_ROCKSDB_AVAILABLE
678 ";type=rocksdb,open_files=2000,filter_bits=12,cache_mb=256,"
679 "file_size_mb=8,file_size_mult=2"
682 ";type=memory|path=NodeStore"
695 boost::split(config_strings, args, boost::algorithm::is_any_of(
";"));
696 for (
auto iter = config_strings.
begin(); iter != config_strings.
end();)
700 iter = config_strings.
erase(iter);
715BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Timing, nodestore,
xrpl, 1);
A generic endpoint for log messages.
void seed(result_type seed)
RAII temporary directory.
std::string path() const
Get the native path for the temporary directory.
log_os< char > log
Logging output stream.
testcase_t testcase
Memberspace for declaring test cases.
std::string const & arg() const
Return the argument associated with the runner.
static std::shared_ptr< NodeObject > createObject(NodeObjectType type, Blob &&data, uint256 const &hash)
Create an object from fields.
A backend used for the NodeStore.
virtual void store(std::shared_ptr< NodeObject > const &object)=0
Store a single object.
virtual Status fetch(uint256 const &hash, std::shared_ptr< NodeObject > *pObject)=0
Fetch a single object.
Simple NodeStore Scheduler that just performs the tasks synchronously.
static Manager & instance()
Returns the instance of the manager singleton.
virtual std::unique_ptr< Backend > make_Backend(Section const ¶meters, std::size_t burstSize, Scheduler &scheduler, beast::Journal journal)=0
Create a backend.
Scheduling for asynchronous backend activity.
std::uniform_int_distribution< std::uint32_t > d_size_
beast::xor_shift_engine gen_
Sequence(std::uint8_t prefix)
std::discrete_distribution< std::uint32_t > d_type_
std::shared_ptr< NodeObject > obj(std::size_t n)
void batch(std::size_t n, Batch &b, std::size_t size)
uint256 key(std::size_t n)
parallel_for_lambda(std::size_t n, std::atomic< std::size_t > &c)
void operator()(Args &&... args)
std::atomic< std::size_t > & c_
void(Timing_test::*)(Section const &, Params const &, beast::Journal) test_func
static std::string to_string(duration_type const &d)
void do_work(Section const &config, Params const ¶ms, beast::Journal journal)
duration_type do_test(test_func f, Section const &config, Params const ¶ms, beast::Journal journal)
void do_missing(Section const &config, Params const ¶ms, beast::Journal journal)
std::size_t const default_items
void parallel_for(std::size_t const n, std::size_t number_of_threads, Args const &... args)
void do_insert(Section const &config, Params const ¶ms, beast::Journal journal)
static Section parse(std::string s)
void parallel_for_id(std::size_t const n, std::size_t number_of_threads, Args const &... args)
void do_tests(std::size_t threads, test_list const &tests, std::vector< std::string > const &config_strings)
static std::string to_string(Section const &config)
void run() override
Runs the suite.
void do_fetch(Section const &config, Params const ¶ms, beast::Journal journal)
void do_mixed(Section const &config, Params const ¶ms, beast::Journal journal)
std::size_t const default_repeat
Holds a collection of configuration values.
const_iterator end() const
void set(std::string const &key, std::string const &value)
Set a key/value pair.
const_iterator begin() const
void append(std::vector< std::string > const &lines)
Append a set of lines to this section.
static constexpr std::size_t size()
T emplace_back(T... args)
A namespace for easy access to logging severity values.
bool isSame(std::shared_ptr< NodeObject > const &lhs, std::shared_ptr< NodeObject > const &rhs)
Returns true if objects are identical.
std::unique_ptr< Backend > make_Backend(Section const &config, Scheduler &scheduler, beast::Journal journal)
static void rngcpy(void *buffer, std::size_t bytes, Generator &g)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
T get(Section const §ion, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
XRPL_NO_SANITIZE_ADDRESS void Rethrow()
Rethrow the exception currently being handled.
constexpr auto megabytes(T value) noexcept
T setprecision(T... args)