Preserve finger after insert
This commit is contained in:
@@ -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
|
||||
|
Reference in New Issue
Block a user