diff --git a/ConflictSet.cpp b/ConflictSet.cpp index 91e9459..49734bd 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -4115,12 +4115,25 @@ struct Job { // original key, and there is existing node in the tree further along the search // path of the original key 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; TrivialSpan remaining; Node *endInsertionPoint; // 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); // State relevant to every insertion struct Context { @@ -4167,12 +4180,12 @@ template void pointIter(Job *job, Context *context) { TaggedNodePointer *child = getChildUpdatingMaxVersion(n, job->remaining, context->writeVersion); 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); } job->n = *child; 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); } ++context->iterations; @@ -4315,7 +4328,7 @@ pointWrite: remaining = TrivialSpan(context->writes[index].begin.p, context->writes[index].begin.len); if (remaining.size() == 0) [[unlikely]] { - context->results[index] = {n, remaining, nullptr, {}}; + context->results[index] = {n, remaining}; continuation = complete; } else { continuation = pointIterTable[n->getType()]; @@ -4895,6 +4908,9 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl { // old nodes get forwarding pointers installed and are released after // 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) { #if DEBUG_VERBOSE && !defined(NDEBUG) @@ -4927,6 +4943,13 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl { context.results[i].remaining, writeVersion, &writeContext); } 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) { context.results[i].endInsertionPoint = 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 // that nothing later is on the search path of anything earlier, so we don't // encounter invalidated nodes. - for (int i = 0; i < count; ++i) { - if (context.results[i].endInsertionPoint != nullptr) { - while (context.results[i].insertionPoint->releaseDeferred) { - context.results[i].insertionPoint = - context.results[i].insertionPoint->forwardTo; + for (auto *iter = firstRangeWrite; iter != nullptr; + iter = iter->nextRangeWrite) { + if (iter->endInsertionPoint != nullptr) { + while (iter->insertionPoint->releaseDeferred) { + iter->insertionPoint = iter->insertionPoint->forwardTo; } - while (context.results[i].endInsertionPoint->releaseDeferred) { - context.results[i].endInsertionPoint = - context.results[i].endInsertionPoint->forwardTo; + while (iter->endInsertionPoint->releaseDeferred) { + iter->endInsertionPoint = iter->endInsertionPoint->forwardTo; } - eraseInRange(context.results[i].insertionPoint, - context.results[i].endInsertionPoint, &writeContext, this); + eraseInRange(iter->insertionPoint, iter->endInsertionPoint, + &writeContext, this); } } diff --git a/Internal.h b/Internal.h index 8116f01..253eb45 100644 --- a/Internal.h +++ b/Internal.h @@ -645,7 +645,8 @@ struct TestDriver { bool ok = true; - const int prefixLen = arbitrary->bounded(512); + // const int prefixLen = arbitrary->bounded(512); + const int prefixLen = 0; const int prefixByte = arbitrary->randT(); // Call until it returns true, for "done". Check internal invariants etc