Allow search to search at any version

And re-use non-null iterators in firstGeq
This commit is contained in:
2024-05-09 14:25:03 -07:00
parent 6baf069445
commit 5111834a0b

View File

@@ -368,6 +368,10 @@ struct Finger {
assert(searchPathSize_ > 0); assert(searchPathSize_ > 0);
--searchPathSize_; --searchPathSize_;
} }
uint32_t root() const {
assert(searchPathSize_ > 0);
return searchPath[0];
}
uint32_t backNode() const { uint32_t backNode() const {
assert(searchPathSize_ > 0); assert(searchPathSize_ > 0);
return searchPath[searchPathSize_ - 1]; return searchPath[searchPathSize_ - 1];
@@ -530,10 +534,15 @@ struct VersionedMap::Impl {
int len; int len;
}; };
template <std::memory_order kOrder> Finger search(Key key, int64_t at) const { template <std::memory_order kOrder, class T>
Finger search(Key key, T root, int64_t version) const {
static_assert(std::is_same_v<T, uint32_t>);
Finger finger; Finger finger;
if (root == 0) {
return finger;
}
bool ignored; bool ignored;
finger.push(latestRoot, ignored); finger.push(root, ignored);
// Initialize finger to the search path of `key` // Initialize finger to the search path of `key`
for (;;) { for (;;) {
@@ -546,7 +555,7 @@ struct VersionedMap::Impl {
// No duplicates // No duplicates
break; break;
} }
finger.push(child<kOrder>(n, c > 0, latestVersion), c > 0); finger.push(child<kOrder>(n, c > 0, version), c > 0);
} }
return finger; return finger;
} }
@@ -744,8 +753,8 @@ struct VersionedMap::Impl {
case Clear: { case Clear: {
insert({m.param1, m.param1Len}, {{nullptr, -1}}); insert({m.param1, m.param1Len}, {{nullptr, -1}});
if (m.param2Len > 0) { if (m.param2Len > 0) {
auto iter = search<std::memory_order_relaxed>({m.param1, m.param1Len}, auto iter = search<std::memory_order_relaxed>(
latestVersion); {m.param1, m.param1Len}, latestRoot, latestVersion);
move<std::memory_order_relaxed>(iter, latestVersion, true); move<std::memory_order_relaxed>(iter, latestVersion, true);
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}) {
@@ -755,6 +764,7 @@ struct VersionedMap::Impl {
} }
} break; } break;
default: // GCOVR_EXCL_LINE default: // GCOVR_EXCL_LINE
assert(false); // GCOVR_EXCL_LINE
__builtin_unreachable(); // GCOVR_EXCL_LINE __builtin_unreachable(); // GCOVR_EXCL_LINE
} }
} }
@@ -874,10 +884,14 @@ VersionedMap::Iterator &VersionedMap::Iterator::operator++() {
} }
impl->map->move<std::memory_order_acquire>(impl->finger, impl->version, true); impl->map->move<std::memory_order_acquire>(impl->finger, impl->version, true);
impl->materializeClearEndingHere = if (impl->finger.searchPathSize() > 0) {
impl->finger.searchPathSize() > 0 && const auto &entry = *impl->map->mm.base[impl->finger.backNode()].entry;
impl->map->mm.base[impl->finger.backNode()].entry->pointMutation() && impl->materializeClearEndingHere = entry.pointMutation() && entry.clearTo();
impl->map->mm.base[impl->finger.backNode()].entry->clearTo(); assert(entry.pointVersion <= impl->version);
assert(entry.rangeVersion <= impl->version);
} else {
impl->materializeClearEndingHere = false;
}
return *this; return *this;
} }
@@ -923,13 +937,21 @@ bool VersionedMap::Iterator::operator==(const Iterator &other) const {
void VersionedMap::Impl::firstGeq(const Key *key, const int64_t *version, void VersionedMap::Impl::firstGeq(const Key *key, const int64_t *version,
Iterator *iterator, int count) const { Iterator *iterator, int count) const {
// TODO ILP! // TODO ILP!
auto handle = roots.getThreadSafeHandle();
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
// TODO re-use root if passed-in iterator version matches
auto finger = search<std::memory_order_acquire>(key[i], version[i]); uint32_t root;
if (iterator[i].impl != nullptr) { if (iterator[i].impl != nullptr) {
root = iterator[i].impl->version == version[i]
? iterator[i].impl->finger.root()
: handle.rootForVersion(version[i]);
iterator[i].impl->~Impl(); iterator[i].impl->~Impl();
new (iterator[i].impl) Iterator::Impl();
} else {
root = handle.rootForVersion(version[i]);
iterator[i].impl = new (malloc(sizeof(Iterator::Impl))) Iterator::Impl();
} }
iterator[i].impl = new (malloc(sizeof(Iterator::Impl))) Iterator::Impl(); auto finger = search<std::memory_order_acquire>(key[i], root, version[i]);
if (finger.searchPathSize() == 0) { if (finger.searchPathSize() == 0) {
iterator[i].impl->cmp = 1; iterator[i].impl->cmp = 1;
@@ -937,6 +959,7 @@ void VersionedMap::Impl::firstGeq(const Key *key, const int64_t *version,
iterator[i].impl->cmp = 1; iterator[i].impl->cmp = 1;
move<std::memory_order_acquire>(finger, version[i], true); move<std::memory_order_acquire>(finger, version[i], true);
if (finger.searchPathSize() > 0) { if (finger.searchPathSize() > 0) {
assert(finger.backNode() != 0);
const auto &entry = *mm.base[finger.backNode()].entry; const auto &entry = *mm.base[finger.backNode()].entry;
iterator[i].impl->materializeClearEndingHere = iterator[i].impl->materializeClearEndingHere =
entry.clearTo() && entry.pointMutation(); entry.clearTo() && entry.pointMutation();
@@ -974,7 +997,7 @@ VersionedMap::Iterator VersionedMap::begin(int64_t version) const {
result.impl->finger.pop(); result.impl->finger.pop();
} else { } else {
uint32_t c; uint32_t c;
while ((c = impl->child<std::memory_order_relaxed>( while ((c = impl->child<std::memory_order_acquire>(
result.impl->finger.backNode(), false, version)) != 0) { result.impl->finger.backNode(), false, version)) != 0) {
result.impl->finger.push(c, false); result.impl->finger.push(c, false);
} }
@@ -1048,6 +1071,8 @@ VersionedMap::Impl *cast(const VersionedMap &m) {
#ifdef ENABLE_MAIN #ifdef ENABLE_MAIN
#include <nanobench.h> #include <nanobench.h>
void breakpoint_me() {}
int main() { int main() {
{ {
weaselab::VersionedMap versionedMap{0}; weaselab::VersionedMap versionedMap{0};
@@ -1076,11 +1101,14 @@ int main() {
}; };
versionedMap.addMutations(m, sizeof(m) / sizeof(m[0]), 3); versionedMap.addMutations(m, sizeof(m) / sizeof(m[0]), 3);
} }
const int64_t v = 3; const int64_t v = 2;
cast(versionedMap)->printInOrder(v); cast(versionedMap)->printInOrder(v);
weaselab::VersionedMap::Key k = {(const uint8_t *)"zz", 2}; weaselab::VersionedMap::Key k = {(const uint8_t *)"a", 1};
weaselab::VersionedMap::Iterator iter; weaselab::VersionedMap::Iterator iter;
versionedMap.firstGeq(&k, &v, &iter, 1); versionedMap.firstGeq(&k, &v, &iter, 1);
auto begin = versionedMap.begin(v);
assert(iter == begin);
breakpoint_me();
for (auto end = versionedMap.end(v); iter != end; ++iter) { for (auto end = versionedMap.end(v); iter != end; ++iter) {
const auto &m = *iter; const auto &m = *iter;
switch (m.type) { switch (m.type) {