Improve worst-case radix tree checkRangeRead

This commit is contained in:
2024-06-25 21:20:36 -07:00
parent 76d0785b33
commit 488c723726
2 changed files with 37 additions and 22 deletions

View File

@@ -1621,28 +1621,31 @@ downLeftSpine:
} }
} }
// Return the max version among all keys starting with the search path of n + // Return whether or not the max version among all keys starting with the search
// [child], where child in (begin, end). Does not account for the range version // path of n + [child], where child in (begin, end) is <= readVersion. Does not
// of firstGt(searchpath(n) + [end - 1]) // account for the range version of firstGt(searchpath(n) + [end - 1])
int64_t maxBetweenExclusive(Node *n, int begin, int end) { bool checkMaxBetweenExclusive(Node *n, int begin, int end,
int64_t readVersion) {
assume(-1 <= begin); assume(-1 <= begin);
assume(begin <= 256); assume(begin <= 256);
assume(-1 <= end); assume(-1 <= end);
assume(end <= 256); assume(end <= 256);
assume(begin < end); assume(begin < end);
int64_t result = std::numeric_limits<int64_t>::lowest();
{ {
int c = getChildGeq(n, begin + 1); int c = getChildGeq(n, begin + 1);
if (c >= 0 && c < end) { if (c >= 0 && c < end) {
auto *child = getChildExists(n, c); auto *child = getChildExists(n, c);
if (child->entryPresent) { if (child->entryPresent) {
result = std::max(result, child->entry.rangeVersion); if (!(child->entry.rangeVersion <= readVersion)) {
return false;
};
} }
begin = c; begin = c;
} else { } else {
return result; return true;
} }
} }
switch (n->getType()) { switch (n->getType()) {
case Type_Node0: // GCOVR_EXCL_LINE case Type_Node0: // GCOVR_EXCL_LINE
// We would have returned above, after not finding a child // We would have returned above, after not finding a child
@@ -1651,7 +1654,9 @@ int64_t maxBetweenExclusive(Node *n, int begin, int end) {
auto *self = static_cast<Node3 *>(n); auto *self = static_cast<Node3 *>(n);
for (int i = 0; i < self->numChildren && self->index[i] < end; ++i) { for (int i = 0; i < self->numChildren && self->index[i] < end; ++i) {
if (begin <= self->index[i]) { if (begin <= self->index[i]) {
result = std::max(result, self->children[i].childMaxVersion); if (self->children[i].childMaxVersion > readVersion) {
return false;
}
} }
} }
} break; } break;
@@ -1659,37 +1664,45 @@ int64_t maxBetweenExclusive(Node *n, int begin, int end) {
auto *self = static_cast<Node16 *>(n); auto *self = static_cast<Node16 *>(n);
for (int i = 0; i < self->numChildren && self->index[i] < end; ++i) { for (int i = 0; i < self->numChildren && self->index[i] < end; ++i) {
if (begin <= self->index[i]) { if (begin <= self->index[i]) {
result = std::max(result, self->children[i].childMaxVersion); if (self->children[i].childMaxVersion > readVersion) {
return false;
}
} }
} }
} break; } break;
case Type_Node48: { case Type_Node48: {
bool conflict[256] = {};
auto *self = static_cast<Node48 *>(n); auto *self = static_cast<Node48 *>(n);
self->bitSet.forEachInRange( self->bitSet.forEachInRange(
[&](int i) { [&](int i) {
result = conflict[i] =
std::max(result, self->children[self->index[i]].childMaxVersion); self->children[self->index[i]].childMaxVersion > readVersion;
}, },
begin, end); begin, end);
break; bool result = true;
for (auto c : conflict) {
result &= !c;
}
return result;
} }
case Type_Node256: { case Type_Node256: {
bool conflict[256] = {};
auto *self = static_cast<Node256 *>(n); auto *self = static_cast<Node256 *>(n);
self->bitSet.forEachInRange( self->bitSet.forEachInRange(
[&](int i) { [&](int i) {
result = std::max(result, self->children[i].childMaxVersion); conflict[i] = self->children[i].childMaxVersion > readVersion;
}, },
begin, end); begin, end);
break; bool result = true;
for (auto c : conflict) {
result &= !c;
}
return result;
} }
default: // GCOVR_EXCL_LINE default: // GCOVR_EXCL_LINE
__builtin_unreachable(); // GCOVR_EXCL_LINE __builtin_unreachable(); // GCOVR_EXCL_LINE
} }
#if DEBUG_VERBOSE && !defined(NDEBUG) return true;
fprintf(stderr, "At `%s', max version in (%02x, %02x) is %" PRId64 "\n",
getSearchPathPrintable(n).c_str(), begin, end, result);
#endif
return result;
} }
Vector<uint8_t> getSearchPath(Arena &arena, Node *n) { Vector<uint8_t> getSearchPath(Arena &arena, Node *n) {
@@ -1722,7 +1735,7 @@ bool checkRangeStartsWith(Node *n, std::span<const uint8_t> key, int begin,
#endif #endif
auto remaining = key; auto remaining = key;
if (remaining.size() == 0) { if (remaining.size() == 0) {
return maxBetweenExclusive(n, begin, end) <= readVersion; return checkMaxBetweenExclusive(n, begin, end, readVersion);
} }
auto *child = getChild(n, remaining[0]); auto *child = getChild(n, remaining[0]);
@@ -1821,7 +1834,7 @@ struct CheckRangeLeftSide {
} }
if (searchPathLen >= prefixLen) { if (searchPathLen >= prefixLen) {
if (maxBetweenExclusive(n, remaining[0], 256) > readVersion) { if (!checkMaxBetweenExclusive(n, remaining[0], 256, readVersion)) {
ok = false; ok = false;
return true; return true;
} }
@@ -1963,7 +1976,7 @@ struct CheckRangeRightSide {
return true; return true;
} }
if (maxBetweenExclusive(n, -1, remaining[0]) > readVersion) { if (!checkMaxBetweenExclusive(n, -1, remaining[0], readVersion)) {
ok = false; ok = false;
return true; return true;
} }

View File

@@ -1,3 +1,5 @@
___stack_chk_fail
___stack_chk_guard
__tlv_bootstrap __tlv_bootstrap
_abort _abort
_bzero _bzero