tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Christophe Pierret" <cpier...@sparus-software.com>
Subject RE: Comet API and InputStream.available()
Date Wed, 24 Jan 2007 11:52:39 GMT
Here is what I understood:

Assumption #1:
================
When you receive a CometEvent.EventType.READ event, you can always read() at least one byte
from the request's InputStream without blocking.

Is this correct ?
If not correct, then this mail goes directly to trash (and sorry for the inconvenience...)

If correct, then returning 1 for InputStream.available() in this context makes sense and gives
an indication that a read can occur without blocking (without the need to convey the same
information by a side-channel).
For reference: http://java.sun.com/j2se/1.4.2/docs/api/java/io/InputStream.html for InputStream.available()
method contract with the caller. 

Note that available() returning 0 makes sense also. In this context, it means "I cannot guarantee
that you can read without blocking".
But returning 0 will force the Comet API user to use the kind of hack I used, e.g.: I have
read in the Comet API doc that I can read at least one byte without blocking and I will use
another channel to convey information about it.
For example: 
public void doOnlyNonBlockingReads(InputStream is, boolean canReadOneByteEvenIfAvailableReturns0)

The fact that data is not yet read "under the hood" is not an issue as long as Assumption#1
is correct, you can read one byte of data without blocking, when you decide to call one of
the read() methods.

I believe that when making a blocking read in a thread would be a critical issue, one should
never call InputStream.read() methods if InputStream.available() returns 0 ... You simply
don't have the guarantee that it won't block.

If you don't think that returning 1 for available() in the "CometEvent.EventType.READ event
case" is a good thing, then 
I can live with a hack in my code ;^) 
I just believe this would make the Comet API better for others and easier to use. 
Reading the data on socket before going into the READ event could also be a solution to this
kind of issue but raises other kind of problems.

Christophe

-----Message d'origine-----
De : Filip Hanik - Dev Lists [mailto:devlists@hanik.com] 
Envoyé : mardi 23 janvier 2007 18:14
À : Tomcat Developers List
Objet : Re: Comet API and InputStream.available()

ok, I'm confused, why would available return 1 when there is no data to be read?
the values for available are
 >0 data to be read
0 no data to be read
-1 end of stream reached

I don't think we have -1 in our values, as that would only happen if the client closed the
connection, and at that point we will probably call another event, although initially I know
the NIO connector calls read with 0 data to be read

Filip

