Skip over point writes in phase 3

This commit is contained in:
2024-10-30 15:08:27 -07:00
parent 051bfb05fe
commit c4b0aa1085
2 changed files with 37 additions and 14 deletions

View File

@@ -4115,12 +4115,25 @@ struct Job {
// original key, and there is existing node in the tree further along the search // original key, and there is existing node in the tree further along the search
// path of the original key // path of the original key
struct Result { struct Result {
Result() = default;
Result(Node *insertionPoint, TrivialSpan remaining)
: insertionPoint(insertionPoint), remaining(remaining),
endInsertionPoint(nullptr) {}
Result(Node *insertionPoint, TrivialSpan remaining, Node *endInsertionPoint,
TrivialSpan endRemaining)
: insertionPoint(insertionPoint), remaining(remaining),
endInsertionPoint(endInsertionPoint), endRemaining(endRemaining) {}
Node *insertionPoint; Node *insertionPoint;
TrivialSpan remaining; TrivialSpan remaining;
Node *endInsertionPoint; // Range write only Node *endInsertionPoint; // Range write only
TrivialSpan endRemaining; // Range write only TrivialSpan endRemaining; // Range write only
Result *nextRangeWrite; // Linked list to skip over point writes in phase 3.
// Populated in phase 2
}; };
static_assert(std::is_trivial_v<Result>);
// State relevant to every insertion // State relevant to every insertion
struct Context { struct Context {
@@ -4167,12 +4180,12 @@ template <class NodeT> void pointIter(Job *job, Context *context) {
TaggedNodePointer *child = TaggedNodePointer *child =
getChildUpdatingMaxVersion(n, job->remaining, context->writeVersion); getChildUpdatingMaxVersion(n, job->remaining, context->writeVersion);
if (child == nullptr) [[unlikely]] { if (child == nullptr) [[unlikely]] {
context->results[job->index] = {job->n, job->remaining, nullptr, {}}; context->results[job->index] = {job->n, job->remaining};
MUSTTAIL return complete(job, context); MUSTTAIL return complete(job, context);
} }
job->n = *child; job->n = *child;
if (job->remaining.size() == 0) [[unlikely]] { if (job->remaining.size() == 0) [[unlikely]] {
context->results[job->index] = {job->n, job->remaining, nullptr, {}}; context->results[job->index] = {job->n, job->remaining};
MUSTTAIL return complete(job, context); MUSTTAIL return complete(job, context);
} }
++context->iterations; ++context->iterations;
@@ -4315,7 +4328,7 @@ pointWrite:
remaining = TrivialSpan(context->writes[index].begin.p, remaining = TrivialSpan(context->writes[index].begin.p,
context->writes[index].begin.len); context->writes[index].begin.len);
if (remaining.size() == 0) [[unlikely]] { if (remaining.size() == 0) [[unlikely]] {
context->results[index] = {n, remaining, nullptr, {}}; context->results[index] = {n, remaining};
continuation = complete; continuation = complete;
} else { } else {
continuation = pointIterTable[n->getType()]; continuation = pointIterTable[n->getType()];
@@ -4895,6 +4908,9 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
// old nodes get forwarding pointers installed and are released after // old nodes get forwarding pointers installed and are released after
// phase 2. The search path of a node does not change in this phase. // phase 2. The search path of a node does not change in this phase.
interleaved_insert::Result *firstRangeWrite = nullptr;
interleaved_insert::Result *lastRangeWrite;
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
#if DEBUG_VERBOSE && !defined(NDEBUG) #if DEBUG_VERBOSE && !defined(NDEBUG)
@@ -4927,6 +4943,13 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
context.results[i].remaining, writeVersion, context.results[i].remaining, writeVersion,
&writeContext); &writeContext);
} else { } else {
if (firstRangeWrite == nullptr) {
firstRangeWrite = context.results + i;
} else {
lastRangeWrite->nextRangeWrite = context.results + i;
}
lastRangeWrite = context.results + i;
lastRangeWrite->nextRangeWrite = nullptr;
while (context.results[i].endInsertionPoint->releaseDeferred) { while (context.results[i].endInsertionPoint->releaseDeferred) {
context.results[i].endInsertionPoint = context.results[i].endInsertionPoint =
context.results[i].endInsertionPoint->forwardTo; context.results[i].endInsertionPoint->forwardTo;
@@ -4943,18 +4966,17 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
// Phase 3: Erase nodes within written ranges. Going left to right ensures // Phase 3: Erase nodes within written ranges. Going left to right ensures
// that nothing later is on the search path of anything earlier, so we don't // that nothing later is on the search path of anything earlier, so we don't
// encounter invalidated nodes. // encounter invalidated nodes.
for (int i = 0; i < count; ++i) { for (auto *iter = firstRangeWrite; iter != nullptr;
if (context.results[i].endInsertionPoint != nullptr) { iter = iter->nextRangeWrite) {
while (context.results[i].insertionPoint->releaseDeferred) { if (iter->endInsertionPoint != nullptr) {
context.results[i].insertionPoint = while (iter->insertionPoint->releaseDeferred) {
context.results[i].insertionPoint->forwardTo; iter->insertionPoint = iter->insertionPoint->forwardTo;
} }
while (context.results[i].endInsertionPoint->releaseDeferred) { while (iter->endInsertionPoint->releaseDeferred) {
context.results[i].endInsertionPoint = iter->endInsertionPoint = iter->endInsertionPoint->forwardTo;
context.results[i].endInsertionPoint->forwardTo;
} }
eraseInRange(context.results[i].insertionPoint, eraseInRange(iter->insertionPoint, iter->endInsertionPoint,
context.results[i].endInsertionPoint, &writeContext, this); &writeContext, this);
} }
} }

View File

@@ -645,7 +645,8 @@ struct TestDriver {
bool ok = true; bool ok = true;
const int prefixLen = arbitrary->bounded(512); // const int prefixLen = arbitrary->bounded(512);
const int prefixLen = 0;
const int prefixByte = arbitrary->randT<uint8_t>(); const int prefixByte = arbitrary->randT<uint8_t>();
// Call until it returns true, for "done". Check internal invariants etc // Call until it returns true, for "done". Check internal invariants etc