CB-582: close the question when ask() leaves by throwing
Found reviewing CB-582 before the merge, not by the implementer. ask() clears its question on three paths — no-waiter, timed out, and (from answer()) answered. It can also leave by throwing: an interrupt while blocked on the answer, or an ExecutionException from the answer future. Those run only the finally block, which tore down the rendezvous turn but not the push loop's copy. The result was a question that stayed pending for good: named in every nudge until it hit its own cap, then left in pendingQuestions with no remover at all. Teardown now happens where the rendezvous teardown already happens, so the two cannot drift apart again. Closing a turnId that was never pending is a no-op, so the normal paths are unaffected. The new test fails on the pre-fix code with expected: <STOP> but was: <INJECT>.
This commit is contained in:
@@ -536,6 +536,14 @@ public final class MessageService {
|
||||
// Only the fresh owner tears down the shared turn; a duplicate must leave it open.
|
||||
if (ticket.fresh()) {
|
||||
rendezvous.closeAsk(ticket.turnId());
|
||||
// CB-582: tear the push loop's copy down at the same point, not only on the three
|
||||
// paths that call clearAsyncQuestion. The answer future can complete exceptionally
|
||||
// (ExecutionException) or the thread be interrupted, and both leave this method by
|
||||
// throwing — the question would stay pending forever, keep being named in nudges
|
||||
// until its own cap, and never be removed from the map. Already-closed is a no-op.
|
||||
if (pushLoop != null) {
|
||||
pushLoop.questionClosed(ticket.turnId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user