tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Filip Hanik - Dev Lists <devli...@hanik.com>
Subject Re: Comet changes
Date Tue, 08 May 2007 19:33:01 GMT
Remy Maucherat wrote:
> Filip Hanik - Dev Lists wrote:
>> Remy Maucherat wrote:
>>> Filip Hanik - Dev Lists wrote:
>>> That doesn't look like much of a problem to me. The user in that 
>>> case would be writing in a situation where canWrite is false (since 
>>> the data hasn't been written yet), which is an error. To resume 
>>> writing stuff after canWrite becomes false, the servlet would have 
>>> to wait until it gets the write event.
>> and that's my issue, no we are adding a "new hidden API", ie, we are 
>> changing the behavior of the old blocking API.
>> I like that even less than doing a cast to invoke nbWrite on 
>> writer/outputstream.
>
> We have a disagreement then ;)
not any longer, I like the idea of "non blocking mode"
>
>> outputstream.write should always do a blocking write and return only 
>> when all data is written, not be transformed by the canWrite behavior.
>
> I thought we were talking about non blocking IO. If we're talking 
> about that, then the rules are slightly adjusted when the connection 
> are placed in non blocking mode (the main difference is that reads and 
> writes on the socket are allowed to return 0, which means that no 
> bytes were written or read; the idea is then to hide this as much as 
> possible behind all the usual structures of the servlet API to be able 
> to continue using its services, including buffering and i18n).
>
>> if you dont like casting, then simply adding nbRead/nbWrite to the 
>> CometEvent interface solves all problems.
>> no need for canWrite, as in the scenario where canWrite returns 
>> false, nbWrite returns 0. same behavior. just simpler and more 
>> consistent with Java and it's non blocking features.
>
> I don't think you talked about nbWrite before, so I don't really know 
> what nbWrite is.
nbWrite - non-blocking-write
>
> The process I am talking about works like this:
> - the servlet has to place the connection in non blocking mode using a 
> method of the event (by default it uses blocking IO)
> - the servlet writes its data as if it was blocking IO (there's really 
> no way around this), but checks after each write if it is allowed to 
> continue writing using a method which will return some flag; the value 
> of this flag will indicate that it is not allowed to continue writing 
> if the last write on the socket returned 0
> - the leftover data is kept in the socket buffer - in APR, it is the 
> bbuf field of the InternalAprOutputBuffer class
> - if the flag was set and another write is attempted, throw an exception
> - the background thread which had his write interrupted and had to 
> stop then calls a "notifyWrite" callback which will add the socket in 
> a write poller
> - when the poller signals the socket, and the event method of the 
> processor is called, the leftover data in the buffer is written, and 
> the flag indicating that it's allowed to write is set to allow it if 
> all bytes were written (if not -> goes back to the poller)
> - the processor invokes the adpater which invokes the servlet with a 
> write event
> - the servlet should then notify its background thread that it may 
> resume writing on that socket (obviously, if a connection goes to the 
> poller too often, it could decide to give up)
> - reads become non blocking, and will cause an error if a read 
> returned 0 (basically, the servlet should never attempt to read in 
> that case); there's no real difference with blocking IO
>
> So it does non blocking reads and writes, but it remains very similar 
> from the Servlet perspective.
ok, I'd like to modify the process a little bit. (to make it "connection 
centric" which is what Comet really is)

- the servlet has to place the connection in non blocking mode using a 
method of the event (by default it uses blocking IO) - This can only be 
done during an "event". can NOT be done async
- the servlet writes its data as if it was blocking IO (there's really 
no way around this), but checks after each write if it is allowed to 
continue writing using a method which will return some flag; the value 
of this flag will indicate that it is not allowed to continue writing if 
the last write on the socket returned 0, even easier, if bbuf.length is > 0
- the leftover data is kept in the socket buffer
- if the flag was set and another write is attempted, throw an exception
- when the poller signals the socket, and the event method of the 
processor is called, the leftover data in the buffer is written, and the 
flag indicating that it's allowed to write is set to allow it if all 
bytes were written (if not -> goes back to the poller)
- when write completes, an event is thrown EventType=NOTIFY 
EventSubType=WRITE_COMPLETE
- the servlet should then notify its background thread that it may 
resume writing on that socket, timeout rules for writing are also put in 
place


Here are some changes.
1. The background thread should not have to call notifyWrite, since we 
provide READ event, we can also provide
   an automatic event is thrown when a write completes EventType=NOTIFY 
EventSubType=WRITE_COMPLETE, as soon as the write does complete
   One exception, if the write completes on the first write attempt, 
canWrite returns true immediately after outputstream/writer.write(...)
   It is easier to implement, as we don't have to keep track of if they 
want to be notified or not.
   So basically, outputstream.write() -> canWrite==true -> we finished 
writing everything
   and in the same fashion, outputstream.write() -> canWrite==false -> 
we can expect a NOTIFY event
   canWrite should measure the length of bbuf, that's the easiest way to 
know if we can write or not

2. The automatic NOTIFY/WRITE_COMPLETE event, as talked about above

3. Since a write can timeout, and event ERROR/TIMEOUT might happen 
instead of NOTIFY/WRITE_COMPLETE.
   This is one case where ERROR/TIMEOUT should close the socket, and 
that is why I think it should always do it
   regardless of have we do it now. Keeping a connection open after a 
TIMEOUT is not good, cause it makes it so much harder to clean up
   In a write timeout, we have data left in a buffer

4. Implementation detail, in TC 6 the buffers are sent in a separate 
flush to the socket
   Can we just merge this with the first servlet flush or automatic flush
   This will simply send the response headers with the first data for 
the response, hence be included in the
   "non block" write logic without further workarounds for that.

5. non block read
   After thinking about it, and since we send "events" when data is 
available on the socket
   I don't think we should enable them.
   The only time a non block read, would be in Comet connections that 
are in:
   a) the connection is non block mode &&
   b) the connection is not registered for a OP_READ with the Poller
   Because of the concurrency problems that can arise from non-block 
read and the connection being registered for READ with the poller,
   this feature is actually better if it is left implemented as it is 
today.

6. READ event
   However, there is a need to modify the read, currently the 
CoyoteAdapter will end up in a blocking read if not enough data
   has been fetched that is needed for the filter.
   The filter should be able to back out, so that the connection gets 
returned to the poller to retrieve more data
   Bottom line is that Comet threads should never call 
inputstream.read() unless it is a READ event
   If we feel there is a need, we can make non block read available to 
the servlet, although I see that lower priority than the write
   stuff and the blocking CoyoteAdapter.read


>
> All in all, NB IO is cute, but I'd like to know which use case it 
> addresses in Servlet land. Hopefully it's not to be able to implement 
> a stream server ;)
It's huge, thousands of comet connections, and 1 background thread, 
since Comet's main advantage is "server push" over all the other techniques
that one thread should never block.

OK. So I'm all along with this way of doing it, it will work out pretty 
well,

comment on this load of bull that I just put together please

Filip

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


Mime
View raw message