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