1#include <xrpl/basics/contract.h> 
    2#include <xrpl/basics/rocksdb.h> 
    3#include <xrpl/beast/clock/basic_seconds_clock.h> 
    4#include <xrpl/beast/core/LexicalCast.h> 
    5#include <xrpl/beast/rfc2616.h> 
    6#include <xrpl/beast/unit_test.h> 
    7#include <xrpl/nodestore/detail/codec.h> 
    9#include <boost/beast/core/string.hpp> 
   10#include <boost/regex.hpp> 
   12#include <nudb/create.hpp> 
   13#include <nudb/detail/format.hpp> 
   14#include <nudb/xxhasher.hpp> 
   73template <
class Rep, 
class Period>
 
   91            os << round<nanoseconds>(d).count();
 
  107            os << round<microseconds>(d).count();
 
  123            os << round<milliseconds>(d).count();
 
  139            os << round<seconds>(d).count();
 
  155            os << round<minutes>(d).count();
 
 
  162template <
class Period, 
class Rep>
 
  203        auto const elapsed = now - 
start_;
 
  214        auto const rate = elapsed.count() / double(work);
 
  217        log << 
"Remaining: " << 
detail::fmtdur(remain) << 
" (" << work << 
" of " 
 
 
  236    static boost::regex 
const re1(
 
  239        "([a-zA-Z][_a-zA-Z0-9]*)"   
  246        boost::regex_constants::optimize);
 
  249    for (
auto const& kv : v)
 
  252        if (!boost::regex_match(kv, m, re1))
 
  253            Throw<std::runtime_error>(
"invalid parameter " + kv);
 
  256            Throw<std::runtime_error>(
"duplicate parameter " + m[1]);
 
 
  263#if XRPL_ROCKSDB_AVAILABLE 
  273        using namespace nudb;
 
  274        using namespace nudb::detail;
 
  277        auto const args = parse_args(arg());
 
  278        bool usage = args.empty();
 
  280        if (!usage && args.find(
"from") == args.end())
 
  282            log << 
"Missing parameter: from";
 
  285        if (!usage && args.find(
"to") == args.end())
 
  287            log << 
"Missing parameter: to";
 
  290        if (!usage && args.find(
"buffer") == args.end())
 
  292            log << 
"Missing parameter: buffer";
 
  299                << 
"--unittest-arg=from=<from>,to=<to>,buffer=<buffer>\n" 
  300                << 
"from:   RocksDB database to import from\n" 
  301                << 
"to:     NuDB database to import to\n" 
  302                << 
"buffer: Buffer size (bigger is faster)\n" 
  303                << 
"NuDB database must not already exist.";
 
  312        auto const from_path = args.at(
"from");
 
  313        auto const to_path = args.at(
"to");
 
  315        using hash_type = nudb::xxhasher;
 
  316        auto const bulk_size = 64 * 1024 * 1024;
 
  317        float const load_factor = 0.5;
 
  319        auto const dp = to_path + 
".dat";
 
  320        auto const kp = to_path + 
".key";
 
  324        log << 
"from:    " << from_path
 
  334            rocksdb::Options options;
 
  335            options.create_if_missing = 
false;
 
  336            options.max_open_files = 2000;  
 
  337            rocksdb::DB* pdb = 
nullptr;
 
  339                rocksdb::DB::OpenForReadOnly(options, from_path, &pdb);
 
  341                Throw<std::runtime_error>(
 
  342                    "Can't open '" + from_path + 
"': " + 
status.ToString());
 
  348        dh.version = currentVersion;
 
  355        df.create(file_mode::append, dp, ec);
 
  357            Throw<nudb::system_error>(ec);
 
  358        bulk_writer<native_file> dw(df, 0, bulk_size);
 
  361                auto os = dw.prepare(dat_file_header::size, ec);
 
  363                    Throw<nudb::system_error>(ec);
 
  366            rocksdb::ReadOptions options;
 
  367            options.verify_checksums = 
false;
 
  368            options.fill_cache = 
