diff --git a/ConflictSet.cpp b/ConflictSet.cpp index 26b50c0..b82a388 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -2883,56 +2883,65 @@ checkMaxBetweenExclusiveImpl(Node *n, int begin, int end, InternalVersionT readVersion, ReadContext *); #endif +// Consume the partial key of `self` if it exists, and update `self` and `key` +// such that `self` is along the search path of `key`, and has maxVersion +// `writeVersion` +void consumePartialKey(Node *&self, std::span &key, + InternalVersionT writeVersion, WriteContext *tls, + ConflictSet::Impl *impl) { + if (self->partialKeyLen > 0) { + // Handle an existing partial key + int commonLen = std::min(self->partialKeyLen, key.size()); + int partialKeyIndex = + longestCommonPrefix(self->partialKey(), key.data(), commonLen); + if (partialKeyIndex < self->partialKeyLen) { + auto *old = self; + InternalVersionT oldMaxVersion = + exchangeMaxVersion(old, writeVersion, impl); + + // *self will have one child (old) + auto *newSelf = tls->allocate(partialKeyIndex); + + newSelf->parent = old->parent; + newSelf->parentsIndex = old->parentsIndex; + newSelf->partialKeyLen = partialKeyIndex; + newSelf->entryPresent = false; + newSelf->numChildren = 1; + + memcpy(newSelf->partialKey(), old->partialKey(), newSelf->partialKeyLen); + + uint8_t oldDistinguishingByte = old->partialKey()[partialKeyIndex]; + old->parent = newSelf; + old->parentsIndex = oldDistinguishingByte; + newSelf->index[0] = oldDistinguishingByte; + newSelf->children[0] = old; + newSelf->childMaxVersion[0] = oldMaxVersion; + self = newSelf; + + memmove(old->partialKey(), old->partialKey() + partialKeyIndex + 1, + old->partialKeyLen - (partialKeyIndex + 1)); + old->partialKeyLen -= partialKeyIndex + 1; + + // We would consider decreasing capacity here, but we can't invalidate + // old since it's not on the search path. setOldestVersion will clean it + // up. + } + key = key.subspan(partialKeyIndex, key.size() - partialKeyIndex); + } +} + // Returns a pointer to the newly inserted node. Caller must set // `entryPresent`, and `entry` fields. All nodes along the search path of the // result will have `maxVersion` set to `writeVersion` as a postcondition. Nodes // along the search path may be invalidated. -[[nodiscard]] Node *insert(Node **self, std::span key, - InternalVersionT writeVersion, WriteContext *tls, - ConflictSet::Impl *impl) { +[[nodiscard]] +Node *insert(Node **self, std::span key, + InternalVersionT writeVersion, WriteContext *tls, + ConflictSet::Impl *impl) { for (;; ++tls->accum.insert_iterations) { - if ((*self)->partialKeyLen > 0) { - // Handle an existing partial key - int commonLen = std::min((*self)->partialKeyLen, key.size()); - int partialKeyIndex = - longestCommonPrefix((*self)->partialKey(), key.data(), commonLen); - if (partialKeyIndex < (*self)->partialKeyLen) { - auto *old = *self; - InternalVersionT oldMaxVersion = - exchangeMaxVersion(old, writeVersion, impl); - - // *self will have one child (old) - auto *newSelf = tls->allocate(partialKeyIndex); - - newSelf->parent = old->parent; - newSelf->parentsIndex = old->parentsIndex; - newSelf->partialKeyLen = partialKeyIndex; - newSelf->entryPresent = false; - newSelf->numChildren = 1; - - memcpy(newSelf->partialKey(), old->partialKey(), - newSelf->partialKeyLen); - - uint8_t oldDistinguishingByte = old->partialKey()[partialKeyIndex]; - old->parent = newSelf; - old->parentsIndex = oldDistinguishingByte; - newSelf->index[0] = oldDistinguishingByte; - newSelf->children[0] = old; - newSelf->childMaxVersion[0] = oldMaxVersion; - *self = newSelf; - - memmove(old->partialKey(), old->partialKey() + partialKeyIndex + 1, - old->partialKeyLen - (partialKeyIndex + 1)); - old->partialKeyLen -= partialKeyIndex + 1; - - // We would consider decreasing capacity here, but we can't invalidate - // old since it's not on the search path. setOldestVersion will clean it - // up. - } - key = key.subspan(partialKeyIndex, key.size() - partialKeyIndex); - } + consumePartialKey(*self, key, writeVersion, tls, impl); assert(maxVersion(*self, impl) <= writeVersion); setMaxVersion(*self, impl, writeVersion);