Preserve finger after insert

This commit is contained in:
2024-05-24 14:17:11 -07:00
parent d51c58e6d5
commit d11150926b

View File

@@ -615,9 +615,10 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
// If `val` is set, then this is a point mutation at `latestVersion`.
// Otherwise it's the end of a range mutation at `latestVersion`.
void insert(Key key, std::optional<Val> val) {
Finger finger;
// `finger` becomes the search path of `key`
void insert(Key key, std::optional<Val> val, Finger &finger) {
bool ignored;
finger.clear();
finger.push(latestRoot, ignored);
bool inserted;
@@ -674,7 +675,7 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
}
// Prepare new node
uint32_t node = newNode(
const uint32_t node = newNode(
pointVersion, rangeVersion, key.p, key.len, val->p, val->len,
inserted ? gRandom.next() : mm.base[finger.backNode()].entry->priority);
if (!inserted) {
@@ -684,9 +685,34 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
n.pointer[1] = child<std::memory_order_relaxed>(finger.backNode(), true,
latestVersion);
}
finger.backNodeRef() = node;
uint32_t oldSize = finger.searchPathSize();
// Rotate and propagate up the search path
if (inserted) {
// Rotate
for (;;) {
const uint32_t node = finger.backNode();
oldSize = finger.searchPathSize();
if (finger.searchPathSize() == 1) {
// Made it to the root
latestRoot = node;
break;
}
const bool direction = finger.backDirection();
finger.pop();
auto &parent = finger.backNodeRef();
parent = update(parent, direction, node, latestVersion);
if (mm.base[node].entry->priority > mm.base[parent].entry->priority) {
rotate(parent, latestVersion, !direction);
} else {
break;
}
}
}
// Propagate
for (;;) {
const uint32_t node = finger.backNode();
if (finger.searchPathSize() == 1) {
// Made it to the root
latestRoot = node;
@@ -694,18 +720,24 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
}
const bool direction = finger.backDirection();
finger.pop();
auto parent = finger.backNode();
const auto old = finger.backNode();
auto &parent = finger.backNodeRef();
parent = update(parent, direction, node, latestVersion);
if (inserted &&
mm.base[node].entry->priority > mm.base[parent].entry->priority) {
rotate(parent, latestVersion, !direction);
} else {
if (parent == finger.backNode()) {
break;
}
if (parent == old) {
break;
}
node = parent;
}
finger.setSearchPathSizeUnsafe(oldSize);
#ifndef NDEBUG
{
Finger expected;
search<std::memory_order_relaxed>(key, latestRoot, latestVersion,
expected);
assert(finger == expected);
}
#endif
}
// Removes `finger` from the tree, and leaves `finger` pointing to insertion
@@ -861,23 +893,23 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
// TODO Improve ILP?
for (int i = 0; i < numMutations; ++i) {
const auto &m = mutations[i];
Finger iter;
switch (m.type) {
case Set: {
insert({m.param1, m.param1Len}, {{m.param2, m.param2Len}});
insert({m.param1, m.param1Len}, {{m.param2, m.param2Len}}, iter);
} break;
case Clear: {
insert({m.param1, m.param1Len}, {{nullptr, -1}});
insert({m.param1, m.param1Len}, {{nullptr, -1}}, iter);
if (m.param2Len > 0) {
Finger iter;
search<std::memory_order_relaxed>({m.param1, m.param1Len}, latestRoot,
latestVersion, iter);
move<std::memory_order_relaxed, true>(iter, latestVersion);
while (iter.searchPathSize() > 0 &&
mm.base[iter.backNode()] < Key{m.param2, m.param2Len}) {
remove(iter);
move<std::memory_order_relaxed, true>(iter, latestVersion);
}
insert({m.param2, m.param2Len}, {});
// TODO reuse finger? It should be one rank away from its insertion
// point
insert({m.param2, m.param2Len}, {}, iter);
}
} break;
default: // GCOVR_EXCL_LINE