Use mutationIndex instead of materializeClearEndingHere

This commit is contained in:
2024-05-09 16:12:54 -07:00
parent 5111834a0b
commit bb12e92635

View File

@@ -812,9 +812,17 @@ struct VersionedMap::Iterator::Impl {
int64_t version;
const VersionedMap::Impl *map;
int cmp;
// True if this is a point mutation and a range mutation, and we're
// materializing the range mutation instead of the point mutation.
bool materializeClearEndingHere = false;
// State for materializing mutations associated with the entry at `finger`.
// Cases:
// - If finger is a set and the end of a clear, then mutation[0] is the clear
// and mutation[1] is the set.
// - If finger is a set and not the end of a clear, then mutation[0] is the
// set
// - If finger is a clear and not a set, then mutation[0] is the clear
int mutationCount;
int mutationIndex;
VersionedMutation mutations[2];
};
VersionedMap::Iterator::~Iterator() {
@@ -850,48 +858,78 @@ VersionedMap::Iterator::operator=(Iterator &&other) noexcept {
return *this;
}
// TODO once we have good testing for this, design a state machine that fuses
// adjacent point and range clears at the same version.
VersionedMap::Iterator::VersionedMutation
VersionedMap::Iterator::operator*() const {
assert(impl->finger.backNode() != 0);
assert(impl->finger.searchPathSize() != 0);
const auto &entry = *impl->map->mm.base[impl->finger.backNode()].entry;
if (impl->materializeClearEndingHere) {
assert(entry.pointMutation() && entry.clearTo());
auto prev = *this;
--prev;
const auto &prevEntry =
*prev.impl->map->mm.base[prev.impl->finger.backNode()].entry;
return {prevEntry.getKey(), entry.getKey(), prevEntry.keyLen + 1,
entry.keyLen, Clear, entry.rangeVersion};
assert(impl->mutationIndex < impl->mutationCount);
assert(impl->mutationIndex >= 0);
return impl->mutations[impl->mutationIndex];
}
void materializeMutations(VersionedMap::Iterator::Impl *impl, const Entry *prev,
const Entry *next) {
if (prev == nullptr) {
auto copy = impl->finger;
impl->map->move<std::memory_order_acquire>(copy, impl->version, false);
if (copy.searchPathSize() > 0) {
prev = impl->map->mm.base[copy.backNode()].entry;
} else {
assert(!impl->map->mm.base[impl->finger.backNode()].entry->clearTo());
}
}
if (entry.valLen >= 0) {
return {entry.getKey(), entry.getVal(), entry.keyLen, entry.valLen, Set,
entry.pointVersion};
} else {
return {entry.getKey(), nullptr, entry.keyLen, 0,
Clear, entry.pointVersion};
if (next == nullptr) {
auto copy = impl->finger;
impl->map->move<std::memory_order_acquire>(copy, impl->version, true);
if (copy.searchPathSize() > 0) {
next = impl->map->mm.base[copy.backNode()].entry;
}
}
const auto &entry = *impl->map->mm.base[impl->finger.backNode()].entry;
impl->mutationCount = 0;
if (entry.clearTo()) {
impl->mutations[impl->mutationCount++] = {
prev->getKey(),
entry.getKey(),
prev->pointMutation() && prev->valLen < 0 &&
prev->pointVersion == entry.rangeVersion
? prev->keyLen
: prev->keyLen + 1,
entry.keyLen,
VersionedMap::Clear,
entry.rangeVersion};
}
if (entry.pointMutation()) {
if (entry.valLen < 0) {
if (next == nullptr ||
!(next->clearTo() && next->rangeVersion == entry.pointVersion)) {
impl->mutations[impl->mutationCount++] = {
entry.getKey(), nullptr, entry.keyLen, 0,
VersionedMap::Clear, entry.pointVersion};
}
} else {
impl->mutations[impl->mutationCount++] = {
entry.getKey(), entry.getVal(), entry.keyLen,
entry.valLen, VersionedMap::Set, entry.pointVersion};
}
}
}
VersionedMap::Iterator &VersionedMap::Iterator::operator++() {
const auto &entry = *impl->map->mm.base[impl->finger.backNode()].entry;
if (impl->materializeClearEndingHere) {
assert(entry.pointMutation() && entry.clearTo());
impl->materializeClearEndingHere = false;
if (impl->mutationIndex < impl->mutationCount - 1) {
++impl->mutationIndex;
return *this;
}
impl->map->move<std::memory_order_acquire>(impl->finger, impl->version, true);
if (impl->finger.searchPathSize() > 0) {
do {
const auto &entry = *impl->map->mm.base[impl->finger.backNode()].entry;
impl->materializeClearEndingHere = entry.pointMutation() && entry.clearTo();
assert(entry.pointVersion <= impl->version);
assert(entry.rangeVersion <= impl->version);
} else {
impl->materializeClearEndingHere = false;
}
impl->map->move<std::memory_order_acquire>(impl->finger, impl->version,
true);
if (impl->finger.searchPathSize() > 0) {
materializeMutations(impl, &entry, nullptr);
}
} while (impl->mutationCount == 0);
impl->mutationIndex = 0;
return *this;
}
@@ -903,16 +941,20 @@ VersionedMap::Iterator VersionedMap::Iterator::operator++(int) {
}
VersionedMap::Iterator &VersionedMap::Iterator::operator--() {
const auto &entry = *impl->map->mm.base[impl->finger.backNode()].entry;
if (entry.pointMutation() && entry.clearTo() &&
!impl->materializeClearEndingHere) {
impl->materializeClearEndingHere = true;
if (impl->mutationIndex > 0) {
--impl->mutationIndex;
return *this;
}
impl->map->move<std::memory_order_acquire>(impl->finger, impl->version,
false);
impl->materializeClearEndingHere = false;
do {
const auto &entry = *impl->map->mm.base[impl->finger.backNode()].entry;
impl->map->move<std::memory_order_acquire>(impl->finger, impl->version,
false);
if (impl->finger.searchPathSize() > 0) {
materializeMutations(impl, nullptr, &entry);
}
} while (impl->mutationCount == 0);
impl->mutationIndex = impl->mutationCount - 1;
return *this;
}
@@ -930,8 +972,7 @@ bool VersionedMap::Iterator::operator==(const Iterator &other) const {
return impl->finger.searchPathSize() == other.impl->finger.searchPathSize();
}
return impl->finger.backNode() == other.impl->finger.backNode() &&
impl->materializeClearEndingHere ==
other.impl->materializeClearEndingHere;
impl->mutationIndex == other.impl->mutationIndex;
}
void VersionedMap::Impl::firstGeq(const Key *key, const int64_t *version,
@@ -960,9 +1001,6 @@ void VersionedMap::Impl::firstGeq(const Key *key, const int64_t *version,
move<std::memory_order_acquire>(finger, version[i], true);
if (finger.searchPathSize() > 0) {
assert(finger.backNode() != 0);
const auto &entry = *mm.base[finger.backNode()].entry;
iterator[i].impl->materializeClearEndingHere =
entry.clearTo() && entry.pointMutation();
}
} else {
iterator[i].impl->cmp = 0;
@@ -971,6 +1009,24 @@ void VersionedMap::Impl::firstGeq(const Key *key, const int64_t *version,
iterator[i].impl->finger = finger;
iterator[i].impl->version = version[i];
iterator[i].impl->map = this;
const Entry *prev = nullptr;
for (;;) {
if (iterator[i].impl->finger.searchPathSize() > 0) {
materializeMutations(iterator[i].impl, prev, nullptr);
if (iterator[i].impl->mutationCount > 0) {
break;
}
} else {
break;
}
prev = iterator[i]
.impl->map->mm.base[iterator[i].impl->finger.backNode()]
.entry;
iterator[i].impl->map->move<std::memory_order_acquire>(
iterator[i].impl->finger, iterator[i].impl->version, true);
}
iterator[i].impl->mutationIndex = 0;
}
}
@@ -1003,7 +1059,23 @@ VersionedMap::Iterator VersionedMap::begin(int64_t version) const {
}
}
result.impl->map = impl;
result.impl->materializeClearEndingHere = false;
const Entry *prev = nullptr;
for (;;) {
if (result.impl->finger.searchPathSize() > 0) {
materializeMutations(result.impl, prev, nullptr);
if (result.impl->mutationCount > 0) {
break;
}
} else {
break;
}
prev = result.impl->map->mm.base[result.impl->finger.backNode()].entry;
result.impl->map->move<std::memory_order_acquire>(
result.impl->finger, result.impl->version, true);
}
result.impl->mutationIndex = 0;
result.impl->version = version;
return result;
}
@@ -1013,7 +1085,7 @@ VersionedMap::Iterator VersionedMap::end(int64_t version) const {
result.impl = new (malloc(sizeof(Iterator::Impl))) Iterator::Impl();
result.impl->cmp = 1;
result.impl->map = impl;
result.impl->materializeClearEndingHere = false;
result.impl->mutationIndex = 0;
result.impl->version = version;
return result;
}
@@ -1101,7 +1173,7 @@ int main() {
};
versionedMap.addMutations(m, sizeof(m) / sizeof(m[0]), 3);
}
const int64_t v = 2;
const int64_t v = 3;
cast(versionedMap)->printInOrder(v);
weaselab::VersionedMap::Key k = {(const uint8_t *)"a", 1};
weaselab::VersionedMap::Iterator iter;