From cdf42fcb34799468b0cc2dcda33fc1657ba9edc3 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Tue, 2 Jul 2024 13:06:53 -0700 Subject: [PATCH] Add gcScanStep Also remove oldestVersion arg in write call tree --- ConflictSet.cpp | 66 ++++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/ConflictSet.cpp b/ConflictSet.cpp index b29735c..5ff7f65 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -2646,9 +2646,9 @@ void destroyTree(Node *root) { } } -void addPointWrite(Node *&root, InternalVersionT oldestVersion, - std::span key, InternalVersionT writeVersion, - NodeAllocators *allocators, ConflictSet::Impl *impl) { +void addPointWrite(Node *&root, std::span key, + InternalVersionT writeVersion, NodeAllocators *allocators, + ConflictSet::Impl *impl) { auto *n = insert(&root, key, writeVersion, allocators, impl); if (!n->entryPresent) { auto *p = nextLogical(n); @@ -2659,24 +2659,22 @@ void addPointWrite(Node *&root, InternalVersionT oldestVersion, n->entry.pointVersion = writeVersion; setMaxVersion(n, impl, writeVersion); n->entry.rangeVersion = - p != nullptr ? p->entry.rangeVersion : oldestVersion; + p != nullptr ? p->entry.rangeVersion : InternalVersionT::zero; } else { assert(writeVersion >= n->entry.pointVersion); n->entry.pointVersion = writeVersion; } } -void addWriteRange(Node *&root, InternalVersionT oldestVersion, - std::span begin, std::span end, - InternalVersionT writeVersion, NodeAllocators *allocators, - ConflictSet::Impl *impl) { +void addWriteRange(Node *&root, std::span begin, + std::span end, InternalVersionT writeVersion, + NodeAllocators *allocators, ConflictSet::Impl *impl) { int lcp = longestCommonPrefix(begin.data(), end.data(), std::min(begin.size(), end.size())); if (lcp == int(begin.size()) && end.size() == begin.size() + 1 && end.back() == 0) { - return addPointWrite(root, oldestVersion, begin, writeVersion, allocators, - impl); + return addPointWrite(root, begin, writeVersion, allocators, impl); } const bool beginIsPrefix = lcp == int(begin.size()); auto remaining = begin.subspan(0, lcp); @@ -2724,7 +2722,7 @@ void addWriteRange(Node *&root, InternalVersionT oldestVersion, if (insertedBegin) { auto *p = nextLogical(beginNode); beginNode->entry.rangeVersion = - p != nullptr ? p->entry.rangeVersion : oldestVersion; + p != nullptr ? p->entry.rangeVersion : InternalVersionT::zero; beginNode->entry.pointVersion = writeVersion; assert(maxVersion(beginNode, impl) <= writeVersion); setMaxVersion(beginNode, impl, writeVersion); @@ -2743,7 +2741,7 @@ void addWriteRange(Node *&root, InternalVersionT oldestVersion, if (insertedEnd) { auto *p = nextLogical(endNode); endNode->entry.pointVersion = - p != nullptr ? p->entry.rangeVersion : oldestVersion; + p != nullptr ? p->entry.rangeVersion : InternalVersionT::zero; auto m = maxVersion(endNode, impl); setMaxVersion(endNode, impl, std::max(m, endNode->entry.pointVersion)); @@ -2862,30 +2860,18 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl { auto end = std::span(w.end.p, w.end.len); if (w.end.len > 0) { keyUpdates += 3; - addWriteRange(root, oldestVersion, begin, end, - InternalVersionT(writeVersion), &allocators, this); + addWriteRange(root, begin, end, InternalVersionT(writeVersion), + &allocators, this); } else { keyUpdates += 2; - addPointWrite(root, oldestVersion, begin, - InternalVersionT(writeVersion), &allocators, this); + addPointWrite(root, begin, InternalVersionT(writeVersion), &allocators, + this); } } } - void setOldestVersion(int64_t o) { - InternalVersionT oldestVersion{o}; - assert(o >= oldestVersionFullPrecision); - this->oldestVersionFullPrecision = o; - this->oldestVersion = oldestVersion; - InternalVersionT::zero = oldestVersion; -#ifdef NDEBUG - // This is here for performance reasons, since we want to amortize the cost - // of storing the search path as a string. In tests, we want to exercise the - // rest of the code often. - if (keyUpdates < 100) { - return; - } -#endif + // Spends up to `fuel` gc'ing, and returns its unused fuel + int64_t gcScanStep(int64_t fuel) { Node *n = firstGeq(root, removalKey).n; // There's no way to erase removalKey without introducing a key after it assert(n != nullptr); @@ -2893,7 +2879,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl { if (n == root) { n = nextPhysical(n); } - for (; keyUpdates > 0 && n != nullptr; --keyUpdates) { + for (; fuel > 0 && n != nullptr; --fuel) { if (n->entryPresent && std::max(n->entry.pointVersion, n->entry.rangeVersion) <= oldestVersion) { // Any transaction n would have prevented from committing is @@ -2915,6 +2901,24 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl { removalKeyArena = Arena(); removalKey = getSearchPath(removalKeyArena, n); } + return fuel; + } + + void setOldestVersion(int64_t o) { + InternalVersionT oldestVersion{o}; + assert(o >= oldestVersionFullPrecision); + this->oldestVersionFullPrecision = o; + this->oldestVersion = oldestVersion; + InternalVersionT::zero = oldestVersion; +#ifdef NDEBUG + // This is here for performance reasons, since we want to amortize the cost + // of storing the search path as a string. In tests, we want to exercise the + // rest of the code often. + if (keyUpdates < 100) { + return; + } +#endif + keyUpdates = gcScanStep(keyUpdates); } explicit Impl(int64_t oldestVersion)