Interleave calls for two conflict sets in tests

This commit is contained in:
2024-07-23 11:12:02 -07:00
parent ec85a06d01
commit c649bc7964
3 changed files with 113 additions and 64 deletions

View File

@@ -3928,7 +3928,7 @@ checkMaxVersion(Node *root, Node *node, InternalVersionT oldestVersion,
bool &success, ConflictSet::Impl *impl) { bool &success, ConflictSet::Impl *impl) {
checkVersionsGeqOldestExtant(node, checkVersionsGeqOldestExtant(node,
InternalVersionT(impl->oldestExtantVersion)); InternalVersionT(impl->oldestExtantVersion));
auto expected = InternalVersionT::zero; auto expected = oldestVersion;
if (node->entryPresent) { if (node->entryPresent) {
expected = std::max(expected, node->entry.pointVersion); expected = std::max(expected, node->entry.pointVersion);
} }
@@ -4151,26 +4151,42 @@ int main(void) { printTree(); }
#ifdef ENABLE_FUZZ #ifdef ENABLE_FUZZ
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
TestDriver<ConflictSet::Impl> driver{data, size}; Arbitrary arbitrary({data, size});
TestDriver<ConflictSet::Impl> driver1{arbitrary};
TestDriver<ConflictSet::Impl> driver2{arbitrary};
bool done1 = false;
bool done2 = false;
for (;;) { for (;;) {
bool done = driver.next(); if (!done1) {
if (!driver.ok) { done1 = driver1.next();
debugPrintDot(stdout, driver.cs.root, &driver.cs); if (!driver1.ok) {
fflush(stdout); debugPrintDot(stdout, driver1.cs.root, &driver1.cs);
abort(); fflush(stdout);
abort();
}
if (!checkCorrectness(driver1.cs.root, driver1.cs.oldestVersion,
&driver1.cs)) {
debugPrintDot(stdout, driver1.cs.root, &driver1.cs);
fflush(stdout);
abort();
}
} }
#if DEBUG_VERBOSE && !defined(NDEBUG) if (!done2) {
fprintf(stderr, "Check correctness\n"); done2 = driver2.next();
#endif if (!driver2.ok) {
bool success = debugPrintDot(stdout, driver2.cs.root, &driver2.cs);
checkCorrectness(driver.cs.root, driver.cs.oldestVersion, &driver.cs); fflush(stdout);
if (!success) { abort();
debugPrintDot(stdout, driver.cs.root, &driver.cs); }
fflush(stdout); if (!checkCorrectness(driver2.cs.root, driver2.cs.oldestVersion,
abort(); &driver2.cs)) {
debugPrintDot(stdout, driver2.cs.root, &driver2.cs);
fflush(stdout);
abort();
}
} }
if (done) { if (done1 && done2) {
break; break;
} }
} }

View File

