diff --git a/ConflictSet.cpp b/ConflictSet.cpp index 4e4ba60..4f1790d 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -1682,7 +1682,8 @@ void mergeWithChild(Node *&self, WriteContext *tls, ConflictSet::Impl *impl, child->parentsIndex = self->parentsIndex; // Max versions are stored in the parent, so we need to update it now - // that we have a new parent. + // that we have a new parent. Safe we call since the root never has a partial + // key. setMaxVersion(child, std::max(childMaxVersion, tls->zero)); self = child; @@ -1957,6 +1958,7 @@ bool checkPrefixRead(Node *n, const std::span key, auto remaining = key; for (;; ++tls->prefix_read_iterations_accum) { if (remaining.size() == 0) { + // There's no way to encode a prefix read of "", so n is not the root return maxVersion(n) <= readVersion; } @@ -2754,6 +2756,7 @@ struct CheckRangeRightSide { bool backtrack() { for (;;) { + // searchPathLen > prefixLen implies n is not the root if (searchPathLen > prefixLen && maxVersion(n) > readVersion) { ok = false; return true; @@ -2855,6 +2858,9 @@ bool checkRangeRead(Node *n, std::span begin, return false; } + // This makes it safe to check maxVersion within CheckRangeLeftSide. If this + // were false, then we would have returned above since lcp == begin.size(). + assert(!(n->parent == nullptr && begin.size() == 0)); CheckRangeLeftSide checkRangeLeftSide{n, begin, lcp + 1, readVersion, tls}; CheckRangeRightSide checkRangeRightSide{n, end, lcp + 1, readVersion, tls}; @@ -3069,7 +3075,8 @@ void addWriteRange(Node *&root, std::span begin, beginNode = erase(beginNode, tls, impl, /*logical*/ true, endNode)) { } - // Inserting end trashed endNode's maxVersion. Fix that + // Inserting end trashed endNode's maxVersion. Fix that. Safe to call since + // the end key always has non-zero size. fixupMaxVersion(endNode, tls); }