On Mar 23, 2013, at 10:05 AM, igaz wrote: > So I won't bury the lede: what exactly (and why) is Tomcat doing 'simulated' > read blocking when using the NIO connector? > > I've done some due diligence including downloading the latest source > (7.0.37) and searching the tomcat mailing lists. > Firstly, to make things simpler, let's take comet processing and writes off > the table. > > In the tomcat doc, there is the nice table that compares the various http > connectors and it reads this about nio: > Read HTTP Request: non-blocking (I assume that means read all of the http > request headers) > Read HTTP Body: sim blocking (e.g. in a POST) > > I've browsed the code and the NIOEndpoint.Acceptor and NIOEndpoint.Poller > all essentially make sense and look familiar to someone who has some > experience with Java NIO > But there's quite a bit of code to look at (and lots of abstraction) and I > haven't got much further than there. > What I don't understand is the HTTP Body: sim blocking part. > Thinking about that, the only conclusion I can draw is that > HttpRequest.getParameter('xxxx') potentially blocks?!?! i.e. tomcat is > 'deferring' the parsing of the HTTP Body (as in the case of a POST) until > the application Servlet 'asks' for it? > I've always assumed that the HTTPRequest that is passed to the Servlet is > fully formed. > In one of the posts I saw a comment that (I believe Filip) mentioned > something about Servlets that call getInputStream() > requiring simulated blocking. But why would any servlet code ever do that? > After all, it has the HttpRequest which is a nice abstraction over the input > stream
I don't know enough about this to provide a lot of insight, but I can provide some. > (hmm, maybe when reading uploaded files)? Exactly. As of Servlet 3.0/Tomcat 7.0, multipart processing is handled directly by the container. So, if you have multipart processing enabled for a particular Servlet, the entire request gets processed BEFORE that Servlet's doGet/doPost/etc. methods are called. However, before Tomcat 7 this that was not the case, and you had to handle file uploads manually. Also, you can't do everything with built-in multipart processing that you can with manual processing (like file upload progress bars), so even today sometimes it is necessary to manage file uploads yourself. So, if multipart processing is enabled, the entire request is read and parsed before doGet/doPost/etc. are called. If it is not enabled, calls to getParamater() inside these methods could block, because the request body has not yet been read in order to give you an opportunity to do so yourself. Either way, inside filters, the request has never been fully processed yet (you may need to alter or wrap it somehow). > > So the first question is (assuming my inference is correct), why use > simulated blocking at all? Just read the entire http request (headers and > body) until you detect that the request is complete (and using standard NIO > techniques, viz. a selector). Is there something in the servlet specs that > proscribes that? Yes. The Servlet spec does deal with this. I won't copy-and-paste that in here. You're welcome to download and read it [1]. :-) > > And the second question is how? I guess you invoke > SocketChannel.configureBlocking(true) and then do SocketChannel.reads() > > It seems that using NIO to only read the HTTP headers vitiates the > performance benefits of NIO somewhat and I'm sure you're doing it for a good > reason . . . I can't speak to this. Someone else maybe can. [1] http://download.oracle.com/otndocs/jcp/servlet-3.0-fr-oth-JSpec/