users@servlet-spec.java.net

[servlet-spec users] Re: Issues on Nonblocking IO

From: Rémy Maucherat <rmaucher_at_redhat.com>
Date: Tue, 29 Jan 2013 14:29:28 +0100

On 01/29/2013 01:55 PM, Eugene Chung(정의근) wrote:
>
> Nice to meet you, everyone.
>
> I'm Eugene Chung from TmaxSoft. I am taking over for Mr.Paek as an EG
> member.
> I've sent this e-mail to "jsr340-experts_at_servlet-spec.java.net
> <mailto:jsr340-experts_at_servlet-spec.java.net>" but it's denied by
> SYMPA. :-)
> So I choose the users list.
>
> Recently, I'm implementing the new NIO features based on Public Review.
> And I want to address some issues which should be handled by
> specification.
>
>
> 1. AsyncContext.dispatch() and nonblocking mode
>
> If an application calls AsyncContext.dispatch() after using
> nonblocking mode, what should we do?
> As we know, asynchronous dispatch means that the container assigns a
> container-managed thread to that context.
> So it doesn't seem to need nonblocking mode anymore like traditional
> servlet.
> And if the target of dispatch is a jsp file, application developers
> must consider about NIO in jsp. This might be a burden for them.
> I think there could be two options.
> a. Change to blocking mode implicitly
> b. Throw ISE when AsyncContext.dispatch() is called after nonblocking
> mode is started

The blocking operation is not allowed if it would block (the current
thinking is that it should throw an ISE). Also, it is impossible to
dispatch to a JSP, since a JSP should be using a Writer to output its
content, and the async mode is only for bytes (= OutputStream). So the
call to getWriter on the request will fail.
>
> 2. AsyncContext.complete() and nonblocking write
>
> What behaviour of AsyncContext.complete() on nonblocking write mode
> is desirable? If some data is remained in the internal buffer, should
> the container return complete() after all data remained is flushed or
> just return even if it is not completely flushed? In latter case, the
> container must flush data with other thread.

If the application is doing some asynchronous processing, like writing
data, it becomes responsible for dealing with concurrency. Doing
something asynchrounous is not mandatory, it is possible to do your
async data output exclusively in container threads and in that case
there are obviously fewer issues to be aware of.

As you guessed correctly, the async IO should go along with the
AsyncContext introduced in Servlet 3.0, without it the request will end
after processing the Servlet's service method.
>
>
> 3. Restriction on 'void' bulk write methods
>
> Application developers should aware that they shall NOT modify their
> buffers right after ServletOutputStream.write(byte[]) is returned.
> They must wait until ServletOutputStream.isReady() is true. Then they
> can modify their buffer again.
> If we permit this, it's definitely memory copy overhead.
> I read about this restriction somewhere in the EG mailing list but I
> couldn't find any written warnings in the API or spec..

Although the IO will not block, the container has to take care of the
content for the user, and the container does not own the array. The
consequence is that the write should not be done, for example, with a
very large array (otherwise, using write(byte[], start, length) is a
good workaround) because there's indeed some copy overhead.

There were some proposals for an API like Tomcat's sendfile (but more
generic using a ByteBuffer) to allow that use case, but it failed to
receive support for the time being.
>
>
> 4. Thread that has event ownership
>
> AsyncContext can be used by an application-managed thread (pool). The
> container don't know what it will be.
> Application developers may want that event methods of read and write
> listeners are called by their own threads.
> If this requirement can happen, I think we may need to provide API
> like setReadListener(ReadListener, ThreadPool).
> ThreadPool can be java.util.concurrent.Executor or JSR 236
> ManagedExecutorService(actually it's also Executor).

All events / dispatches / service etc are always called in the container
threads, and there should be only one container thread processing one of
these at a given point in time, otherwise the concurrency issues become
hard to solve. I am not aware of AsyncContext allowing use of an
external thread pool somewhere, start(Runnable) will run in a container
thread for example.

Rémy