Improve range write performance

This commit is contained in:
2024-02-01 16:52:22 -08:00
parent 802615e38b
commit 22daf0b9cb
2 changed files with 73 additions and 35 deletions

View File

@@ -8,3 +8,11 @@ repos:
rev: e2c2116d86a80e72e7146a06e68b7c228afc6319 rev: e2c2116d86a80e72e7146a06e68b7c228afc6319
hooks: hooks:
- id: cmake-format - id: cmake-format
- repo: local
hooks:
- id: debug verbose check
name: disallow checking in DEBUG_VERBOSE=1
description: disallow checking in DEBUG_VERBOSE=1
entry: '^#define DEBUG_VERBOSE 1$'
language: pygrep
types: [c++]

View File

@@ -543,6 +543,27 @@ Node *&getOrCreateChild(Node *&self, uint8_t index) {
} }
} }
void fixMaxVersion(Node *self) {
for (;;) {
int64_t result = std::numeric_limits<int64_t>::lowest();
if (self->entryPresent) {
result = std::max(result, self->entry.pointVersion);
result = std::max(result, self->entry.rangeVersion);
}
for (int i = getChildGeq(self, 0); i >= 0; i = getChildGeq(self, i + 1)) {
result = std::max(result, getChildExists(self, i)->maxVersion);
}
if (self->maxVersion == result) {
break;
}
self->maxVersion = result;
if (self->parent == nullptr) {
break;
}
self = self->parent;
}
}
// Precondition - an entry for index must exist in the node // Precondition - an entry for index must exist in the node
void eraseChild(Node *self, uint8_t index) { void eraseChild(Node *self, uint8_t index) {
free(getChildExists(self, index)); free(getChildExists(self, index));
@@ -814,21 +835,6 @@ 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 { struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
void check(const ReadRange *reads, Result *result, int count) const { void check(const ReadRange *reads, Result *result, int count) const {
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
@@ -858,33 +864,54 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
const auto &w = writes[i]; const auto &w = writes[i];
if (w.end.len > 0) { if (w.end.len > 0) {
auto *n = insert(&root, std::span<const uint8_t>(w.end.p, w.end.len), auto *begin =
std::numeric_limits<int64_t>::lowest()); insert(&root, std::span<const uint8_t>(w.begin.p, w.begin.len),
if (!n->entryPresent) { w.writeVersion);
auto *p = prevLogical(n);
assert(p != nullptr); const bool insertedBegin = !std::exchange(begin->entryPresent, true);
n->entryPresent = true; begin->entry.pointVersion = w.writeVersion;
n->entry.pointVersion = p->entry.rangeVersion;
n->entry.rangeVersion = p->entry.rangeVersion; auto *end = insert(&root, std::span<const uint8_t>(w.end.p, w.end.len),
std::numeric_limits<int64_t>::lowest());
const bool insertedEnd = !std::exchange(end->entryPresent, true);
if (insertedEnd) {
// begin may have been invalidated
auto iter =
lastLeq(root, std::span<const uint8_t>(w.begin.p, w.begin.len));
assert(iter.cmp == 0);
begin = iter.n;
} }
auto *end = n; if (insertedBegin) {
n = insert(&root, std::span<const uint8_t>(w.begin.p, w.begin.len), auto *p = prevLogical(begin);
std::numeric_limits<int64_t>::lowest()); assert(p != nullptr);
auto *begin = n; begin->entry.rangeVersion = p->entry.rangeVersion;
n->entryPresent = true; }
n->entry.pointVersion = w.writeVersion;
n->entry.rangeVersion = w.writeVersion; if (insertedEnd) {
for (n = nextLogical(n); n != end;) { auto *p = prevLogical(end);
auto *old = n; assert(p != nullptr);
n = nextLogical(n); end->entryPresent = true;
end->entry.pointVersion = p->entry.rangeVersion;
end->entry.rangeVersion = p->entry.rangeVersion;
}
begin->entry.rangeVersion = w.writeVersion;
for (begin = nextLogical(begin); begin != end;) {
auto *old = begin;
begin = nextLogical(begin);
old->entryPresent = false; old->entryPresent = false;
fixMaxVersion(old);
if (old->numChildren == 0 && old->parent != nullptr) { if (old->numChildren == 0 && old->parent != nullptr) {
eraseChild(old->parent, old->parentsIndex); eraseChild(old->parent, old->parentsIndex);
} }
} }
invalidateMax(begin);
invalidateMax(end); if (insertedEnd) {
fixMaxVersion(end);
}
} else { } else {
auto *n = auto *n =
insert(&root, std::span<const uint8_t>(w.begin.p, w.begin.len), insert(&root, std::span<const uint8_t>(w.begin.p, w.begin.len),
@@ -1175,6 +1202,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
fflush(stdout); fflush(stdout);
abort(); abort();
} }
#if DEBUG_VERBOSE && !defined(NDEBUG)
fprintf(stderr, "Check correctness\n");
#endif
bool success = checkCorrectness(driver.cs.root, driver.refImpl); bool success = checkCorrectness(driver.cs.root, driver.refImpl);
if (!success) { if (!success) {
debugPrintDot(stdout, driver.cs.root); debugPrintDot(stdout, driver.cs.root);