users@servlet-spec.java.net

[servlet-spec users] [jsr340-experts] Re: Servlet 3.1 EDR updated draft

From: Greg Wilkins <gregw_at_intalio.com>
Date: Fri, 1 Jun 2012 15:08:23 +0200

On 1 June 2012 14:37, Remy Maucherat <rmaucher_at_redhat.com> wrote:
> On Fri, 2012-06-01 at 14:26 +0200, Remy Maucherat wrote:
>> Yes, this is why I said that the callback must happen after the
>> canWrite() method is called and returns false, this is actually the
>> trigger [it is not when the flag flips]. This is an important trick to
>> make it work.
>>
>> I think I described the algorithm in detail already.
>
> Note (before I get misinterpreted to death) that this is *my* solution.

I like the Remy model. It solves several problems:
   + reduces the number of callbacks - you only do a callback if the
write does not complete by the time that you want to do the next
write.
   + because callbacks are never done for a write that does complete
immediately, there is no possibility to use the calling thread for the
callback - thus we don't have the stack growth problem.
   + users who are doing a complete write in a single buffer don't
need to worry about either canWrite or callbacks - they can write and
forget.

So if this is really what is intended by the current spec, then I
think the text needs to be worked on to make it really clear that
onWritePossible will be called IFF (if and only if) canWrite has been
called AND has returned false AND a writelistener has previously been
set. The alternative option of setting the writelistener each time is
semantically equivalent, but as WriteListeners will often be anonymous
innerclasses, then it is far more convenient to call canWrite().

Note also that the decision to use the existing ServletOutputStream
APIs for writing is really means that we are adopting a quasi NIO.2
style. With "traditional" async APIs, there is the possibility of a
partial write and the caller has to deal with those. But by using
the SOS.write methods we do not have the possibility of a partial
write because they don't pass back a count, so we are kind of like
NIO.2 where the write call will write the entire buffer and call you
back when it is done. The only modification is that rather than
always passing a callback, we are setting the callback previously and
then using canWrite() to activate the callback only when it is really
needed.

Now if we specified the buffering model to be pass by reference rather
than pass by value, then I would be very happy indeed with this hybrid
model of async IO.

regards