mirror of https://github.com/grpc/grpc-java.git
Update Netty to 9d70cf3 to pick up https://github.com/netty/netty/commit/8271c8a which eliminates
explicit flushing from Nettys HTTP2 codec.
This commit is contained in:
parent
4a05869db7
commit
f2cba89e48
|
|
@ -103,6 +103,7 @@ public class MessageDeframer implements Closeable {
|
||||||
private CompositeReadableBuffer unprocessed = new CompositeReadableBuffer();
|
private CompositeReadableBuffer unprocessed = new CompositeReadableBuffer();
|
||||||
private long pendingDeliveries;
|
private long pendingDeliveries;
|
||||||
private boolean deliveryStalled = true;
|
private boolean deliveryStalled = true;
|
||||||
|
private boolean inDelivery = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a deframer. Compression will not be supported.
|
* Creates a deframer. Compression will not be supported.
|
||||||
|
|
@ -216,6 +217,13 @@ public class MessageDeframer implements Closeable {
|
||||||
* Reads and delivers as many messages to the sink as possible.
|
* Reads and delivers as many messages to the sink as possible.
|
||||||
*/
|
*/
|
||||||
private void deliver() {
|
private void deliver() {
|
||||||
|
// We can have reentrancy here when using a direct executor, triggered by calls to
|
||||||
|
// request more messages. This is safe as we simply loop until pendingDelivers = 0
|
||||||
|
if (inDelivery) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inDelivery = true;
|
||||||
|
try {
|
||||||
// Process the uncompressed bytes.
|
// Process the uncompressed bytes.
|
||||||
boolean stalled = false;
|
boolean stalled = false;
|
||||||
while (pendingDeliveries > 0 && readRequiredBytes()) {
|
while (pendingDeliveries > 0 && readRequiredBytes()) {
|
||||||
|
|
@ -235,9 +243,9 @@ public class MessageDeframer implements Closeable {
|
||||||
throw new AssertionError("Invalid state: " + state);
|
throw new AssertionError("Invalid state: " + state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We are stalled when there are no more bytes to process. This allows delivering errors as soon
|
// We are stalled when there are no more bytes to process. This allows delivering errors as
|
||||||
// as the buffered input has been consumed, independent of whether the application has requested
|
// soon as the buffered input has been consumed, independent of whether the application
|
||||||
// another message.
|
// has requested another message.
|
||||||
stalled = !isDataAvailable();
|
stalled = !isDataAvailable();
|
||||||
|
|
||||||
if (endOfStream) {
|
if (endOfStream) {
|
||||||
|
|
@ -260,6 +268,9 @@ public class MessageDeframer implements Closeable {
|
||||||
if (stalled && !previouslyStalled) {
|
if (stalled && !previouslyStalled) {
|
||||||
listener.deliveryStalled();
|
listener.deliveryStalled();
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
inDelivery = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isDataAvailable() {
|
private boolean isDataAvailable() {
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.Matchers.anyInt;
|
import static org.mockito.Matchers.anyInt;
|
||||||
import static org.mockito.Mockito.atLeastOnce;
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
|
import static org.mockito.Mockito.doAnswer;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
@ -49,6 +50,9 @@ import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.JUnit4;
|
import org.junit.runners.JUnit4;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Matchers;
|
||||||
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
@ -184,6 +188,26 @@ public class MessageDeframerTest {
|
||||||
verifyNoMoreInteractions(listener);
|
verifyNoMoreInteractions(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deliverIsReentrantSafe() {
|
||||||
|
doAnswer(new Answer() {
|
||||||
|
@Override
|
||||||
|
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||||
|
deframer.request(1);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}).when(listener).messageRead(Matchers.<InputStream>any());
|
||||||
|
deframer.deframe(buffer(new byte[] {0, 0, 0, 0, 1, 3}), true);
|
||||||
|
verifyNoMoreInteractions(listener);
|
||||||
|
|
||||||
|
deframer.request(1);
|
||||||
|
verify(listener).messageRead(messages.capture());
|
||||||
|
assertEquals(Bytes.asList(new byte[] {3}), bytes(messages));
|
||||||
|
verify(listener).endOfStream();
|
||||||
|
verify(listener, atLeastOnce()).bytesRead(anyInt());
|
||||||
|
verifyNoMoreInteractions(listener);
|
||||||
|
}
|
||||||
|
|
||||||
private static List<Byte> bytes(ArgumentCaptor<InputStream> captor) {
|
private static List<Byte> bytes(ArgumentCaptor<InputStream> captor) {
|
||||||
return bytes(captor.getValue());
|
return bytes(captor.getValue());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 1cce998bb06f42ff47925390872dcc5c487bbf59
|
Subproject commit 9d70cf33c2ccea42d0fe651be61b2e0a6579fcb1
|
||||||
|
|
@ -130,6 +130,7 @@ class NettyClientHandler extends Http2ConnectionHandler {
|
||||||
|
|
||||||
// Initialize the connection window if we haven't already.
|
// Initialize the connection window if we haven't already.
|
||||||
initConnectionWindow();
|
initConnectionWindow();
|
||||||
|
ctx.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -132,5 +132,7 @@ class NettyClientStream extends Http2ClientStream {
|
||||||
@Override
|
@Override
|
||||||
protected void returnProcessedBytes(int processedBytes) {
|
protected void returnProcessedBytes(int processedBytes) {
|
||||||
handler.returnProcessedBytes(http2Stream, processedBytes);
|
handler.returnProcessedBytes(http2Stream, processedBytes);
|
||||||
|
// Need to flush as window update may have been written
|
||||||
|
channel.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,5 +105,7 @@ class NettyServerStream extends AbstractServerStream<Integer> {
|
||||||
@Override
|
@Override
|
||||||
protected void returnProcessedBytes(int processedBytes) {
|
protected void returnProcessedBytes(int processedBytes) {
|
||||||
handler.returnProcessedBytes(http2Stream, processedBytes);
|
handler.returnProcessedBytes(http2Stream, processedBytes);
|
||||||
|
// Need to flush as window update may have been written
|
||||||
|
channel.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,6 @@ public class NettyClientHandlerTest extends NettyHandlerTestBase {
|
||||||
|
|
||||||
ByteBuf expected = rstStreamFrame(3, (int) Http2Error.CANCEL.code());
|
ByteBuf expected = rstStreamFrame(3, (int) Http2Error.CANCEL.code());
|
||||||
verify(ctx).write(eq(expected), eq(promise));
|
verify(ctx).write(eq(expected), eq(promise));
|
||||||
verify(ctx).flush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -221,7 +220,6 @@ public class NettyClientHandlerTest extends NettyHandlerTestBase {
|
||||||
|
|
||||||
ByteBuf expected = rstStreamFrame(3, (int) Http2Error.CANCEL.code());
|
ByteBuf expected = rstStreamFrame(3, (int) Http2Error.CANCEL.code());
|
||||||
verify(ctx).write(eq(expected), eq(promise));
|
verify(ctx).write(eq(expected), eq(promise));
|
||||||
verify(ctx).flush();
|
|
||||||
|
|
||||||
promise = mock(ChannelPromise.class);
|
promise = mock(ChannelPromise.class);
|
||||||
handler.write(ctx, new CancelStreamCommand(stream), promise);
|
handler.write(ctx, new CancelStreamCommand(stream), promise);
|
||||||
|
|
@ -235,7 +233,6 @@ public class NettyClientHandlerTest extends NettyHandlerTestBase {
|
||||||
handler.write(ctx, new SendGrpcFrameCommand(stream, content, true), promise);
|
handler.write(ctx, new SendGrpcFrameCommand(stream, content, true), promise);
|
||||||
verify(promise, never()).setFailure(any(Throwable.class));
|
verify(promise, never()).setFailure(any(Throwable.class));
|
||||||
ByteBuf bufWritten = captureWrite(ctx);
|
ByteBuf bufWritten = captureWrite(ctx);
|
||||||
verify(ctx).flush();
|
|
||||||
int startIndex = bufWritten.readerIndex() + Http2CodecUtil.FRAME_HEADER_LENGTH;
|
int startIndex = bufWritten.readerIndex() + Http2CodecUtil.FRAME_HEADER_LENGTH;
|
||||||
int length = bufWritten.writerIndex() - startIndex;
|
int length = bufWritten.writerIndex() - startIndex;
|
||||||
ByteBuf writtenContent = bufWritten.slice(startIndex, length);
|
ByteBuf writtenContent = bufWritten.slice(startIndex, length);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue