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:[EMAIL PROTECTED] 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:[EMAIL PROTECTED] 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: [EMAIL PROTECTED] For > additional commands, e-mail: [EMAIL PROTECTED] > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [EMAIL PROTECTED] For > additional commands, e-mail: [EMAIL PROTECTED] > > > > --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]