Range write WIP

This commit is contained in:
2024-01-31 17:06:59 -08:00
parent 812eb27708
commit 96aca4a1da
2 changed files with 88 additions and 30 deletions

View File

@@ -6,6 +6,7 @@
#include <cassert> #include <cassert>
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <inttypes.h>
#include <limits> #include <limits>
#include <span> #include <span>
#include <string> #include <string>
@@ -35,7 +36,7 @@ enum class Type : int8_t {
struct Node { struct Node {
/* begin section that's copied to the next node */ /* begin section that's copied to the next node */
Node *parent = nullptr; Node *parent = nullptr;
int64_t maxVersion = std::numeric_limits<int64_t>::lowest(); int64_t maxVersion;
Entry entry; Entry entry;
int16_t numChildren = 0; int16_t numChildren = 0;
bool entryPresent = false; bool entryPresent = false;
@@ -85,6 +86,16 @@ struct BitSet {
} }
} }
void reset(int i) {
assert(0 <= i);
assert(i < 256);
if (i < 128) {
lo &= ~(__uint128_t(1) << i);
} else {
hi &= ~(__uint128_t(1) << (i - 128));
}
}
int firstSetGeq(int i) const { int firstSetGeq(int i) const {
if (i < 128) { if (i < 128) {
int a = std::countr_zero(lo >> i); int a = std::countr_zero(lo >> i);
@@ -552,6 +563,7 @@ Node *&getOrCreateChild(Node *&self, uint8_t index) {
(self->numChildren - (nodeIndex + 1))); (self->numChildren - (nodeIndex + 1)));
} else if (self->type == Type::Node48) { } else if (self->type == Type::Node48) {
auto *self48 = static_cast<Node48 *>(self); auto *self48 = static_cast<Node48 *>(self);
self48->bitSet.reset(index);
int8_t toRemoveChildrenIndex = std::exchange(self48->index[index], -1); int8_t toRemoveChildrenIndex = std::exchange(self48->index[index], -1);
int8_t lastChildrenIndex = --self48->nextFree; int8_t lastChildrenIndex = --self48->nextFree;
assert(toRemoveChildrenIndex >= 0); assert(toRemoveChildrenIndex >= 0);
@@ -564,6 +576,7 @@ Node *&getOrCreateChild(Node *&self, uint8_t index) {
} }
} else { } else {
auto *self256 = static_cast<Node256 *>(self); auto *self256 = static_cast<Node256 *>(self);
self256->bitSet.reset(index);
self256->children[index] = nullptr; self256->children[index] = nullptr;
} }
--self->numChildren; --self->numChildren;
@@ -762,6 +775,7 @@ outerLoop:
auto &child = getOrCreateChild(self, key.front()); auto &child = getOrCreateChild(self, key.front());
if (!child) { if (!child) {
child = newNode(); child = newNode();
child->maxVersion = writeVersion;
child->parent = self; child->parent = self;
child->parentsIndex = key.front(); child->parentsIndex = key.front();
} }
@@ -816,18 +830,45 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
void addWrites(const WriteRange *writes, int count) { void addWrites(const WriteRange *writes, int count) {
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
const auto &w = writes[i]; const auto &w = writes[i];
// TODO support non-point writes if (w.end.len > 0) {
assert(w.end.len == 0); auto *n = insert(&root, std::span<const uint8_t>(w.end.p, w.end.len),
auto *n = insert(&root, std::span<const uint8_t>(w.begin.p, w.begin.len), std::numeric_limits<int64_t>::lowest());
w.writeVersion); if (!n->entryPresent) {
if (!n->entryPresent) { auto *p = prevLogical(n);
auto *p = prevLogical(n); assert(p != nullptr);
assert(p != nullptr); 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);
n->entryPresent = true; n->entryPresent = true;
n->entry.pointVersion = w.writeVersion; n->entry.pointVersion = w.writeVersion;
n->entry.rangeVersion = p->entry.rangeVersion; n->entry.rangeVersion = w.writeVersion;
for (n = nextLogical(n); n != end;) {
auto *old = n;
n = nextLogical(n);
if (old->numChildren == 0 && old->parent != nullptr) {
eraseChild(old->parent, old->parentsIndex);
}
}
} else { } else {
n->entry.pointVersion = std::max(n->entry.pointVersion, w.writeVersion); auto *n =
insert(&root, std::span<const uint8_t>(w.begin.p, w.begin.len),
w.writeVersion);
if (!n->entryPresent) {
auto *p = prevLogical(n);
assert(p != nullptr);
n->entryPresent = true;
n->entry.pointVersion = w.writeVersion;
n->entry.rangeVersion = p->entry.rangeVersion;
} else {
n->entry.pointVersion =
std::max(n->entry.pointVersion, w.writeVersion);
}
} }
} }
} }
@@ -952,12 +993,14 @@ void printLogical(std::string &result, Node *node) {
assert(n != nullptr); assert(n != nullptr);
auto partialKey = printable(Key{n->partialKey, n->partialKeyLen}); auto partialKey = printable(Key{n->partialKey, n->partialKeyLen});
if (n->entryPresent) { if (n->entryPresent) {
fprintf(file, " k_%p [label=\"m=%d p=%d r=%d %s\"];\n", (void *)n, fprintf(file,
int(n->maxVersion), int(n->entry.pointVersion), " k_%p [label=\"m=%" PRId64 " p=%" PRId64 " r=%" PRId64
int(n->entry.rangeVersion), partialKey.c_str()); " %s\"];\n",
(void *)n, n->maxVersion, n->entry.pointVersion,
n->entry.rangeVersion, partialKey.c_str());
} else { } else {
fprintf(file, " k_%p [label=\"m=%d %s\"];\n", (void *)n, fprintf(file, " k_%p [label=\"m=%" PRId64 " %s\"];\n", (void *)n,
int(n->maxVersion), partialKey.c_str()); n->maxVersion, partialKey.c_str());
} }
for (int child = getChildGeq(n, 0); child >= 0; for (int child = getChildGeq(n, 0); child >= 0;
child = getChildGeq(n, child + 1)) { child = getChildGeq(n, child + 1)) {
@@ -1002,9 +1045,9 @@ void checkParentPointers(Node *node, bool &success) {
} }
if (node->maxVersion != expected) { if (node->maxVersion != expected) {
Arena arena; Arena arena;
fprintf(stderr, "%s has max version %d. Expected %d\n", fprintf(stderr, "%s has max version %" PRId64 " . Expected %" PRId64 "\n",
printable(getSearchPath(arena, node)).c_str(), printable(getSearchPath(arena, node)).c_str(), node->maxVersion,
int(node->maxVersion), int(expected)); expected);
success = false; success = false;
} }
return expected; return expected;

View File

@@ -14,7 +14,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#define DEBUG_VERBOSE 0 #define DEBUG_VERBOSE 1
// This header contains code that we want to reuse outside of ConflictSet.cpp or // This header contains code that we want to reuse outside of ConflictSet.cpp or
// want to exclude from coverage since it's only testing related. // want to exclude from coverage since it's only testing related.
@@ -459,11 +459,11 @@ template <class ConflictSetImpl> struct TestDriver {
} }
Arena arena; Arena arena;
{ {
int numWrites = arbitrary.bounded(kMaxKeyLen); int numWriteKeys = arbitrary.bounded(10);
int64_t v = ++writeVersion; int64_t v = ++writeVersion;
auto *writes = new (arena) ConflictSet::WriteRange[numWrites]; auto *writes = new (arena) ConflictSet::WriteRange[numWriteKeys];
auto keys = set<std::string_view>(arena); auto keys = set<std::string_view>(arena);
while (int(keys.size()) < numWrites) { while (int(keys.size()) < numWriteKeys) {
if (!arbitrary.hasEntropy()) { if (!arbitrary.hasEntropy()) {
return true; return true;
} }
@@ -473,16 +473,31 @@ template <class ConflictSetImpl> struct TestDriver {
keys.insert(std::string_view((const char *)begin, keyLen)); keys.insert(std::string_view((const char *)begin, keyLen));
} }
auto iter = keys.begin(); auto iter = keys.begin();
for (int i = 0; i < numWrites; ++i) { int numWrites = 0;
writes[i].begin.p = (const uint8_t *)iter->data(); for (int i = 0; i < numWriteKeys; ++i, ++numWrites) {
writes[i].begin.len = iter->size(); writes[numWrites].begin.p = (const uint8_t *)iter->data();
writes[numWrites].begin.len = iter->size();
++iter; ++iter;
writes[i].end.len = 0; if (i + 1 < numWriteKeys && arbitrary.bounded(2)) {
writes[i].writeVersion = v; ++i;
writes[numWrites].end.p = (const uint8_t *)iter->data();
writes[numWrites].end.len = iter->size();
++iter;
} else {
writes[numWrites].end.len = 0;
}
writes[numWrites].writeVersion = v;
#if DEBUG_VERBOSE && !defined(NDEBUG) #if DEBUG_VERBOSE && !defined(NDEBUG)
fprintf(stderr, "Write: {%s} -> %d\n", if (writes[numWrites].end.len == 0) {
printable(writes[i].begin).c_str(), fprintf(stderr, "Write: {%s} -> %d\n",
int(writes[i].writeVersion)); printable(writes[numWrites].begin).c_str(),
int(writes[numWrites].writeVersion));
} else {
fprintf(stderr, "Write: [%s, %s) -> %d\n",
printable(writes[numWrites].begin).c_str(),
printable(writes[numWrites].end).c_str(),
int(writes[numWrites].writeVersion));
}
#endif #endif
} }
assert(iter == keys.end()); assert(iter == keys.end());