Allow search to search at any version
And re-use non-null iterators in firstGeq
This commit is contained in:
@@ -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) {
|
||||||
|
Reference in New Issue
Block a user