BufferedInputStream#fill() hanging in SocketInputStream#read0()
chris.hegarty at oracle.com
Tue Sep 7 13:08:36 UTC 2010
This stacktrace is exactly the same as what you will see if the server
does not respond. The HTTP client is trying to read the initial
response, but there is none. Is possible that the server is eagerly
accepting the connection but not processing it?
BIS should not be a problem here since it wraps a SocketInputStream.
SocketInputStream.read(byte,int,int) will only be invoked once by BIS
(unless the byte has not been filled and there is more data in the
socket buffer). The SocketInputStream.read(byte,int,int) will only
block if there is no data in the buffer, otherwise it should return
whatever is there.
A simple test shows that BIS is not a problem. Connect two sockets, wrap
the inputstream of one with BIS, then send a small amount of data. It
will not block (indefinitely) even though BIS is forcing a read of 8K
from the underlying stream.
From a performance perspective BIS is important for the HTTP client
implementation. Without it we would be required to read the message
headers from the socket buffer one byte at a time.
Andreas Kohn wrote:
> in an application that makes heavy use of JAX-RS, and for that reason
> small HTTP connections, I frequently observe situations where
> BufferedInputStream would hang like this:
> "ae03a305-557e-4db6-b9b8-2bf50f056aaf" prio=10 tid=0x00002aab0175a000 nid=0x30dc runnable [0x0000000048cb3000]
> java.lang.Thread.State: RUNNABLE
> at java.net.SocketInputStream.socketRead0(Native Method)
> at java.net.SocketInputStream.read(SocketInputStream.java:129)
> at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
> at java.io.BufferedInputStream.read1(BufferedInputStream.java:258)
> at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
> - locked <0x00002aaab605b670> (a java.io.BufferedInputStream)
> at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:687)
> at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:632)
> at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1072)
> Typically when looking into those hangs with a debugger it seems that the HTTP response
> was received fully, but the BufferedIInputStream tries to fill its buffer with more bytes than
> were originally requested by the HttpClient. The HTTP server is now waiting for the client to
> continue sending requests, while the client is stuck, hoping that the server will send more bytes
> to fill its buffer with.
> Currently the only option I have in this case is restart the application (even killing the server
> does not lead to a connection reset for some reason!), which in many cases is quite unacceptable.
> Disabling Keep-Alive connections helps if the hanging occurs when reading response bodies, but not
> when the hanging occurs while the header is being read.
> I believe this essentially the issue 6192696 (BufferedInputStream.read(byte, int, int)
> can block if the entire buffer can't be filled). I understand that this issue had had multiple
> fix-attempts, which could not be done due reliance on a proper and performing #available() implementation.
> But, wouldn't it be enough to just prevent fill() from filling more than the user wanted to
> read in the first place? For the HTTP example the Content-Length gives that information, and the
> server will not send more than that, but on the other hand it is safe for the connection to block
> until those bytes are received.
> Attached is a patch that implements that idea, am I missing something here? Note that I left #read()
> without arguments alone.
> I've been running with this patch for a few weeks now in test environments, and it seems to have no
> negative impact on classloading speed as detailed in the original bug comment trail.
More information about the core-libs-dev