> On 30 March 2012 03:27, Rajiv Mordani<rajiv.mordani_at_oracle.com>  wrote:
>> Ok we have been discussing this also internally - where we remove the
>> parameter in
>> the canWrite method - so the method signature would be
>>
>> boolean canWrite();
>>
>> and of course I already suggested that we have the write methods return an
>> int which
>> indicates. So we will do that.
Once we don't have integer parameter neither in canWrite nor in 
notifyCanWrite, AFAIU we can guarantee that if canWrite() returned true 
- next "write" method call (despite the size of the passed data) will 
not block.*
*-------------------------------------------------------------------
if (os.canWrite()) {
         os.write(appBuffer); <---- no blocking here even if appBuffer 
is huge
}
-------------------------------------------------------------------
It sounds good to me because once we have the appBuffer in memory ready 
to be written, it makes no difference (application maintains the 
reference or the write queue does) where the buffer reference is kept.
The biggest question for me is if/how/when I can reuse appBuffer again?
If the appBuffer is less than the sevlet buffer, we can just copy it 
into the servlet buffer.  I don't see any problems with that usecase.  
I'm more interested in the usecase where the appBuffer is larger than 
the servlet buffer.
Remy proposes to copy the appBuffer remainder, left after our 
Channel.write(...) attempt(s), to an internal buffer, so the appBuffer 
can be reused right after returning from the "write" call.
-------------------------------------------------------------------
if (os.canWrite()) {
         os.write(appBuffer);
}
<-------------    starting here we can reuse appBuffer
-------------------------------------------------------------------
 From usability point of view it sounds great, however it's not 
efficient when we deal w/ big appBuffers, especially if we try to write 
direct/mapped ByteBuffers.
If we want to avoid buffers copy and still want to reuse appBuffer, the 
code may look like:
-------------------------------------------------------------------
if (os.canWrite()) {
         os.write(appBuffer);
}
os.flush(); <---------- flush servlet buffer
if (os.canWrite()) {
     (1) <----------------  starting here we can reuse appBuffer
} else {
         os.notifyCanWrite(new WriteListener() {
                     void onWritePossible() {
                                 (2) <----------------  starting here we 
can reuse appBuffer
                     }
         }
}
-------------------------------------------------------------------
So in this case we always have to flush() and then make sure we 
canWrite() before reusing appBuffer.
For sure, as we see, from the usability point of view the cost of 
copy-free approach is relatively high, but if we deal w/ large 
mapped/direct buffers, may be it's worth?
Just an idea, may be it's not good, but anyway:
1) When dealing w/ byte[] (existing OutputStream API) we go w/ Remy's 
suggestion, which may involve internal byte[] copying. IMO this approach 
is clear and very intuitive to Servlet developers, even though it's not 
optimal in some cases.
2) Introduce new method(s) (Servlet)OutputStream.write(ByteBuffer), 
which will be implemented in a copy-free fashion. We'll document the 
fact, that developer can reuse the ByteBuffer only after making sure 
it's not used by container.
Thanks.
WBR,
Alexey.