Skip to content

Commit 9bf9ad1

Browse files
committed
servlet: fix TomcatTransportTest detects write when not ready
1 parent 6a2028c commit 9bf9ad1

File tree

1 file changed

+20
-8
lines changed

1 file changed

+20
-8
lines changed

servlet/src/main/java/io/grpc/servlet/AsyncServletOutputStreamWriter.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,11 @@ private void assureReadyAndDrainedTurnsFalse() {
217217
*/
218218
private void runOrBuffer(ActionItem actionItem) throws IOException {
219219
WriteState curState = writeState.get();
220-
if (curState.readyAndDrained) { // write to the outputStream directly
220+
221+
// Evaluate Tomcat's actual state alongside our cached state
222+
boolean actualReady = curState.readyAndDrained && isReady.getAsBoolean();
223+
224+
if (actualReady) { // write to the outputStream directly
221225
actionItem.run();
222226
if (actionItem == completeAction) {
223227
return;
@@ -232,13 +236,21 @@ private void runOrBuffer(ActionItem actionItem) throws IOException {
232236
} else { // buffer to the writeChain
233237
writeChain.offer(actionItem);
234238
if (!writeState.compareAndSet(curState, curState.withReadyAndDrained(false))) {
235-
checkState(
236-
writeState.get().readyAndDrained,
237-
"Bug: onWritePossible() should have changed readyAndDrained to true, but not");
238-
ActionItem lastItem = writeChain.poll();
239-
if (lastItem != null) {
240-
checkState(lastItem == actionItem, "Bug: lastItem != actionItem");
241-
runOrBuffer(lastItem);
239+
// STATE CHANGED! Determine why the CAS failed based on our initial state.
240+
if (curState.readyAndDrained) {
241+
// We dropped here solely because isReady() was false.
242+
// CAS failed because another concurrent thread already CAS'd it to false.
243+
// This is completely safe. Tomcat will call onWritePossible(). Do nothing.
244+
} else {
245+
// Original logic: We started as false, CAS failed because onWritePossible set it to true.
246+
checkState(
247+
writeState.get().readyAndDrained,
248+
"Bug: onWritePossible() should have changed readyAndDrained to true, but not");
249+
ActionItem lastItem = writeChain.poll();
250+
if (lastItem != null) {
251+
checkState(lastItem == actionItem, "Bug: lastItem != actionItem");
252+
runOrBuffer(lastItem);
253+
}
242254
}
243255
} // state has not changed since
244256
}

0 commit comments

Comments
 (0)