18#include <leveldb/env.h>
19#include <leveldb/helpers/memenv/memenv.h>
60class DeterministicEnv final :
public leveldb::EnvWrapper
62 using WorkFunction =
void (*)(
void*);
65 WorkFunction function;
73 explicit DeterministicEnv(leveldb::Env* base) :
EnvWrapper(base) {}
78 m_queue.push_back({function, arg});
88 if (m_queue.empty())
return false;
89 work = m_queue.front();
106const std::string OBFUSCATION_KEY{
"\000obfuscate_key", 14};
113 std::vector<uint8_t> v(size);
114 std::iota(v.begin(), v.end(),
static_cast<uint8_t>(key ^ (key >> 8)));
120struct LevelDBBytewiseU16Cmp {
125using Oracle = std::map<uint16_t, uint32_t, LevelDBBytewiseU16Cmp>;
127struct FailUnserialize {
128 template <
typename Stream>
129 void Unserialize(Stream&) {
throw std::ios_base::failure{
"always fail"}; }
143 bool obfuscate, std::optional<uint16_t>
seek_key = std::nullopt)
145 const std::unique_ptr<CDBIterator> it{
dbw.NewIterator()};
152 for (; it->Valid(); it->Next()) {
188 .
path =
"dbwrapper_fuzz",
190 .obfuscate = obfuscate,
193 .testing_env = testing_env,
200template <
typename DrainWorkFn,
typename RunOneFn>
202 leveldb::Env* testing_env,
240 const auto fill{[&] {
282 std::vector<uint8_t> value;
283 const bool found{
dbw->Read(key, value)};
284 if (
const auto it{
oracle.find(key)}; it !=
oracle.end()) {
322 (
void)
dbw->DynamicMemoryUsage();
340 const auto memenv{std::unique_ptr<leveldb::Env>{leveldb::NewMemEnv(leveldb::Env::Default())}};
345 [&] {
return det_env.RunOne(); },
353 const auto memenv{std::unique_ptr<leveldb::Env>{leveldb::NewMemEnv(leveldb::Env::Default())}};
357 [] { return false; },
368 const auto memenv{std::unique_ptr<leveldb::Env>{leveldb::NewMemEnv(leveldb::Env::Default())}};
383 for (
size_t i{start}; i < end; ++i) {
399 std::vector<std::tuple<ReadOp, uint16_t>>
queries;
414 std::ranges::generate(
tasks, [&] {
417 std::vector<size_t> order(
queries.size());
418 std::iota(order.begin(), order.end(),
size_t{0});
421 std::vector<uint8_t> v;
427 const auto& [op, key] =
queries[i];
443 if (it->Valid() && it->GetKey(
key_str) &&
key_str == OBFUSCATION_KEY) it->Next();
constexpr uint16_t internal_bswap_16(uint16_t x)
#define Assert(val)
Identity function.
Batch of changes queued to be written to a CDBWrapper.
void Write(const K &key, const V &value)
bool Read(const K &key, V &value) const
Wrapper around TryRead() that preserves the original Read() semantics: returns true on success,...
CDBIterator * NewIterator()
bool Exists(const K &key) const
void WriteBatch(CDBBatch &batch, bool fSync=false)
void Write(const K &key, const V &value, bool fSync=false)
T ConsumeIntegralInRange(T min, T max)
T PickValueInArray(const T(&array)[size])
uint256 rand256() noexcept
generate a random uint256.
Fixed-size thread pool for running arbitrary tasks concurrently.
void Start(int num_workers) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Start worker threads.
constexpr size_t DBWRAPPER_MAX_FILE_SIZE
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
void Unserialize(Stream &, V)=delete
User-controlled performance and debug options.
bool force_compact
Compact database on startup.
Application-specific storage settings.
fs::path path
Location in the filesystem where leveldb data will be stored.
std::vector< uint16_t > keys
TestDbWrapper(provider, &det_env, [&] { det_env.DrainWork();}, [&] { return det_env.RunOne();}, false)
constexpr size_t SEED_BATCH_SIZE
std::vector< std::function< void()> > tasks(MAX_READ_WORKERS)
std::vector< std::tuple< ReadOp, uint16_t > > queries
SeedRandomStateForTest(SeedRand::ZEROS)
FuzzedDataProvider provider
uint256 ConsumeUInt256(FuzzedDataProvider &fuzzed_data_provider) noexcept
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
@ ZEROS
Seed with a compile time constant of zeros.
#define EXCLUSIVE_LOCKS_REQUIRED(...)
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.