@@ -580,11 +580,10 @@ namespace {
template <class ConflictSetImpl, bool kEnableAssertions = true> template <class ConflictSetImpl, bool kEnableAssertions = true>
struct TestDriver { struct TestDriver {
Arbitrary arbitrary; Arbitrary *arbitrary;
explicit TestDriver(const uint8_t *data, size_t size) explicit TestDriver(Arbitrary &a) : arbitrary(&a) {}
: arbitrary({data, size}) {}
int64_t oldestVersion = arbitrary.next(); int64_t oldestVersion = arbitrary->next();
int64_t writeVersion = oldestVersion; int64_t writeVersion = oldestVersion;
ConflictSetImpl cs{oldestVersion}; ConflictSetImpl cs{oldestVersion};
ReferenceImpl refImpl{oldestVersion}; ReferenceImpl refImpl{oldestVersion};
@@ -593,33 +592,34 @@ struct TestDriver {
bool ok = true; bool ok = true;
const int prefixLen = arbitrary.bounded(512); const int prefixLen = arbitrary->bounded(512);
const int prefixByte = arbitrary.randT<uint8_t>(); const int prefixByte = arbitrary->randT<uint8_t>();
// Call until it returns true, for "done". Check internal invariants etc // Call until it returns true, for "done". Check internal invariants etc
// between calls to next. // between calls to next.
bool next() { bool next() {
assert(cs.getBytes() >= 0); assert(cs.getBytes() >= 0);
if (!arbitrary.hasEntropy()) { if (!arbitrary->hasEntropy()) {
return true; return true;
} }
Arena arena; Arena arena;
{ {
int numPointWrites = arbitrary.bounded(100); int numPointWrites = arbitrary->bounded(100);
int numRangeWrites = arbitrary.bounded(100); int numRangeWrites = arbitrary->bounded(100);
int64_t v = (writeVersion += arbitrary.bounded(10) ? arbitrary.bounded(10) int64_t v =
: arbitrary.next()); (writeVersion +=
arbitrary->bounded(10) ? arbitrary->bounded(10) : arbitrary->next());
auto *writes = auto *writes =
new (arena) ConflictSet::WriteRange[numPointWrites + numRangeWrites]; new (arena) ConflictSet::WriteRange[numPointWrites + numRangeWrites];
auto keys = set<std::string_view>(arena); auto keys = set<std::string_view>(arena);
while (int(keys.size()) < numPointWrites + numRangeWrites * 2) { while (int(keys.size()) < numPointWrites + numRangeWrites * 2) {
if (!arbitrary.hasEntropy()) { if (!arbitrary->hasEntropy()) {
return true; return true;
} }
int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen); int keyLen = prefixLen + arbitrary->bounded(kMaxKeySuffixLen);
auto *begin = new (arena) uint8_t[keyLen]; auto *begin = new (arena) uint8_t[keyLen];
memset(begin, prefixByte, prefixLen); memset(begin, prefixByte, prefixLen);
arbitrary.randomBytes(begin + prefixLen, keyLen - prefixLen); arbitrary->randomBytes(begin + prefixLen, keyLen - prefixLen);
keys.insert(std::string_view((const char *)begin, keyLen)); keys.insert(std::string_view((const char *)begin, keyLen));
} }
@@ -629,7 +629,7 @@ struct TestDriver {
rangesRemaining = numRangeWrites; rangesRemaining = numRangeWrites;
pointsRemaining > 0 || rangesRemaining > 0; ++i) { pointsRemaining > 0 || rangesRemaining > 0; ++i) {
bool pointRead = pointsRemaining > 0 && rangesRemaining > 0 bool pointRead = pointsRemaining > 0 && rangesRemaining > 0
? bool(arbitrary.bounded(2)) ? bool(arbitrary->bounded(2))
: pointsRemaining > 0; : pointsRemaining > 0;
if (pointRead) { if (pointRead) {
assert(pointsRemaining > 0); assert(pointsRemaining > 0);
@@ -667,14 +667,14 @@ struct TestDriver {
// Test non-canonical writes // Test non-canonical writes
if (numPointWrites > 0) { if (numPointWrites > 0) {
int overlaps = arbitrary.bounded(numPointWrites); int overlaps = arbitrary->bounded(numPointWrites);
for (int i = 0; i < numPointWrites + numRangeWrites && overlaps > 0; for (int i = 0; i < numPointWrites + numRangeWrites && overlaps > 0;
++i) { ++i) {
if (writes[i].end.len == 0) { if (writes[i].end.len == 0) {
int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen); int keyLen = prefixLen + arbitrary->bounded(kMaxKeySuffixLen);
auto *begin = new (arena) uint8_t[keyLen]; auto *begin = new (arena) uint8_t[keyLen];
memset(begin, prefixByte, prefixLen); memset(begin, prefixByte, prefixLen);
arbitrary.randomBytes(begin + prefixLen, keyLen - prefixLen); arbitrary->randomBytes(begin + prefixLen, keyLen - prefixLen);
writes[i].end.len = keyLen; writes[i].end.len = keyLen;
writes[i].end.p = begin; writes[i].end.p = begin;
auto c = auto c =
@@ -692,10 +692,10 @@ struct TestDriver {
} }
} }
} }
if (arbitrary.bounded(2)) { if (arbitrary->bounded(2)) {
// Shuffle writes // Shuffle writes
for (int i = numPointWrites + numRangeWrites - 1; i > 0; --i) { for (int i = numPointWrites + numRangeWrites - 1; i > 0; --i) {
int j = arbitrary.bounded(i + 1); int j = arbitrary->bounded(i + 1);
if (i != j) { if (i != j) {
using std::swap; using std::swap;
swap(writes[i], writes[j]); swap(writes[i], writes[j]);
@@ -704,7 +704,7 @@ struct TestDriver {
} }
oldestVersion += oldestVersion +=
arbitrary.bounded(10) ? arbitrary.bounded(10) : arbitrary.next(); arbitrary->bounded(10) ? arbitrary->bounded(10) : arbitrary->next();
oldestVersion = std::min(oldestVersion, writeVersion); oldestVersion = std::min(oldestVersion, writeVersion);
#ifdef THREAD_TEST #ifdef THREAD_TEST
@@ -739,24 +739,24 @@ struct TestDriver {
#endif #endif
} }
{ {
int numPointReads = arbitrary.bounded(100); int numPointReads = arbitrary->bounded(100);
int numRangeReads = arbitrary.bounded(100); int numRangeReads = arbitrary->bounded(100);
int64_t v = std::max<int64_t>(writeVersion - (arbitrary.bounded(10) int64_t v = std::max<int64_t>(writeVersion - (arbitrary->bounded(10)
? arbitrary.bounded(10) ? arbitrary->bounded(10)
: arbitrary.next()), : arbitrary->next()),
0); 0);
auto *reads = auto *reads =
new (arena) ConflictSet::ReadRange[numPointReads + numRangeReads]; new (arena) ConflictSet::ReadRange[numPointReads + numRangeReads];
auto keys = set<std::string_view>(arena); auto keys = set<std::string_view>(arena);
while (int(keys.size()) < numPointReads + numRangeReads * 2) { while (int(keys.size()) < numPointReads + numRangeReads * 2) {
if (!arbitrary.hasEntropy()) { if (!arbitrary->hasEntropy()) {
return true; return true;
} }
int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen); int keyLen = prefixLen + arbitrary->bounded(kMaxKeySuffixLen);
auto *begin = new (arena) uint8_t[keyLen]; auto *begin = new (arena) uint8_t[keyLen];
memset(begin, prefixByte, prefixLen); memset(begin, prefixByte, prefixLen);
arbitrary.randomBytes(begin + prefixLen, keyLen - prefixLen); arbitrary->randomBytes(begin + prefixLen, keyLen - prefixLen);
keys.insert(std::string_view((const char *)begin, keyLen)); keys.insert(std::string_view((const char *)begin, keyLen));
} }
@@ -765,7 +765,7 @@ struct TestDriver {
for (int pointsRemaining = numPointReads, rangesRemaining = numRangeReads; for (int pointsRemaining = numPointReads, rangesRemaining = numRangeReads;
pointsRemaining > 0 || rangesRemaining > 0; ++i) { pointsRemaining > 0 || rangesRemaining > 0; ++i) {
bool pointRead = pointsRemaining > 0 && rangesRemaining > 0 bool pointRead = pointsRemaining > 0 && rangesRemaining > 0
? bool(arbitrary.bounded(2)) ? bool(arbitrary->bounded(2))
: pointsRemaining > 0; : pointsRemaining > 0;
if (pointRead) { if (pointRead) {
assert(pointsRemaining > 0); assert(pointsRemaining > 0);

View File

@@ -13,25 +13,58 @@ int main(int argc, char **argv) {
std::stringstream buffer; std::stringstream buffer;
buffer << t.rdbuf(); buffer << t.rdbuf();
auto str = buffer.str(); auto str = buffer.str();
TestDriver<ConflictSet, !PERF_TEST> driver{(const uint8_t *)str.data(), Arbitrary arbitrary({(const uint8_t *)str.data(), str.size()});
str.size()}; TestDriver<ConflictSet, !PERF_TEST> driver1{arbitrary};
while (!driver.next()) TestDriver<ConflictSet, !PERF_TEST> driver2{arbitrary};
; bool done1 = false;
if (!driver.ok) { bool done2 = false;
abort(); for (;;) {
if (!done1) {
done1 = driver1.next();
if (!driver1.ok) {
abort();
}
}
if (!done2) {
done2 = driver2.next();
if (!driver2.ok) {
abort();
}
}
if (done1 && done2) {
break;
}
} }
ConflictSet::MetricsV1 *metrics; {
int metricsCount; ConflictSet::MetricsV1 *metrics;
driver.cs.getMetricsV1(&metrics, &metricsCount); int metricsCount;
printf("#################### METRICS FOR %s ####################\n", driver1.cs.getMetricsV1(&metrics, &metricsCount);
argv[i]); printf("#################### METRICS for ConflictSet 1 for %s "
for (int i = 0; i < metricsCount; ++i) { "####################\n",
printf("# HELP %s %s\n", metrics[i].name, metrics[i].help); argv[i]);
printf("# TYPE %s %s\n", metrics[i].name, for (int i = 0; i < metricsCount; ++i) {
metrics[i].type == metrics[i].Counter ? "counter" : "gauge"); printf("# HELP %s %s\n", metrics[i].name, metrics[i].help);
printf("%s %g\n", metrics[i].name, metrics[i].getValue()); printf("# TYPE %s %s\n", metrics[i].name,
metrics[i].type == metrics[i].Counter ? "counter" : "gauge");
printf("%s %g\n", metrics[i].name, metrics[i].getValue());
}
puts("");
}
{
ConflictSet::MetricsV1 *metrics;
int metricsCount;
driver2.cs.getMetricsV1(&metrics, &metricsCount);
printf("#################### METRICS for ConflictSet 2 for %s "
"####################\n",
argv[i]);
for (int i = 0; i < metricsCount; ++i) {
printf("# HELP %s %s\n", metrics[i].name, metrics[i].help);
printf("# TYPE %s %s\n", metrics[i].name,
metrics[i].type == metrics[i].Counter ? "counter" : "gauge");
printf("%s %g\n", metrics[i].name, metrics[i].getValue());
}
puts("");
} }
puts("");
} }
} }