From bb12e926358e8e1d4ee809c137d70d33977d59ce Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Thu, 9 May 2024 16:12:54 -0700 Subject: [PATCH] Use mutationIndex instead of materializeClearEndingHere --- VersionedMap.cpp | 168 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 120 insertions(+), 48 deletions(-) diff --git a/VersionedMap.cpp b/VersionedMap.cpp index 9733b94..7b05150 100644 --- a/VersionedMap.cpp +++ b/VersionedMap.cpp @@ -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(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(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(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(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(impl->finger, impl->version, - false); - impl->materializeClearEndingHere = false; + do { + const auto &entry = *impl->map->mm.base[impl->finger.backNode()].entry; + impl->map->move(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(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( + 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( + 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;