diff --git a/ConflictSet.cpp b/ConflictSet.cpp index 3873ba5..ca6de00 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -464,13 +464,107 @@ template void runSequential(std::span remaining) { } } +struct ReferenceImpl { + explicit ReferenceImpl(int64_t oldestVersion) : oldestVersion(oldestVersion) { + writeVersionMap[""] = oldestVersion; + } + void check(const ConflictSet::ReadRange *reads, ConflictSet::Result *results, + int count) const { + for (int i = 0; i < count; ++i) { + if (reads[i].readVersion < oldestVersion) { + results[i] = ConflictSet::TooOld; + continue; + } + auto begin = + std::string((const char *)reads[i].begin.p, reads[i].begin.len); + auto end = + reads[i].end.len == 0 + ? begin + std::string("\x00", 1) + : std::string((const char *)reads[i].end.p, reads[i].end.len); + int64_t maxVersion = oldestVersion; + for (auto iter = --writeVersionMap.upper_bound(begin), + endIter = writeVersionMap.lower_bound(end); + iter != endIter; ++iter) { + maxVersion = std::max(maxVersion, iter->second); + } + results[i] = maxVersion > reads[i].readVersion ? ConflictSet::Conflict + : ConflictSet::Commit; + } + } + void addWrites(const ConflictSet::WriteRange *writes, int count) { + for (int i = 0; i < count; ++i) { + auto begin = + std::string((const char *)writes[i].begin.p, writes[i].begin.len); + auto end = + writes[i].end.len == 0 + ? begin + std::string("\x00", 1) + : std::string((const char *)writes[i].end.p, writes[i].end.len); + auto writeVersion = writes[i].writeVersion; + auto prevVersion = (--writeVersionMap.upper_bound(end))->second; + for (auto iter = writeVersionMap.lower_bound(begin), + endIter = writeVersionMap.lower_bound(end); + iter != endIter;) { + iter = writeVersionMap.erase(iter); + } + writeVersionMap[begin] = writeVersion; + writeVersionMap[end] = prevVersion; + } + } + + void setOldestVersion(int64_t oldestVersion) { + this->oldestVersion = oldestVersion; + } + + void printLogical(std::string &result) { + for (const auto &[k, v] : writeVersionMap) { + std::string key; + for (uint8_t c : k) { + key += "x"; + key += "0123456789abcdef"[c / 16]; + key += "0123456789abcdef"[c % 16]; + } + result += key + " -> " + std::to_string(v) + "\n"; + } + } + + int64_t oldestVersion; + std::map writeVersionMap; +}; + +using Key = ConflictSet::Key; + +[[maybe_unused]] Key toKey(Arena &arena, int n) { + constexpr int kMaxLength = 8; + int i = kMaxLength; + uint8_t *itoaBuf = new (arena) uint8_t[kMaxLength]; + memset(itoaBuf, '0', kMaxLength); + do { + itoaBuf[--i] = "0123456789abcdef"[n % 16]; + n /= 16; + } while (n); + return Key{itoaBuf, kMaxLength}; +} + +[[maybe_unused]] Key toKeyAfter(Arena &arena, int n) { + constexpr int kMaxLength = 8; + int i = kMaxLength; + uint8_t *itoaBuf = new (arena) uint8_t[kMaxLength + 1]; + memset(itoaBuf, '0', kMaxLength); + itoaBuf[kMaxLength] = 0; + do { + itoaBuf[--i] = "0123456789abcdef"[n % 16]; + n /= 16; + } while (n); + return Key{itoaBuf, kMaxLength + 1}; +} + // ==================== END UTILITIES IMPL ==================== +// ==================== BEGIN IMPLEMENTATION ==================== + #define SHOW_PRIORITY 0 #define DEBUG 0 -using Key = ConflictSet::Key; - static auto operator<=>(const Key &lhs, const Key &rhs) { const int minLen = std::min(lhs.len, rhs.len); const int c = memcmp(lhs.p, rhs.p, minLen); @@ -738,34 +832,7 @@ void lastLeqMulti(Arena &arena, Node *root, std::span keys, } } -[[maybe_unused]] Key toKey(Arena &arena, int n) { - constexpr int kMaxLength = 8; - int i = kMaxLength; - uint8_t *itoaBuf = new (arena) uint8_t[kMaxLength]; - memset(itoaBuf, '0', kMaxLength); - do { - itoaBuf[--i] = "0123456789abcdef"[n % 16]; - n /= 16; - } while (n); - return Key{itoaBuf, kMaxLength}; -} - -[[maybe_unused]] Key toKeyAfter(Arena &arena, int n) { - constexpr int kMaxLength = 8; - int i = kMaxLength; - uint8_t *itoaBuf = new (arena) uint8_t[kMaxLength + 1]; - memset(itoaBuf, '0', kMaxLength); - itoaBuf[kMaxLength] = 0; - do { - itoaBuf[--i] = "0123456789abcdef"[n % 16]; - n /= 16; - } while (n); - return Key{itoaBuf, kMaxLength + 1}; -} - // Recompute maxVersion, and propagate up the tree as necessary -// TODO interleave this? Will require careful analysis for correctness, and the -// performance gains may not be worth it. void updateMaxVersion(Node *n) { for (;;) { int64_t maxVersion = std::max(n->pointVersion, n->rangeVersion); @@ -847,7 +914,6 @@ void rotate(Node **node, bool dir) { return expected; } -template bool checkCorrectness(Node *node, ReferenceImpl &refImpl) { bool success = true; // Check bst invariant @@ -1073,6 +1139,8 @@ struct __attribute__((__visibility__("hidden"))) ConflictSet::Impl { } }; +// ==================== END IMPLEMENTATION ==================== + void ConflictSet::check(const ReadRange *reads, Result *results, int count) const { return impl->check(reads, results, count); @@ -1140,73 +1208,6 @@ namespace std { void __throw_length_error(const char *) { __builtin_unreachable(); } } // namespace std -struct ReferenceImpl { - explicit ReferenceImpl(int64_t oldestVersion) : oldestVersion(oldestVersion) { - writeVersionMap[""] = oldestVersion; - } - void check(const ConflictSet::ReadRange *reads, ConflictSet::Result *results, - int count) const { - for (int i = 0; i < count; ++i) { - if (reads[i].readVersion < oldestVersion) { - results[i] = ConflictSet::TooOld; - continue; - } - auto begin = - std::string((const char *)reads[i].begin.p, reads[i].begin.len); - auto end = - reads[i].end.len == 0 - ? begin + std::string("\x00", 1) - : std::string((const char *)reads[i].end.p, reads[i].end.len); - int64_t maxVersion = oldestVersion; - for (auto iter = --writeVersionMap.upper_bound(begin), - endIter = writeVersionMap.lower_bound(end); - iter != endIter; ++iter) { - maxVersion = std::max(maxVersion, iter->second); - } - results[i] = maxVersion > reads[i].readVersion ? ConflictSet::Conflict - : ConflictSet::Commit; - } - } - void addWrites(const ConflictSet::WriteRange *writes, int count) { - for (int i = 0; i < count; ++i) { - auto begin = - std::string((const char *)writes[i].begin.p, writes[i].begin.len); - auto end = - writes[i].end.len == 0 - ? begin + std::string("\x00", 1) - : std::string((const char *)writes[i].end.p, writes[i].end.len); - auto writeVersion = writes[i].writeVersion; - auto prevVersion = (--writeVersionMap.upper_bound(end))->second; - for (auto iter = writeVersionMap.lower_bound(begin), - endIter = writeVersionMap.lower_bound(end); - iter != endIter;) { - iter = writeVersionMap.erase(iter); - } - writeVersionMap[begin] = writeVersion; - writeVersionMap[end] = prevVersion; - } - } - - void setOldestVersion(int64_t oldestVersion) { - this->oldestVersion = oldestVersion; - } - - void printLogical(std::string &result) { - for (const auto &[k, v] : writeVersionMap) { - std::string key; - for (uint8_t c : k) { - key += "x"; - key += "0123456789abcdef"[c / 16]; - key += "0123456789abcdef"[c % 16]; - } - result += key + " -> " + std::to_string(v) + "\n"; - } - } - - int64_t oldestVersion; - std::map writeVersionMap; -}; - #ifdef ENABLE_TESTS int main(void) { int64_t writeVersion = 0;