Fix bugs found by exercising the code
This commit is contained in:
2
.clangd
2
.clangd
@@ -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]
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user