diff --git a/src/test/fuzz/dbwrapper.cpp b/src/test/fuzz/dbwrapper.cpp index 1b5cd7b025d..265f0ca3a09 100644 --- a/src/test/fuzz/dbwrapper.cpp +++ b/src/test/fuzz/dbwrapper.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -169,12 +170,13 @@ void VerifyIterator(CDBWrapper& dbw, const Oracle& oracle, /** Maximum number of concurrent reader threads in dbwrapper_concurrent_reads. */ constexpr size_t MAX_READ_WORKERS{8}; -ThreadPool g_read_pool{"dbfuzz"}; -Mutex g_read_pool_mutex; +/** Maximum number of queries each worker executes in dbwrapper_concurrent_reads. */ +constexpr size_t MAX_READ_QUERIES_PER_WORKER{128}; -void StartReadPoolIfNeeded() EXCLUSIVE_LOCKS_REQUIRED(!g_read_pool_mutex) +ThreadPool g_read_pool{"dbfuzz"}; + +void StartReadPoolIfNeeded() { - LOCK(g_read_pool_mutex); if (!g_read_pool.WorkersCount()) g_read_pool.Start(MAX_READ_WORKERS); } @@ -357,7 +359,7 @@ FUZZ_TARGET(dbwrapper_threaded, .init = [] { static auto setup{MakeNoLogFileCont /*allow_force_compact=*/true); } -FUZZ_TARGET(dbwrapper_concurrent_reads, .init = [] { static auto setup{MakeNoLogFileContext<>()}; }) EXCLUSIVE_LOCKS_REQUIRED(!g_read_pool_mutex) +FUZZ_TARGET(dbwrapper_concurrent_reads, .init = [] { static auto setup{MakeNoLogFileContext<>()}; }) { StartReadPoolIfNeeded(); SeedRandomStateForTest(SeedRand::ZEROS); @@ -371,7 +373,7 @@ FUZZ_TARGET(dbwrapper_concurrent_reads, .init = [] { static auto setup{MakeNoLog // Seed the DB. Drain work after small batches so we don't deadlock on a // scheduled compaction. - const size_t num_entries{provider.ConsumeIntegralInRange(100, 3'000)}; + const size_t num_entries{provider.ConsumeIntegralInRange(100, 5'000)}; std::vector keys; keys.reserve(num_entries); Oracle oracle; @@ -416,12 +418,13 @@ FUZZ_TARGET(dbwrapper_concurrent_reads, .init = [] { static auto setup{MakeNoLog std::vector order(queries.size()); std::iota(order.begin(), order.end(), size_t{0}); std::ranges::shuffle(order, thread_rng); + const size_t queries_to_run{std::min(queries.size(), MAX_READ_QUERIES_PER_WORKER)}; std::vector v; std::string key_str; start_latch.arrive_and_wait(); const std::unique_ptr it{db.NewIterator()}; // Every read must agree with the oracle, the source of truth. - for (const auto i : order) { + for (const auto i : std::span{order}.first(queries_to_run)) { const auto& [op, key] = queries[i]; switch (op) { case ReadOp::Read: diff --git a/src/test/fuzz/threadpool.cpp b/src/test/fuzz/threadpool.cpp index a5b01db1383..48ec3ec883a 100644 --- a/src/test/fuzz/threadpool.cpp +++ b/src/test/fuzz/threadpool.cpp @@ -43,13 +43,11 @@ static void GetFuture(std::future& future, uint32_t& fail_counter) // instability in the fuzzing environment. // This is also how we use it in the app's lifecycle. ThreadPool g_pool{"fuzz"}; -Mutex g_pool_mutex; // Global to verify we always have the same number of threads. size_t g_num_workers = 3; -static void StartPoolIfNeeded() EXCLUSIVE_LOCKS_REQUIRED(!g_pool_mutex) +static void StartPoolIfNeeded() { - LOCK(g_pool_mutex); if (g_pool.WorkersCount() == g_num_workers) return; g_pool.Start(g_num_workers); } @@ -60,7 +58,7 @@ static void setup_threadpool_test() LogInstance().DisableLogging(); } -FUZZ_TARGET(threadpool, .init = setup_threadpool_test) EXCLUSIVE_LOCKS_REQUIRED(!g_pool_mutex) +FUZZ_TARGET(threadpool, .init = setup_threadpool_test) { // Because LibAFL calls fork() after calling the init setup function, // the child processes end up having one thread active and no workers.