Fix lastLeq bug
This commit is contained in:
@@ -544,7 +544,9 @@ Node *&getOrCreateChild(Node *&self, uint8_t index) {
|
||||
}
|
||||
|
||||
// Precondition - an entry for index must exist in the node
|
||||
[[maybe_unused]] void eraseChild(Node *self, uint8_t index) {
|
||||
void eraseChild(Node *self, uint8_t index) {
|
||||
free(getChildExists(self, index));
|
||||
|
||||
if (self->type == Type::Node4) {
|
||||
auto *self4 = static_cast<Node4 *>(self);
|
||||
int nodeIndex = getNodeIndex(self4, index);
|
||||
@@ -654,7 +656,8 @@ std::string_view getSearchPath(Arena &arena, Node *n) {
|
||||
}
|
||||
std::reverse(result.begin(), result.end());
|
||||
if (result.size() > 0) {
|
||||
return std::string_view((const char *)&result[0], result.size()); // NOLINT
|
||||
return std::string_view((const char *)&result[0],
|
||||
result.size()); // NOLINT
|
||||
} else {
|
||||
return std::string_view();
|
||||
}
|
||||
@@ -672,8 +675,10 @@ Iterator lastLeq(Node *n, const std::span<const uint8_t> key) {
|
||||
}
|
||||
if (c > 0) {
|
||||
n = prevPhysical(n);
|
||||
goto scanBackward;
|
||||
} else {
|
||||
goto downRightSpine;
|
||||
}
|
||||
goto outerLoop;
|
||||
}
|
||||
if (commonLen == n->partialKeyLen) {
|
||||
// partial key matches
|
||||
@@ -682,7 +687,7 @@ Iterator lastLeq(Node *n, const std::span<const uint8_t> key) {
|
||||
// n is the first physical node greater than remaining, and there's no
|
||||
// eq node
|
||||
n = prevPhysical(n);
|
||||
goto outerLoop;
|
||||
goto scanBackward;
|
||||
}
|
||||
}
|
||||
{
|
||||
@@ -696,7 +701,7 @@ Iterator lastLeq(Node *n, const std::span<const uint8_t> key) {
|
||||
if (n->entryPresent) {
|
||||
return {n, 0};
|
||||
} else {
|
||||
goto outerLoop;
|
||||
goto scanBackward;
|
||||
}
|
||||
} else {
|
||||
int c = getChildLeq(n, remaining[0]);
|
||||
@@ -704,22 +709,29 @@ Iterator lastLeq(Node *n, const std::span<const uint8_t> key) {
|
||||
n = getChildExists(n, c);
|
||||
remaining = remaining.subspan(1, remaining.size() - 1);
|
||||
} else {
|
||||
// The physical node corresponding to search path `key` does not exist.
|
||||
// Let's find the physical node corresponding to the highest search key
|
||||
// (not necessarily present) less than key
|
||||
// Move down the right spine
|
||||
for (;;) {
|
||||
if (c >= 0) {
|
||||
n = getChildExists(n, c);
|
||||
} else {
|
||||
goto outerLoop;
|
||||
}
|
||||
c = getChildLeq(n, 255);
|
||||
if (c >= 0) {
|
||||
n = getChildExists(n, c);
|
||||
goto downRightSpine;
|
||||
} else {
|
||||
goto scanBackward;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
outerLoop:
|
||||
downRightSpine:
|
||||
// The physical node corresponding to search path `key` does not
|
||||
// exist. Let's find the physical node corresponding to the highest
|
||||
// search key (not necessarily present) less than key.
|
||||
// Move down the right spine
|
||||
for (;;) {
|
||||
int c = getChildLeq(n, 255);
|
||||
if (c >= 0) {
|
||||
n = getChildExists(n, c);
|
||||
} else {
|
||||
goto scanBackward;
|
||||
}
|
||||
}
|
||||
scanBackward:
|
||||
// Iterate backwards along existing physical nodes until we find a present
|
||||
// entry
|
||||
for (; !n->entryPresent; n = prevPhysical(n)) {
|
||||
@@ -802,6 +814,21 @@ void destroyTree(Node *root) {
|
||||
}
|
||||
}
|
||||
|
||||
void invalidateMax(Node *self) {
|
||||
int64_t expectedMax = std::numeric_limits<int64_t>::lowest();
|
||||
if (self->entryPresent) {
|
||||
expectedMax = std::max(expectedMax, self->entry.pointVersion);
|
||||
expectedMax = std::max(expectedMax, self->entry.rangeVersion);
|
||||
}
|
||||
for (int i = getChildGeq(self, 0); i >= 0; i = getChildGeq(self, i + 1)) {
|
||||
expectedMax = std::max(expectedMax, getChildExists(self, i)->maxVersion);
|
||||
}
|
||||
self->maxVersion = expectedMax;
|
||||
if (self->parent != nullptr) {
|
||||
invalidateMax(self->parent);
|
||||
}
|
||||
}
|
||||
|
||||
struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
void check(const ReadRange *reads, Result *result, int count) const {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
@@ -816,8 +843,8 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
lastLeq(root, std::span<const uint8_t>(r.begin.p, r.begin.len));
|
||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||
Arena arena;
|
||||
printf("LastLeq for `%s' got `%s'\n", printable(r.begin).c_str(),
|
||||
printable(getSearchPath(arena, l)).c_str());
|
||||
fprintf(stderr, "LastLeq for `%s' got `%s'\n", printable(r.begin).c_str(),
|
||||
printable(getSearchPath(arena, l)).c_str());
|
||||
#endif
|
||||
assert(l != nullptr);
|
||||
assert(l->entryPresent);
|
||||
@@ -839,22 +866,25 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
n->entryPresent = true;
|
||||
n->entry.pointVersion = p->entry.rangeVersion;
|
||||
n->entry.rangeVersion = p->entry.rangeVersion;
|
||||
n->maxVersion = p->entry.rangeVersion;
|
||||
}
|
||||
|
||||
auto *end = n;
|
||||
n = insert(&root, std::span<const uint8_t>(w.begin.p, w.begin.len),
|
||||
w.writeVersion);
|
||||
std::numeric_limits<int64_t>::lowest());
|
||||
auto *begin = n;
|
||||
n->entryPresent = true;
|
||||
n->entry.pointVersion = w.writeVersion;
|
||||
n->entry.rangeVersion = w.writeVersion;
|
||||
for (n = nextLogical(n); n != end;) {
|
||||
auto *old = n;
|
||||
n = nextLogical(n);
|
||||
old->entryPresent = false;
|
||||
if (old->numChildren == 0 && old->parent != nullptr) {
|
||||
eraseChild(old->parent, old->parentsIndex);
|
||||
}
|
||||
}
|
||||
invalidateMax(begin);
|
||||
invalidateMax(end);
|
||||
} else {
|
||||
auto *n =
|
||||
insert(&root, std::span<const uint8_t>(w.begin.p, w.begin.len),
|
||||
@@ -1138,14 +1168,23 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
TestDriver<ConflictSet::Impl> driver{data, size};
|
||||
static_assert(driver.kMaxKeyLen > Node::kPartialKeyMaxLen);
|
||||
|
||||
do {
|
||||
for (;;) {
|
||||
bool done = driver.next();
|
||||
if (!driver.ok) {
|
||||
debugPrintDot(stdout, driver.cs.root);
|
||||
fflush(stdout);
|
||||
abort();
|
||||
}
|
||||
bool success = checkCorrectness(driver.cs.root, driver.refImpl);
|
||||
if (!success) {
|
||||
debugPrintDot(stdout, driver.cs.root);
|
||||
fflush(stdout);
|
||||
abort();
|
||||
}
|
||||
} while (!driver.next());
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user