jsr340-experts@servlet-spec.java.net

[jsr340-experts] Re: setWriteListener setReadListener

From: Greg Wilkins <gregw_at_intalio.com>
Date: Mon, 20 May 2013 18:17:21 +1000

To be really clear about the async behaviour, I'm wondering if we should
include a state machine in the MR? That helped clarify the async request
lifecycle.


This is the state machine that I'm currently implementing in Jetty for
writes, which includes auto blocking:


ACTION BLOCKING READY PENDING UNREADY
COMPLETE AUTOBLOCK
------------------------------------------------------------------------------------------------

setWriteListener() READY->owp ise ise ise
ise ise

write() BLOCKING PENDING AUTOBLOCK wpe
AUTOBLOCK wpe

isReady() ise READY:true UNREADY:false UNREADY:false
READY:true ise

write completed BLOCKING - COMPLETE READY->owp
- AUTOBLOCK/COMPLETE

------------------------------------------------------------------------------------------------


ise = IllegalStateException
wpe = WritePendingException
->owp = call onWritePossible


So some typical sequences of events/states are

Blocking writes:

   1. getOutputStream() BLOCKING
   2. write() BLOCKING
   3. write() BLOCKING
   4. ...

Async writes that complete immediately twice and then is incomplete twice

   1. getOutputStream() BLOCKING
   2. setWriteListener() READY->owp
   3. onWritePossible()
   1. write() PENDING
      2. write 3.1 completed COMPLETE
      3. isReady() READY:true
      4. write() PENDING
      5. write 3.4 complete COMPLETE
      6. isReady() READY:true
      7. write() PENDING
      8. isReady() UNREADY:false
   4. write 3.7 complete READY->owp
   5. onWritePossibe()
   1. write() PENDING
      2. isReady() UNREADY:false
   6. write 5.1 complete READY->owp
   7. onWritePossibe() READY


Async write that starts a thread to do an autoblocking write that happens
after async write completes

   1. getOutputStream() BLOCKING
   2. setWriteListener() READY->owp
   3. onWritePossible()
   1. write() PENDING
      2. AsyncContext#start(task)
      4. write 3.1 complete COMPLETE
   5. task#run()
      1. write() AUTOBLOCK
      2. write complete COMPLETE
      3. write() AUTOBLOCK
      4. write complete COMPLETE
      5. ....

Async write that starts a thread to do an autoblocking write that happens
before async write completes

   1. getOutputStream() BLOCKING
   2. setWriteListener() READY->owp
   3. onWritePossible()
   1. write() PENDING
      2. AsyncContext#start(task)
   4. task#run()
      1. write() AUTOBLOCK
      2. write 3.1 complete AUTOBLOCK
      3. write 4.1 complete COMPLETE
      4. write() AUTOBLOCK
      5. write 4.4 complete COMPLETE
      6. ....

and finally an autoblocking thread can switch back to async:

   1. task#run()
      1. write() AUTOBLOCK
      2. write 3.1 complete AUTOBLOCK
      3. write 4.1 complete COMPLETE
      4. write() AUTOBLOCK
      5. write 4.4 complete COMPLETE
      6. isReady() READY:true
      7. write() PENDING
      8. write 4.7 complete COMPLETE
      9. isReady() READY:true
      10. write() PENDING
      11. isReady() UNREADY:false
   2. write 1.10 completes READY->owp
   3. onWritePossible()
      1. write() PENDING
      2. isReady UNREADY:false
   4. ...


If we don't want autoblocking, then I just think we throw ISE instead of
entering AUTOBLOCK state
Does this look similar enough to what others are doing? Is it worthwhile
to put something like this (perhaps state diagram) in the MR?

cheers





On 20 May 2013 14:35, Greg Wilkins <gregw_at_intalio.com> wrote:

>
> On 17 May 2013 19:25, Rémy Maucherat <rmaucher_at_redhat.com> wrote:
>
>> Looking at some of the more creative uses of the API, like websockets,
>> Mark found some issues and there has been a discussion about having
>> concurrent read/write, or autoblocking (both should allow implementing
>> websockets, but experimentation is ongoing).
>
>
> I've read that thread lots of interesting points raised but no clear
> conclusion. This is a really a significant part of any implementation, so
> I think it is very important that we clarify what is allowable ASAP.
>
> Currently as the spec is written, it implies that only a single thread can
> be in either a servlet dispatch, a read callback or a write callback.
> Another way of saying that is that once asynchronous IO is initiated, the
> container expects that the application will not block in servlet dispatch
> or any read/write callbacks, as to do so will prevent other calls being
> made.
>
> As Mark says, this is a limitation that will prevent things like
> simulating blocking APIs with the async IO or even mixing blocking input
> with async output. However, the AsyncContext#start(Runnable) method
> is available and we could always say that an application that wishes to
> block should use that API to access a different thread. So for example
> the JSR356 implementation should not callback websocket methods directly
> from IO callbacks nor servlet dispatch as those callbacks could use a
> blocking websocket API. Instead the JSR356 implementation should use
> AsyncContext#start(Runnable) to access other threads to do those callbacks,
> which are free to block.
>
> We could say that we will move this thread dispatch mechanism to the
> container so that applications need not have to deal with dispatching
> threads themselves, but that would mean that all IO callbacks would have to
> be dispatched with a thread that we can allow to block. That means that
> we pay a price even if we don't have any blocking in our callbacks. So
> I think I prefer that we stick with how the spec is written and only allow
> a single thread. We just need to be more explicit in a MR that the
> callbacks cannot block and should use AsyncContext#start if they have
> might.
>
> I also think that this means that the initial callbacks to onWritePossible
> onReadPossible should not happen until after the thread dispatched to the
> servlet returns.
>
> cheers
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> --
> Greg Wilkins <gregw_at_intalio.com>
> http://www.webtide.com
> Developer advice and support from the Jetty & CometD experts.
> Intalio, the modern way to build business applications.
>



-- 
Greg Wilkins <gregw_at_intalio.com>
http://www.webtide.com
Developer advice and support from the Jetty & CometD experts.
Intalio, the modern way to build business applications.