Initialize version sooner in VersionedMap::begin

This commit is contained in:
2024-05-16 18:45:26 -07:00
parent 1e1f5d6d5c
commit 190cd05c13
4 changed files with 38 additions and 33 deletions

View File

@@ -138,12 +138,16 @@ struct Facade {
String(m.param2, m.param2Len); String(m.param2, m.param2Len);
break; break;
case weaselab::VersionedMap::Clear: case weaselab::VersionedMap::Clear:
if (m.param2Len == 0) {
unversioned.erase(String(m.param1, m.param1Len));
} else {
for (auto unversionedIter = for (auto unversionedIter =
unversioned.lower_bound(String(m.param1, m.param1Len)); unversioned.lower_bound(String(m.param1, m.param1Len));
unversionedIter != unversioned.end() && unversionedIter != unversioned.end() &&
unversionedIter->first < String(m.param2, m.param2Len);) { unversionedIter->first < String(m.param2, m.param2Len);) {
unversionedIter = unversioned.erase(unversionedIter); unversionedIter = unversioned.erase(unversionedIter);
} }
}
break; break;
} }
} }

View File

@@ -2,6 +2,7 @@
#include "Internal.h" #include "Internal.h"
#include "KeyCompare.h" #include "KeyCompare.h"
#include <inttypes.h>
#include <map> #include <map>
#include <set> #include <set>
@@ -81,10 +82,13 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
case 1: { case 1: {
// Set oldest version // Set oldest version
facade.setOldestVersion(facade.getOldestVersion() + const int64_t newOldestVersion =
gArbitrary.bounded(facade.getVersion() -
facade.getOldestVersion() + facade.getOldestVersion() +
1)); gArbitrary.bounded(facade.getVersion() - facade.getOldestVersion() +
1);
facade.setOldestVersion(newOldestVersion);
} break; } break;
case 2: { case 2: {
// Check range read // Check range read

View File

@@ -123,6 +123,11 @@ struct RootSet::Impl {
firstToFree = firstToFree->next; firstToFree = firstToFree->next;
safe_free(tmp, ThreadSafeHandle::Impl::sizeForCapacity(tmp->capacity)); safe_free(tmp, ThreadSafeHandle::Impl::sizeForCapacity(tmp->capacity));
} }
#ifndef NDEBUG
assert(rootCount() > 0);
auto *h = handle.load(std::memory_order_relaxed);
assert(h->versions()[h->lastLeq(oldestVersion)] <= oldestVersion);
#endif
} }
const uint32_t *roots() const { const uint32_t *roots() const {

View File

@@ -262,62 +262,49 @@ struct MemManager {
} }
void gc(const uint32_t *roots, int numRoots, int64_t oldestVersion) { void gc(const uint32_t *roots, int numRoots, int64_t oldestVersion) {
#if DEBUG_VERBOSE
if (debugVerboseEnabled) {
printf("GC roots:\n");
for (int i = 0; i < numRoots; ++i) {
printf(" %u\n", roots[i]);
}
}
#endif
// Calculate reachable set // Calculate reachable set
BitSet reachable{next}; BitSet reachable{next};
// Each node has at most 3 children and nodes along the search path aren't // Each node has at most 3 children and nodes along the search path aren't
// in the stack, so we need 2 * kPathLengthUpperBound // in the stack, so we need 2 * kPathLengthUpperBound
uint32_t stack[2 * kPathLengthUpperBound]; uint32_t stack[2 * kPathLengthUpperBound];
int stackIndex = 0; int stackIndex = 0;
auto tryPush = [&](uint32_t p) { auto tryPush = [&](uint32_t parent, uint32_t child) {
if (!reachable.set(child)) {
#if DEBUG_VERBOSE #if DEBUG_VERBOSE
if (debugVerboseEnabled) { if (debugVerboseEnabled) {
printf(" GC: visit: %u\n", p); printf(" GC: reach: %u (parent %u)\n", child, parent);
}
#endif
if (!reachable.set(p)) {
#if DEBUG_VERBOSE
if (debugVerboseEnabled) {
printf(" GC: push on to stack: %u\n", p);
} }
#endif #endif
assert(stackIndex < sizeof(stack) / sizeof(stack[0])); assert(stackIndex < sizeof(stack) / sizeof(stack[0]));
stack[stackIndex++] = p; stack[stackIndex++] = child;
} }
}; };
for (int i = 0; i < numRoots; ++i) { for (int i = 0; i < numRoots; ++i) {
if (roots[i] == 0) { if (roots[i] == 0) {
continue; continue;
} }
tryPush(roots[i]); tryPush(0, roots[i]);
while (stackIndex > 0) { while (stackIndex > 0) {
uint32_t p = stack[--stackIndex]; uint32_t p = stack[--stackIndex];
auto &node = base[p]; auto &node = base[p];
if (node.updated.load(std::memory_order_relaxed)) { if (node.updated.load(std::memory_order_relaxed)) {
if (node.pointer[!node.replacedPointer] != 0) { if (node.pointer[!node.replacedPointer] != 0) {
tryPush(node.pointer[!node.replacedPointer]); tryPush(p, node.pointer[!node.replacedPointer]);
} }
if (oldestVersion < node.updateVersion) { if (oldestVersion < node.updateVersion) {
if (node.pointer[node.replacedPointer] != 0) { if (node.pointer[node.replacedPointer] != 0) {
tryPush(node.pointer[node.replacedPointer]); tryPush(p, node.pointer[node.replacedPointer]);
} }
} }
if (node.pointer[2] != 0) { if (node.pointer[2] != 0) {
tryPush(node.pointer[2]); tryPush(p, node.pointer[2]);
} }
} else { } else {
if (node.pointer[0] != 0) { if (node.pointer[0] != 0) {
tryPush(node.pointer[0]); tryPush(p, node.pointer[0]);
} }
if (node.pointer[1] != 0) { if (node.pointer[1] != 0) {
tryPush(node.pointer[1]); tryPush(p, node.pointer[1]);
} }
} }
} }
@@ -495,6 +482,11 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
result = n.pointer[which]; result = n.pointer[which];
} }
assert(result == 0 || result >= kMinAddressable); assert(result == 0 || result >= kMinAddressable);
#ifndef NDEBUG
if (result != 0) {
assert(mm.base[result].entry != nullptr);
}
#endif
return result; return result;
} }
@@ -1174,6 +1166,7 @@ void VersionedMap::firstGeq(const Key *key, const int64_t *version,
VersionedMap::Iterator VersionedMap::begin(int64_t version) const { VersionedMap::Iterator VersionedMap::begin(int64_t version) const {
VersionedMap::Iterator result; VersionedMap::Iterator result;
result.impl = new (safe_malloc(sizeof(Iterator::Impl))) Iterator::Impl(); result.impl = new (safe_malloc(sizeof(Iterator::Impl))) Iterator::Impl();
result.impl->version = version;
bool ignored; bool ignored;
result.impl->finger.push( result.impl->finger.push(
@@ -1205,7 +1198,6 @@ VersionedMap::Iterator VersionedMap::begin(int64_t version) const {
} }
result.impl->mutationIndex = 0; result.impl->mutationIndex = 0;
result.impl->version = version;
return result; return result;
} }