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
// 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<Result>);
// State relevant to every insertion
struct Context {
@@ -4167,12 +4180,12 @@ template <class NodeT> 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);
}
}

View File

@@ -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<uint8_t>();
// Call until it returns true, for "done". Check internal invariants etc