false;
 
  372            for (it->SeekToFirst(); it->Valid(); it->Next())
 
  374                if (it->key().size() != 32)
 
  375                    Throw<std::runtime_error>(
 
  376                        "Unexpected key size " +
 
  378                void const* 
const key = it->key().data();
 
  379                void const* 
const data = it->value().data();
 
  380                auto const size = it->value().size();
 
  390                    BEAST_EXPECT(
check.second == size);
 
  395                auto os = dw.prepare(
 
  396                    field<uint48_t>::size +  
 
  401                    Throw<nudb::system_error>(ec);
 
  402                write<uint48_t>(os, 
out.second);
 
  409                Throw<nudb::system_error>(ec);
 
  412        log << 
"Import data: " 
  414        auto const df_size = df.size(ec);
 
  416            Throw<nudb::system_error>(ec);
 
  419        kh.version = currentVersion;
 
  421        kh.appnum = dh.appnum;
 
  423        kh.salt = make_salt();
 
  424        kh.pepper = pepper<hash_type>(kh.salt);
 
  425        kh.block_size = block_size(kp);
 
  428            std::ceil(nitems / (bucket_capacity(kh.block_size) * load_factor));
 
  429        kh.modulus = ceil_pow2(kh.buckets);
 
  431        kf.create(file_mode::append, kp, ec);
 
  433            Throw<nudb::system_error>(ec);
 
  434        buffer buf(kh.block_size);
 
  437            ostream os(buf.get(), kh.block_size);
 
  439            kf.write(0, buf.get(), kh.block_size, ec);
 
  441                Throw<nudb::system_error>(ec);
 
  448        buf.reserve(buckets * kh.block_size);
 
  449        auto const passes = (kh.buckets + buckets - 1) / buckets;
 
  450        log << 
"items:   " << nitems
 
  460        progress p(df_size * passes);
 
  462        for (
std::size_t b0 = 0; b0 < kh.buckets; b0 += buckets)
 
  464            auto const b1 = 
std::min(b0 + buckets, kh.buckets);
 
  466            auto const bn = b1 - b0;
 
  470                bucket b(kh.block_size, buf.get() + i * kh.block_size, empty);
 
  474            bulk_reader<native_file> r(
 
  475                df, dat_file_header::size, df_size, bulk_size);
 
  478                auto const offset = r.offset();
 
  481                auto is = r.prepare(field<uint48_t>::size, ec);  
 
  483                    Throw<nudb::system_error>(ec);
 
  484                read<uint48_t>(is, size);
 
  493                        Throw<nudb::system_error>(ec);
 
  496                    auto const n = bucket_index(h, kh.buckets, kh.modulus);
 
  497                    p(log, npass * df_size + r.offset());
 
  498                    if (n < b0 || n >= b1)
 
  501                        kh.block_size, buf.get() + (n - b0) * kh.block_size);
 
  502                    maybe_spill(b, dw, ec);
 
  504                        Throw<nudb::system_error>(ec);
 
  505                    b.insert(offset, size, h);
 
  511                    is = r.prepare(field<std::uint16_t>::size, ec);
 
  513                        Throw<nudb::system_error>(ec);
 
  514                    read<std::uint16_t>(is, size);  
 
  517                        Throw<nudb::system_error>(ec);
 
  521                (b0 + 1) * kh.block_size, buf.get(), bn * kh.block_size, ec);
 
  523                Throw<nudb::system_error>(ec);
 
  528            Throw<nudb::system_error>(ec);
 
  533BEAST_DEFINE_TESTSUITE_MANUAL(
import, nodestore, 
ripple);
 
A clock whose minimum resolution is one second.
 
typename Clock::duration duration
 
typename Clock::time_point time_point
 
void operator()(Log &log, std::size_t work)
 
clock_type::time_point start_
 
clock_type::time_point report_
 
progress(std::size_t work)
 
clock_type::time_point now_
 
save_stream_state(std::ostream &os)
 
save_stream_state & operator=(save_stream_state const &)=delete
 
std::ios::char_type fill_
 
std::streamsize precision_
 
std::ios::fmtflags flags_
 
save_stream_state(save_stream_state const &)=delete
 
void check(bool condition, std::string const &message)
 
Result split(FwdIt first, FwdIt last, Char delim)
Parse a character sequence of values separated by commas.
 
std::map< std::string, std::string, boost::beast::iless > parse_args(std::string const &s)
 
void filter_inner(void *in, std::size_t in_size)
 
void write(nudb::detail::ostream &os, std::size_t t)
 
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)
 
std::string fmtdur(std::chrono::duration< Period, Rep > const &d)
 
std::ostream & pretty_time(std::ostream &os, std::chrono::duration< Rep, Period > d)
 
auto const data
General field definitions, or fields used in multiple transaction namespaces.
 
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
 
int run(int argc, char **argv)
 
T setprecision(T... args)