Fix two node-copying bugs in update
This commit is contained in:
@@ -638,7 +638,8 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
|
||||
auto &c = mm.base[copy];
|
||||
c.entry = n.entry->addref();
|
||||
c.pointer[which] = child;
|
||||
c.pointer[!which] = n.pointer[!which];
|
||||
c.pointer[!which] =
|
||||
this->child<std::memory_order_relaxed>(node, !which, latestVersion);
|
||||
c.updated.store(false, std::memory_order_relaxed);
|
||||
c.updateVersion = version;
|
||||
assert(copy == 0 || copy >= kMinAddressable);
|
||||
@@ -649,11 +650,12 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
|
||||
// The reason these aren't data races is that concurrent readers are
|
||||
// reading < `version`
|
||||
if (updated && n.replacedPointer != which) {
|
||||
auto result = doCopy();
|
||||
// We can't update n.replacedPointer without introducing a data race
|
||||
// (unless we packed it into the atomic?) so we copy. pointer[2] becomes
|
||||
// unreachable, but need to tell the garbage collector.
|
||||
n.pointer[2] = 0;
|
||||
return doCopy();
|
||||
return result;
|
||||
} else if (updated) {
|
||||
n.pointer[2] = child;
|
||||
} else {
|
||||
@@ -808,12 +810,13 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
|
||||
void remove(Finger &finger) {
|
||||
|
||||
#ifndef NDEBUG
|
||||
uint32_t expected;
|
||||
Entry *expected;
|
||||
{
|
||||
Finger copy;
|
||||
finger.copyTo(copy);
|
||||
move<std::memory_order_relaxed>(copy, latestVersion, true);
|
||||
expected = copy.searchPathSize() > 0 ? copy.backNode() : 0;
|
||||
expected =
|
||||
copy.searchPathSize() > 0 ? mm.base[copy.backNode()].entry : nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -850,7 +853,7 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
|
||||
// propagate up the search path, all the way to the root since we may have
|
||||
// more rotations to do even if an update doesn't change a node pointer
|
||||
auto node = finger.backNode();
|
||||
const auto oldSize = finger.searchPathSize();
|
||||
const auto oldSize = finger.searchPathSize() - (node == 0);
|
||||
for (;;) {
|
||||
if (finger.searchPathSize() == 1) {
|
||||
// Made it to the root
|
||||
@@ -873,12 +876,17 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
|
||||
finger.push(c, false);
|
||||
}
|
||||
} else {
|
||||
move<std::memory_order_relaxed>(finger, latestVersion, true);
|
||||
while (finger.searchPathSize() > 1 && finger.backDirection() == true) {
|
||||
finger.pop();
|
||||
}
|
||||
finger.pop();
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (finger.searchPathSize() > 0) {
|
||||
assert(finger.backNode() == expected);
|
||||
assert(mm.base[finger.backNode()].entry == expected);
|
||||
} else {
|
||||
assert(expected == nullptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1342,7 +1350,7 @@ void VersionedMap::Impl::printInOrderHelper(int64_t version, uint32_t node,
|
||||
return;
|
||||
}
|
||||
printInOrderHelper(version,
|
||||
child<std::memory_order_relaxed>(node, false, version),
|
||||
child<std::memory_order_relaxed>(node, true, version),
|
||||
depth + 1);
|
||||
for (int i = 0; i < depth; ++i) {
|
||||
printf(" ");
|
||||
@@ -1360,7 +1368,7 @@ void VersionedMap::Impl::printInOrderHelper(int64_t version, uint32_t node,
|
||||
}
|
||||
printf("\n");
|
||||
VersionedMap::Impl::printInOrderHelper(
|
||||
version, child<std::memory_order_relaxed>(node, true, version),
|
||||
version, child<std::memory_order_relaxed>(node, false, version),
|
||||
depth + 1);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user