Add gcScanStep

Also remove oldestVersion arg in write call tree
This commit is contained in:
2024-07-02 13:06:53 -07:00
parent cbe40b5dba
commit cdf42fcb34

View File

@@ -2646,9 +2646,9 @@ void destroyTree(Node *root) {
}
}
void addPointWrite(Node *&root, InternalVersionT oldestVersion,
std::span<const uint8_t> key, InternalVersionT writeVersion,
NodeAllocators *allocators, ConflictSet::Impl *impl) {
void addPointWrite(Node *&root, std::span<const uint8_t> key,
InternalVersionT writeVersion, NodeAllocators *allocators,
ConflictSet::Impl *impl) {
auto *n = insert<true>(&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<const uint8_t> begin, std::span<const uint8_t> end,
InternalVersionT writeVersion, NodeAllocators *allocators,
ConflictSet::Impl *impl) {
void addWriteRange(Node *&root, std::span<const uint8_t> begin,
std::span<const uint8_t> 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<InternalVersionT>(m, endNode->entry.pointVersion));
@@ -2862,30 +2860,18 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
auto end = std::span<const uint8_t>(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)