Move consumePartialKey, and allow empty partial key
This commit is contained in:
100
ConflictSet.cpp
100
ConflictSet.cpp
@@ -1125,6 +1125,53 @@ Node *getFirstChildExists(Node *self) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Consume any partial key of `self`, and update `self` and
|
||||||
|
// `key` such that `self` is along the search path of `key`
|
||||||
|
void consumePartialKey(Node *&self, std::span<const uint8_t> &key,
|
||||||
|
InternalVersionT writeVersion, WriteContext *tls) {
|
||||||
|
if (self->partialKeyLen == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Handle an existing partial key
|
||||||
|
int commonLen = std::min<int>(self->partialKeyLen, key.size());
|
||||||
|
int partialKeyIndex =
|
||||||
|
longestCommonPrefix(self->partialKey(), key.data(), commonLen);
|
||||||
|
if (partialKeyIndex < self->partialKeyLen) {
|
||||||
|
auto *old = self;
|
||||||
|
// Since root cannot have a partial key
|
||||||
|
assert(old->parent != nullptr);
|
||||||
|
InternalVersionT oldMaxVersion = exchangeMaxVersion(old, writeVersion);
|
||||||
|
|
||||||
|
// *self will have one child (old)
|
||||||
|
auto *newSelf = tls->allocate<Node3>(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);
|
||||||
|
}
|
||||||
|
|
||||||
// Caller is responsible for assigning a non-null pointer to the returned
|
// Caller is responsible for assigning a non-null pointer to the returned
|
||||||
// reference if null. Updates child's max version to `newMaxVersion` if child
|
// reference if null. Updates child's max version to `newMaxVersion` if child
|
||||||
// exists but does not have a partial key.
|
// exists but does not have a partial key.
|
||||||
@@ -2743,51 +2790,6 @@ checkMaxBetweenExclusiveImpl<true>(Node *n, int begin, int end,
|
|||||||
InternalVersionT readVersion, ReadContext *);
|
InternalVersionT readVersion, ReadContext *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Consume the partial key of `self` (which must exist), and update `self` and
|
|
||||||
// `key` such that `self` is along the search path of `key`
|
|
||||||
void consumePartialKey(Node *&self, std::span<const uint8_t> &key,
|
|
||||||
InternalVersionT writeVersion, WriteContext *tls) {
|
|
||||||
assert(self->partialKeyLen > 0);
|
|
||||||
// Handle an existing partial key
|
|
||||||
int commonLen = std::min<int>(self->partialKeyLen, key.size());
|
|
||||||
int partialKeyIndex =
|
|
||||||
longestCommonPrefix(self->partialKey(), key.data(), commonLen);
|
|
||||||
if (partialKeyIndex < self->partialKeyLen) {
|
|
||||||
auto *old = self;
|
|
||||||
// Since root cannot have a partial key
|
|
||||||
assert(old->parent != nullptr);
|
|
||||||
InternalVersionT oldMaxVersion = exchangeMaxVersion(old, writeVersion);
|
|
||||||
|
|
||||||
// *self will have one child (old)
|
|
||||||
auto *newSelf = tls->allocate<Node3>(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 the pointer to the newly inserted node in the tree. Caller
|
// Returns a pointer the pointer to the newly inserted node in the tree. Caller
|
||||||
// must set `entryPresent`, and `entry` fields. All nodes along the search path
|
// must set `entryPresent`, and `entry` fields. All nodes along the search path
|
||||||
// of the result will have `maxVersion` set to `writeVersion` as a
|
// of the result will have `maxVersion` set to `writeVersion` as a
|
||||||
@@ -2814,11 +2816,9 @@ Node **insert(Node **self, std::span<const uint8_t> key,
|
|||||||
|
|
||||||
self = &child;
|
self = &child;
|
||||||
|
|
||||||
if ((*self)->partialKeyLen > 0) {
|
consumePartialKey(*self, key, writeVersion, tls);
|
||||||
consumePartialKey(*self, key, writeVersion, tls);
|
assert(maxVersion(*self, impl) <= writeVersion);
|
||||||
assert(maxVersion(*self, impl) <= writeVersion);
|
setMaxVersion(*self, impl, writeVersion);
|
||||||
setMaxVersion(*self, impl, writeVersion);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user