-
Type:
Improvement
-
Resolution: Unresolved
-
Priority:
Major - P3
-
None
-
Affects Version/s: None
-
Component/s: None
-
Replication
-
None
-
None
-
None
-
None
-
None
-
None
-
None
Summary
awaitReplication unconditionally calls _futureGetNoThrowWithDeadline, which enters runWithDeadline even when the replication future is already satisfied. Adding a future.isReady() check before this call eliminates the runWithDeadline overhead for the common case where secondaries have already caught up.
Background
In replication_coordinator_impl.cpp, after registering a waiter and obtaining a future, awaitReplication calls _futureGetNoThrowWithDeadline.
_futureGetNoThrowWithDeadline calls opCtx->runWithDeadline(...), which pushes and pops a deadline onto the OperationContext deadline stack. When _doneWaitingForReplication returned true (replication already caught up), _startWaitingForReplication returns a ready future, but the runWithDeadline overhead is still paid.
isReady() is a single relaxed atomic load. The same fast-path pattern is already used in awaitHelloResponse and waitUntilOpTime.
Proposed fix
if (future.isReady()) {
return {future.getNoThrow(), duration_cast(timer.elapsed())};
}
auto status = _futureGetNoThrowWithDeadline(opCtx, future, wTimeoutDate, timeoutError);
Expected impact
Eliminates runWithDeadline overhead for already-satisfied waiters. This seems to be the dominant case when secondaries are keeping up with the primary.
Acceptance criteria
- awaitReplication skips _futureGetNoThrowWithDeadline when the future is already ready
- Existing replication correctness tests pass
- No regression on write latency tail percentiles