Implement phase 2

This commit is contained in:
2024-10-28 16:30:06 -07:00
parent b8fefff3ba
commit e8a8b5aef1

View File

@@ -264,7 +264,7 @@ struct Node {
/* begin section that's copied to the next node */ /* begin section that's copied to the next node */
union { union {
Entry entry; Entry entry;
/* Set to the forwarding point for this node if deferredReleased is set */ /* Set to the forwarding point for this node if releaseDeferred is set */
Node *forwardTo; Node *forwardTo;
}; };
Node *parent; Node *parent;
@@ -278,15 +278,12 @@ struct Node {
/* If set, this node has been replaced and the next node in the forwarding /* If set, this node has been replaced and the next node in the forwarding
* chain is `forwardTo`*/ * chain is `forwardTo`*/
bool deferredReleased; bool releaseDeferred;
uint8_t *partialKey(); uint8_t *partialKey();
Type getType() const { Type getType() const { return type; }
assert(!deferredReleased);
return type;
}
int32_t getCapacity() const { int32_t getCapacity() const {
assert(!deferredReleased); assert(!releaseDeferred);
return partialKeyCapacity; return partialKeyCapacity;
} }
@@ -320,7 +317,7 @@ struct Node0 : Node {
constexpr static auto kType = Type_Node0; constexpr static auto kType = Type_Node0;
uint8_t *partialKey() { uint8_t *partialKey() {
assert(!deferredReleased); assert(!releaseDeferred);
return (uint8_t *)(this + 1); return (uint8_t *)(this + 1);
} }
void copyChildrenAndKeyFrom(const Node0 &other); void copyChildrenAndKeyFrom(const Node0 &other);
@@ -338,7 +335,7 @@ struct Node3 : Node {
uint8_t index[kMaxNodes]; uint8_t index[kMaxNodes];
uint8_t *partialKey() { uint8_t *partialKey() {
assert(!deferredReleased); assert(!releaseDeferred);
return (uint8_t *)(this + 1); return (uint8_t *)(this + 1);
} }
void copyChildrenAndKeyFrom(const Node0 &other); void copyChildrenAndKeyFrom(const Node0 &other);
@@ -357,7 +354,7 @@ struct Node16 : Node {
uint8_t index[kMaxNodes]; uint8_t index[kMaxNodes];
uint8_t *partialKey() { uint8_t *partialKey() {
assert(!deferredReleased); assert(!releaseDeferred);
return (uint8_t *)(this + 1); return (uint8_t *)(this + 1);
} }
void copyChildrenAndKeyFrom(const Node3 &other); void copyChildrenAndKeyFrom(const Node3 &other);
@@ -382,7 +379,7 @@ struct Node48 : Node {
int8_t index[256]; int8_t index[256];
uint8_t *partialKey() { uint8_t *partialKey() {
assert(!deferredReleased); assert(!releaseDeferred);
return (uint8_t *)(this + 1); return (uint8_t *)(this + 1);
} }
void copyChildrenAndKeyFrom(const Node16 &other); void copyChildrenAndKeyFrom(const Node16 &other);
@@ -405,7 +402,7 @@ struct Node256 : Node {
InternalVersionT maxOfMax[kMaxOfMaxTotalPages]; InternalVersionT maxOfMax[kMaxOfMaxTotalPages];
uint8_t *partialKey() { uint8_t *partialKey() {
assert(!deferredReleased); assert(!releaseDeferred);
return (uint8_t *)(this + 1); return (uint8_t *)(this + 1);
} }
void copyChildrenAndKeyFrom(const Node48 &other); void copyChildrenAndKeyFrom(const Node48 &other);
@@ -708,7 +705,7 @@ template <class T> struct BoundedFreeListAllocator {
T *allocate(int partialKeyCapacity) { T *allocate(int partialKeyCapacity) {
T *result = allocate_helper(partialKeyCapacity); T *result = allocate_helper(partialKeyCapacity);
result->endOfRange = false; result->endOfRange = false;
result->deferredReleased = false; result->releaseDeferred = false;
if constexpr (!std::is_same_v<T, Node0>) { if constexpr (!std::is_same_v<T, Node0>) {
memset(result->children, 0, sizeof(result->children)); memset(result->children, 0, sizeof(result->children));
const auto z = InternalVersionT::zero; const auto z = InternalVersionT::zero;
@@ -852,10 +849,13 @@ struct WriteContext {
} }
// Place in a list to be released in the next call to releaseDeferred. // Place in a list to be released in the next call to releaseDeferred.
void deferRelease(Node *n) { void deferRelease(Node *n, Node *forwardTo) {
n->releaseDeferred = true;
n->forwardTo = forwardTo;
n->parent = deferredList; n->parent = deferredList;
deferredList = n; deferredList = n;
} }
// Release all nodes passed to deferRelease since the last call to // Release all nodes passed to deferRelease since the last call to
// releaseDeferred. // releaseDeferred.
void releaseDeferred() { void releaseDeferred() {
@@ -1672,7 +1672,7 @@ TaggedNodePointer &getOrCreateChild(TaggedNodePointer &self,
auto *newSelf = writeContext->allocate<Node3>(self->partialKeyLen); auto *newSelf = writeContext->allocate<Node3>(self->partialKeyLen);
newSelf->copyChildrenAndKeyFrom(*self0); newSelf->copyChildrenAndKeyFrom(*self0);
writeContext->release(self0); writeContext->deferRelease(self0, newSelf);
self = newSelf; self = newSelf;
goto insert3; goto insert3;
@@ -1682,7 +1682,7 @@ TaggedNodePointer &getOrCreateChild(TaggedNodePointer &self,
auto *self3 = static_cast<Node3 *>(self); auto *self3 = static_cast<Node3 *>(self);
auto *newSelf = writeContext->allocate<Node16>(self->partialKeyLen); auto *newSelf = writeContext->allocate<Node16>(self->partialKeyLen);
newSelf->copyChildrenAndKeyFrom(*self3); newSelf->copyChildrenAndKeyFrom(*self3);
writeContext->release(self3); writeContext->deferRelease(self3, newSelf);
self = newSelf; self = newSelf;
goto insert16; goto insert16;
} }
@@ -1711,7 +1711,7 @@ TaggedNodePointer &getOrCreateChild(TaggedNodePointer &self,
auto *self16 = static_cast<Node16 *>(self); auto *self16 = static_cast<Node16 *>(self);
auto *newSelf = writeContext->allocate<Node48>(self->partialKeyLen); auto *newSelf = writeContext->allocate<Node48>(self->partialKeyLen);
newSelf->copyChildrenAndKeyFrom(*self16); newSelf->copyChildrenAndKeyFrom(*self16);
writeContext->release(self16); writeContext->deferRelease(self16, newSelf);
self = newSelf; self = newSelf;
goto insert48; goto insert48;
} }
@@ -1742,7 +1742,7 @@ TaggedNodePointer &getOrCreateChild(TaggedNodePointer &self,
auto *self48 = static_cast<Node48 *>(self); auto *self48 = static_cast<Node48 *>(self);
auto *newSelf = writeContext->allocate<Node256>(self->partialKeyLen); auto *newSelf = writeContext->allocate<Node256>(self->partialKeyLen);
newSelf->copyChildrenAndKeyFrom(*self48); newSelf->copyChildrenAndKeyFrom(*self48);
writeContext->release(self48); writeContext->deferRelease(self48, newSelf);
self = newSelf; self = newSelf;
goto insert256; goto insert256;
} }
@@ -4738,6 +4738,16 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
// Phase 2: Perform insertions. Nodes may be upsized during this phase, but // Phase 2: Perform insertions. Nodes may be upsized during this phase, but
// old nodes get forwarding pointers installed and are released after // old nodes get forwarding pointers installed and are released after
// phase 2. // phase 2.
for (int i = 0; i < count; ++i) {
while (context.results[i].insertionPoint->releaseDeferred) {
context.results[i].insertionPoint =
context.results[i].insertionPoint->forwardTo;
}
addPointWrite(getInTree(context.results[i].insertionPoint, this),
context.results[i].remaining, writeVersion, &writeContext);
}
safe_free(context.results, sizeof(interleaved_insert::Result) * count);
} }
void addWrites(const WriteRange *writes, int count, int64_t writeVersion) { void addWrites(const WriteRange *writes, int count, int64_t writeVersion) {
@@ -4788,7 +4798,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
break; break;
} }
} }
if (0 && allPointWrites) { if (allPointWrites) {
interleavedPointWrites(writes, count, InternalVersionT(writeVersion)); interleavedPointWrites(writes, count, InternalVersionT(writeVersion));
} else { } else {
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
@@ -4806,6 +4816,8 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
} }
} }
writeContext.releaseDeferred();
// Run gc at least 200% the rate we're inserting entries // Run gc at least 200% the rate we're inserting entries
keyUpdates += std::max<int64_t>(writeContext.accum.entries_inserted - keyUpdates += std::max<int64_t>(writeContext.accum.entries_inserted -
writeContext.accum.entries_erased, writeContext.accum.entries_erased,