tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Christophe Pierret" <cpier...@sparus-software.com>
Subject Comet API and InputStream.available()
Date Tue, 23 Jan 2007 12:21:15 GMT
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


Mime
View raw message