prev->link_older = w->link_older;
w->status = Status::Incomplete("Write stall");
SetState(w, STATE_COMPLETED);
- if (prev->link_older) {
+ // Only update `link_newer` if it's already set.
+ // `CreateMissingNewerLinks()` will update the nullptr `link_newer` later,
+ // which assumes the the first non-nullptr `link_newer` is the last
+ // nullptr link in the writer list.
+ // If `link_newer` is set here, `CreateMissingNewerLinks()` may stop
+ // updating the whole list when it sees the first non nullptr link.
+ if (prev->link_older && prev->link_older->link_newer) {
prev->link_older->link_newer = prev;
}
w = prev->link_older;
// (newest_writer) is inclusive. Iteration goes from old to new.
Writer* w = leader;
while (w != newest_writer) {
+ assert(w->link_newer);
w = w->link_newer;
if (w->sync && !leader->sync) {
}
if (w->callback != nullptr && !w->callback->AllowWriteBatching()) {
- // dont batch writes that don't want to be batched
+ // don't batch writes that don't want to be batched
break;
}
Writer* w = leader;
while (w != newest_writer) {
+ assert(w->link_newer);
w = w->link_newer;
if (w->batch == nullptr) {
if (w == last_writer) {
break;
}
+ assert(next);
w = next;
}
// Note that leader has to exit last, since it owns the write group.
}
// else we're the last parallel worker and should perform exit duties.
w->status = write_group->status;
+ // Callers of this function must ensure w->status is checked.
+ write_group->status.PermitUncheckedError();
return true;
}
static WriteThread::AdaptationContext eabgl_ctx("ExitAsBatchGroupLeader");
void WriteThread::ExitAsBatchGroupLeader(WriteGroup& write_group,
- Status status) {
+ Status& status) {
Writer* leader = write_group.leader;
Writer* last_writer = write_group.last_writer;
assert(leader->link_older == nullptr);
+ // If status is non-ok already, then write_group.status won't have the chance
+ // of being propagated to caller.
+ if (!status.ok()) {
+ write_group.status.PermitUncheckedError();
+ }
+
// Propagate memtable write error to the whole group.
if (status.ok() && !write_group.status.ok()) {
status = write_group.status;
// leader now
while (last_writer != leader) {
+ assert(last_writer);
last_writer->status = status;
// we need to read link_older before calling SetState, because as soon
// as it is marked committed the other thread's Await may return and