diff --git a/ConflictSet.cpp b/ConflictSet.cpp index 2f7a538..c4898c5 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -615,6 +615,13 @@ Node *prevPhysical(Node *node) { } } +Node *prevLogical(Node *node) { + for (node = prevPhysical(node); node != nullptr && !node->entryPresent; + node = prevPhysical(node)) + ; + return node; +} + struct Iterator { Node *n; int cmp; @@ -707,7 +714,12 @@ outerLoop: return {n, -1}; } -void insert(Node **self_, std::span key, int64_t writeVersion) { +// Returns a pointer to the newly inserted node. caller is reponsible for +// setting 'entry' fields on the result, which may have !entryPresent. The +// search path for `key` will have maxVersion at least `writeVersion` as a +// postcondition. +[[nodiscard]] Node *insert(Node **self_, std::span key, + int64_t writeVersion) { for (;;) { auto &self = *self_; // Handle an existing partial key @@ -745,13 +757,7 @@ void insert(Node **self_, std::span key, int64_t writeVersion) { self->maxVersion = std::max(self->maxVersion, writeVersion); if (key.size() == 0) { - auto l = lastLeq(self, key); - self->entryPresent = true; - self->entry.pointVersion = writeVersion; - assert(l.n != nullptr); - assert(l.n->entryPresent); - self->entry.rangeVersion = l.n->entry.rangeVersion; - return; + return self; } auto &child = getOrCreateChild(self, key.front()); if (!child) { @@ -812,8 +818,17 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl { const auto &w = writes[i]; // TODO support non-point writes assert(w.end.len == 0); - insert(&root, std::span(w.begin.p, w.begin.len), - w.writeVersion); + auto *n = insert(&root, std::span(w.begin.p, w.begin.len), + w.writeVersion); + if (!n->entryPresent) { + auto *p = prevLogical(n); + assert(p != nullptr); + n->entryPresent = true; + n->entry.pointVersion = w.writeVersion; + n->entry.rangeVersion = p->entry.rangeVersion; + } else { + n->entry.pointVersion = std::max(n->entry.pointVersion, w.writeVersion); + } } } void setOldestVersion(int64_t oldestVersion) {