Check reads in fuzzer

This commit is contained in:
2024-01-19 16:44:38 -08:00
parent 4993462797
commit 2e6649db44
2 changed files with 83 additions and 29 deletions

View File

@@ -908,21 +908,38 @@ struct __attribute__((__visibility__("hidden"))) ConflictSet::Impl {
}
void check(const ReadRange *reads, Result *results, int count) const {
Arena arena;
auto *iters = new (arena) Iterator[count];
auto *begins = new (arena) Key[count];
int searchCount = 0;
for (int i = 0; i < count; ++i) {
begins[i] = reads[i].begin;
if (reads[i].readVersion >= oldestVersion) {
++searchCount;
} else {
results[i] = ConflictSet::TooOld;
}
}
lastLeqMulti(arena, root, std::span<Key>(begins, count), iters);
// TODO check non-singleton reads lol
Arena arena;
auto *iters = new (arena) Iterator[searchCount];
auto *begins = new (arena) Key[searchCount];
int j = 0;
for (int i = 0; i < count; ++i) {
assert(reads[i].end.len == 0);
assert(iters[i].node != nullptr);
if ((iters[i].cmp == 0
? iters[i].node->pointVersion
: iters[i].node->rangeVersion) > reads[i].readVersion) {
results[i] = ConflictSet::Conflict;
if (reads[i].readVersion >= oldestVersion) {
begins[j++] = reads[i].begin;
}
}
lastLeqMulti(arena, root, std::span<Key>(begins, searchCount), iters);
// TODO check non-singleton reads lol
j = 0;
for (int i = 0; i < count; ++i) {
if (reads[i].readVersion >= oldestVersion) {
assert(reads[i].end.len == 0);
assert(iters[i].node != nullptr);
if ((iters[j].cmp == 0
? iters[j].node->pointVersion
: iters[j].node->rangeVersion) > reads[i].readVersion) {
results[i] = ConflictSet::Conflict;
} else {
results[i] = ConflictSet::Commit;
}
++j;
}
}
}
@@ -1226,25 +1243,60 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
while (gArbitrary.hasEntropy()) {
Arena arena;
int numWrites = gArbitrary.bounded(10);
int64_t v = ++writeVersion;
auto *writes = new (arena) ConflictSet::WriteRange[numWrites];
std::set<int> keys;
while (int(keys.size()) < numWrites) {
keys.insert(gRandom.bounded(100));
{
int numWrites = gArbitrary.bounded(10);
int64_t v = ++writeVersion;
auto *writes = new (arena) ConflictSet::WriteRange[numWrites];
std::set<int, std::less<int>, ArenaAlloc<int>> keys{
ArenaAlloc<int>(&arena)};
while (int(keys.size()) < numWrites) {
keys.insert(gRandom.bounded(100));
}
auto iter = keys.begin();
for (int i = 0; i < numWrites; ++i) {
writes[i].begin = toKey(arena, *iter++);
writes[i].end.len = 0;
writes[i].writeVersion = v;
}
cs.addWrites(writes, numWrites);
refImpl.addWrites(writes, numWrites);
}
auto iter = keys.begin();
for (int i = 0; i < numWrites; ++i) {
writes[i].begin = toKey(arena, *iter++);
writes[i].end.len = 0;
writes[i].writeVersion = v;
}
cs.addWrites(writes, numWrites);
refImpl.addWrites(writes, numWrites);
bool success = checkCorrectness(cs.root, refImpl);
if (!success) {
abort();
}
{
int numReads = gArbitrary.bounded(10);
int64_t v = writeVersion - gArbitrary.bounded(10);
auto *reads = new (arena) ConflictSet::ReadRange[numReads];
std::set<int, std::less<int>, ArenaAlloc<int>> keys{
ArenaAlloc<int>(&arena)};
while (int(keys.size()) < numReads) {
keys.insert(gRandom.bounded(100));
}
auto iter = keys.begin();
for (int i = 0; i < numReads; ++i) {
reads[i].begin = toKey(arena, *iter++);
reads[i].end.len = 0;
reads[i].readVersion = v;
}
auto *results1 = new (arena) ConflictSet::Result[numReads];
auto *results2 = new (arena) ConflictSet::Result[numReads];
cs.check(reads, results1, numReads);
refImpl.check(reads, results2, numReads);
for (int i = 0; i < numReads; ++i) {
if (results1[i] != results2[i]) {
fprintf(stderr,
"Expected %d, got %d for read of %.*s at version %d\n",
results2[i], results1[i], reads[i].begin.len,
reads[i].begin.p, int(reads[i].readVersion));
std::string referenceLogicalMap;
refImpl.printLogical(referenceLogicalMap);
fprintf(stderr, "Logical map:\n\n%s\n", referenceLogicalMap.c_str());
abort();
}
}
}
}
return 0;
}