Christophe Pierret wrote:
> I suggest a minor update to the behaviour exhibited by the CoyoteInputStream.available()
method when called from inside a Comet.READ event.
> Instead of returning 0 on first call (before trying to read), available() should return
1 when initially called, as it seems guaranteed that reading one byte won't block.  It is
still consistent with InputStream.available() documentation :
> *  Returns the number of bytes that can be read (or skipped over) from this input stream
without blocking by the next caller of a method for this input stream.
>
> When first read occurs, it should then return the real available bytes.
>
> I had to implement this behaviour myself when using Comet API in my product, since I
already had a working implementation for a fragmented packet reader based on ByteBuffer (done
for NIO kind of IO). 
> In this case available() would return byteBuffer.limit() - byteBuffer.position().
>
> Please have a look at code fragment at the end of mail to get the idea.
> I call InputStreamByteBuffer.setInputStream() only once for each Comet.READ event.
> Since I cannot afford to do a blocking read, I loop while( (avail= 
> myInputStreamByteBuffer.available())==0 ) and read inside the loop until (avail - count_bytes_read)
==0 ...
> My InputStream adapter code is a bit too much convoluted for my taste, but it currently
works with Comet/CoyoteInputStream.
>
> I think that implementing this kind of behaviour in Tomcat in the InputStream returned
by HttpServletRequest.getInputStream() would be a good thing.
> It could be done either by writing a wrapper around CoyoteInputStream or by adding some
extra (optional) behaviour to CoyoteInputStream activated only when inside a Comet read, or
by doing it at the InputBuffer level.
>
> What do you think of this idea ?
> If you agree, I volunteer to test the updated code (or even propose a patch for it).
>
> Here is the code fragment excerpted from my Inputstream adaptator:
> public static class InputStreamByteBuffer implements IByteBuffer
>     {
>         private InputStream inputStream;
>         private boolean fixTomcatAvailable;
>         InputStreamByteBuffer(InputStream is)
>         {
>             this.inputStream = is;
>             fixTomcatAvailable = true;
>         }
>
>         public InputStream getInputStream()
>         {
>             return inputStream;
>         }
>
>         public void setInputStream(InputStream inputStream)
>         {
>             fixTomcatAvailable = true;
>             this.inputStream = inputStream;
>         }
>
>         public int available() throws NPIOException
>         {
>             try
>             {
>                 int avail = inputStream.available();
>                 if (avail==0 && fixTomcatAvailable)
>                 {
>                     return 1; 
>                 }
>                 return avail;
>             }
>             catch (IOException se)
>             {
>                 NPIOException.rethrow(se);
>             }
>             return 0; // never reached
>         }
>         public byte get() throws NPIOException
>         {
>             if (fixTomcatAvailable) fixTomcatAvailable = false;
>             return (byte)Serializer.readByte(inputStream);
>         }
>         public void get(byte[] dst, int offset, int length) throws NPIOException
>         {
>             if (fixTomcatAvailable) fixTomcatAvailable = false;
>             try
>             {
>             	inputStream.read(dst,offset,length);
>             }
>             catch (IOException se)
>             {
>                 NPIOException.rethrow(se);
>             }
>         }
>     }
> public interface IByteBuffer
>     {
>         int available() throws NPIOException;
>         byte get() throws NPIOException;
>         void get(byte[] dst, int offset, int length) throws NPIOException;
>     }
>
> Sorry, it was a bit long, but shorter would not have been quite 
> clear... Even if I don't think this is very clear yet ;-) Christophe 
> Pierret
>
>
> -----Message d'origine-----
> De : Remy Maucherat [mailto:remm@apache.org] Envoyé : lundi 22 janvier 
> 2007 20:37 À : Tomcat Developers List Objet : Re: Congratulations to 
> tomcat developers for the Comet API
>
> Christophe Pierret wrote:
>   
>> I only had to port the patches for
>> http://issues.apache.org/bugzilla/show_bug.cgi?id=40960
>> and
>> http://issues.apache.org/bugzilla/show_bug.cgi?id=37869
>>     
>
> These two patches have been merged in HEAD.
>
>   
>> Feedback on the Comet API:
>> - There may be some ways to improve the documentation of the API: 
>> from what I saw (I got caught by this one :-), it seems that one need 
>> to call
>> CometEvent.close() before throwing an exception in READ events or the 
>> event keeps coming back forever.  I could not find a reference to 
>> this behaviour in documentation.
>>     
>
> Throw an exception like what ? If an exception is thrown by something in the event method,
it should close the connection with an error without further problems (CoyoteAdapter.event
will return false to the connector's event method, which does return a code asking for closing
the socket - and more importantly, doesn't put it back in the poller). 
> CometEvent.close() doesn't do much, so I don't understand how it can cause a different
behavior.
>
>   
>> - Is there a rationale for receiving READ events when 
>> request.getInputStream().available()==0  ?
>>     
>
> There's a reason: the actual read will be done on the socket when you read on the Java
input stream, so it's normal to have available == 0. 
> The event guarantees that the blocking read will not block. Filip suggested having the
read done before calling event, but I thought it added complexity.
>
> Rémy
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org For 
> additional commands, e-mail: dev-help@tomcat.apache.org
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org For 
> additional commands, e-mail: dev-help@tomcat.apache.org
>
>
>
>   


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org For additional commands, e-mail:
dev-help@tomcat.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Mime
View raw message