mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-21 14:20:56 +00:00
chore: Gtest migration followups first pass (#7884)
This commit is contained in:
@@ -20,21 +20,22 @@
|
||||
namespace xrpl::node_store {
|
||||
namespace {
|
||||
|
||||
constexpr std::size_t kPoolSizes[] = {1000, 10000, 100000};
|
||||
constexpr int kThreadCounts[] = {1, 4, 8};
|
||||
constexpr auto kPoolSizes = std::to_array<std::size_t>({1000, 10000, 100000});
|
||||
constexpr auto kThreadCounts = std::to_array<std::size_t>({1, 4, 8});
|
||||
constexpr std::size_t kBatchSize = 256;
|
||||
constexpr std::size_t kMissRatio = 5;
|
||||
|
||||
constexpr std::string_view kNamePrefix = "BM_Backend_";
|
||||
constexpr std::string_view kNameSeparator = "/";
|
||||
|
||||
struct RunState
|
||||
{
|
||||
std::unique_ptr<BackendHarness> harness;
|
||||
Batch present; // prefix-1 objects, eligible to be stored
|
||||
Batch recent; // prefix-1 objects in the "future" key space
|
||||
std::vector<uint256> missing; // prefix-2 keys that are never stored
|
||||
std::vector<std::size_t> shuffle; // [0, poolSize) permutation for random-like access
|
||||
std::size_t avgPayload = 0; // mean getData().size() over `present`
|
||||
std::unique_ptr<BackendHarness> harness; ///< backend under test, rebuilt per run
|
||||
Batch present; ///< prefix-1 objects, eligible to be stored
|
||||
Batch recent; ///< prefix-1 objects in the "future" key space
|
||||
std::vector<uint256> missing; ///< prefix-2 keys that are never stored
|
||||
std::vector<std::size_t> shuffle; ///< [0, poolSize) permutation for random-like access
|
||||
std::size_t avgPayload = 0; ///< mean getData().size() over `present`
|
||||
|
||||
void
|
||||
release()
|
||||
@@ -85,7 +86,7 @@ Workload const kInsert{
|
||||
},
|
||||
.iterate =
|
||||
[](IterateContext const& ctx) {
|
||||
auto& [rs, backend, index, poolSize] = ctx;
|
||||
auto const& [rs, backend, index, poolSize] = ctx;
|
||||
backend.store(rs.present[index % poolSize]);
|
||||
},
|
||||
.reportBytes = true,
|
||||
@@ -104,7 +105,7 @@ Workload const kFetch{
|
||||
},
|
||||
.iterate =
|
||||
[](IterateContext const& ctx) {
|
||||
auto& [rs, backend, index, poolSize] = ctx;
|
||||
auto const& [rs, backend, index, poolSize] = ctx;
|
||||
std::shared_ptr<NodeObject> result;
|
||||
backend.fetch(rs.present[index % poolSize]->getHash(), &result);
|
||||
benchmark::DoNotOptimize(result);
|
||||
@@ -118,7 +119,7 @@ Workload const kMissing{
|
||||
.setup = [](SetupContext const& ctx) { ctx.rs.missing = makeMissingKeys(ctx.poolSize); },
|
||||
.iterate =
|
||||
[](IterateContext const& ctx) {
|
||||
auto& [rs, backend, index, poolSize] = ctx;
|
||||
auto const& [rs, backend, index, poolSize] = ctx;
|
||||
std::shared_ptr<NodeObject> result;
|
||||
backend.fetch(rs.missing[index % poolSize], &result);
|
||||
benchmark::DoNotOptimize(result);
|
||||
@@ -139,10 +140,10 @@ Workload const kMixed{
|
||||
},
|
||||
.iterate =
|
||||
[](IterateContext const& ctx) {
|
||||
auto& [rs, backend, index, poolSize] = ctx;
|
||||
auto const& [rs, backend, index, poolSize] = ctx;
|
||||
std::shared_ptr<NodeObject> result;
|
||||
auto const pick = rs.shuffle[index % poolSize];
|
||||
if (index % 5 == 0)
|
||||
if (index % kMissRatio == 0)
|
||||
{
|
||||
backend.fetch(rs.missing[pick], &result);
|
||||
}
|
||||
@@ -170,7 +171,7 @@ Workload const kWork{
|
||||
},
|
||||
.iterate =
|
||||
[](IterateContext const& ctx) {
|
||||
auto& [rs, backend, index, poolSize] = ctx;
|
||||
auto const& [rs, backend, index, poolSize] = ctx;
|
||||
auto const slot = index % poolSize;
|
||||
auto const pick = rs.shuffle[slot];
|
||||
|
||||
@@ -239,7 +240,7 @@ registerWorkload(BackendConfig const& bc, Workload const& w)
|
||||
{
|
||||
auto rs = std::make_shared<RunState>();
|
||||
auto* b = benchmark::RegisterBenchmark(name, makeRunner(w, cfg, rs));
|
||||
b->RangeMultiplier(10)->Range(kPoolSizes[0], kPoolSizes[std::size(kPoolSizes) - 1]);
|
||||
b->RangeMultiplier(10)->Range(kPoolSizes.front(), kPoolSizes.back());
|
||||
b->Threads(1)->Threads(4)->Threads(8)->UseRealTime();
|
||||
|
||||
return;
|
||||
@@ -249,14 +250,14 @@ registerWorkload(BackendConfig const& bc, Workload const& w)
|
||||
{
|
||||
for (auto const threads : kThreadCounts)
|
||||
{
|
||||
if (poolSize % static_cast<std::size_t>(threads) != 0)
|
||||
if (poolSize % threads != 0)
|
||||
continue;
|
||||
|
||||
auto rs = std::make_shared<RunState>();
|
||||
benchmark::RegisterBenchmark(name, makeRunner(w, cfg, rs))
|
||||
->Arg(poolSize)
|
||||
->Iterations(poolSize / static_cast<std::size_t>(threads))
|
||||
->Threads(threads)
|
||||
->Iterations(poolSize / threads)
|
||||
->Threads(static_cast<int>(threads))
|
||||
->UseRealTime();
|
||||
}
|
||||
}
|
||||
@@ -289,7 +290,7 @@ registerStoreBatch(BackendConfig const& bc)
|
||||
rs->harness = std::make_unique<BackendHarness>(cfg);
|
||||
rs->present = makePool(1, poolSize);
|
||||
rs->avgPayload = averagePayload(rs->present);
|
||||
std::vector<Batch> const batches = sliceBatches(rs->present, kBatchSize);
|
||||
std::vector<Batch> const batches = sliceFixedBatches(rs->present, kBatchSize);
|
||||
if (batches.empty())
|
||||
{
|
||||
state.SkipWithError("pool smaller than one batch");
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
#include <ranges>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -40,18 +41,13 @@ inline void
|
||||
rngcpy(void* buffer, std::size_t bytes, Generator& g)
|
||||
{
|
||||
using result_type = typename Generator::result_type;
|
||||
while (bytes >= sizeof(result_type))
|
||||
while (bytes > 0)
|
||||
{
|
||||
auto const v = g();
|
||||
std::memcpy(buffer, &v, sizeof(v));
|
||||
buffer = reinterpret_cast<std::uint8_t*>(buffer) + sizeof(v);
|
||||
bytes -= sizeof(v);
|
||||
}
|
||||
|
||||
if (bytes > 0)
|
||||
{
|
||||
auto const v = g();
|
||||
std::memcpy(buffer, &v, bytes);
|
||||
auto const chunk = std::min(bytes, sizeof(result_type));
|
||||
std::memcpy(buffer, &v, chunk);
|
||||
buffer = reinterpret_cast<std::uint8_t*>(buffer) + chunk;
|
||||
bytes -= chunk;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +141,7 @@ makePool(std::uint8_t prefix, std::size_t count, std::size_t start = 0)
|
||||
Sequence seq(prefix);
|
||||
Batch pool;
|
||||
pool.reserve(count);
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
for (auto i = 0uz; i < count; ++i)
|
||||
pool.push_back(seq.obj(start + i));
|
||||
return pool;
|
||||
}
|
||||
@@ -158,7 +154,7 @@ makeMissingKeys(std::size_t count)
|
||||
Sequence seq(2);
|
||||
std::vector<uint256> keys;
|
||||
keys.reserve(count);
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
for (auto i = 0uz; i < count; ++i)
|
||||
keys.push_back(seq.key(i));
|
||||
return keys;
|
||||
}
|
||||
@@ -206,16 +202,16 @@ inline std::vector<std::size_t>
|
||||
makeShuffle(std::size_t size, std::uint64_t seed)
|
||||
{
|
||||
std::vector<std::size_t> v(size);
|
||||
std::iota(v.begin(), v.end(), std::size_t{0});
|
||||
std::ranges::iota(v, 0uz);
|
||||
beast::xor_shift_engine gen(seed);
|
||||
std::shuffle(v.begin(), v.end(), gen);
|
||||
std::ranges::shuffle(v, gen);
|
||||
return v;
|
||||
}
|
||||
|
||||
// Partition a pool into fixed-size batches. Any trailing remainder shorter than
|
||||
// `batchSize` is dropped, so every returned batch has exactly `batchSize`.
|
||||
inline std::vector<Batch>
|
||||
sliceBatches(Batch const& pool, std::size_t batchSize)
|
||||
sliceFixedBatches(Batch const& pool, std::size_t batchSize)
|
||||
{
|
||||
std::vector<Batch> batches;
|
||||
if (batchSize == 0)
|
||||
@@ -228,13 +224,10 @@ sliceBatches(Batch const& pool, std::size_t batchSize)
|
||||
|
||||
/**
|
||||
* @brief RAII owner of a NodeStore Backend opened on a private temporary directory.
|
||||
*
|
||||
* Member declaration order matters: `tempDir` is declared first so it is
|
||||
* destroyed last, after the backend has closed and released its files.
|
||||
*/
|
||||
struct BackendHarness
|
||||
{
|
||||
beast::TempDir tempDir;
|
||||
beast::TempDir tempDir; ///< Declared first so it is destroyed last
|
||||
DummyScheduler scheduler;
|
||||
beast::Journal journal{beast::Journal::getNullSink()};
|
||||
std::unique_ptr<Backend> backend;
|
||||
|
||||
@@ -50,11 +50,11 @@ struct Barrier
|
||||
{
|
||||
std::mutex mtx;
|
||||
std::condition_variable cv;
|
||||
int count;
|
||||
int const initial;
|
||||
std::size_t count;
|
||||
std::size_t const initial;
|
||||
std::size_t generation{0};
|
||||
|
||||
explicit Barrier(int n) : count(n), initial(n)
|
||||
explicit Barrier(std::size_t n) : count(n), initial(n)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ TEST(IntrusiveSharedTest, basics)
|
||||
auto id = b->id;
|
||||
EXPECT_EQ(TIBase::getState(id), Alive);
|
||||
EXPECT_EQ(b->useCount(), 1);
|
||||
for (int i = 0; i < 10; ++i)
|
||||
for (auto i = 0uz; i < 10; ++i)
|
||||
{
|
||||
strong.push_back(b);
|
||||
}
|
||||
@@ -232,7 +232,7 @@ TEST(IntrusiveSharedTest, basics)
|
||||
id = b->id;
|
||||
EXPECT_EQ(TIBase::getState(id), Alive);
|
||||
EXPECT_EQ(b->useCount(), 1);
|
||||
for (int i = 0; i < 10; ++i)
|
||||
for (auto i = 0uz; i < 10; ++i)
|
||||
{
|
||||
weak.emplace_back(b);
|
||||
EXPECT_EQ(b->useCount(), 1);
|
||||
@@ -280,17 +280,17 @@ TEST(IntrusiveSharedTest, basics)
|
||||
TIBase::ResetStatesGuard const rsg{true};
|
||||
|
||||
using enum TrackedState;
|
||||
using swu = SharedWeakUnion<TIBase>;
|
||||
swu b = makeSharedIntrusive<TIBase>();
|
||||
using SharedWeak = SharedWeakUnion<TIBase>;
|
||||
SharedWeak b = makeSharedIntrusive<TIBase>();
|
||||
EXPECT_TRUE(b.isStrong() && b.useCount() == 1);
|
||||
auto id = b.get()->id;
|
||||
EXPECT_EQ(TIBase::getState(id), Alive);
|
||||
swu w = b;
|
||||
SharedWeak w = b;
|
||||
EXPECT_TRUE(TIBase::getState(id) == Alive);
|
||||
EXPECT_TRUE(w.isStrong() && b.useCount() == 2);
|
||||
w.convertToWeak();
|
||||
EXPECT_TRUE(w.isWeak() && b.useCount() == 1);
|
||||
swu s = w;
|
||||
SharedWeak s = w;
|
||||
EXPECT_TRUE(s.isWeak() && b.useCount() == 1);
|
||||
s.convertToStrong();
|
||||
EXPECT_TRUE(s.isStrong() && b.useCount() == 2);
|
||||
@@ -380,43 +380,57 @@ TEST(IntrusiveSharedTest, partial_delete)
|
||||
std::atomic<bool> destructorRan{false};
|
||||
std::atomic<bool> partialDeleteRan{false};
|
||||
std::latch partialDeleteStartedSyncPoint{2};
|
||||
|
||||
strong->tracingCallback = [&](TrackedState cur, std::optional<TrackedState> next) {
|
||||
using enum TrackedState;
|
||||
if (next == DeletedStarted)
|
||||
if (!next)
|
||||
return;
|
||||
|
||||
switch (*next)
|
||||
{
|
||||
// strong goes out of scope while weak is still in scope
|
||||
// This checks that partialDelete has run to completion
|
||||
// before the destructor is called. A sleep is inserted
|
||||
// inside the partial delete to make sure the destructor is
|
||||
// given an opportunity to run during partial delete.
|
||||
EXPECT_EQ(cur, PartiallyDeleted);
|
||||
}
|
||||
if (next == PartiallyDeletedStarted)
|
||||
{
|
||||
partialDeleteStartedSyncPoint.arrive_and_wait();
|
||||
using namespace std::chrono_literals;
|
||||
// Sleep and let the weak pointer go out of scope,
|
||||
// potentially triggering a destructor while partial delete
|
||||
// is running. The test is to make sure that doesn't happen.
|
||||
std::this_thread::sleep_for(800ms);
|
||||
}
|
||||
if (next == PartiallyDeleted)
|
||||
{
|
||||
EXPECT_FALSE(partialDeleteRan.exchange(true) || destructorRan.load());
|
||||
}
|
||||
if (next == Deleted)
|
||||
{
|
||||
EXPECT_FALSE(destructorRan.exchange(true));
|
||||
case DeletedStarted:
|
||||
// strong goes out of scope while weak is still in scope
|
||||
// This checks that partialDelete has run to completion
|
||||
// before the destructor is called. A sleep is inserted
|
||||
// inside the partial delete to make sure the destructor is
|
||||
// given an opportunity to run during partial delete.
|
||||
EXPECT_EQ(cur, PartiallyDeleted);
|
||||
break;
|
||||
|
||||
case PartiallyDeletedStarted: {
|
||||
partialDeleteStartedSyncPoint.arrive_and_wait();
|
||||
using namespace std::chrono_literals;
|
||||
// Sleep and let the weak pointer go out of scope,
|
||||
// potentially triggering a destructor while partial delete
|
||||
// is running. The test is to make sure that doesn't happen.
|
||||
std::this_thread::sleep_for(800ms);
|
||||
break;
|
||||
}
|
||||
|
||||
case PartiallyDeleted:
|
||||
EXPECT_FALSE(partialDeleteRan.exchange(true) || destructorRan.load());
|
||||
break;
|
||||
|
||||
case Deleted:
|
||||
EXPECT_FALSE(destructorRan.exchange(true));
|
||||
break;
|
||||
|
||||
case Uninitialized:
|
||||
case Alive:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
std::thread t1{[&] {
|
||||
partialDeleteStartedSyncPoint.arrive_and_wait();
|
||||
weak.reset(); // Trigger a full delete as soon as the partial
|
||||
// delete starts
|
||||
}};
|
||||
|
||||
std::thread t2{[&] {
|
||||
strong.reset(); // Trigger a partial delete
|
||||
}};
|
||||
|
||||
t1.join();
|
||||
t2.join();
|
||||
|
||||
@@ -444,13 +458,24 @@ TEST(IntrusiveSharedTest, destructor)
|
||||
std::latch weakResetSyncPoint{2};
|
||||
strong->tracingCallback = [&](TrackedState cur, std::optional<TrackedState> next) {
|
||||
using enum TrackedState;
|
||||
if (next == PartiallyDeleted)
|
||||
if (!next)
|
||||
return;
|
||||
|
||||
switch (*next)
|
||||
{
|
||||
EXPECT_FALSE(partialDeleteRan.exchange(true) || destructorRan.load());
|
||||
}
|
||||
if (next == Deleted)
|
||||
{
|
||||
EXPECT_FALSE(destructorRan.exchange(true));
|
||||
case PartiallyDeleted:
|
||||
EXPECT_FALSE(partialDeleteRan.exchange(true) || destructorRan.load());
|
||||
break;
|
||||
|
||||
case Deleted:
|
||||
EXPECT_FALSE(destructorRan.exchange(true));
|
||||
break;
|
||||
|
||||
case Uninitialized:
|
||||
case Alive:
|
||||
case PartiallyDeletedStarted:
|
||||
case DeletedStarted:
|
||||
break;
|
||||
}
|
||||
};
|
||||
std::thread t1{[&] {
|
||||
@@ -492,25 +517,36 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_variant)
|
||||
auto tracingCallback = [&](TrackedState cur, std::optional<TrackedState> next) {
|
||||
using enum TrackedState;
|
||||
auto [destructorRan, partialDeleteRan] = getDestructorState();
|
||||
if (next == PartiallyDeleted)
|
||||
if (!next)
|
||||
return;
|
||||
|
||||
switch (*next)
|
||||
{
|
||||
EXPECT_FALSE(partialDeleteRan || destructorRan);
|
||||
setPartialDeleteRan();
|
||||
}
|
||||
if (next == Deleted)
|
||||
{
|
||||
EXPECT_FALSE(destructorRan);
|
||||
setDestructorRan();
|
||||
case PartiallyDeleted:
|
||||
EXPECT_FALSE(partialDeleteRan || destructorRan);
|
||||
setPartialDeleteRan();
|
||||
break;
|
||||
|
||||
case Deleted:
|
||||
EXPECT_FALSE(destructorRan);
|
||||
setDestructorRan();
|
||||
break;
|
||||
|
||||
case Uninitialized:
|
||||
case Alive:
|
||||
case PartiallyDeletedStarted:
|
||||
case DeletedStarted:
|
||||
break;
|
||||
}
|
||||
};
|
||||
auto createVecOfPointers = [&](auto const& toClone, std::default_random_engine& eng)
|
||||
-> std::vector<std::variant<SharedIntrusive<TIBase>, WeakIntrusive<TIBase>>> {
|
||||
std::vector<std::variant<SharedIntrusive<TIBase>, WeakIntrusive<TIBase>>> result;
|
||||
std::uniform_int_distribution<> toCreateDist(4, 64);
|
||||
std::uniform_int_distribution<std::size_t> toCreateDist(4, 64);
|
||||
std::uniform_int_distribution<> isStrongDist(0, 1);
|
||||
auto numToCreate = toCreateDist(eng);
|
||||
result.reserve(numToCreate);
|
||||
for (int i = 0; i < numToCreate; ++i)
|
||||
for (auto i = 0uz; i < numToCreate; ++i)
|
||||
{
|
||||
if (isStrongDist(eng))
|
||||
{
|
||||
@@ -523,8 +559,8 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_variant)
|
||||
}
|
||||
return result;
|
||||
};
|
||||
constexpr int kLoopIters = 2 * 1024;
|
||||
constexpr int kNumThreads = 16;
|
||||
constexpr auto kLoopIters = 2uz * 1024;
|
||||
constexpr auto kNumThreads = 16uz;
|
||||
std::vector<SharedIntrusive<TIBase>> toClone;
|
||||
Barrier loopStartSyncPoint{kNumThreads};
|
||||
Barrier postCreateToCloneSyncPoint{kNumThreads};
|
||||
@@ -533,7 +569,7 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_variant)
|
||||
std::random_device rd;
|
||||
std::vector<std::default_random_engine> result;
|
||||
result.reserve(kNumThreads);
|
||||
for (int i = 0; i < kNumThreads; ++i)
|
||||
for (auto i = 0uz; i < kNumThreads; ++i)
|
||||
result.emplace_back(rd());
|
||||
return result;
|
||||
}();
|
||||
@@ -541,8 +577,8 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_variant)
|
||||
// cloneAndDestroy clones the strong pointer into a vector of mixed
|
||||
// strong and weak pointers and destroys them all at once.
|
||||
// threadId==0 is special.
|
||||
auto cloneAndDestroy = [&](int threadId) {
|
||||
for (int i = 0; i < kLoopIters; ++i)
|
||||
auto cloneAndDestroy = [&](std::size_t threadId) {
|
||||
for (auto i = 0uz; i < kLoopIters; ++i)
|
||||
{
|
||||
// ------ Sync Point ------
|
||||
loopStartSyncPoint.arriveAndWait();
|
||||
@@ -582,11 +618,11 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_variant)
|
||||
};
|
||||
std::vector<std::thread> threads;
|
||||
threads.reserve(kNumThreads);
|
||||
for (int i = 0; i < kNumThreads; ++i)
|
||||
for (auto i = 0uz; i < kNumThreads; ++i)
|
||||
{
|
||||
threads.emplace_back(cloneAndDestroy, i);
|
||||
}
|
||||
for (int i = 0; i < kNumThreads; ++i)
|
||||
for (auto i = 0uz; i < kNumThreads; ++i)
|
||||
{
|
||||
threads[i].join();
|
||||
}
|
||||
@@ -623,31 +659,42 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_union)
|
||||
auto tracingCallback = [&](TrackedState cur, std::optional<TrackedState> next) {
|
||||
using enum TrackedState;
|
||||
auto [destructorRan, partialDeleteRan] = getDestructorState();
|
||||
if (next == PartiallyDeleted)
|
||||
if (!next)
|
||||
return;
|
||||
|
||||
switch (*next)
|
||||
{
|
||||
EXPECT_FALSE(partialDeleteRan || destructorRan);
|
||||
setPartialDeleteRan();
|
||||
}
|
||||
if (next == Deleted)
|
||||
{
|
||||
EXPECT_FALSE(destructorRan);
|
||||
setDestructorRan();
|
||||
case PartiallyDeleted:
|
||||
EXPECT_FALSE(partialDeleteRan || destructorRan);
|
||||
setPartialDeleteRan();
|
||||
break;
|
||||
|
||||
case Deleted:
|
||||
EXPECT_FALSE(destructorRan);
|
||||
setDestructorRan();
|
||||
break;
|
||||
|
||||
case Uninitialized:
|
||||
case Alive:
|
||||
case PartiallyDeletedStarted:
|
||||
case DeletedStarted:
|
||||
break;
|
||||
}
|
||||
};
|
||||
auto createVecOfPointers =
|
||||
[&](auto const& toClone,
|
||||
std::default_random_engine& eng) -> std::vector<SharedWeakUnion<TIBase>> {
|
||||
std::vector<SharedWeakUnion<TIBase>> result;
|
||||
std::uniform_int_distribution<> toCreateDist(4, 64);
|
||||
std::uniform_int_distribution<std::size_t> toCreateDist(4, 64);
|
||||
auto numToCreate = toCreateDist(eng);
|
||||
result.reserve(numToCreate);
|
||||
for (int i = 0; i < numToCreate; ++i)
|
||||
for (auto i = 0uz; i < numToCreate; ++i)
|
||||
result.emplace_back(SharedIntrusive<TIBase>(toClone));
|
||||
return result;
|
||||
};
|
||||
constexpr int kLoopIters = 2 * 1024;
|
||||
constexpr int kFlipPointersLoopIters = 256;
|
||||
constexpr int kNumThreads = 16;
|
||||
constexpr auto kLoopIters = 2uz * 1024;
|
||||
constexpr auto kFlipPointersLoopIters = 256uz;
|
||||
constexpr auto kNumThreads = 16uz;
|
||||
std::vector<SharedIntrusive<TIBase>> toClone;
|
||||
Barrier loopStartSyncPoint{kNumThreads};
|
||||
Barrier postCreateToCloneSyncPoint{kNumThreads};
|
||||
@@ -657,7 +704,7 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_union)
|
||||
std::random_device rd;
|
||||
std::vector<std::default_random_engine> result;
|
||||
result.reserve(kNumThreads);
|
||||
for (int i = 0; i < kNumThreads; ++i)
|
||||
for (auto i = 0uz; i < kNumThreads; ++i)
|
||||
result.emplace_back(rd());
|
||||
return result;
|
||||
}();
|
||||
@@ -666,8 +713,8 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_union)
|
||||
// mixed strong and weak pointers, runs a loop that randomly
|
||||
// changes strong pointers to weak pointers, and destroys them
|
||||
// all at once.
|
||||
auto cloneAndDestroy = [&](int threadId) {
|
||||
for (int i = 0; i < kLoopIters; ++i)
|
||||
auto cloneAndDestroy = [&](std::size_t threadId) {
|
||||
for (auto i = 0uz; i < kLoopIters; ++i)
|
||||
{
|
||||
// ------ Sync Point ------
|
||||
loopStartSyncPoint.arriveAndWait();
|
||||
@@ -702,7 +749,7 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_union)
|
||||
postCreateVecOfPointersSyncPoint.arriveAndWait();
|
||||
|
||||
std::uniform_int_distribution<> isStrongDist(0, 1);
|
||||
for (int f = 0; f < kFlipPointersLoopIters; ++f)
|
||||
for (auto f = 0uz; f < kFlipPointersLoopIters; ++f)
|
||||
{
|
||||
for (auto& p : v)
|
||||
{
|
||||
@@ -725,11 +772,11 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_union)
|
||||
};
|
||||
std::vector<std::thread> threads;
|
||||
threads.reserve(kNumThreads);
|
||||
for (int i = 0; i < kNumThreads; ++i)
|
||||
for (auto i = 0uz; i < kNumThreads; ++i)
|
||||
{
|
||||
threads.emplace_back(cloneAndDestroy, i);
|
||||
}
|
||||
for (int i = 0; i < kNumThreads; ++i)
|
||||
for (auto i = 0uz; i < kNumThreads; ++i)
|
||||
{
|
||||
threads[i].join();
|
||||
}
|
||||
@@ -761,21 +808,32 @@ TEST(IntrusiveSharedTest, multithreaded_locking_weak)
|
||||
auto tracingCallback = [&](TrackedState cur, std::optional<TrackedState> next) {
|
||||
using enum TrackedState;
|
||||
auto [destructorRan, partialDeleteRan] = getDestructorState();
|
||||
if (next == PartiallyDeleted)
|
||||
if (!next)
|
||||
return;
|
||||
|
||||
switch (*next)
|
||||
{
|
||||
EXPECT_FALSE(partialDeleteRan || destructorRan);
|
||||
setPartialDeleteRan();
|
||||
}
|
||||
if (next == Deleted)
|
||||
{
|
||||
EXPECT_FALSE(destructorRan);
|
||||
setDestructorRan();
|
||||
case PartiallyDeleted:
|
||||
EXPECT_FALSE(partialDeleteRan || destructorRan);
|
||||
setPartialDeleteRan();
|
||||
break;
|
||||
|
||||
case Deleted:
|
||||
EXPECT_FALSE(destructorRan);
|
||||
setDestructorRan();
|
||||
break;
|
||||
|
||||
case Uninitialized:
|
||||
case Alive:
|
||||
case PartiallyDeletedStarted:
|
||||
case DeletedStarted:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr int kLoopIters = 2 * 1024;
|
||||
constexpr int kLockWeakLoopIters = 256;
|
||||
constexpr int kNumThreads = 16;
|
||||
constexpr auto kLoopIters = 2uz * 1024;
|
||||
constexpr auto kLockWeakLoopIters = 256uz;
|
||||
constexpr auto kNumThreads = 16uz;
|
||||
std::vector<SharedIntrusive<TIBase>> toLock;
|
||||
Barrier loopStartSyncPoint{kNumThreads};
|
||||
Barrier postCreateToLockSyncPoint{kNumThreads};
|
||||
@@ -784,8 +842,8 @@ TEST(IntrusiveSharedTest, multithreaded_locking_weak)
|
||||
// lockAndDestroy creates weak pointers from the strong pointer
|
||||
// and runs a loop that locks the weak pointer. At the end of the loop
|
||||
// all the pointers are destroyed all at once.
|
||||
auto lockAndDestroy = [&](int threadId) {
|
||||
for (int i = 0; i < kLoopIters; ++i)
|
||||
auto lockAndDestroy = [&](std::size_t threadId) {
|
||||
for (auto i = 0uz; i < kLoopIters; ++i)
|
||||
{
|
||||
// ------ Sync Point ------
|
||||
loopStartSyncPoint.arriveAndWait();
|
||||
@@ -816,7 +874,7 @@ TEST(IntrusiveSharedTest, multithreaded_locking_weak)
|
||||
// Multiple threads all create a weak pointer from the same
|
||||
// strong pointer
|
||||
WeakIntrusive const weak{toLock[threadId]};
|
||||
for (int wi = 0; wi < kLockWeakLoopIters; ++wi)
|
||||
for (auto wi = 0uz; wi < kLockWeakLoopIters; ++wi)
|
||||
{
|
||||
EXPECT_FALSE(weak.expired());
|
||||
auto strong = weak.lock();
|
||||
@@ -831,11 +889,11 @@ TEST(IntrusiveSharedTest, multithreaded_locking_weak)
|
||||
};
|
||||
std::vector<std::thread> threads;
|
||||
threads.reserve(kNumThreads);
|
||||
for (int i = 0; i < kNumThreads; ++i)
|
||||
for (auto i = 0uz; i < kNumThreads; ++i)
|
||||
{
|
||||
threads.emplace_back(lockAndDestroy, i);
|
||||
}
|
||||
for (int i = 0; i < kNumThreads; ++i)
|
||||
for (auto i = 0uz; i < kNumThreads; ++i)
|
||||
{
|
||||
threads[i].join();
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ TEST(mallocTrim, repeated_calls)
|
||||
beast::Journal const journal{beast::Journal::getNullSink()};
|
||||
|
||||
// Call malloc_trim multiple times to ensure it's safe
|
||||
for (int i = 0; i < 5; ++i)
|
||||
for (auto i = 0uz; i < 5; ++i)
|
||||
{
|
||||
MallocTrimReport const report = mallocTrim("iteration_" + std::to_string(i), journal);
|
||||
|
||||
|
||||
@@ -323,11 +323,11 @@ TEST(NumberTest, add)
|
||||
__LINE__,
|
||||
},
|
||||
{
|
||||
// Does not round. Mantissas are going to be > maxRep, so if
|
||||
// Does not round. Mantissas are going to be > kMaxRep, so if
|
||||
// added together as uint64_t's, the result will overflow.
|
||||
// With addition using uint128_t, there's no problem. After
|
||||
// normalizing, the resulting mantissa ends up less than
|
||||
// maxRep.
|
||||
// kMaxRep.
|
||||
Number{false, 9'999'999'999'999'999'990ULL, 0, Number::Normalized{}},
|
||||
Number{false, 9'999'999'999'999'999'990ULL, 0, Number::Normalized{}},
|
||||
Number{false, 1'999'999'999'999'999'998ULL, 1, Number::Normalized{}},
|
||||
@@ -1078,14 +1078,6 @@ TEST(NumberTest, root)
|
||||
EXPECT_EQ(result, z) << ss.str();
|
||||
}
|
||||
};
|
||||
/*
|
||||
auto tests = [&](auto const& cSmall, auto const& cLarge) {
|
||||
test(cSmall);
|
||||
if (scale != MantissaRange::mantissa_scale::small)
|
||||
test(cLarge);
|
||||
};
|
||||
*/
|
||||
|
||||
auto const cSmall = std::to_array<Case>(
|
||||
{{Number{2}, 2, Number{1414213562373095049, -18}},
|
||||
{Number{2'000'000}, 2, Number{1414213562373095049, -15}},
|
||||
@@ -1511,7 +1503,7 @@ TEST(NumberTest, to_string)
|
||||
NumberRoundModeGuard const mg(Number::RoundingMode::TowardsZero);
|
||||
|
||||
auto const maxMantissa = Number::maxMantissa();
|
||||
EXPECT_EQ(maxMantissa, (9'999'999'999'999'999));
|
||||
EXPECT_EQ(maxMantissa, 9'999'999'999'999'999);
|
||||
test(
|
||||
Number{false, (maxMantissa * 1000) + 999, -3, Number::Normalized()},
|
||||
"9999999999999999",
|
||||
@@ -1550,7 +1542,7 @@ TEST(NumberTest, to_string)
|
||||
NumberRoundModeGuard const mg(Number::RoundingMode::TowardsZero);
|
||||
|
||||
auto const maxMantissa = Number::maxMantissa();
|
||||
EXPECT_EQ((maxMantissa), (9'999'999'999'999'999'999ULL));
|
||||
EXPECT_EQ(maxMantissa, 9'999'999'999'999'999'999ULL);
|
||||
test(
|
||||
Number{false, maxMantissa, 0, Number::Normalized{}},
|
||||
"9999999999999999990",
|
||||
|
||||
@@ -151,7 +151,7 @@ randomBigInt(std::uint8_t minSize = 1, std::uint8_t maxSize = 5)
|
||||
auto const numCoeff = numCoeffDist(eng);
|
||||
std::vector<std::uint64_t> coeffs;
|
||||
coeffs.reserve(numCoeff);
|
||||
for (int i = 0; i < numCoeff; ++i)
|
||||
for (auto i = 0uz; i < numCoeff; ++i)
|
||||
{
|
||||
coeffs.push_back(dist(eng));
|
||||
}
|
||||
@@ -167,7 +167,7 @@ TEST(Base58Test, multiprecision)
|
||||
auto eng = randEngine();
|
||||
std::uniform_int_distribution<std::uint64_t> dist;
|
||||
std::uniform_int_distribution<std::uint64_t> dist1(1);
|
||||
for (int i = 0; i < kIters; ++i)
|
||||
for (auto i = 0uz; i < kIters; ++i)
|
||||
{
|
||||
std::uint64_t const d = dist(eng);
|
||||
if (d == 0u)
|
||||
@@ -185,7 +185,7 @@ TEST(Base58Test, multiprecision)
|
||||
EXPECT_EQ(refMod.convert_to<std::uint64_t>(), mod);
|
||||
EXPECT_EQ(foundDiv, refDiv);
|
||||
}
|
||||
for (int i = 0; i < kIters; ++i)
|
||||
for (auto i = 0uz; i < kIters; ++i)
|
||||
{
|
||||
std::uint64_t const d = dist(eng);
|
||||
auto bigInt = multiprecision_utils::randomBigInt(/*minSize*/ 2);
|
||||
@@ -204,7 +204,7 @@ TEST(Base58Test, multiprecision)
|
||||
auto const foundAdd = multiprecision_utils::toBoostMP(bigInt);
|
||||
EXPECT_EQ(refAdd, foundAdd);
|
||||
}
|
||||
for (int i = 0; i < kIters; ++i)
|
||||
for (auto i = 0uz; i < kIters; ++i)
|
||||
{
|
||||
std::uint64_t const d = dist1(eng);
|
||||
// Force overflow
|
||||
@@ -221,7 +221,7 @@ TEST(Base58Test, multiprecision)
|
||||
auto const foundAdd = multiprecision_utils::toBoostMP(bigInt);
|
||||
EXPECT_NE(refAdd, foundAdd);
|
||||
}
|
||||
for (int i = 0; i < kIters; ++i)
|
||||
for (auto i = 0uz; i < kIters; ++i)
|
||||
{
|
||||
std::uint64_t const d = dist(eng);
|
||||
auto bigInt = multiprecision_utils::randomBigInt(/* minSize */ 2);
|
||||
@@ -239,7 +239,7 @@ TEST(Base58Test, multiprecision)
|
||||
auto const foundMul = multiprecision_utils::toBoostMP(bigInt);
|
||||
EXPECT_EQ(refMul, foundMul);
|
||||
}
|
||||
for (int i = 0; i < kIters; ++i)
|
||||
for (auto i = 0uz; i < kIters; ++i)
|
||||
{
|
||||
std::uint64_t const d = dist1(eng);
|
||||
// Force overflow
|
||||
@@ -265,7 +265,7 @@ TEST(Base58Test, fast_matches_ref)
|
||||
|
||||
std::array<std::uint8_t, 64> b256ResultBuf[2];
|
||||
std::array<std::span<std::uint8_t>, 2> b256Result;
|
||||
for (int i = 0; i < 2; ++i)
|
||||
for (auto i = 0uz; i < 2; ++i)
|
||||
{
|
||||
std::span const outBuf{b58ResultBuf[i]};
|
||||
if (i == 0)
|
||||
@@ -297,7 +297,7 @@ TEST(Base58Test, fast_matches_ref)
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
for (auto i = 0uz; i < 2; ++i)
|
||||
{
|
||||
std::span const outBuf{b256ResultBuf[i].data(), b256ResultBuf[i].size()};
|
||||
if (i == 0)
|
||||
@@ -339,7 +339,7 @@ TEST(Base58Test, fast_matches_ref)
|
||||
|
||||
std::array<std::uint8_t, 64> b256ResultBuf[2];
|
||||
std::array<std::span<std::uint8_t>, 2> b256Result;
|
||||
for (int i = 0; i < 2; ++i)
|
||||
for (auto i = 0uz; i < 2; ++i)
|
||||
{
|
||||
std::span const outBuf{b58ResultBuf[i].data(), b58ResultBuf[i].size()};
|
||||
if (i == 0)
|
||||
@@ -370,7 +370,7 @@ TEST(Base58Test, fast_matches_ref)
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
for (auto i = 0uz; i < 2; ++i)
|
||||
{
|
||||
std::span const outBuf{b256ResultBuf[i].data(), b256ResultBuf[i].size()};
|
||||
if (i == 0)
|
||||
@@ -425,7 +425,7 @@ TEST(Base58Test, fast_matches_ref)
|
||||
|
||||
// test with random data
|
||||
constexpr std::size_t kIters = 100000;
|
||||
for (int i = 0; i < kIters; ++i)
|
||||
for (auto i = 0uz; i < kIters; ++i)
|
||||
{
|
||||
std::array<std::uint8_t, 128> b256DataBuf{};
|
||||
auto const [tokType, b256Data] = randomB256TestData(b256DataBuf);
|
||||
|
||||
@@ -59,65 +59,67 @@ struct BaseUintTest : public ::testing::Test
|
||||
static void
|
||||
testComparisons()
|
||||
{
|
||||
{
|
||||
static constexpr std::array<std::pair<std::string_view, std::string_view>, 6> kTestArgs{
|
||||
{{"0000000000000000", "0000000000000001"},
|
||||
{"0000000000000000", "ffffffffffffffff"},
|
||||
{"1234567812345678", "2345678923456789"},
|
||||
{"8000000000000000", "8000000000000001"},
|
||||
{"aaaaaaaaaaaaaaa9", "aaaaaaaaaaaaaaaa"},
|
||||
{"fffffffffffffffe", "ffffffffffffffff"}}};
|
||||
using HexPair = std::pair<std::string_view, std::string_view>;
|
||||
|
||||
for (auto const& arg : kTestArgs)
|
||||
{
|
||||
static constexpr auto kTestArgs = std::to_array<HexPair>({
|
||||
{"0000000000000000", "0000000000000001"},
|
||||
{"0000000000000000", "ffffffffffffffff"},
|
||||
{"1234567812345678", "2345678923456789"},
|
||||
{"8000000000000000", "8000000000000001"},
|
||||
{"aaaaaaaaaaaaaaa9", "aaaaaaaaaaaaaaaa"},
|
||||
{"fffffffffffffffe", "ffffffffffffffff"},
|
||||
});
|
||||
|
||||
for (auto const& [smallerText, largerText] : kTestArgs)
|
||||
{
|
||||
xrpl::BaseUInt<64> const u{arg.first}, v{arg.second};
|
||||
xrpl::BaseUInt<64> const smaller{smallerText}, larger{largerText};
|
||||
// For code readability, we want to use general boolean
|
||||
// expectations instead of specific EXPECT_LT etc.
|
||||
EXPECT_TRUE(u < v);
|
||||
EXPECT_TRUE(u <= v);
|
||||
EXPECT_TRUE(u != v);
|
||||
EXPECT_FALSE(u == v);
|
||||
EXPECT_FALSE(u > v);
|
||||
EXPECT_FALSE(u >= v);
|
||||
EXPECT_FALSE(v < u);
|
||||
EXPECT_FALSE(v <= u);
|
||||
EXPECT_TRUE(v != u);
|
||||
EXPECT_FALSE(v == u);
|
||||
EXPECT_TRUE(v > u);
|
||||
EXPECT_TRUE(v >= u);
|
||||
EXPECT_TRUE(u == u);
|
||||
EXPECT_TRUE(v == v);
|
||||
EXPECT_TRUE(smaller < larger);
|
||||
EXPECT_TRUE(smaller <= larger);
|
||||
EXPECT_TRUE(smaller != larger);
|
||||
EXPECT_FALSE(smaller == larger);
|
||||
EXPECT_FALSE(smaller > larger);
|
||||
EXPECT_FALSE(smaller >= larger);
|
||||
EXPECT_FALSE(larger < smaller);
|
||||
EXPECT_FALSE(larger <= smaller);
|
||||
EXPECT_TRUE(larger != smaller);
|
||||
EXPECT_FALSE(larger == smaller);
|
||||
EXPECT_TRUE(larger > smaller);
|
||||
EXPECT_TRUE(larger >= smaller);
|
||||
EXPECT_TRUE(smaller == smaller);
|
||||
EXPECT_TRUE(larger == larger);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
static constexpr std::array<std::pair<std::string_view, std::string_view>, 6> kTestArgs{
|
||||
{
|
||||
{"000000000000000000000000", "000000000000000000000001"},
|
||||
{"000000000000000000000000", "ffffffffffffffffffffffff"},
|
||||
{"0123456789ab0123456789ab", "123456789abc123456789abc"},
|
||||
{"555555555555555555555555", "55555555555a555555555555"},
|
||||
{"aaaaaaaaaaaaaaa9aaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||
{"fffffffffffffffffffffffe", "ffffffffffffffffffffffff"},
|
||||
}};
|
||||
static constexpr auto kTestArgs = std::to_array<HexPair>({
|
||||
{"000000000000000000000000", "000000000000000000000001"},
|
||||
{"000000000000000000000000", "ffffffffffffffffffffffff"},
|
||||
{"0123456789ab0123456789ab", "123456789abc123456789abc"},
|
||||
{"555555555555555555555555", "55555555555a555555555555"},
|
||||
{"aaaaaaaaaaaaaaa9aaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||
{"fffffffffffffffffffffffe", "ffffffffffffffffffffffff"},
|
||||
});
|
||||
|
||||
for (auto const& arg : kTestArgs)
|
||||
for (auto const& [smallerText, largerText] : kTestArgs)
|
||||
{
|
||||
xrpl::BaseUInt<96> const u{arg.first}, v{arg.second};
|
||||
EXPECT_TRUE(u < v);
|
||||
EXPECT_TRUE(u <= v);
|
||||
EXPECT_TRUE(u != v);
|
||||
EXPECT_FALSE(u == v);
|
||||
EXPECT_FALSE(u > v);
|
||||
EXPECT_FALSE(u >= v);
|
||||
EXPECT_FALSE(v < u);
|
||||
EXPECT_FALSE(v <= u);
|
||||
EXPECT_TRUE(v != u);
|
||||
EXPECT_FALSE(v == u);
|
||||
EXPECT_TRUE(v > u);
|
||||
EXPECT_TRUE(v >= u);
|
||||
EXPECT_TRUE(u == u);
|
||||
EXPECT_TRUE(v == v);
|
||||
xrpl::BaseUInt<96> const smaller{smallerText}, larger{largerText};
|
||||
EXPECT_TRUE(smaller < larger);
|
||||
EXPECT_TRUE(smaller <= larger);
|
||||
EXPECT_TRUE(smaller != larger);
|
||||
EXPECT_FALSE(smaller == larger);
|
||||
EXPECT_FALSE(smaller > larger);
|
||||
EXPECT_FALSE(smaller >= larger);
|
||||
EXPECT_FALSE(larger < smaller);
|
||||
EXPECT_FALSE(larger <= smaller);
|
||||
EXPECT_TRUE(larger != smaller);
|
||||
EXPECT_FALSE(larger == smaller);
|
||||
EXPECT_TRUE(larger > smaller);
|
||||
EXPECT_TRUE(larger >= smaller);
|
||||
EXPECT_TRUE(smaller == smaller);
|
||||
EXPECT_TRUE(larger == larger);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -401,14 +403,14 @@ TEST_F(BaseUintTest, base_uint)
|
||||
{
|
||||
}
|
||||
};
|
||||
constexpr StrBaseUInt kTestCases[] = {
|
||||
constexpr auto kTestCases = std::to_array<StrBaseUInt>({
|
||||
"000000000000000000000000",
|
||||
"000000000000000000000001",
|
||||
"fedcba9876543210ABCDEF91",
|
||||
"19FEDCBA0123456789abcdef",
|
||||
"800000000000000000000000",
|
||||
"fFfFfFfFfFfFfFfFfFfFfFfF",
|
||||
};
|
||||
});
|
||||
|
||||
for (StrBaseUInt const& t : kTestCases)
|
||||
{
|
||||
|
||||
@@ -19,11 +19,11 @@ struct JoinTest : public ::testing::Test
|
||||
|
||||
TEST_F(JoinTest, join)
|
||||
{
|
||||
auto test = [](auto collectionanddelimiter, std::string expected) {
|
||||
auto test = [](auto collectionAndDelimiter, std::string expected) {
|
||||
std::stringstream ss;
|
||||
// Put something else in the buffer before and after to ensure that
|
||||
// the << operator returns the stream correctly.
|
||||
ss << "(" << collectionanddelimiter << ")";
|
||||
ss << "(" << collectionAndDelimiter << ")";
|
||||
auto const str = ss.str();
|
||||
EXPECT_EQ(str.substr(1, str.length() - 2), expected);
|
||||
EXPECT_EQ(str.front(), '(');
|
||||
|
||||
@@ -69,7 +69,7 @@ TEST(CensorshipDetectorTest, censorship_detector)
|
||||
runRound(cdet, ++round, {23, 24, 25, 26}, {25, 27}, {23, 26}, {24});
|
||||
runRound(cdet, ++round, {23, 26, 28}, {26, 28}, {23}, {});
|
||||
|
||||
for (int i = 0; i != 10; ++i)
|
||||
for (auto i = 0uz; i != 10; ++i)
|
||||
runRound(cdet, ++round, {23}, {}, {23}, {});
|
||||
|
||||
runRound(cdet, ++round, {23, 29}, {29}, {23}, {});
|
||||
|
||||
@@ -118,9 +118,9 @@ public:
|
||||
std::vector<ForkInfo> res;
|
||||
|
||||
// Loop over all pairs of uniqueUNLs
|
||||
for (int i = 0; i < uniqueUNLs.size(); ++i)
|
||||
for (auto i = 0uz; i < uniqueUNLs.size(); ++i)
|
||||
{
|
||||
for (int j = (i + 1); j < uniqueUNLs.size(); ++j)
|
||||
for (auto j = i + 1; j < uniqueUNLs.size(); ++j)
|
||||
{
|
||||
auto const& unlA = uniqueUNLs[i];
|
||||
auto const& unlB = uniqueUNLs[j];
|
||||
|
||||
@@ -24,11 +24,12 @@ randomWeightedShuffle(std::vector<T> v, std::vector<double> w, G& g)
|
||||
{
|
||||
using std::swap;
|
||||
|
||||
for (int i = 0; i < v.size() - 1; ++i)
|
||||
for (auto i = 0uz; i + 1 < v.size(); ++i)
|
||||
{
|
||||
// pick a random item weighted by w
|
||||
std::discrete_distribution<> dd(w.begin() + i, w.end()); // NOLINT(misc-const-correctness)
|
||||
auto idx = dd(g);
|
||||
// Pick a random item from the unplaced tail, weighted by w.
|
||||
// NOLINTNEXTLINE(misc-const-correctness)
|
||||
std::discrete_distribution<std::size_t> dd(w.begin() + i, w.end());
|
||||
auto const idx = i + dd(g);
|
||||
std::swap(v[i], v[idx]);
|
||||
std::swap(w[i], w[idx]);
|
||||
}
|
||||
|
||||
@@ -27,11 +27,11 @@ namespace {
|
||||
std::vector<std::string>
|
||||
allBackends()
|
||||
{
|
||||
std::vector<std::string> types{"memory", "nudb"};
|
||||
#if XRPL_ROCKSDB_AVAILABLE
|
||||
types.emplace_back("rocksdb");
|
||||
return {"memory", "nudb", "rocksdb"};
|
||||
#else
|
||||
return {"memory", "nudb"};
|
||||
#endif
|
||||
return types;
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
|
||||
@@ -17,9 +17,12 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/TestSink.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <ranges>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl::Resource {
|
||||
|
||||
@@ -54,9 +57,10 @@ protected:
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
populateGossip(Gossip& gossip)
|
||||
static Gossip
|
||||
makeGossip()
|
||||
{
|
||||
Gossip gossip;
|
||||
std::uint8_t const v(10 + randInt(9));
|
||||
std::uint8_t const n(10 + randInt(9));
|
||||
gossip.items.reserve(n);
|
||||
@@ -71,8 +75,9 @@ protected:
|
||||
static_cast<std::uint8_t>(v + i),
|
||||
}};
|
||||
item.address = beast::IP::Endpoint{beast::IP::AddressV4{d}};
|
||||
gossip.items.push_back(item);
|
||||
gossip.items.push_back(std::move(item));
|
||||
}
|
||||
return gossip;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -87,8 +92,8 @@ TEST_F(ResourceManagerTest, limited_warn_drop)
|
||||
Consumer c{logic.newInboundEndpoint(addr)};
|
||||
|
||||
// Create load until we get a warning
|
||||
int n = 10000;
|
||||
bool warned = false;
|
||||
auto n = 10000;
|
||||
auto warned = false;
|
||||
|
||||
while (--n >= 0)
|
||||
{
|
||||
@@ -97,7 +102,7 @@ TEST_F(ResourceManagerTest, limited_warn_drop)
|
||||
warned = true;
|
||||
break;
|
||||
}
|
||||
++logic.clock();
|
||||
logic.advance();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(warned) << "Loop count exceeded without warning";
|
||||
@@ -113,7 +118,7 @@ TEST_F(ResourceManagerTest, limited_warn_drop)
|
||||
EXPECT_TRUE(c.disconnect(j_));
|
||||
break;
|
||||
}
|
||||
++logic.clock();
|
||||
logic.advance();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(dropped) << "Loop count exceeded without dropping";
|
||||
@@ -135,7 +140,7 @@ TEST_F(ResourceManagerTest, limited_warn_drop)
|
||||
auto n = kSecondsUntilExpiration + 1s;
|
||||
while (--n > 0s)
|
||||
{
|
||||
++logic.clock();
|
||||
logic.advance();
|
||||
logic.periodicActivity();
|
||||
Consumer const c{logic.newInboundEndpoint(addr)};
|
||||
if (c.disposition() != Disposition::Drop)
|
||||
@@ -167,7 +172,7 @@ TEST_F(ResourceManagerTest, unlimited_warn_drop)
|
||||
warned = true;
|
||||
break;
|
||||
}
|
||||
++logic.clock();
|
||||
logic.advance();
|
||||
}
|
||||
|
||||
EXPECT_FALSE(warned) << "Should loop forever with no warning";
|
||||
@@ -175,6 +180,8 @@ TEST_F(ResourceManagerTest, unlimited_warn_drop)
|
||||
|
||||
TEST_F(ResourceManagerTest, charges)
|
||||
{
|
||||
static constexpr auto kDecayTicks = 128uz;
|
||||
|
||||
TestLogic logic{j_};
|
||||
|
||||
{
|
||||
@@ -183,7 +190,7 @@ TEST_F(ResourceManagerTest, charges)
|
||||
Charge const fee{1000};
|
||||
JLOG(j_.info()) << "Charging " << c.toString() << " " << fee << " per second";
|
||||
c.charge(fee);
|
||||
for (int i = 0; i < 128; ++i)
|
||||
for (auto tick = 0uz; tick < kDecayTicks; ++tick)
|
||||
{
|
||||
JLOG(j_.info()) << "Time= " << logic.clock().now().time_since_epoch().count()
|
||||
<< ", Balance = " << c.balance();
|
||||
@@ -196,7 +203,7 @@ TEST_F(ResourceManagerTest, charges)
|
||||
Consumer c{logic.newInboundEndpoint(address)};
|
||||
Charge const fee{1000};
|
||||
JLOG(j_.info()) << "Charging " << c.toString() << " " << fee << " per second";
|
||||
for (int i = 0; i < 128; ++i)
|
||||
for (auto tick = 0uz; tick < kDecayTicks; ++tick)
|
||||
{
|
||||
c.charge(fee);
|
||||
JLOG(j_.info()) << "Time= " << logic.clock().now().time_since_epoch().count()
|
||||
@@ -210,13 +217,10 @@ TEST_F(ResourceManagerTest, imports)
|
||||
{
|
||||
TestLogic logic{j_};
|
||||
|
||||
Gossip g[5];
|
||||
|
||||
for (auto& i : g)
|
||||
populateGossip(i);
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
logic.importConsumers(std::to_string(i), g[i]);
|
||||
static constexpr auto kGossipSources = 5uz;
|
||||
std::ranges::for_each(std::views::iota(0uz, kGossipSources), [&](auto const i) {
|
||||
logic.importConsumers(std::to_string(i), makeGossip());
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(ResourceManagerTest, import)
|
||||
@@ -233,7 +237,7 @@ TEST_F(ResourceManagerTest, import)
|
||||
1,
|
||||
}};
|
||||
item.address = beast::IP::Endpoint{beast::IP::AddressV4{d}};
|
||||
g.items.push_back(item);
|
||||
g.items.push_back(std::move(item));
|
||||
|
||||
logic.importConsumers("g", g);
|
||||
}
|
||||
|
||||
@@ -257,12 +257,9 @@ TEST_P(SHAMapTest, add_traverse_snapshot_build_tear_and_iterate)
|
||||
map.invariants();
|
||||
}
|
||||
|
||||
int h = 7;
|
||||
auto keyIndex = kKeys.size();
|
||||
for (auto const& k : map)
|
||||
{
|
||||
EXPECT_EQ(k.key(), kKeys[h]);
|
||||
--h;
|
||||
}
|
||||
EXPECT_EQ(k.key(), kKeys[--keyIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,7 +285,11 @@ TEST_F(SHAMapPathProof, verify_proof_path)
|
||||
uint256 rootHash;
|
||||
std::vector<Blob> goodPath;
|
||||
|
||||
for (unsigned char c = 1; c < 100; ++c)
|
||||
static constexpr unsigned char kFirstKey = 1;
|
||||
static constexpr unsigned char kKeyCount = 100;
|
||||
static constexpr unsigned char kLastKey = kKeyCount - 1;
|
||||
|
||||
for (unsigned char c = kFirstKey; c < kKeyCount; ++c)
|
||||
{
|
||||
uint256 k(c);
|
||||
map.addItem(SHAMapNodeType::TnAccountState, makeShamapitem(k, Slice{k.data(), k.size()}));
|
||||
@@ -304,7 +305,7 @@ TEST_F(SHAMapPathProof, verify_proof_path)
|
||||
auto& proofPath = *path;
|
||||
|
||||
EXPECT_TRUE(map.verifyProofPath(root, k, proofPath));
|
||||
if (c == 1)
|
||||
if (c == kFirstKey)
|
||||
{
|
||||
// extra node
|
||||
proofPath.insert(proofPath.begin(), proofPath.front());
|
||||
@@ -313,7 +314,7 @@ TEST_F(SHAMapPathProof, verify_proof_path)
|
||||
uint256 const wrongKey(c + 1);
|
||||
EXPECT_FALSE(map.getProofPath(wrongKey));
|
||||
}
|
||||
if (c == 99)
|
||||
if (c == kLastKey)
|
||||
{
|
||||
key = k;
|
||||
rootHash = root;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <shamap/common.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <list>
|
||||
#include <utility>
|
||||
@@ -33,15 +34,17 @@ protected:
|
||||
boost::intrusive_ptr<SHAMapItem>
|
||||
makeRandomAS()
|
||||
{
|
||||
static constexpr auto kWordsPerState = 3uz;
|
||||
|
||||
Serializer s;
|
||||
|
||||
for (int d = 0; d < 3; ++d)
|
||||
for (auto word = 0uz; word < kWordsPerState; ++word)
|
||||
s.add32(randInt<std::uint32_t>(eng_));
|
||||
return makeShamapitem(s.getSHA512Half(), s.slice());
|
||||
}
|
||||
|
||||
bool
|
||||
confuseMap(SHAMap& map, int count)
|
||||
confuseMap(SHAMap& map, std::size_t count)
|
||||
{
|
||||
// add a bunch of random states to a map, then remove them
|
||||
// map should be the same
|
||||
@@ -49,7 +52,7 @@ protected:
|
||||
|
||||
std::list<uint256> items;
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
for (auto i = 0uz; i < count; ++i)
|
||||
{
|
||||
auto item = makeRandomAS();
|
||||
items.push_back(item->key());
|
||||
@@ -86,26 +89,30 @@ TEST_F(SHAMapSyncTest, sync)
|
||||
SHAMap source{SHAMapType::FREE, f};
|
||||
SHAMap destination{SHAMapType::FREE, f2};
|
||||
|
||||
int const items = 10000;
|
||||
for (int i = 0; i < items; ++i)
|
||||
static constexpr auto kItemCount = 10000uz;
|
||||
static constexpr auto kInvariantInterval = 100uz;
|
||||
static constexpr auto kNodesToConfuse = 500uz;
|
||||
static constexpr auto kMaxNodesPerRequest = 2048;
|
||||
|
||||
for (auto i = 0uz; i < kItemCount; ++i)
|
||||
{
|
||||
source.addItem(SHAMapNodeType::TnAccountState, makeRandomAS());
|
||||
if (i % 100 == 0)
|
||||
if (i % kInvariantInterval == 0)
|
||||
source.invariants();
|
||||
}
|
||||
|
||||
source.invariants();
|
||||
ASSERT_TRUE(confuseMap(source, 500));
|
||||
ASSERT_TRUE(confuseMap(source, kNodesToConfuse));
|
||||
source.invariants();
|
||||
|
||||
source.setImmutable();
|
||||
|
||||
int count = 0;
|
||||
std::size_t count = 0;
|
||||
source.visitLeaves([&count]([[maybe_unused]] auto const& item) { ++count; });
|
||||
EXPECT_EQ(count, items);
|
||||
EXPECT_EQ(count, kItemCount);
|
||||
|
||||
std::vector<SHAMapMissingNode> missingNodes;
|
||||
source.walkMap(missingNodes, 2048);
|
||||
source.walkMap(missingNodes, kMaxNodesPerRequest);
|
||||
EXPECT_TRUE(missingNodes.empty());
|
||||
|
||||
destination.setSynching();
|
||||
@@ -128,7 +135,7 @@ TEST_F(SHAMapSyncTest, sync)
|
||||
f.clock().advance(std::chrono::seconds(1));
|
||||
|
||||
// get the list of nodes we know we need
|
||||
auto nodesMissing = destination.getMissingNodes(2048, nullptr);
|
||||
auto nodesMissing = destination.getMissingNodes(kMaxNodesPerRequest, nullptr);
|
||||
|
||||
if (nodesMissing.empty())
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user