Add reference implementation
This commit is contained in:
176
FacadeFuzz.cpp
176
FacadeFuzz.cpp
@@ -8,6 +8,113 @@
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
struct Reference {
|
||||
|
||||
explicit Reference(int64_t version)
|
||||
: version(version), oldestVersion(version) {
|
||||
versioned[version] = std::map<String, String>();
|
||||
}
|
||||
|
||||
struct View {
|
||||
|
||||
std::vector<std::pair<String, String>> rangeRead(const String &begin,
|
||||
const String &end,
|
||||
int limit,
|
||||
bool reverse) const {
|
||||
std::vector<std::pair<String, String>> result;
|
||||
if (begin >= end) {
|
||||
return result;
|
||||
}
|
||||
if (reverse) {
|
||||
auto iter = map->lower_bound(end);
|
||||
const auto beginIter = map->begin();
|
||||
if (iter == beginIter) {
|
||||
return result;
|
||||
}
|
||||
--iter;
|
||||
for (; iter->first >= begin && limit > 0; --iter) {
|
||||
result.push_back(*iter);
|
||||
--limit;
|
||||
if (iter == beginIter) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto iter = map->lower_bound(begin),
|
||||
iterEnd = map->lower_bound(end);
|
||||
iter != iterEnd && limit > 0; ++iter) {
|
||||
result.push_back(*iter);
|
||||
--limit;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @private
|
||||
explicit View(const std::map<String, String> *map) : map(map) {}
|
||||
|
||||
private:
|
||||
const std::map<String, String> *map;
|
||||
};
|
||||
|
||||
void addMutations(const weaselab::VersionedMap::Mutation *mutations,
|
||||
int numMutations, int64_t version) {
|
||||
assert(this->version < version);
|
||||
this->version = version;
|
||||
auto back = (--versioned.end())->second;
|
||||
auto &latest = versioned[version];
|
||||
latest = std::move(back);
|
||||
for (int i = 0; i < numMutations; ++i) {
|
||||
switch (mutations[i].type) {
|
||||
case weaselab::VersionedMap::Set:
|
||||
latest[String(mutations[i].param1, mutations[i].param1Len)] =
|
||||
String(mutations[i].param2, mutations[i].param2Len);
|
||||
break;
|
||||
case weaselab::VersionedMap::Clear:
|
||||
if (mutations[i].param2Len > 0) {
|
||||
latest.erase(latest.lower_bound(
|
||||
String(mutations[i].param1, mutations[i].param1Len)),
|
||||
latest.lower_bound(String(mutations[i].param2,
|
||||
mutations[i].param2Len)));
|
||||
} else {
|
||||
latest.erase(String(mutations[i].param1, mutations[i].param1Len));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setOldestVersion(int64_t version) {
|
||||
oldestVersion = version;
|
||||
while (versioned.size() > 1) {
|
||||
auto first = versioned.begin();
|
||||
auto second = first;
|
||||
++second;
|
||||
if (second->first <= version) {
|
||||
versioned.erase(first);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
View viewAt(int64_t version) const {
|
||||
auto iter = versioned.lower_bound(version);
|
||||
if (iter->first > version) {
|
||||
--iter;
|
||||
}
|
||||
return View{&iter->second};
|
||||
}
|
||||
|
||||
int64_t getVersion() const { return version; }
|
||||
int64_t getOldestVersion() const { return oldestVersion; }
|
||||
|
||||
private:
|
||||
int64_t version;
|
||||
int64_t oldestVersion;
|
||||
std::map<int64_t, std::map<String, String>> versioned;
|
||||
};
|
||||
|
||||
constexpr int kKeySize = 4;
|
||||
|
||||
weaselab::VersionedMap::Key randomKey(Arena &arena) {
|
||||
@@ -32,6 +139,7 @@ struct KeyComp {
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
initFuzz(data, size);
|
||||
|
||||
Reference reference{0};
|
||||
Facade facade{0};
|
||||
Arena arena;
|
||||
|
||||
@@ -78,22 +186,34 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
facade.addMutations(mutations.data(), mutations.size(),
|
||||
facade.getVersion() + 1);
|
||||
assert(reference.getVersion() == facade.getVersion());
|
||||
const int64_t newVersion = reference.getVersion() + 1;
|
||||
|
||||
#if DEBUG
|
||||
for (const auto &m : mutations) {
|
||||
printf("%s %.*s %.*s\n",
|
||||
m.type == weaselab::VersionedMap::Set ? "set" : "clear",
|
||||
m.param1Len, m.param1, m.param2Len, m.param2);
|
||||
}
|
||||
printf("Version: %" PRId64 "\n", newVersion);
|
||||
#endif
|
||||
facade.addMutations(mutations.data(), mutations.size(), newVersion);
|
||||
reference.addMutations(mutations.data(), mutations.size(), newVersion);
|
||||
|
||||
} break;
|
||||
case 1: {
|
||||
// Set oldest version
|
||||
#if DEBUG
|
||||
printf("Set oldest version\n");
|
||||
#endif
|
||||
|
||||
const int64_t newOldestVersion =
|
||||
facade.getOldestVersion() +
|
||||
gArbitrary.bounded(facade.getVersion() - facade.getOldestVersion() +
|
||||
1);
|
||||
reference.getOldestVersion() +
|
||||
gArbitrary.bounded(reference.getVersion() -
|
||||
reference.getOldestVersion() + 1);
|
||||
#if DEBUG
|
||||
printf("Set oldest version %" PRId64 "\n", newOldestVersion);
|
||||
#endif
|
||||
|
||||
facade.setOldestVersion(newOldestVersion);
|
||||
reference.setOldestVersion(newOldestVersion);
|
||||
|
||||
} break;
|
||||
case 2: {
|
||||
@@ -103,16 +223,46 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
printf("Check range read\n");
|
||||
#endif
|
||||
|
||||
const int64_t version = facade.getOldestVersion() +
|
||||
gArbitrary.bounded(facade.getVersion() -
|
||||
facade.getOldestVersion() + 1);
|
||||
assert(reference.getOldestVersion() == facade.getOldestVersion());
|
||||
const int64_t version =
|
||||
reference.getOldestVersion() +
|
||||
gArbitrary.bounded(reference.getVersion() -
|
||||
reference.getOldestVersion() + 1);
|
||||
|
||||
auto begin = arbitraryKey(arena);
|
||||
auto end = arbitraryKey(arena);
|
||||
const int limit = gArbitrary.bounded(100000);
|
||||
const bool reverse = gArbitrary.bounded(2);
|
||||
|
||||
facade.viewAt(version).rangeRead(String(begin.p, begin.len),
|
||||
String(end.p, end.len), limit, reverse);
|
||||
auto result = facade.viewAt(version).rangeRead(
|
||||
String(begin.p, begin.len), String(end.p, end.len), limit, reverse);
|
||||
|
||||
auto expected = reference.viewAt(version).rangeRead(
|
||||
String(begin.p, begin.len), String(end.p, end.len), limit, reverse);
|
||||
|
||||
#if DEBUG
|
||||
printf("[%.*s, %.*s) version=%" PRId64 " limit=%d %s result:\n",
|
||||
begin.len, begin.p, end.len, end.p, version, limit,
|
||||
reverse ? "reverse" : "forward");
|
||||
for (const auto &r : result) {
|
||||
printf("%.*s %.*s\n", (int)r.first.length(), r.first.data(),
|
||||
(int)r.second.length(), r.second.data());
|
||||
}
|
||||
|
||||
if (result != expected) {
|
||||
printf("[%.*s, %.*s) version=%" PRId64 " limit=%d %s expected:\n",
|
||||
begin.len, begin.p, end.len, end.p, version, limit,
|
||||
reverse ? "reverse" : "forward");
|
||||
for (const auto &r : expected) {
|
||||
printf("%.*s %.*s\n", (int)r.first.length(), r.first.data(),
|
||||
(int)r.second.length(), r.second.data());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
assert(result == expected);
|
||||
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user