diff --git a/ConflictSet.cpp b/ConflictSet.cpp index 491ce01..46b034a 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -294,6 +294,8 @@ struct Node48 : Node { int8_t nextFree; int8_t index[256]; Child children[kMaxNodes]; + // Max of each "page" of 16 children + int64_t maxOfMax[16]; uint8_t *partialKey() { return (uint8_t *)(this + 1); } @@ -417,6 +419,7 @@ inline void Node48::copyChildrenAndKeyFrom(const Node16 &other) { children[i] = other.children[i]; assert(children[i].child->parent == &other); children[i].child->parent = this; + maxOfMax[x >> 4] = std::max(maxOfMax[x >> 4], children[i].childMaxVersion); ++i; } } @@ -431,6 +434,7 @@ inline void Node48::copyChildrenAndKeyFrom(const Node48 &other) { assert(children[i].child->parent == &other); children[i].child->parent = this; } + memcpy(maxOfMax, other.maxOfMax, sizeof(maxOfMax)); memcpy(partialKey(), &other + 1, partialKeyLen); } @@ -453,6 +457,7 @@ inline void Node48::copyChildrenAndKeyFrom(const Node256 &other) { ++i; }, 0, 256); + memcpy(maxOfMax, other.maxOfMax, sizeof(maxOfMax)); memcpy(partialKey(), &other + 1, partialKeyLen); } @@ -467,10 +472,9 @@ inline void Node256::copyChildrenAndKeyFrom(const Node48 &other) { children[c] = other.children[other.index[c]]; assert(children[c].child->parent == &other); children[c].child->parent = this; - maxOfMax[c >> 4] = - std::max(maxOfMax[c >> 4], children[c].childMaxVersion); }, 0, 256); + memcpy(maxOfMax, other.maxOfMax, sizeof(maxOfMax)); memcpy(partialKey(), &other + 1, partialKeyLen); } @@ -571,7 +575,7 @@ template struct BoundedFreeListAllocator { if constexpr (!std::is_same_v) { memset(result->children, 0, sizeof(result->children)); } - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v || std::is_same_v) { memset(result->maxOfMax, 0, sizeof(result->maxOfMax)); } return result; @@ -1688,13 +1692,37 @@ bool checkMaxBetweenExclusive(Node *n, int begin, int end, } break; case Type_Node48: { auto *self = static_cast(n); + // Check the first page + if (self->maxOfMax[begin >> 4] > readVersion) { + bool result = true; + self->bitSet.forEachInRange( + [&](int i) { + result &= + self->children[self->index[i]].childMaxVersion <= readVersion; + }, + begin, std::min((begin & ~15) + 16, end)); + if (!result) { + return result; + } + } + // Check the last page + if (end >= 1 && self->maxOfMax[(end - 1) >> 4] > readVersion) { + bool result = true; + self->bitSet.forEachInRange( + [&](int i) { + result &= + self->children[self->index[i]].childMaxVersion <= readVersion; + }, + std::max(begin, end & ~15), end); + if (!result) { + return result; + } + } + // Check inner pages bool result = true; - self->bitSet.forEachInRange( - [&](int i) { - result &= - self->children[self->index[i]].childMaxVersion <= readVersion; - }, - begin, end); + for (int i = (begin >> 4) + 1; i < (end - 1) >> 4; ++i) { + result &= self->maxOfMax[i] <= readVersion; + } return result; } case Type_Node256: { @@ -2656,6 +2684,7 @@ void setMaxVersion(Node *n, ConflictSet::Impl *impl, int64_t newMax) { auto *n48 = static_cast(n); assert(n48->bitSet.test(index)); n48->children[n48->index[index]].childMaxVersion = newMax; + n48->maxOfMax[index >> 4] = std::max(n48->maxOfMax[index >> 4], newMax); return; } case Type_Node256: {