diff --git a/ConflictSet.cpp b/ConflictSet.cpp index a9b8e43..ca2558a 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -173,7 +173,7 @@ int BitSet::firstSetGeq(int i) const { return -1; } -enum Type { +enum Type : int8_t { Type_Node0, Type_Node3, Type_Node16, @@ -191,6 +191,8 @@ struct Node { int32_t partialKeyLen; int16_t numChildren; bool entryPresent; + // Temp variable used to signal the end of the range during addWriteRange + bool endOfRange; uint8_t parentsIndex; /* end section that's copied to the next node */ @@ -625,6 +627,7 @@ template struct BoundedFreeListAllocator { T *allocate(int partialKeyCapacity) { T *result = allocate_helper(partialKeyCapacity); + result->endOfRange = false; if constexpr (!std::is_same_v) { memset(result->children, 0, sizeof(result->children)); const auto z = InternalVersionT::zero; @@ -1727,11 +1730,10 @@ void maybeDownsize(Node *self, WriteContext *tls, ConflictSet::Impl *impl, // Precondition: self is not the root. May invalidate nodes along the search // path to self. May invalidate children of self->parent. Returns a pointer to -// the node after self. If erase invalidates the pointee of `dontInvalidate`, it -// will update it to its new pointee as well. Precondition: `self->entryPresent` -template +// the node after self. Precondition: `self->entryPresent` + Node *erase(Node *self, WriteContext *tls, ConflictSet::Impl *impl, - bool logical, Node *&dontInvalidate) { + bool logical) { ++tls->accum.entries_erased; assert(self->parent != nullptr); @@ -1749,13 +1751,7 @@ Node *erase(Node *self, WriteContext *tls, ConflictSet::Impl *impl, self->entryPresent = false; if (self->numChildren != 0) { - const bool update = result == dontInvalidate; maybeDownsize(self, tls, impl, result); - if constexpr (kCheckDontInvalidate) { - if (update) { - dontInvalidate = result; - } - } return result; } @@ -1835,23 +1831,11 @@ Node *erase(Node *self, WriteContext *tls, ConflictSet::Impl *impl, __builtin_unreachable(); // GCOVR_EXCL_LINE } - const bool update = result == dontInvalidate; maybeDownsize(parent, tls, impl, result); - if constexpr (kCheckDontInvalidate) { - if (update) { - dontInvalidate = result; - } - } return result; } -Node *erase(Node *self, WriteContext *tls, ConflictSet::Impl *impl, - bool logical) { - Node *dummy; - return erase(self, tls, impl, logical, dummy); -} - Node *nextSibling(Node *node) { for (;;) { if (node->parent == nullptr) { @@ -3064,13 +3048,21 @@ void addWriteRange(Node *&root, std::span begin, } endNode->entry.rangeVersion = writeVersion; - for (beginNode = nextLogical(beginNode); beginNode != endNode; - beginNode = erase(beginNode, tls, impl, /*logical*/ true, endNode)) { + // Erase nodes in range + assert(!beginNode->endOfRange); + assert(!endNode->endOfRange); + endNode->endOfRange = true; + auto *iter = beginNode; + for (iter = nextLogical(iter); !iter->endOfRange; + iter = erase(iter, tls, impl, /*logical*/ true)) { + assert(!iter->endOfRange); } + assert(iter->endOfRange); + iter->endOfRange = false; - // Inserting end trashed endNode's maxVersion. Fix that. Safe to call since - // the end key always has non-zero size. - fixupMaxVersion(endNode, tls); + // Inserting end trashed the last node's maxVersion. Fix that. Safe to call + // since the end key always has non-zero size. + fixupMaxVersion(iter, tls); } Node *firstGeqPhysical(Node *n, const std::span key) {