Fix bugs found by exercising the code

This commit is contained in:
2024-05-01 17:10:14 -07:00
parent 3713e5e5bb
commit 9dbd9e028a
2 changed files with 72 additions and 21 deletions

View File

@@ -1,2 +1,2 @@
CompileFlags:
Add: [-DENABLE_MAIN, -UNDEBUG, -DENABLE_FUZZ, -DTHREAD_TEST, -fexceptions]
Add: [-DENABLE_MAIN, -UNDEBUG, -DENABLE_FUZZ, -DTHREAD_TEST, -fexceptions, -DDEBUG_VERBOSE=1]

View File

@@ -9,6 +9,10 @@
#include <unordered_set>
#include <xxhash.h>
#ifndef DEBUG_VERBOSE
#define DEBUG_VERBOSE 0
#endif
void *mmapSafe(void *addr, size_t len, int prot, int flags, int fd,
off_t offset) {
void *result = mmap(addr, len, prot, flags, fd, offset);
@@ -254,6 +258,9 @@ struct MemManager {
if (newFirstUnaddressable < firstUnaddressable) {
for (int i = newFirstUnaddressable; i < firstUnaddressable; ++i) {
if (base[i].entry != nullptr) {
#if DEBUG_VERBOSE
printf("Collecting %u\n", i);
#endif
base[i].entry->delref();
}
}
@@ -269,6 +276,9 @@ struct MemManager {
reachable.iterateAbsentApproxBackwards(
[&](uint32_t i) {
if (base[i].entry != nullptr) {
#if DEBUG_VERBOSE
printf("Collecting %u\n", i);
#endif
base[i].entry->delref();
base[i].entry = nullptr;
}
@@ -311,7 +321,7 @@ struct RootSet {
/// Inform that there will be no calls to rootForVersion with a version less
/// than `oldestVersion`
void setOldestVersion(int64_t oldestVersion) {
const uint32_t firstToKeep = rootForVersion(oldestVersion);
const uint32_t firstToKeep = lastLeq(oldestVersion);
if (firstToKeep != 0) {
memmove(nodes, nodes + firstToKeep,
@@ -321,29 +331,12 @@ struct RootSet {
end -= firstToKeep;
}
assert(end > 0);
assert(nodes[0] <= oldestVersion);
assert(versions[0] <= oldestVersion);
}
/// Get a root node that can correctly be used for `version`
uint32_t rootForVersion(int64_t version) const {
assert(end > 0);
assert(nodes[0] <= version);
// Find the last version <= oldestVersion
int left = 0;
int right = end;
int result = 0;
while (left <= right) {
int mid = left + (right - left) / 2;
if (versions[mid] <= version) {
result = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
assert(result < end);
return result;
return nodes[lastLeq(version)];
}
const uint32_t *roots() const { return nodes; }
@@ -364,6 +357,26 @@ struct RootSet {
}
private:
uint32_t lastLeq(int64_t version) const {
assert(end > 0);
assert(versions[0] <= version);
// Find the last version <= oldestVersion
int left = 1;
int right = end - 1;
int result = 0;
while (left <= right) {
int mid = left + (right - left) / 2;
if (versions[mid] <= version) {
result = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
assert(result < end);
return result;
}
uint32_t *nodes;
// versions[i] is the version of nodes[i]
int64_t *versions;
@@ -463,6 +476,27 @@ struct VersionedMap::Impl {
return result;
}
void setOldestVersion(int64_t oldestVersion) {
roots.setOldestVersion(oldestVersion);
mm.gc(roots.roots(), roots.rootCount(), oldestVersion);
}
void printInOrder(int64_t version) {
printInOrderHelper(version, roots.rootForVersion(version));
}
void printInOrderHelper(int64_t version, uint32_t node) {
if (node == 0) {
return;
}
printInOrderHelper(version,
child<std::memory_order_relaxed>(node, false, version));
printf("%.*s\n", (int)mm.base[node].entry->keyLen,
mm.base[node].entry->getKey());
printInOrderHelper(version,
child<std::memory_order_relaxed>(node, true, version));
}
MemManager mm;
RootSet roots;
};
@@ -472,6 +506,23 @@ struct VersionedMap::Impl {
#include <nanobench.h>
int main() {
{
weaselab::VersionedMap::Impl impl;
impl.roots.add(impl.newNode(1, (const uint8_t *)"a", 1, nullptr, -1, false),
1);
impl.roots.add(impl.newNode(2, (const uint8_t *)"b", 1, nullptr, -1, false),
2);
impl.roots.add(impl.newNode(3, (const uint8_t *)"c", 1, nullptr, -1, false),
3);
impl.printInOrder(0);
impl.printInOrder(1);
impl.printInOrder(2);
impl.printInOrder(3);
impl.setOldestVersion(3);
}
return 0;
ankerl::nanobench::Bench bench;
bench.minEpochIterations(5000);
weaselab::MemManager mm;