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