diff --git a/ConflictSet.cpp b/ConflictSet.cpp index daebcb3..2a8084d 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -740,8 +740,9 @@ Node *&getChildExists(Node *self, uint8_t index) { } } -// Precondition - an entry for index must exist in the node -int64_t &maxVersion(Node *n, ConflictSet::Impl *); +int64_t maxVersion(Node *n, ConflictSet::Impl *); + +void setMaxVersion(Node *n, ConflictSet::Impl *, int64_t maxVersion); Node *&getInTree(Node *n, ConflictSet::Impl *); @@ -1218,7 +1219,7 @@ void maybeDownsize(Node *self, NodeAllocators *allocators, // Max versions are stored in the parent, so we need to update it now // that we have a new parent. - maxVersion(child, impl) = childMaxVersion; + setMaxVersion(child, impl, childMaxVersion); getInTree(self, impl) = child; allocators->node3.release(self3); @@ -2190,7 +2191,7 @@ template allocators) = old; old->parent = *self; old->parentsIndex = old->partialKey()[partialKeyIndex]; - maxVersion(old, impl) = oldMaxVersion; + setMaxVersion(old, impl, oldMaxVersion); memmove(old->partialKey(), old->partialKey() + partialKeyIndex + 1, old->partialKeyLen - (partialKeyIndex + 1)); @@ -2214,9 +2215,8 @@ template } if constexpr (kBegin) { - auto &m = maxVersion(*self, impl); - assert(writeVersion >= m); - m = writeVersion; + assert(maxVersion(*self, impl) <= writeVersion); + setMaxVersion(*self, impl, writeVersion); } if (key.size() == 0) { @@ -2224,9 +2224,8 @@ template } if constexpr (!kBegin) { - auto &m = maxVersion(*self, impl); - assert(writeVersion >= m); - m = writeVersion; + assert(maxVersion(*self, impl) <= writeVersion); + setMaxVersion(*self, impl, writeVersion); } auto &child = getOrCreateChild(*self, key.front(), allocators); @@ -2237,8 +2236,9 @@ template child->partialKeyLen = 0; child->parent = *self; child->parentsIndex = key.front(); - maxVersion(child, impl) = - kBegin ? writeVersion : std::numeric_limits::lowest(); + setMaxVersion(child, impl, + kBegin ? writeVersion + : std::numeric_limits::lowest()); } self = &child; @@ -2283,7 +2283,7 @@ void addPointWrite(Node *&root, int64_t oldestVersion, n->entryPresent = true; n->entry.pointVersion = writeVersion; - maxVersion(n, impl) = writeVersion; + setMaxVersion(n, impl, writeVersion); n->entry.rangeVersion = p != nullptr ? p->entry.rangeVersion : oldestVersion; } else { @@ -2324,9 +2324,8 @@ void addWriteRange(Node *&root, int64_t oldestVersion, break; } - auto &m = maxVersion(n, impl); - assert(writeVersion >= m); - m = writeVersion; + assert(maxVersion(n, impl) <= writeVersion); + setMaxVersion(n, impl, writeVersion); remaining = remaining.subspan(n->partialKeyLen + 1, remaining.size() - (n->partialKeyLen + 1)); @@ -2353,11 +2352,10 @@ void addWriteRange(Node *&root, int64_t oldestVersion, beginNode->entry.rangeVersion = p != nullptr ? p->entry.rangeVersion : oldestVersion; beginNode->entry.pointVersion = writeVersion; - maxVersion(beginNode, impl) = writeVersion; + assert(maxVersion(beginNode, impl) <= writeVersion); + setMaxVersion(beginNode, impl, writeVersion); } - auto &m = maxVersion(beginNode, impl); - assert(writeVersion >= m); - m = writeVersion; + setMaxVersion(beginNode, impl, writeVersion); assert(writeVersion >= beginNode->entry.pointVersion); beginNode->entry.pointVersion = writeVersion; @@ -2372,8 +2370,8 @@ void addWriteRange(Node *&root, int64_t oldestVersion, auto *p = nextLogical(endNode); endNode->entry.pointVersion = p != nullptr ? p->entry.rangeVersion : oldestVersion; - auto &m = maxVersion(endNode, impl); - m = std::max(m, endNode->entry.pointVersion); + auto m = maxVersion(endNode, impl); + setMaxVersion(endNode, impl, std::max(m, endNode->entry.pointVersion)); } endNode->entry.rangeVersion = writeVersion; @@ -2573,8 +2571,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl { int64_t totalBytes = 0; }; -// Precondition - an entry for index must exist in the node -int64_t &maxVersion(Node *n, ConflictSet::Impl *impl) { +int64_t maxVersion(Node *n, ConflictSet::Impl *impl) { int index = n->parentsIndex; n = n->parent; if (n == nullptr) { @@ -2608,6 +2605,45 @@ int64_t &maxVersion(Node *n, ConflictSet::Impl *impl) { } } +void setMaxVersion(Node *n, ConflictSet::Impl *impl, int64_t newMax) { + int index = n->parentsIndex; + n = n->parent; + if (n == nullptr) { + impl->rootMaxVersion = newMax; + return; + } + switch (n->getType()) { + case Type_Node0: // GCOVR_EXCL_LINE + __builtin_unreachable(); // GCOVR_EXCL_LINE + case Type_Node3: { + auto *n3 = static_cast(n); + int i = getNodeIndex(n3, index); + n3->children[i].childMaxVersion = newMax; + return; + } + case Type_Node16: { + auto *n16 = static_cast(n); + int i = getNodeIndex(n16, index); + n16->children[i].childMaxVersion = newMax; + return; + } + case Type_Node48: { + auto *n48 = static_cast(n); + assert(n48->bitSet.test(index)); + n48->children[n48->index[index]].childMaxVersion = newMax; + return; + } + case Type_Node256: { + auto *n256 = static_cast(n); + assert(n256->bitSet.test(index)); + n256->children[index].childMaxVersion = newMax; + return; + } + default: // GCOVR_EXCL_LINE + __builtin_unreachable(); // GCOVR_EXCL_LINE + } +} + Node *&getInTree(Node *n, ConflictSet::Impl *impl) { return n->parent == nullptr ? impl->root : getChildExists(n->parent, n->parentsIndex);