Re: Proposed simplification of CometEvent

2007-06-28 Thread Remy Maucherat

Filip Hanik - Dev Lists wrote:

nice ultimatum :)
let me go through both the proposals and look it over. after that I 
suggest we simply have/agree on a majority vote without vetoes to be 
able to move on properly.
in the vote announcement, I think we should simply outline the 
differences so that folks understand that rather than getting confused 
in comet concepts.

you and I can draft that outline together offline,


I understand your answer as that your position on this proposal did not 
change.


As far as I am concerned, proposals are consensus, not votes. I also 
don't think people are interested enough to vote.


Rémy

-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Re: Proposed simplification of CometEvent

2007-06-28 Thread jean-frederic clere

Remy Maucherat wrote:

Filip Hanik - Dev Lists wrote:

nice ultimatum :)
let me go through both the proposals and look it over. after that I 
suggest we simply have/agree on a majority vote without vetoes to be 
able to move on properly.
in the vote announcement, I think we should simply outline the 
differences so that folks understand that rather than getting confused 
in comet concepts.

you and I can draft that outline together offline,


I understand your answer as that your position on this proposal did not 
change.


As far as I am concerned, proposals are consensus, not votes. I also 
don't think people are interested enough to vote.


A vote proposal should be [VOTE] in the subject. Like [VOTE] Which Comet 
implementation/API to use.
You just answer to an old thread so that doesn't cache the attention of 
community.


Cheers

Jean-Frederic


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]



Re: Proposed simplification of CometEvent

2007-06-28 Thread Remy Maucherat

Remy Maucherat wrote:

Filip Hanik - Dev Lists wrote:

nice ultimatum :)
let me go through both the proposals and look it over. after that I 
suggest we simply have/agree on a majority vote without vetoes to be 
able to move on properly.
in the vote announcement, I think we should simply outline the 
differences so that folks understand that rather than getting confused 
in comet concepts.

you and I can draft that outline together offline,


I understand your answer as that your position on this proposal did not 
change.


I got confirmation of this through a private email, and since I believe 
a community vote on this is meaningless (at least at this time, where 
it's obvious nobody cares), I am withdrawing my proposal at this time, 
as well as withdrawing my veto for your proposal.


Rémy


-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Re: Proposed simplification of CometEvent

2007-06-27 Thread Remy Maucherat

Remy Maucherat wrote:

Hi,

I've been working on additions to CometEvent to implement the additional 
Comet functionality that was agreed upon before creating the trunk 
branch. Although not functional at the moment, I consider it to be 
developed enough from an algorithmic standpoint to be proposed and 
reviewed (it is also important to not continue an API fork for too long, 
since otherwise it would be harder to merge, so some resolution is 
needed). I went through a few revisions of the API, as more tweaks 
appeared possible. The idea was to allow the extra functionality without 
adding complexity or incompatible changes, since this is most likely 
going to be an interim API.


The repository is at:
https://svn.apache.org/repos/asf/tomcat/sandbox/comet


I made a number of updates since this proposal (which has been vetoed) 
was made. The API makes implicit a lot of behaviors which I found are 
not needed for the end user, and attempts to be fairly high level. In 
particular, I have rewritten the javadoc, which was self conflicting 
(due to forgetting to update some wording inherited from TC 6.0). All 
6.0.13 API usage should remain compatible (I do expect at least one 
behavior fix in 6.0.x, though).


It has the following changes over the 6.0.x branch:
- additions of three methods in CometEvent (sleep and resume, and the
ready flag)
- sleep() delays request processing until either resume() is called, or a
timeout occurs
- sleep() also disables read events until resume() is called (in 
addition to invoking a generic event, resume() also enables read events)

- resume() allows waking up requests which are asleep or waiting for
an IO event
- non blocking IO exclusively (with, as an exception to the rule, a 
switch to blocking IO in very specific cases of synchronous IO operations)

- no additional data structures
- new ActionCode: ACTION_COMET_TIMEOUT (which is cleanup),
ACTION_COMET_RESUME (called by the resume() method),
ACTION_COMET_SLEEP (called by the sleep() method), ACTION_COMET_WRITE
(called by the CometEvent.ready() method without the need for an
explicit callback from the servlet - ready() knows the result of the
last write, and the servlet is supposed to not attempt any further
writing if ready() returns false)
- no additional features, like verification of caller threads (which I
consider useless)
- change to o.a.comet package

I hope I did not forget anything. Certain items could still be changed 
(like the package name, or the name of the ready() method - the problem 
with that one is that it does not particularly imply writing, but OTOH 
the old canWrite and isWriteable names were quite inelegant).


I don't want to block development forever, so if this proposal is 
refused using an outright veto like the previous version of the 
proposal, I will not block competing proposals using a veto of my own. 
However, I will most likely stop participating in trunk development 
(which is not the end of the world since I've been working on Tomcat for 
pretty much forever, so it could be a good time to move on).


Comments ? / Votes ?

Rémy


-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Re: Proposed simplification of CometEvent

2007-06-27 Thread Filip Hanik - Dev Lists

Remy Maucherat wrote:

Remy Maucherat wrote:

Hi,

I've been working on additions to CometEvent to implement the 
additional Comet functionality that was agreed upon before creating 
the trunk branch. Although not functional at the moment, I consider 
it to be developed enough from an algorithmic standpoint to be 
proposed and reviewed (it is also important to not continue an API 
fork for too long, since otherwise it would be harder to merge, so 
some resolution is needed). I went through a few revisions of the 
API, as more tweaks appeared possible. The idea was to allow the 
extra functionality without adding complexity or incompatible 
changes, since this is most likely going to be an interim API.


The repository is at:
https://svn.apache.org/repos/asf/tomcat/sandbox/comet


I made a number of updates since this proposal (which has been vetoed) 
was made. The API makes implicit a lot of behaviors which I found are 
not needed for the end user, and attempts to be fairly high level. In 
particular, I have rewritten the javadoc, which was self conflicting 
(due to forgetting to update some wording inherited from TC 6.0). All 
6.0.13 API usage should remain compatible (I do expect at least one 
behavior fix in 6.0.x, though).


It has the following changes over the 6.0.x branch:
- additions of three methods in CometEvent (sleep and resume, and the
ready flag)
- sleep() delays request processing until either resume() is called, or a
timeout occurs
- sleep() also disables read events until resume() is called (in 
addition to invoking a generic event, resume() also enables read events)

- resume() allows waking up requests which are asleep or waiting for
an IO event
- non blocking IO exclusively (with, as an exception to the rule, a 
switch to blocking IO in very specific cases of synchronous IO 
operations)

- no additional data structures
- new ActionCode: ACTION_COMET_TIMEOUT (which is cleanup),
ACTION_COMET_RESUME (called by the resume() method),
ACTION_COMET_SLEEP (called by the sleep() method), ACTION_COMET_WRITE
(called by the CometEvent.ready() method without the need for an
explicit callback from the servlet - ready() knows the result of the
last write, and the servlet is supposed to not attempt any further
writing if ready() returns false)
- no additional features, like verification of caller threads (which I
consider useless)
- change to o.a.comet package

I hope I did not forget anything. Certain items could still be changed 
(like the package name, or the name of the ready() method - the 
problem with that one is that it does not particularly imply 
writing, but OTOH the old canWrite and isWriteable names were quite 
inelegant).


I don't want to block development forever, so if this proposal is 
refused using an outright veto like the previous version of the 
proposal, I will not block competing proposals using a veto of my own. 
However, I will most likely stop participating in trunk development 
(which is not the end of the world since I've been working on Tomcat 
for pretty much forever, so it could be a good time to move on).

nice ultimatum :)
let me go through both the proposals and look it over. after that I 
suggest we simply have/agree on a majority vote without vetoes to be 
able to move on properly.
in the vote announcement, I think we should simply outline the 
differences so that folks understand that rather than getting confused 
in comet concepts.

you and I can draft that outline together offline,

Filip


Comments ? / Votes ?

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]



Re: Proposed simplification of CometEvent

2007-06-17 Thread Filip Hanik - Dev Lists

Costin Manolache wrote:

On 6/15/07, Filip Hanik - Dev Lists [EMAIL PROTECTED] wrote:


correction, should read

I can implement inputstream.read() to return 0 on both blocking and non
blocking *Comet events*, (since sockets are always non blocking)




Ok, my mistake - what I really meant to say is:  I am only interested in
Comet if it
behaves similar with non-blocking sockets ( regardless of 
implementation ),

i.e. read(), write() called inside
a comet servlet will never block.

well, then you are out of luck, cause that's not in the running right now.
I earlier proposed that CometEvent would have two new methods
nbRead(ByteBuffer) and nbWrite(ByteBuffer) that would do exactly that.

That proposal was quickly shutdown since we thought that we should still 
be using the Servlet API.
And you can't get NIO socket functionality using streams, readers or 
writers.


From the description so far it seems the sandbox version has this 
property

and the trunk has
an option to make it blocking ( or so I understood from your comments ).

I'm not familiar with the concept of 'non blocking *Comet events*' - 
never

heard of an event that
blocks or doesn't block before. If you mean that during a comet event 
read

will be blocking (
based on config or whatever else ) - I think this is a bad design.

That's how 6.0.13 is working, and I don't think its bad design.
Take a look at the first example in
http://people.apache.org/~fhanik/tomcat/aio.html#Example%20code%20snippets
It's a real life example, and clearly shows how much easier it is to 
write code

using blocking read/write methods.

In the current proposal non blocking would also happen on the existing 
Servlet API making it a little harder to program,
but we got there from deciding to stick with the Servlet API and not 
create any new read or write methods.


Filip


Costin



No virus found in this incoming message.
Checked by AVG Free Edition. 
Version: 7.5.472 / Virus Database: 269.9.0/852 - Release Date: 6/17/2007 8:23 AM
  



-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Re: Proposed simplification of CometEvent

2007-06-17 Thread Remy Maucherat

Filip Hanik - Dev Lists wrote:
Ok, one use case scenario would be AJAX requests with asynchronous 
responses on the server, I can see this be extremely common,
I've tried to add in comments to make the example clear, and I don't see 
this example as stupid, as there are a lot more AJAX client frameworks 
than Comet client frameworks.


So there are two things we are show casing
1. The ability to write asynchronously
2. The ability to pipeline HTTP requests (assumption: only dealing with 
GET requests, no HTTP request body)
3. Difference between Comet non blocking and Comet blocking read and 
writes (note, not related to sockets, API only)


What I'd like to point out is that this example, becomes easier with 
blocking read/writes, so I've added that at the bottom for comparison


Let me know if I've made any mistakes here, so that we can work with a 
correct example.


Non blocking read and writes

public class ExampleDelayedAjaxResponse implements CometProcessor {
 ...
 public class DelayedResponder extends Thread {
   public void run() {
 ...
 Client[] clients = getClients();
 for (int i=0; iclients.length; i++ ) {
   CometEvent event = client.getEvent();
   byte[] data = getDelayedResponse(event);
   if (data!=null) {
 if (event.isWriteable()) {
   event.getHttpServletResponse().getOutputStream().write(data);
   if (event.isWriteable()) { //did we write it all?
  event.close(); //close the event, in anticipation of the 
next request

  event.register(OP_CALLBACK); //triggers an END event
   } else { //we didn't write it all, trigger a WRITE event when 
we are done with the write   event.register(OP_WRITE);

   }
 } else {
   //we are not able to write, let us know when we can
   event.register(OP_WRITE);


How can you not be able to write, since you didn't write anything at all 
yet for this request.



 }
 //remove the client from the  async thread
 //since we have received the data for this client.
 clients.remove(event);
   }
 }
 ...
   }
 }
 ...
 public void event(CometEvent event) throws IOException, ServletException {
   ...
   if ( event.getEventType() == CometEvent.EventType.BEGIN ) {
 //configure non blocking
 event.configureBlocking(false);
 //deregister for READ since we want to enable pipe lining on the 
connection  //for the next HTTP request

 event.unregister(OP_READ);
 //add the client to the list
 clients.add(event);
   } if ( event.getEventType() == CometEvent.EventType.READ ) {
 //read client Id and stock list from client
 //and add the event to our list
 assert(this should never happen);
   } if ( event.getEventType() == CometEvent.EventType.WRITE ) {
 //unregister from the write event
 event.unregister(OP_WRITE);
 //we can now write
 byte[] data = getDelayedResponse(event);   if ( data != 
null ) {

   event.getHttpServletResponse().getOutputStream().write(data);
 }
 if( data==null || event.isWriteable() ) {
   event.close();
 }
 } if ( event.getEventType() == CometEvent.EventType.END ) {
 clients.remove(event); } else if (...) {
 ...
   }
   ...
 }
}

Blocking read and writes
public class ExampleDelayedAjaxResponse implements CometProcessor {
 ...
 public class DelayedResponder extends Thread {
   public void run() {
 ...
 Client[] clients = getClients();
 for (int i=0; iclients.length; i++ ) {
   CometEvent event = client.getEvent();
   byte[] data = getDelayedResponse(event);
   if (data!=null) {
 //register for a write, better do that on a thread pool thread
 //since write is blocking
 event.register(OP_WRITE);
 //remove the client from the  async thread
 clients.remove(event);
   }
 }
 ...
   }
 }
 ...
 public void event(CometEvent event) throws IOException, ServletException {
   ...
   if ( event.getEventType() == CometEvent.EventType.BEGIN ) {
 //configure non blocking
 event.configureBlocking(false);
 //deregister for READ since we want to enable pipe lining on the 
connection  //for the next HTTP request


No. The situation where the end of the entity body is reached is 
detected very easily, and handled using a sleep (the 6.0 code is very 
close from that already).



 event.unregister(OP_READ);
 //add the client to the list
 clients.add(event);
   } if ( event.getEventType() == CometEvent.EventType.READ ) {
 //read client Id and stock list from client
 //and add the event to our list
 assert(this should never happen);
   } if ( event.getEventType() == CometEvent.EventType.WRITE ) {
 //unregister from the write event
 event.unregister(OP_WRITE);
 //we can now write
 byte[] data = getDelayedResponse(event);   //note we don't 
have to check for null data here

 

Re: Proposed simplification of CometEvent

2007-06-16 Thread Costin Manolache

On 6/15/07, Filip Hanik - Dev Lists [EMAIL PROTECTED] wrote:


correction, should read

I can implement inputstream.read() to return 0 on both blocking and non
blocking *Comet events*, (since sockets are always non blocking)




Ok, my mistake - what I really meant to say is:  I am only interested in
Comet if it
behaves similar with non-blocking sockets ( regardless of implementation ),
i.e. read(), write() called inside
a comet servlet will never block.


From the description so far it seems the sandbox version has this property

and the trunk has
an option to make it blocking ( or so I understood from your comments ).

I'm not familiar with the concept of 'non blocking *Comet events*' - never
heard of an event that
blocks or doesn't block before. If you mean that during a comet event read
will be blocking (
based on config or whatever else ) - I think this is a bad design.

Costin


Re: Proposed simplification of CometEvent

2007-06-15 Thread Filip Hanik - Dev Lists

Costin Manolache wrote:

On 6/14/07, Filip Hanik - Dev Lists [EMAIL PROTECTED] wrote:


Costin Manolache wrote:
 
 
  Sounds better - but as Remy explained you would first need to 
explain

  why blocking is needed in this context and how to deal with the
 confusion
  of mixing blocking and non-blocking for users, and the 
implementation

  complexities it adds.
 trunk doesn't mix them. a comet connection is either blocking or non
 blocking, it doesn't shift between the two,
 and it allows developers to choose what they want. Just like a
 SocketChannel in java.nio.
 there is nothing confusing about that, unless java.nio is 
confusing :)




 Well, nio is far from perfect - but that's not the point.

 Servlets have a very nice blocking mechanism already - it's the
 servlet API
 :-).
 The question is why would you need to have a Commet connection 
blocking.





because comet is not a servlet, and the ease of use for having blocking

write and read is huge,
especially when Tomcat can notify you when you can write or read, there
is no need to scratch your head and try to use non blocking.
non blocking is more complex, and not for everyone.




I'm not sure I understand - there is a perfectly fine blocking read/write
interface, it's the
plain servlet API.

you're hung up on the servlet API, there is a *huge* difference. :)
If you stick with the servlet API, the thread and connection is a 1 to 1 
mapping. Ie, if you want to do comet over a regular servlet,

you can't have more connections than max threads.
With comet, this limitation goes away. And this limitation or the 
removal thereof has nothing to do with blocking or non blocking,


With comet, you get an event when you need to read or can write, when 
you actually do the read/write the IO logic of it is blocking,
but to you as a developer it is almost transparent. since it would only 
block in extremely rare cases, even with blocking IO.


Please note, that neither Remy nor I have yet really talked about non 
blocking reads, so you might think sandbox is non blocking, well it is not.
It is buffering, but not non blocking. a true non blocking read, would 
require a rewrite of all the buffer filters to keep state between read 
invocations.


We get away from this on the write, cause we can store the last write 
and keep it at the bottom layer. this is not a true non blocking write, 
as this implementation prevents any further write attempts by throwing 
an IOException or IllegalStateException.


I also agree that 'blocking' mode is sometimes easier to code than
event-based, and
I can see the benefit of doing some stuff in blocking mode and some in
non-blocking.

My concern was making the read and write blocking in a commet servlet 
based

on
a config in the CometEvent.

The alternative is to have the comet servlet allways non-blocking for
read/write, but
provide a convenience method that will simulate the blocking read or 
write (

which is
easy, all you need is a blocking waitForEvent(time) ). Benefits:
- the read/write implementation is simpler ( no need to check the config
mode or do tricks ),
- comet is easier to understand
- you can do more advanced things, like using reads in non-blocking 
mode and

writes in blocking
mode.

The code using waitForEvent() is a bit more complicated than the code for
blocking read/write (
but if you want the simplest solution - use regular servlet ), and it is
simpler than a pure
callback based model.





 I think it's very reasonable to add a blocking waitForEvent() to allow
 servlets have a
 simpler ( but less efficient ) implementation.





Comet inherently is a wait for event system. Tomcat acts as a

multiplexer/dispatcher,and fires events into the CometProcessor.



Comet seems to be an event-based system, that's why setting it to 
'blocking

mode' is so
confusing and bad. I'm not sure I agree it has to be a 'blocking wait for
event' system - in Remy
examples at least it is not.



The waitForEvent() method is obsolete in the Comet implementation, as

you are either on a Tomcat thread,
which you can activate at any time or you are on a async thread, and not
sure why you would need to block an async background thread.

 Think about utilities that take the event as param - would they 
need to

 check first
 if it's blocking or not ? And what would blocking give you in addition
to
 waitForEvent() -
 which is actually better since it allows you to un-block on any event,
 not
 only a specific
 read/write.
I can see that there is a huge misunderstanding of how comet actually
does work and what it actually is.
It is true that is essentially just a TCP socket between server and
client, but in addition to that,
Tomcat provides a shell around it, and instead of you having to manage
when to read or when to write,
tomcat becomes an event API.



Sure, it hides some limitations of NIO ( the IO thread that has to do all
things )
and adds some higher-level HTTP stuff.





   - please don't call the method configure(), it's 

Re: Proposed simplification of CometEvent

2007-06-15 Thread Remy Maucherat

Filip Hanik - Dev Lists wrote:
Please note, that neither Remy nor I have yet really talked about non 
blocking reads, so you might think sandbox is non blocking, well it is not.
It is buffering, but not non blocking. a true non blocking read, would 
require a rewrite of all the buffer filters to keep state between read 
invocations.


It is non blocking, as the low level read is always non blocking (in the 
sandbox design).


Rémy


-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Re: Proposed simplification of CometEvent

2007-06-15 Thread Remy Maucherat

Filip Hanik - Dev Lists wrote:

public class ExampleCometStockStreamer implements CometProcessor {
  ...
  public class StockUpdater extends Thread {
public void run() {
  ...
  StockUpdates[] updates = fetchUpdates();
  Client[] clients = getClients(updates);
  for (int i=0; iclients.length; i++ ) {
StockUpdates[] clientList = getClientUpdates(client,updates);
client.setAndMergeNextUpdates(clientList);
client.getEvent().callback();
  }
  ...
}
  }
now its starting to look funny, In the trunk version of the example, I'm 
interested if the socket buffer is ready to receive data,
but the sandbox version of it simply doesn't care, it just calls for a 
tomcat thread.

sandbox:
 client.getEvent().callback(); - no guarantee for writeability
trunk:
 client.getEvent().register(OP_WRITE) - event fires when network buffer 
is ready to receive data.


The only thing funny here is your example. The writes done in the 
callback event are blocking if needed. For an equivalent of your code, 
you could do

if (isWriteable()) { callback(); }
etc

All of these examples are not very good, I think :( In most of these, 
you should not be using Comet I think: CPU usage will skyrocket, 
killing off the benefits over regular Servlets with blocking IO.
Of course the examples aren't very real world'ish, the point was to 
simply show the differences in the API.


However, I think we have uncovered a larger problem than what API do we 
pick right now. The concept of Comet is very clear to the two of us.
I know how your impl would work, and I'm pretty sure you know how mine 
would work. But beyond that, the basics around Comet is still not well 
explained nor understood.
While we are debating method names and implementation details, our 
thread is being misunderstood.


Actually, I believe many people understand event based IO, so I don't 
see the problem. I am not debating an implementation detail or a method 
name (I would like to get good method names ideas, actually), I am 
arguing against your API design, which does not make sense to me.


I think starting to work on the Bayeux impl, or some other examples, 
will shine some more light on this.


Great, I will be able to port this impl to a reasonable API :)

Rémy


-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Re: Proposed simplification of CometEvent

2007-06-15 Thread Filip Hanik - Dev Lists

Remy Maucherat wrote:

Filip Hanik - Dev Lists wrote:
Please note, that neither Remy nor I have yet really talked about non 
blocking reads, so you might think sandbox is non blocking, well it 
is not.
It is buffering, but not non blocking. a true non blocking read, 
would require a rewrite of all the buffer filters to keep state 
between read invocations.


It is non blocking, as the low level read is always non blocking (in 
the sandbox design).

so is the trunk impl, if you consider that non blocking. but if you use
request.getInputStream().read() - that would require all the filters to 
be modified to keep the state of the last read,

so that request.getInputStream().read() can indeed return 0.

in trunk, I found a way to get away with this, I did the following on 
the isReadable()


isReadable() == available()0 || InternalNioInputBuffer.hasData()==true 
|| InternalNioInputBuffer.read()0


where the last InternalNioInputBuffer.read() is non blocking.

are you of a different understanding that the filters would not need any 
modification to make request.getInputStream().read() non blocking?


Filip

-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Re: Proposed simplification of CometEvent

2007-06-15 Thread Costin Manolache

Ok, so let me double check: the low level socket in sandbox is allways read
after a poll() / select(),
and never with a blocking read() ?

After the poll(): the Comet servlet, in a tomcat thread will be able to call
read() in the input
stream, and that will return data or 0 if no more data is available ( or -
call isReadable() and then read(),
or whatever else - but the socket will not be put in blocking mode ) ?

If this is true for sandbox - big +1.

Costin

On 6/15/07, Remy Maucherat [EMAIL PROTECTED] wrote:


Filip Hanik - Dev Lists wrote:
 Please note, that neither Remy nor I have yet really talked about non
 blocking reads, so you might think sandbox is non blocking, well it is
not.
 It is buffering, but not non blocking. a true non blocking read, would
 require a rewrite of all the buffer filters to keep state between read
 invocations.

It is non blocking, as the low level read is always non blocking (in the
sandbox design).

Rémy


-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




Re: Proposed simplification of CometEvent

2007-06-15 Thread Filip Hanik - Dev Lists

Costin Manolache wrote:
Ok, so let me double check: the low level socket in sandbox is allways 
read

after a poll() / select(),
and never with a blocking read() ?

huh? :)



After the poll(): the Comet servlet, in a tomcat thread will be able 
to call

read() in the input
stream, and that will return data or 0 if no more data is available ( 
or -

call isReadable() and then read(),
or whatever else - but the socket will not be put in blocking mode ) ?

and some more huh :)

it is an implementation detail if the socket is blocking or non 
blocking, and has nothing to do

with read() returning 0 or not.

now we are talking about the implementation, not the API. I can 
implement inputstream.read() to return 0 on both blocking and non 
blocking sockets.
btw, for the NIO connector, we only have non blocking sockets, the API 
is an abstraction from the socket layer,




If this is true for sandbox - big +1.
not sure how the above relates to sandbox or trunk, since they use the 
same sockets the same way.

Filip


Costin

On 6/15/07, Remy Maucherat [EMAIL PROTECTED] wrote:


Filip Hanik - Dev Lists wrote:
 Please note, that neither Remy nor I have yet really talked about non
 blocking reads, so you might think sandbox is non blocking, well it is
not.
 It is buffering, but not non blocking. a true non blocking read, would
 require a rewrite of all the buffer filters to keep state between read
 invocations.

It is non blocking, as the low level read is always non blocking (in the
sandbox design).

Rémy


-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]





No virus found in this incoming message.
Checked by AVG Free Edition. 
Version: 7.5.472 / Virus Database: 269.8.15/848 - Release Date: 6/13/2007 12:50 PM
  



-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Re: Proposed simplification of CometEvent

2007-06-15 Thread Filip Hanik - Dev Lists
since we are getting pretty far off track here, I've started a Wiki page 
on what comet is and isn't.

http://wiki.apache.org/tomcat/WhatIsComet

It will be helpful in the future, or we can assimilate this into our 
docs eventually, but for now, I think it is a good drawing board to 
clear out things as we agree on them


Filip


Filip Hanik - Dev Lists wrote:

Costin Manolache wrote:
Ok, so let me double check: the low level socket in sandbox is 
allways read

after a poll() / select(),
and never with a blocking read() ?

huh? :)



After the poll(): the Comet servlet, in a tomcat thread will be able 
to call

read() in the input
stream, and that will return data or 0 if no more data is available ( 
or -

call isReadable() and then read(),
or whatever else - but the socket will not be put in blocking mode ) ?

and some more huh :)

it is an implementation detail if the socket is blocking or non 
blocking, and has nothing to do

with read() returning 0 or not.

now we are talking about the implementation, not the API. I can 
implement inputstream.read() to return 0 on both blocking and non 
blocking sockets.
btw, for the NIO connector, we only have non blocking sockets, the API 
is an abstraction from the socket layer,




If this is true for sandbox - big +1.
not sure how the above relates to sandbox or trunk, since they use the 
same sockets the same way.

Filip


Costin

On 6/15/07, Remy Maucherat [EMAIL PROTECTED] wrote:


Filip Hanik - Dev Lists wrote:
 Please note, that neither Remy nor I have yet really talked about non
 blocking reads, so you might think sandbox is non blocking, well 
it is

not.
 It is buffering, but not non blocking. a true non blocking read, 
would
 require a rewrite of all the buffer filters to keep state between 
read

 invocations.

It is non blocking, as the low level read is always non blocking (in 
the

sandbox design).

Rémy


-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]





No virus found in this incoming message.
Checked by AVG Free Edition. Version: 7.5.472 / Virus Database: 
269.8.15/848 - Release Date: 6/13/2007 12:50 PM
  



-
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]



Re: Proposed simplification of CometEvent

2007-06-15 Thread Filip Hanik - Dev Lists
Ok, one use case scenario would be AJAX requests with asynchronous 
responses on the server, I can see this be extremely common,
I've tried to add in comments to make the example clear, and I don't see 
this example as stupid, as there are a lot more AJAX client frameworks 
than Comet client frameworks.


So there are two things we are show casing
1. The ability to write asynchronously
2. The ability to pipeline HTTP requests (assumption: only dealing with 
GET requests, no HTTP request body)
3. Difference between Comet non blocking and Comet blocking read and 
writes (note, not related to sockets, API only)


What I'd like to point out is that this example, becomes easier with 
blocking read/writes, so I've added that at the bottom for comparison


Let me know if I've made any mistakes here, so that we can work with a 
correct example.


Non blocking read and writes

public class ExampleDelayedAjaxResponse implements CometProcessor {
 ...
 public class DelayedResponder extends Thread {
   public void run() {
 ...
 Client[] clients = getClients();
 for (int i=0; iclients.length; i++ ) {
   CometEvent event = client.getEvent();
   byte[] data = getDelayedResponse(event);
   if (data!=null) {
 if (event.isWriteable()) {
   event.getHttpServletResponse().getOutputStream().write(data);
   if (event.isWriteable()) { //did we write it all?
  event.close(); //close the event, in anticipation of the next 
request
  event.register(OP_CALLBACK); //triggers an END event
   } else { //we didn't write it all, trigger a WRITE event when we are done with the write 
  event.register(OP_WRITE);

   }
 } else {
   //we are not able to write, let us know when we can
   event.register(OP_WRITE);
 }
 //remove the client from the  async thread
 //since we have received the data for this client.
 clients.remove(event);
   }
 }
 ...
   }
 }
 ...
 public void event(CometEvent event) throws IOException, ServletException {
   ...
   if ( event.getEventType() == CometEvent.EventType.BEGIN ) {
 //configure non blocking
 event.configureBlocking(false);
 //deregister for READ since we want to enable pipe lining on the connection 
 //for the next HTTP request

 event.unregister(OP_READ);
 //add the client to the list
 clients.add(event);
   } if ( event.getEventType() == CometEvent.EventType.READ ) {
 //read client Id and stock list from client
 //and add the event to our list
 assert(this should never happen);
   } if ( event.getEventType() == CometEvent.EventType.WRITE ) {
 //unregister from the write event
 event.unregister(OP_WRITE);
 //we can now write
 byte[] data = getDelayedResponse(event);  
 if ( data != null ) {

   event.getHttpServletResponse().getOutputStream().write(data);
 }
 if( data==null || event.isWriteable() ) {
   event.close();
 }
  
   } if ( event.getEventType() == CometEvent.EventType.END ) {
 clients.remove(event);  
   } else if (...) {

 ...
   }
   ...
 }
}

Blocking read and writes 


public class ExampleDelayedAjaxResponse implements CometProcessor {
 ...
 public class DelayedResponder extends Thread {
   public void run() {
 ...
 Client[] clients = getClients();
 for (int i=0; iclients.length; i++ ) {
   CometEvent event = client.getEvent();
   byte[] data = getDelayedResponse(event);
   if (data!=null) {
 //register for a write, better do that on a thread pool thread
 //since write is blocking
 event.register(OP_WRITE);
 //remove the client from the  async thread
 clients.remove(event);
   }
 }
 ...
   }
 }
 ...
 public void event(CometEvent event) throws IOException, ServletException {
   ...
   if ( event.getEventType() == CometEvent.EventType.BEGIN ) {
 //configure non blocking
 event.configureBlocking(false);
 //deregister for READ since we want to enable pipe lining on the connection 
 //for the next HTTP request

 event.unregister(OP_READ);
 //add the client to the list
 clients.add(event);
   } if ( event.getEventType() == CometEvent.EventType.READ ) {
 //read client Id and stock list from client
 //and add the event to our list
 assert(this should never happen);
   } if ( event.getEventType() == CometEvent.EventType.WRITE ) {
 //unregister from the write event
 event.unregister(OP_WRITE);
 //we can now write
 byte[] data = getDelayedResponse(event);  
 //note we don't have to check for null data here

 event.getHttpServletResponse().getOutputStream().write(data);
 event.close();
   } if ( event.getEventType() == CometEvent.EventType.END ) {
 clients.remove(event);
   } else if (...) {
 ...
   }
   ...
 }
}
 
I think this makes a good use case of where blocking makes life easier, 

Re: Proposed simplification of CometEvent

2007-06-15 Thread Filip Hanik - Dev Lists

Filip Hanik - Dev Lists wrote:

Costin Manolache wrote:
Ok, so let me double check: the low level socket in sandbox is 
allways read

after a poll() / select(),
and never with a blocking read() ?

huh? :)



After the poll(): the Comet servlet, in a tomcat thread will be able 
to call

read() in the input
stream, and that will return data or 0 if no more data is available ( 
or -

call isReadable() and then read(),
or whatever else - but the socket will not be put in blocking mode ) ?

and some more huh :)

it is an implementation detail if the socket is blocking or non 
blocking, and has nothing to do

with read() returning 0 or not.

now we are talking about the implementation, not the API. I can 
implement inputstream.read() to return 0 on both blocking and non 
blocking sockets.

correction, should read
I can implement inputstream.read() to return 0 on both blocking and non 
blocking *Comet events*, (since sockets are always non blocking)


btw, for the NIO connector, we only have non blocking sockets, the API 
is an abstraction from the socket layer,




If this is true for sandbox - big +1.
not sure how the above relates to sandbox or trunk, since they use the 
same sockets the same way.

Filip


Costin

On 6/15/07, Remy Maucherat [EMAIL PROTECTED] wrote:


Filip Hanik - Dev Lists wrote:
 Please note, that neither Remy nor I have yet really talked about non
 blocking reads, so you might think sandbox is non blocking, well 
it is

not.
 It is buffering, but not non blocking. a true non blocking read, 
would
 require a rewrite of all the buffer filters to keep state between 
read

 invocations.

It is non blocking, as the low level read is always non blocking (in 
the

sandbox design).

Rémy


-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]





No virus found in this incoming message.
Checked by AVG Free Edition. Version: 7.5.472 / Virus Database: 
269.8.15/848 - Release Date: 6/13/2007 12:50 PM
  



-
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]



Re: Proposed simplification of CometEvent

2007-06-14 Thread Remy Maucherat

Filip Hanik - Dev Lists wrote:

here we go, some examples

http://people.apache.org/~fhanik/tomcat/aio.html#Example%20code%20snippets

and the entire document has been updated to reflect most changes
http://people.apache.org/~fhanik/tomcat/aio.html


Here is an alternative version of the examples using the sandbox API to 
give people an idea, along with some comments. No renaming of 
sleep/callback, or others at this time. Hopefully, I did not make too 
many mistakes.


First example, which can enter a busy loop if all events start returning 
false for isWriteable (which is not very likely, of course):


public class ExampleCometStockStreamer implements CometProcessor {
  ...
  public class StockUpdater extends Thread {
public void run() {
  ...
  StockUpdates[] updates = fetchUpdates();
  Client[] clients = getClients(updates);
  for (int i=0; iclients.length; i++ ) {
CometEvent event = client.getEvent();
StockUpdates[] clientList = getClientUpdates(client,updates);
client.setAndMergeNextUpdates(clientList);
if (event.isWriteable()) {
  byte[] data = getUpdateChunk(client.getNextUpdates());
  event.getHttpServletResponse().getOutputStream().write(data);
}
  }
  ...
}
  }
  ...
  public void event(CometEvent event) throws IOException, 
ServletException {

...
if ( event.getEventType() == CometEvent.EventType.BEGIN ) {
} if ( event.getEventType() == CometEvent.EventType.READ ) {
  //read client Id and stock list from client
  //and add the event to our list
  String clientId = readClientInfo(event,stocks);
  clients.add(clientId, event, stocks);
} if ( event.getEventType() == CometEvent.EventType.WRITE ) {
  //we can now write
  byte[] data = getUpdateChunk(client.getNextUpdates());
  event.getHttpServletResponse().getOutputStream().write(data);
} else if (...) {
  ...
}
...
  }

}

What this example should be doing is remove the client from the list 
when isWriteable returns false, and add it back when it gets a write event.


I can translate the second example, but it could lead to an abusive 
poller use and number of events (all writes are also done synchronously 
with blocking IO, which never makes sense to me).


public class ExampleCometStockStreamer implements CometProcessor {
  ...
  public class StockUpdater extends Thread {
public void run() {
  ...
  StockUpdates[] updates = fetchUpdates();
  Client[] clients = getClients(updates);
  for (int i=0; iclients.length; i++ ) {
StockUpdates[] clientList = getClientUpdates(client,updates);
client.setAndMergeNextUpdates(clientList);
client.getEvent().callback();
  }
  ...
}
  }
  ...
  public void event(CometEvent event) throws IOException, 
ServletException {

...
if ( event.getEventType() == CometEvent.EventType.BEGIN ) {
  //configure blocking
  event.configureBlocking(true);
} if ( event.getEventType() == CometEvent.EventType.READ ) {
  //read client Id and stock list from client
  //and add the event to our list
  String clientId = readClientInfo(event,stocks);
  clients.add(clientId, event, stocks);
} if ( event.getEventType() == CometEvent.EventType.CALLBACK ) {
  Client client = clients.get(event);
  //we can now write
  byte[] data = getUpdateChunk(client.getNextUpdates());
  event.getHttpServletResponse().getOutputStream().write(data);
} else if (...) {
  ...
}
...
  }

}

I think the third example is wrong: there's no reason for isWriteable or 
isReadable to change its result unless they trigger a large amount of 
logic and some IO operations. I thought you said it was wrong ;) Also, 
it will be very vulnerable to busy loops. I can translate it by wrapping 
the content of for (int j=0; jclients.size(); j++) { into a try/catch, 
and removing the calls to isWriteable (which only introduce useless 
events, and may cause additional busy loops).


Straight translation (since isWriteable will trigger a write event which 
will flush, it will work, but busy loops are pretty much certain; it 
also assumes things about the data to read):


public class ExampleAllReadThenWriteComet implements CometProcessor {
  ...
  public class AllWriterThread extends Thread {
byte[] dataChunks = ...;
public void run() {
  ...
  for (int i=0; idataChunks.length; i++ ) {
for (int j=0; jclients.size(); j++) {
  boolean done = false;
  while (!done) {
//first read the first request
//but only if our previous write was completed
if ( clients[j].getEvent().isWriteable()  
clients[j].getEvent().isReadable() ) {
  done = readClientData(clients[j]); //returns true if all 
data has been received for a request

}
  }
  done = false;
  while (!done) {
//write the response
  

Re: Proposed simplification of CometEvent

2007-06-14 Thread Filip Hanik - Dev Lists

Costin Manolache wrote:



 Sounds better - but as Remy explained you would first need to explain
 why blocking is needed in this context and how to deal with the
confusion
 of mixing blocking and non-blocking for users, and the implementation
 complexities it adds.
trunk doesn't mix them. a comet connection is either blocking or non
blocking, it doesn't shift between the two,
and it allows developers to choose what they want. Just like a
SocketChannel in java.nio.
there is nothing confusing about that, unless java.nio is confusing :)




Well, nio is far from perfect - but that's not the point.

Servlets have a very nice blocking mechanism already - it's the 
servlet API

:-).
The question is why would you need to have a Commet connection blocking.
because comet is not a servlet, and the ease of use for having blocking 
write and read is huge,
especially when Tomcat can notify you when you can write or read, there 
is no need to scratch your head and try to use non blocking.

non blocking is more complex, and not for everyone.


I think it's very reasonable to add a blocking waitForEvent() to allow
servlets have a
simpler ( but less efficient ) implementation.
Comet inherently is a wait for event system. Tomcat acts as a 
multiplexer/dispatcher,

and fires events into the CometProcessor.
The waitForEvent() method is obsolete in the Comet implementation, as 
you are either on a Tomcat thread,
which you can activate at any time or you are on a async thread, and not 
sure why you would need to block an async background thread.


Think about utilities that take the event as param - would they need to
check first
if it's blocking or not ? And what would blocking give you in addition to
waitForEvent() -
which is actually better since it allows you to un-block on any event, 
not

only a specific
read/write.
I can see that there is a huge misunderstanding of how comet actually 
does work and what it actually is.
It is true that is essentially just a TCP socket between server and 
client, but in addition to that,
Tomcat provides a shell around it, and instead of you having to manage 
when to read or when to write,

tomcat becomes an event API.






  - please don't call the method configure(), it's commonly used 
with a
  different meaning ( i.e. setting the port or general 
configuration).

  setConnectionMode, etc. And using the enum doesn't sound consistent
 with
  other APIs either.
 we can call it whatever we want. But saying not using enum, its not
 consistent with other APIs in Tomcat,
 means would never take advantage of new language features ever, I 
think

 that would be a shame.


 Same as above - the question is not about using new features, but 
if the

 features
 fit the use. I have no problem with using enums for the event types -
 just
 for
 configure, in the context of configure(enum) versus setBlocking(),
 setFoo().
this has been adjusted based on the feedback, the method is now
configureBlocking(boolean)
the state of it can be used by calling isBlocking()

register is using enums, mainly cause Remy, while he was working with
this API insisted on it.
I had preferred using an int, just like the socket API, but since Remy
had initially agreed to register, and proposed enum and unregister
we went with that.



Ok.

I still think an int is better :)









  - see bellow - I don't think I understand the benefits of mixing
 blocking
  and non-blocking in this interface, it is quite confusing.
 It would be mixing it, its a one time config, during the BEGIN event,
 you say
 configureBlocking(true) or configureBlocking(false).
 Comet is very much connection centric, so you can't mix it.

 In the trunk API, its clear to what you are using, blocking or non
 blocking, in the sandbox API, the swap
 of it happens when invoking isWriteable or isReadable, making the 
state

 of the comet connection confusing to the developer.


 I'm not sure it's true - my understanding is that sandbox is all
 non-blocking.
 Invoking isWriteable is not blocking.

 I think it would be ok to add a blocking waitForEvent() - combined 
with

 isReadable()/isWriteable()
this would be a dead lock, as the Comet API must guarantee that a
CometProcessor.event
is only invoked by one worker thread at any time. The blocking you are
talking about can be done
using an async thread can be done by registering for the event you wish
to be notified in and then
maybe await a latch countdown, or doing a sync/wait() combo.



What would happen in the blocking case when a different event happens ?
Isn't it the same, if you want to guarantee single-threaded behaviour ?

Well - is there any docs on what is the intended thread model of comet
servlets,
A comet servlet is not single-threaded, but a comet event is. from 
Tomcat's stand point.
furthermore, a comet event (which represent a socket connection) can be 
used multithreaded,

but it will be the developers responsibility to sync appropriately.

i.e. SingelThreaded or reentrant ? Multiple 

Re: Proposed simplification of CometEvent

2007-06-14 Thread Filip Hanik - Dev Lists

Remy Maucherat wrote:

Filip Hanik - Dev Lists wrote:

here we go, some examples

http://people.apache.org/~fhanik/tomcat/aio.html#Example%20code%20snippets 



and the entire document has been updated to reflect most changes
http://people.apache.org/~fhanik/tomcat/aio.html


Here is an alternative version of the examples using the sandbox API 
to give people an idea, along with some comments. No renaming of 
sleep/callback, or others at this time. Hopefully, I did not make too 
many mistakes.


First example, which can enter a busy loop if all events start 
returning false for isWriteable (which is not very likely, of course):


public class ExampleCometStockStreamer implements CometProcessor {
  ...
  public class StockUpdater extends Thread {
public void run() {
  ...
  StockUpdates[] updates = fetchUpdates();
  Client[] clients = getClients(updates);
  for (int i=0; iclients.length; i++ ) {
CometEvent event = client.getEvent();
StockUpdates[] clientList = getClientUpdates(client,updates);
client.setAndMergeNextUpdates(clientList);
if (event.isWriteable()) {
  byte[] data = getUpdateChunk(client.getNextUpdates());
  event.getHttpServletResponse().getOutputStream().write(data);
}
  }
  ...
}
  }
Yes, this difference here is one that I would vouch that the API would 
be explicit, instead of implicit.

compare

   if (event.isWriteable()) {
 byte[] data = getUpdateChunk(client.getNextUpdates());
 event.getHttpServletResponse().getOutputStream().write(data);
   } else {
 event.register(OP_WRITE);
   }

with
   if (event.isWriteable()) {
 byte[] data = getUpdateChunk(client.getNextUpdates());
 event.getHttpServletResponse().getOutputStream().write(data);
   }

the implicit registration for a WRITE event is not made clear by the API 
alone, its something you would have to discover.

and one could look for a use case, where a WRITE event wasnt desired.


  ...
  public void event(CometEvent event) throws IOException, 
ServletException {

...
if ( event.getEventType() == CometEvent.EventType.BEGIN ) {
} if ( event.getEventType() == CometEvent.EventType.READ ) {
  //read client Id and stock list from client
  //and add the event to our list
  String clientId = readClientInfo(event,stocks);
  clients.add(clientId, event, stocks);
} if ( event.getEventType() == CometEvent.EventType.WRITE ) {
  //we can now write
  byte[] data = getUpdateChunk(client.getNextUpdates());
  event.getHttpServletResponse().getOutputStream().write(data);
} else if (...) {
  ...
}
...
  }

}

What this example should be doing is remove the client from the list 
when isWriteable returns false, and add it back when it gets a write 

I can translate the second example, but it could lead to an abusive 
poller use and number of events (all writes are also done 
synchronously with blocking IO, which never makes sense to me).


public class ExampleCometStockStreamer implements CometProcessor {
  ...
  public class StockUpdater extends Thread {
public void run() {
  ...
  StockUpdates[] updates = fetchUpdates();
  Client[] clients = getClients(updates);
  for (int i=0; iclients.length; i++ ) {
StockUpdates[] clientList = getClientUpdates(client,updates);
client.setAndMergeNextUpdates(clientList);
client.getEvent().callback();
  }
  ...
}
  }
now its starting to look funny, In the trunk version of the example, I'm 
interested if the socket buffer is ready to receive data,
but the sandbox version of it simply doesn't care, it just calls for a 
tomcat thread.

sandbox:
 client.getEvent().callback(); - no guarantee for writeability
trunk:
 client.getEvent().register(OP_WRITE) - event fires when network 
buffer is ready to receive data.



  ...
  public void event(CometEvent event) throws IOException, 
ServletException {

...
if ( event.getEventType() == CometEvent.EventType.BEGIN ) {
  //configure blocking
  event.configureBlocking(true);
} if ( event.getEventType() == CometEvent.EventType.READ ) {
  //read client Id and stock list from client
  //and add the event to our list
  String clientId = readClientInfo(event,stocks);
  clients.add(clientId, event, stocks);
} if ( event.getEventType() == CometEvent.EventType.CALLBACK ) {
  Client client = clients.get(event);
  //we can now write
  byte[] data = getUpdateChunk(client.getNextUpdates());
  event.getHttpServletResponse().getOutputStream().write(data);
} else if (...) {
  ...
}
...
  }

}




I think the third example is wrong: there's no reason for isWriteable 
or isReadable to change its result unless they trigger a large amount 
of logic and some IO operations. I thought you said it was wrong ;) 
Also, it will be very vulnerable to busy loops. I can translate it 

Re: Proposed simplification of CometEvent

2007-06-14 Thread Costin Manolache

On 6/14/07, Filip Hanik - Dev Lists [EMAIL PROTECTED] wrote:


Costin Manolache wrote:
 
 
  Sounds better - but as Remy explained you would first need to explain
  why blocking is needed in this context and how to deal with the
 confusion
  of mixing blocking and non-blocking for users, and the implementation
  complexities it adds.
 trunk doesn't mix them. a comet connection is either blocking or non
 blocking, it doesn't shift between the two,
 and it allows developers to choose what they want. Just like a
 SocketChannel in java.nio.
 there is nothing confusing about that, unless java.nio is confusing :)



 Well, nio is far from perfect - but that's not the point.

 Servlets have a very nice blocking mechanism already - it's the
 servlet API
 :-).
 The question is why would you need to have a Commet connection blocking.





because comet is not a servlet, and the ease of use for having blocking

write and read is huge,
especially when Tomcat can notify you when you can write or read, there
is no need to scratch your head and try to use non blocking.
non blocking is more complex, and not for everyone.




I'm not sure I understand - there is a perfectly fine blocking read/write
interface, it's the
plain servlet API.

I also agree that 'blocking' mode is sometimes easier to code than
event-based, and
I can see the benefit of doing some stuff in blocking mode and some in
non-blocking.

My concern was making the read and write blocking in a commet servlet based
on
a config in the CometEvent.

The alternative is to have the comet servlet allways non-blocking for
read/write, but
provide a convenience method that will simulate the blocking read or write (
which is
easy, all you need is a blocking waitForEvent(time) ). Benefits:
- the read/write implementation is simpler ( no need to check the config
mode or do tricks ),
- comet is easier to understand
- you can do more advanced things, like using reads in non-blocking mode and
writes in blocking
mode.

The code using waitForEvent() is a bit more complicated than the code for
blocking read/write (
but if you want the simplest solution - use regular servlet ), and it is
simpler than a pure
callback based model.





 I think it's very reasonable to add a blocking waitForEvent() to allow
 servlets have a
 simpler ( but less efficient ) implementation.





Comet inherently is a wait for event system. Tomcat acts as a

multiplexer/dispatcher,and fires events into the CometProcessor.



Comet seems to be an event-based system, that's why setting it to 'blocking
mode' is so
confusing and bad. I'm not sure I agree it has to be a 'blocking wait for
event' system - in Remy
examples at least it is not.



The waitForEvent() method is obsolete in the Comet implementation, as

you are either on a Tomcat thread,
which you can activate at any time or you are on a async thread, and not
sure why you would need to block an async background thread.

 Think about utilities that take the event as param - would they need to
 check first
 if it's blocking or not ? And what would blocking give you in addition
to
 waitForEvent() -
 which is actually better since it allows you to un-block on any event,
 not
 only a specific
 read/write.
I can see that there is a huge misunderstanding of how comet actually
does work and what it actually is.
It is true that is essentially just a TCP socket between server and
client, but in addition to that,
Tomcat provides a shell around it, and instead of you having to manage
when to read or when to write,
tomcat becomes an event API.



Sure, it hides some limitations of NIO ( the IO thread that has to do all
things )
and adds some higher-level HTTP stuff.





   - please don't call the method configure(), it's commonly used
 with a
   different meaning ( i.e. setting the port or general
 configuration).
   setConnectionMode, etc. And using the enum doesn't sound
consistent
  with
   other APIs either.
  we can call it whatever we want. But saying not using enum, its not
  consistent with other APIs in Tomcat,
  means would never take advantage of new language features ever, I
 think
  that would be a shame.
 
 
  Same as above - the question is not about using new features, but
 if the
  features
  fit the use. I have no problem with using enums for the event types -
  just
  for
  configure, in the context of configure(enum) versus setBlocking(),
  setFoo().
 this has been adjusted based on the feedback, the method is now
 configureBlocking(boolean)
 the state of it can be used by calling isBlocking()

 register is using enums, mainly cause Remy, while he was working with
 this API insisted on it.
 I had preferred using an int, just like the socket API, but since Remy
 had initially agreed to register, and proposed enum and unregister
 we went with that.


 Ok.
I still think an int is better :)



 
 
 
 
   - see bellow - I don't think I understand the benefits of mixing
  blocking
   and non-blocking in this interface, it is quite confusing.
 

Re: Proposed simplification of CometEvent

2007-06-13 Thread Jean-Frederic
On Wed, 2007-06-13 at 12:04 +0200, Remy Maucherat wrote:
 Costin Manolache wrote:
  setTimeout() is not optional (the javadoc is out of date, sorry), there
  was an agreement on that earlier. Timeout sets the connection timeout,
  which is most likely useful even if there are events. It's quite
  possible sleep could use a timeout argument (I think calling setTimeout
  is more or less mandatory when using sleep, and OTOH calling setTimout
  is not as important otherwise).
  
  Ok - then sleep needs the extra argument, and will mean same as 
  Thread.sleep(),
  but
  not-blocking ?
 
 This sleep is a non blocking call, and instructs the connection to do 
 nothing until I wake you up (or a timeout occurs, of course).

may be sleep is not the right name... Would suspend be a better name?

Cheers
Jean-Frederic


-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Re: Proposed simplification of CometEvent

2007-06-13 Thread Costin Manolache

On 6/13/07, Filip Hanik - Dev Lists [EMAIL PROTECTED] wrote:


Costin Manolache wrote:
 For a separate opinion:

 In the trunk version:
 - the '...' and array return seem strange and generate GC ( not a big
 issue
 those days, but still inconsistent with the
 rest of tomcat )
yes, its a new language feature, hence it wasn't available in previous
JDKs or Tomcat.
its a vararg, if we don't want it we can switch to arrays, it works the
same way.



Yes, I know it's a vararg and my concern is not that it is not available in
all VMs, but
that it creates temp arrays and GC, which is inconsistent with the rest of
tomcat which is very careful with creating objects.
Also - it's quite useless in this particular case, printf is a good use case
but
that doesn't mean it should be used everywhere.




 - the API seems a bit over-complex - for example, why
 setConfiguration(COMMET_BLOCKING) instead of setBlocking() ?
 I agree that it less likely to break implementations by adding to the
 enom
 instead of adding methods to the interface - not sure
 why it's not an abstract class in the first place.
if we want to simplify it, we would call it
configureBlocking(boolean) - consistent with JDK APIs :)



Sounds better - but as Remy explained you would first need to explain
why blocking is needed in this context and how to deal with the confusion
of mixing blocking and non-blocking for users, and the implementation
complexities it adds.




 - please don't call the method configure(), it's commonly used with a
 different meaning ( i.e. setting the port or general configuration).
 setConnectionMode, etc. And using the enum doesn't sound consistent with
 other APIs either.
we can call it whatever we want. But saying not using enum, its not
consistent with other APIs in Tomcat,
means would never take advantage of new language features ever, I think
that would be a shame.



Same as above - the question is not about using new features, but if the
features
fit the use. I have no problem with using enums for the event types - just
for
configure, in the context of configure(enum) versus setBlocking(), setFoo().





 - see bellow - I don't think I understand the benefits of mixing
blocking
 and non-blocking in this interface, it is quite confusing.
It would be mixing it, its a one time config, during the BEGIN event,
you say
configureBlocking(true) or configureBlocking(false).
Comet is very much connection centric, so you can't mix it.

In the trunk API, its clear to what you are using, blocking or non
blocking, in the sandbox API, the swap
of it happens when invoking isWriteable or isReadable, making the state
of the comet connection confusing to the developer.



I'm not sure it's true - my understanding is that sandbox is all
non-blocking.
Invoking isWriteable is not blocking.

I think it would be ok to add a blocking waitForEvent() - combined with
isReadable()/isWriteable()
it will allow a sort-of blocking model. But having methods that are blocking
sometimes
and sometimes not - based on some config - is dangerous and confusing.

Costin

Filip


 In the sandbox version:
 - sleep() and setTimeout(int) - why not sleep(int millis) ? I think
it's
 confusing to have both and the interactions between them, in
 particular setTimeout is marked optional ? It makes sense to have
 setTimeout() as a general timeout.

 - not sure I understand the use case for isReadable()/isWriteable() -
 when
 will this be called ? My understanding was that when
 the connection is readable, a callback will be generated with
 EventType ==
 READ. Also it's very confusing to mix the 'blocking' in the
 isReadable()/isWriteable() - it would be much cleaner to say that the
 connection is always non-blocking, and add a method to switch to
blocking
 mode ( then use the regular servlet methods maybe ). Using the
 ComentEvent
 for both is IMHO dangerous.

 - will sleep() still allow callbacks ( and if not - what will happen
with
 them )? What's going to happen with callbacks if callback() is not
 called ?


 In general ( both versions):
 - it would be great to move it from o.a.catalina to org.apache.comet

 Costin

 On 6/11/07, Remy Maucherat [EMAIL PROTECTED] wrote:

 Filip Hanik - Dev Lists wrote:
  Ok, let me see if I can summarize.
 
  1. Whether you write out the stored buffer using the Poller thread,
 or a
  Tomcat worker thread (flushed in Http11xxxProcessor) as described
 below
  I originally thought of this as async write, as we are simply doing a
  write with another one of our threads. Originally when we were
talking
  non blocking writes, I was thinking along the lines of non blocking
to
  where the Comet developer had to do that logic, just as he was
 writing a
  socket, possibly like (but not suggested) a
  CometEvent.nonBlockWrite(ByteBuffer).
 
  2. Do we need non blocking? with the methods of isWriteable and the
  ability to register(OP_WRITE)-event(WRITE), if the number of bytes
 you
  write is usually smaller than the socket buffer, chances are 

Re: Proposed simplification of CometEvent

2007-06-13 Thread Costin Manolache

On 6/13/07, Remy Maucherat [EMAIL PROTECTED] wrote:


Costin Manolache wrote:
 setTimeout() is not optional (the javadoc is out of date, sorry), there
 was an agreement on that earlier. Timeout sets the connection timeout,
 which is most likely useful even if there are events. It's quite
 possible sleep could use a timeout argument (I think calling setTimeout
 is more or less mandatory when using sleep, and OTOH calling setTimout
 is not as important otherwise).

 Ok - then sleep needs the extra argument, and will mean same as
 Thread.sleep(),
 but
 not-blocking ?

This sleep is a non blocking call, and instructs the connection to do
nothing until I wake you up (or a timeout occurs, of course).



Please add this to the javadoc :-)
And maybe call it 'setTimerEvent(timeMillis)' or something like that - to
avoid
confusion with Thread.sleep() which is blocking the thread.

IMHO it would be very nice to  also have a blocking waitForEvent(timeMillis)
-
as an alternative to adding blocking mode as in the trunk.



Although the read event indicates there's data to read, isReadable

 indicates if it is possible to continue reading.

 My understanding was that the InputStream in request is used for actual
 reading -
 and available() could do the same thing. What is the difference then
 between
 the 2 ?

isReadable is the same as is.available (and reader.ready). It's there
for a bit of symmetry after adding isWriteable, which may or may not be
useful, and I didn't care about it.



Why not call it available() and return the same as the servlet method ? I
think
it's ok to have 'shortcuts' in the CometEvent - even read()/write() methods
that
would expose more efficient ways to send/get data than the InputStream.



isWriteable indicates if the last write operation managed to write more
 than 0 bytes. If the last write wrote 0, then isWriteable will return
 false, so the servlet knows it should stop writing on this connection
 for now (since it cannot accept any output at the moment). Later on,
the
 servlet will receive a write event, and can resume writing.

 I'm still a bit confused about this - my understanding was that write
event
 means the
 previous buffers were written, and you can write more. There are some
 buffers
 on the OS side as well as buffers on the connector side.

Yes, it means that: the servlet gets a write event, which means it can
start writing again.

 What do you mean by 'managed to write more than 0 bytes' - the write in
the
 OutputStream
 can go to some of the buffers, or to the client. I assume you don't mean
 the
 client ( due to TCP
 delays ).

I was talking about the actual write on the socket (in APR, it's done in
InternalAprOutputBuffer.flushBuffer), which may return 0. At the servlet
layer, as per the contract of the OutputStream API, is must write
everything or fail, and this isn't going to change.



Where 'write everything' means 'maybe buffer some of it at OS or java
layer'.

Could you add more javadocs on how much can you expect to write if
isWriteable() returns
true ? Since the OutputStream method doesn't support partial writes - I
suppose
this would help more than isWriteable.




- If doing synchronous writes inside some event (either a read or

 callback event, most likely), then both blocking and non blocking mode
 make sense. Some servlets may prefer to use blocking mode although it
 could be holding a thread for a while (for example if the idea is only

 maybe a 'waitForEvent()' method to allow a servlet to block if he wants
 to ?

 Or is sleep() supposed to do this - I'm not sure from the comments if
 sleep() will
 block or just triger an event when the interval expires ?

Sleep will by itself only trigger timeout events (the method call itself
will return immediately). The servlet can use the callback method to
trigger an event before the timeout occurs.

 You mean sort of 'notify()' -  i.e. someone calls callback() and will
 trigger the
 servlet to be executed, interrupting any sleep or wait ?

Originally, this was indeed supposed to be called notify, but it's not
possible due to Object.notify :( If you have another name to suggest to
  replace callback ...



Well - servletNotify() or servletWakeup() or sendCometEvent() ?

Costin


In general ( both versions):

  - it would be great to move it from o.a.catalina to org.apache.comet

 It's a possibility.

 I think more comments and examples ( and maybe better names ) would be
 great.

I think there's going to be some code using Comet soon.

Rémy

-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




Re: Proposed simplification of CometEvent

2007-06-13 Thread Filip Hanik - Dev Lists

here we go, some examples

http://people.apache.org/~fhanik/tomcat/aio.html#Example%20code%20snippets

and the entire document has been updated to reflect most changes
http://people.apache.org/~fhanik/tomcat/aio.html


Filip

Filip Hanik - Dev Lists wrote:

I'll work on some examples to illustrate what I mean,
It will be much clearer

Filip

Remy Maucherat wrote:

Filip Hanik - Dev Lists wrote:

Ok, let me see if I can summarize.

1. Whether you write out the stored buffer using the Poller thread, 
or a Tomcat worker thread (flushed in Http11xxxProcessor) as 
described below I originally thought of this as async write, as we 
are simply doing a write with another one of our threads. Originally 
when we were talking non blocking writes, I was thinking along the 
lines of non blocking to where the Comet developer had to do that 
logic, just as he was writing a socket, possibly like (but not 
suggested) a CometEvent.nonBlockWrite(ByteBuffer).


2. Do we need non blocking? with the methods of isWriteable and the 
ability to register(OP_WRITE)-event(WRITE), if the number of bytes 
you write is usually smaller than the socket buffer, chances are 
that most writes will be non blocking. I would even argue a large 
majority would be non blocking, and thus the implementation or the 
complexity thereof would not be needed. And with the ability to do 
async writes, means I can create my own thread pool/write queue to 
perform these writes.


You are writing the opposite thing to the previous email, and we are 
back to non blocking is useless. The problem is that I understand 
blocking IO as write this data, and return when it's done. If the 
socket is in blocking mode, any write done by the servlet may block, 
regardless of what isWriteable says. Of course, it's very unlikely, 
which is why Comet in 6.0.x works.


3. isWriteable - simple method, but I don't like that the method in 
itself performs actions like adding the socket to a poller etc.
  Instead isWriteable==true means that you can write on the socket, 
isWriteable==false you cannot. This method should be able to be 
invoked as many times as its wanted, and is thread safe and doesn't 
do anything funky underneath.


Ok, so you prefer a more complex API (if I follow just in case it 
was useful). I started with an API which would expose all 
operations, and looked into removing what was not explicitly useful.


4. isWriteable - I'm also reading in that you are also suggesting 
that we use this method to declare if we want blocking or non 
blocking writes.


No. The situation where write could (maybe) block is if the servlet 
writes in a Tomcat thread. Typically, this is the reply-later design, 
using the sleep/callback methods. The isWriteable method is not used, 
since the servlet merely wants (in that common design) to send a 
response as fast as possible, and typically this sort of response is 
not too large and unlikely to cause IO problems. This blocking 
behavior is allowed in that case to avoid forcing the user to put in 
more complex logic to deal with the partial write + event, and is set 
just for the amount of time it takes to perform the write (note that 
this ).



  At this point this method is doing three things:
  a) returns true/false if we can write data
  b) delegates a socket to the poller to write data and generate a 
event(WRITE) to the comet processor

  c) configures a write to be blocking or non blocking
  This is for sure not what I would expect of a simple API, if 
simple means less keystrokes than yes, but simple to me also means 
intuitive and easily understood.


So you have plenty of methods to do the same thing.

Given points 1-4, this is what is going to happen to every single 
developer
 I) They are going to use stream.write and event.isWriteable all the 
time, not realizing what it actually does
II) They are going to get confused when they receive an IOException 
for trying to perform a write, cause they used isWriteable and the 
socket went into non blocking mode


If that's what you want to believe ...

At this point, this 'simple' API, obviously not so simple, instead 
it becomes very complicated, as I would almost have to reverse 
engineer the code to truly understand what it does.
It may be simple to you and me, but that is because we are 
implementing it.


I really don't see what is complex, especially when you look at the 
code the user would write for the simple cases, where you don't even 
have to use any API besides stream.write:

- reply later
- wait for read events, and write data in response to it

The complex case deals with handling incomplete async writes if you 
don't simply drop connection.


so what does this mean to 'isReadable'? That I'm automatically 
registering for a READ event if it returns false? Maybe I don't want 
a READ event, I just want to see if any data has trickled in. so if 
I call sleep(), should I then call isReadable() to reregister for 
the read. how is this simpler than that 

Re: Proposed simplification of CometEvent

2007-06-13 Thread Costin Manolache



 Sounds better - but as Remy explained you would first need to explain
 why blocking is needed in this context and how to deal with the
confusion
 of mixing blocking and non-blocking for users, and the implementation
 complexities it adds.
trunk doesn't mix them. a comet connection is either blocking or non
blocking, it doesn't shift between the two,
and it allows developers to choose what they want. Just like a
SocketChannel in java.nio.
there is nothing confusing about that, unless java.nio is confusing :)




Well, nio is far from perfect - but that's not the point.

Servlets have a very nice blocking mechanism already - it's the servlet API
:-).
The question is why would you need to have a Commet connection blocking.

I think it's very reasonable to add a blocking waitForEvent() to allow
servlets have a
simpler ( but less efficient ) implementation.

Think about utilities that take the event as param - would they need to
check first
if it's blocking or not ? And what would blocking give you in addition to
waitForEvent() -
which is actually better since it allows you to un-block on any event, not
only a specific
read/write.





  - please don't call the method configure(), it's commonly used with a
  different meaning ( i.e. setting the port or general configuration).
  setConnectionMode, etc. And using the enum doesn't sound consistent
 with
  other APIs either.
 we can call it whatever we want. But saying not using enum, its not
 consistent with other APIs in Tomcat,
 means would never take advantage of new language features ever, I think
 that would be a shame.


 Same as above - the question is not about using new features, but if the
 features
 fit the use. I have no problem with using enums for the event types -
 just
 for
 configure, in the context of configure(enum) versus setBlocking(),
 setFoo().
this has been adjusted based on the feedback, the method is now
configureBlocking(boolean)
the state of it can be used by calling isBlocking()

register is using enums, mainly cause Remy, while he was working with
this API insisted on it.
I had preferred using an int, just like the socket API, but since Remy
had initially agreed to register, and proposed enum and unregister
we went with that.



Ok.








  - see bellow - I don't think I understand the benefits of mixing
 blocking
  and non-blocking in this interface, it is quite confusing.
 It would be mixing it, its a one time config, during the BEGIN event,
 you say
 configureBlocking(true) or configureBlocking(false).
 Comet is very much connection centric, so you can't mix it.

 In the trunk API, its clear to what you are using, blocking or non
 blocking, in the sandbox API, the swap
 of it happens when invoking isWriteable or isReadable, making the state
 of the comet connection confusing to the developer.


 I'm not sure it's true - my understanding is that sandbox is all
 non-blocking.
 Invoking isWriteable is not blocking.

 I think it would be ok to add a blocking waitForEvent() - combined with
 isReadable()/isWriteable()
this would be a dead lock, as the Comet API must guarantee that a
CometProcessor.event
is only invoked by one worker thread at any time. The blocking you are
talking about can be done
using an async thread can be done by registering for the event you wish
to be notified in and then
maybe await a latch countdown, or doing a sync/wait() combo.



What would happen in the blocking case when a different event happens ?
Isn't it the same, if you want to guarantee single-threaded behaviour ?

Well - is there any docs on what is the intended thread model of comet
servlets,
i.e. SingelThreaded or reentrant ? Multiple events can happen at same time
( or very close -
one event soon after a Comet servlet is called, before it returns), so this
is a general problem.



it will allow a sort-of blocking model. But having methods that are
 blocking
 sometimes
 and sometimes not - based on some config - is dangerous and confusing.
As I mentioned, the trunk Comet API is actually very similar to java.nio
API, hence developers familiar with that will instantly recognize
themselves and should get comfortable with the API.



I still don't recognize it as NIO :-), and I am not very comfortable with
the
changes between blocking and non-blocking in NIO ( including all the crazy
things that can happen only in the IO thread ).


Here are some of the things that might need to be clarified about the

trunk API:

1. It is possible to not be registered for any events, and even do
polling for data asynchronously




You would still get the BEGIN event I assume.

All you need to poll data async is waitForEvent(), or select() if you like
to emulate nio.

2. ERROR and END events, are an exception, you cant unregister for

those, as those might require the
   underlying socket to be closed, or has already been closed



In what thread would you get those ( in blocking mode ?)



5. The current READ event in CoyoteAdapter ends up performing a blocking


Re: Proposed simplification of CometEvent

2007-06-12 Thread Remy Maucherat

Costin Manolache wrote:

In the sandbox version:
- sleep() and setTimeout(int) - why not sleep(int millis) ? I think it's
confusing to have both and the interactions between them, in
particular setTimeout is marked optional ? It makes sense to have
setTimeout() as a general timeout.


setTimeout() is not optional (the javadoc is out of date, sorry), there 
was an agreement on that earlier. Timeout sets the connection timeout, 
which is most likely useful even if there are events. It's quite 
possible sleep could use a timeout argument (I think calling setTimeout 
is more or less mandatory when using sleep, and OTOH calling setTimout 
is not as important otherwise).



- not sure I understand the use case for isReadable()/isWriteable() - when
will this be called ? My understanding was that when
the connection is readable, a callback will be generated with EventType ==
READ. Also it's very confusing to mix the 'blocking' in the
isReadable()/isWriteable() - it would be much cleaner to say that the
connection is always non-blocking, and add a method to switch to blocking
mode ( then use the regular servlet methods maybe ). Using the ComentEvent
for both is IMHO dangerous.


Although the read event indicates there's data to read, isReadable 
indicates if it is possible to continue reading.


isWriteable indicates if the last write operation managed to write more 
than 0 bytes. If the last write wrote 0, then isWriteable will return 
false, so the servlet knows it should stop writing on this connection 
for now (since it cannot accept any output at the moment). Later on, the 
servlet will receive a write event, and can resume writing.


It is possible to add a blockingMode flag, but I've looked into it a 
bit, and found out it is not really needed:
- If doing asynchronous writes using a background thread, non blocking 
helps (if somehow a connection blocks, no other connection will get any 
data until the write completes or times out). I don't see how blocking 
mode could be desired in this case, and the servlet should always be 
using isWriteable.
- If doing synchronous writes inside some event (either a read or 
callback event, most likely), then both blocking and non blocking mode 
make sense. Some servlets may prefer to use blocking mode although it 
could be holding a thread for a while (for example if the idea is only 
to delay the response), and some others could choose to be more 
scalable. Since it is possible to detect if the write is done inside a 
Tomcat thread, and since a servlet which wishes to handle incomplete 
writes would be using isWriteable, it is possible to know when we're in 
the situation where the servlet would prefer blocking. In that case, the 
algorithm in the write method of the connector would be: check if the 
last write returned 0, set blocking mode, flush leftover bytes and send 
the additional bytes which are being written, set non blocking mode. 
It's a trick (of course, it is possible to do the same thing for read), 
and the main drawback is that there are extra operations, but they would 
occur only if needed.



- will sleep() still allow callbacks ( and if not - what will happen with
them )? What's going to happen with callbacks if callback() is not called ?


Yes, sleep is meant mostly to handle the reply-later design easily. The 
servlet calls sleep(), and is supposed to call callback() 
(asnychronously, most likely) as a result of something. The connection 
will then wake and the servlet will get a callback event. If callback is 
not called, the connection will timeout and the servlet will get its 
timeout event (according to the connector timeout or the one that has 
been configured for the connection).



In general ( both versions):
- it would be great to move it from o.a.catalina to org.apache.comet


It's a possibility.

Rémy

-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Re: Proposed simplification of CometEvent

2007-06-12 Thread Costin Manolache

On 6/12/07, Remy Maucherat [EMAIL PROTECTED] wrote:


Costin Manolache wrote:
 In the sandbox version:
 - sleep() and setTimeout(int) - why not sleep(int millis) ? I think
it's
 confusing to have both and the interactions between them, in
 particular setTimeout is marked optional ? It makes sense to have
 setTimeout() as a general timeout.

setTimeout() is not optional (the javadoc is out of date, sorry), there
was an agreement on that earlier. Timeout sets the connection timeout,
which is most likely useful even if there are events. It's quite
possible sleep could use a timeout argument (I think calling setTimeout
is more or less mandatory when using sleep, and OTOH calling setTimout
is not as important otherwise).



Ok - then sleep needs the extra argument, and will mean same as Thread.sleep(),
but
not-blocking ?



- not sure I understand the use case for isReadable()/isWriteable() - when
 will this be called ? My understanding was that when
 the connection is readable, a callback will be generated with EventType
==
 READ. Also it's very confusing to mix the 'blocking' in the
 isReadable()/isWriteable() - it would be much cleaner to say that the
 connection is always non-blocking, and add a method to switch to
blocking
 mode ( then use the regular servlet methods maybe ). Using the
ComentEvent
 for both is IMHO dangerous.

Although the read event indicates there's data to read, isReadable
indicates if it is possible to continue reading.



My understanding was that the InputStream in request is used for actual
reading -
and available() could do the same thing. What is the difference then between
the 2 ?


isWriteable indicates if the last write operation managed to write more

than 0 bytes. If the last write wrote 0, then isWriteable will return
false, so the servlet knows it should stop writing on this connection
for now (since it cannot accept any output at the moment). Later on, the
servlet will receive a write event, and can resume writing.



I'm still a bit confused about this - my understanding was that write event
means the
previous buffers were written, and you can write more. There are some
buffers
on the OS side as well as buffers on the connector side.

What do you mean by 'managed to write more than 0 bytes' - the write in the
OutputStream
can go to some of the buffers, or to the client. I assume you don't mean the
client ( due to TCP
delays ).


It is possible to add a blockingMode flag, but I've looked into it a

bit, and found out it is not really needed:



I agree, it is cleaner to not mix them.



- If doing synchronous writes inside some event (either a read or
callback event, most likely), then both blocking and non blocking mode
make sense. Some servlets may prefer to use blocking mode although it
could be holding a thread for a while (for example if the idea is only



maybe a 'waitForEvent()' method to allow a servlet to block if he wants to ?


Or is sleep() supposed to do this - I'm not sure from the comments if
sleep() will
block or just triger an event when the interval expires ?



- will sleep() still allow callbacks ( and if not - what will happen with
 them )? What's going to happen with callbacks if callback() is not
called ?

Yes, sleep is meant mostly to handle the reply-later design easily. The
servlet calls sleep(), and is supposed to call callback()
(asnychronously, most likely) as a result of something. The connection
will then wake and the servlet will get a callback event. If callback is
not called, the connection will timeout and the servlet will get its
timeout event (according to the connector timeout or the one that has
been configured for the connection).




You mean sort of 'notify()' -  i.e. someone calls callback() and will
trigger the
servlet to be executed, interrupting any sleep or wait ?



In general ( both versions):
 - it would be great to move it from o.a.catalina to org.apache.comet

It's a possibility.



I think more comments and examples ( and maybe better names ) would be
great.

In any case - the sandbox version seems better as an API, I really don't
like the
arrays and setConfig in the trunk, and certainly don't like having 2
variants.


Costin


Re: Proposed simplification of CometEvent

2007-06-11 Thread Filip Hanik - Dev Lists

Ok, let me see if I can summarize.

1. Whether you write out the stored buffer using the Poller thread, or a 
Tomcat worker thread (flushed in Http11xxxProcessor) as described below 
I originally thought of this as async write, as we are simply doing a 
write with another one of our threads. Originally when we were talking 
non blocking writes, I was thinking along the lines of non blocking to 
where the Comet developer had to do that logic, just as he was writing a 
socket, possibly like (but not suggested) a 
CometEvent.nonBlockWrite(ByteBuffer).


2. Do we need non blocking? with the methods of isWriteable and the 
ability to register(OP_WRITE)-event(WRITE), if the number of bytes you 
write is usually smaller than the socket buffer, chances are that most 
writes will be non blocking. I would even argue a large majority would 
be non blocking, and thus the implementation or the complexity thereof 
would not be needed. And with the ability to do async writes, means I 
can create my own thread pool/write queue to perform these writes.


3. isWriteable - simple method, but I don't like that the method in 
itself performs actions like adding the socket to a poller etc.
  Instead isWriteable==true means that you can write on the socket, 
isWriteable==false you cannot. This method should be able to be invoked 
as many times as its wanted, and is thread safe and doesn't do anything 
funky underneath.


4. isWriteable - I'm also reading in that you are also suggesting that 
we use this method to declare if we want blocking or non blocking writes.

  At this point this method is doing three things:
  a) returns true/false if we can write data
  b) delegates a socket to the poller to write data and generate a 
event(WRITE) to the comet processor

  c) configures a write to be blocking or non blocking
  This is for sure not what I would expect of a simple API, if simple 
means less keystrokes than yes, but simple to me also means intuitive 
and easily understood.


Given points 1-4, this is what is going to happen to every single developer
 I) They are going to use stream.write and event.isWriteable all the 
time, not realizing what it actually does
II) They are going to get confused when they receive an IOException for 
trying to perform a write, cause they used isWriteable and the socket 
went into non blocking mode


At this point, this 'simple' API, obviously not so simple, instead it 
becomes very complicated, as I would almost have to reverse engineer the 
code to truly understand what it does.

It may be simple to you and me, but that is because we are implementing it.

so what does this mean to 'isReadable'? That I'm automatically 
registering for a READ event if it returns false? Maybe I don't want a 
READ event, I just want to see if any data has trickled in. so if I call 
sleep(), should I then call isReadable() to reregister for the read. how 
is this simpler than that register/unregister.


Where does that leave us, well:
a) We are almost in sync on the implementation side of it
b) I believe your API is not intuitive, nor usable, as it simply doesn't 
reflect what is going on and/or what a programmer wants done
c) Your API doesn't become simpler just cause we merge three methods 
into one - configure(NON_BLOCK), write(byte[]), register(OP_WRITE)
c) The API I propose, you think is overengineered, I think it just makes 
things much clearer, the fact that it automatically allows for future 
extension is a side effect rather than design decision



So bottom line is, user will get the same implementation (or very close 
to what we've talked about), question is what API are they going to get?


Filip



Remy Maucherat wrote:

Filip Hanik - Dev Lists wrote:
I think I did present understandable explanations, so if you don't 
bother reading (as usual ...), I suppose I should stop wasting my time.
throwing your hands in the air and saying you're not going to waste 
your time, is in your personal interest only and you are of course 
welcome to do anything you wish. Throwing in derogatory statements 
like the one above, wont help you achieve your goal, it will only 
risk you being taken less seriously, and it doesn't benefit you nor 
the community.


You are writing self conflicting statements in the previous emails, 
which makes discussion difficult.


Here it is now, where we (magically) agree on core definitions:
 async - using more than one thread to do stuff
 and that is what you are proposing, to dispatch the write to the poller
 thread.
 non blocking - a method call which returns immediately without, well,
 blocking
 yes

And in the previous email, it was:
 Actually, this is very simple to implement. Read is obvious. For
 write, the algorithm for the flushBuffer method would be very similar
 to what it is now, but if a write returns 0, leftover bytes 
would be

 put in a ByteChunk. isWriteable, if called, will return false, and
 place the socket in the poller with write notifications.
 that's 

Re: Proposed simplification of CometEvent

2007-06-11 Thread Remy Maucherat

Filip Hanik - Dev Lists wrote:

Ok, let me see if I can summarize.

1. Whether you write out the stored buffer using the Poller thread, or a 
Tomcat worker thread (flushed in Http11xxxProcessor) as described below 
I originally thought of this as async write, as we are simply doing a 
write with another one of our threads. Originally when we were talking 
non blocking writes, I was thinking along the lines of non blocking to 
where the Comet developer had to do that logic, just as he was writing a 
socket, possibly like (but not suggested) a 
CometEvent.nonBlockWrite(ByteBuffer).


2. Do we need non blocking? with the methods of isWriteable and the 
ability to register(OP_WRITE)-event(WRITE), if the number of bytes you 
write is usually smaller than the socket buffer, chances are that most 
writes will be non blocking. I would even argue a large majority would 
be non blocking, and thus the implementation or the complexity thereof 
would not be needed. And with the ability to do async writes, means I 
can create my own thread pool/write queue to perform these writes.


You are writing the opposite thing to the previous email, and we are 
back to non blocking is useless. The problem is that I understand 
blocking IO as write this data, and return when it's done. If the 
socket is in blocking mode, any write done by the servlet may block, 
regardless of what isWriteable says. Of course, it's very unlikely, 
which is why Comet in 6.0.x works.


3. isWriteable - simple method, but I don't like that the method in 
itself performs actions like adding the socket to a poller etc.
  Instead isWriteable==true means that you can write on the socket, 
isWriteable==false you cannot. This method should be able to be invoked 
as many times as its wanted, and is thread safe and doesn't do anything 
funky underneath.


Ok, so you prefer a more complex API (if I follow just in case it was 
useful). I started with an API which would expose all operations, and 
looked into removing what was not explicitly useful.


4. isWriteable - I'm also reading in that you are also suggesting that 
we use this method to declare if we want blocking or non blocking writes.


No. The situation where write could (maybe) block is if the servlet 
writes in a Tomcat thread. Typically, this is the reply-later design, 
using the sleep/callback methods. The isWriteable method is not used, 
since the servlet merely wants (in that common design) to send a 
response as fast as possible, and typically this sort of response is not 
too large and unlikely to cause IO problems. This blocking behavior is 
allowed in that case to avoid forcing the user to put in more complex 
logic to deal with the partial write + event, and is set just for the 
amount of time it takes to perform the write (note that this ).



  At this point this method is doing three things:
  a) returns true/false if we can write data
  b) delegates a socket to the poller to write data and generate a 
event(WRITE) to the comet processor

  c) configures a write to be blocking or non blocking
  This is for sure not what I would expect of a simple API, if simple 
means less keystrokes than yes, but simple to me also means intuitive 
and easily understood.


So you have plenty of methods to do the same thing.


Given points 1-4, this is what is going to happen to every single developer
 I) They are going to use stream.write and event.isWriteable all the 
time, not realizing what it actually does
II) They are going to get confused when they receive an IOException for 
trying to perform a write, cause they used isWriteable and the socket 
went into non blocking mode


If that's what you want to believe ...

At this point, this 'simple' API, obviously not so simple, instead it 
becomes very complicated, as I would almost have to reverse engineer the 
code to truly understand what it does.

It may be simple to you and me, but that is because we are implementing it.


I really don't see what is complex, especially when you look at the code 
the user would write for the simple cases, where you don't even have to 
use any API besides stream.write:

- reply later
- wait for read events, and write data in response to it

The complex case deals with handling incomplete async writes if you 
don't simply drop connection.


so what does this mean to 'isReadable'? That I'm automatically 
registering for a READ event if it returns false? Maybe I don't want a 
READ event, I just want to see if any data has trickled in. so if I call 
sleep(), should I then call isReadable() to reregister for the read. how 
is this simpler than that register/unregister.


Read events always occur, unless you use sleep/callback. If this is not 
written clearly in the javadocs already, I need to change them.



Where does that leave us, well:
a) We are almost in sync on the implementation side of it


Not really, there's a big disconnect in the understanding of non 
blocking vs blocking, and according to you, non blocking 

Re: Proposed simplification of CometEvent

2007-06-11 Thread Filip Hanik - Dev Lists

I'll work on some examples to illustrate what I mean,
It will be much clearer

Filip

Remy Maucherat wrote:

Filip Hanik - Dev Lists wrote:

Ok, let me see if I can summarize.

1. Whether you write out the stored buffer using the Poller thread, 
or a Tomcat worker thread (flushed in Http11xxxProcessor) as 
described below I originally thought of this as async write, as we 
are simply doing a write with another one of our threads. Originally 
when we were talking non blocking writes, I was thinking along the 
lines of non blocking to where the Comet developer had to do that 
logic, just as he was writing a socket, possibly like (but not 
suggested) a CometEvent.nonBlockWrite(ByteBuffer).


2. Do we need non blocking? with the methods of isWriteable and the 
ability to register(OP_WRITE)-event(WRITE), if the number of bytes 
you write is usually smaller than the socket buffer, chances are that 
most writes will be non blocking. I would even argue a large majority 
would be non blocking, and thus the implementation or the complexity 
thereof would not be needed. And with the ability to do async writes, 
means I can create my own thread pool/write queue to perform these 
writes.


You are writing the opposite thing to the previous email, and we are 
back to non blocking is useless. The problem is that I understand 
blocking IO as write this data, and return when it's done. If the 
socket is in blocking mode, any write done by the servlet may block, 
regardless of what isWriteable says. Of course, it's very unlikely, 
which is why Comet in 6.0.x works.


3. isWriteable - simple method, but I don't like that the method in 
itself performs actions like adding the socket to a poller etc.
  Instead isWriteable==true means that you can write on the socket, 
isWriteable==false you cannot. This method should be able to be 
invoked as many times as its wanted, and is thread safe and doesn't 
do anything funky underneath.


Ok, so you prefer a more complex API (if I follow just in case it was 
useful). I started with an API which would expose all operations, and 
looked into removing what was not explicitly useful.


4. isWriteable - I'm also reading in that you are also suggesting 
that we use this method to declare if we want blocking or non 
blocking writes.


No. The situation where write could (maybe) block is if the servlet 
writes in a Tomcat thread. Typically, this is the reply-later design, 
using the sleep/callback methods. The isWriteable method is not used, 
since the servlet merely wants (in that common design) to send a 
response as fast as possible, and typically this sort of response is 
not too large and unlikely to cause IO problems. This blocking 
behavior is allowed in that case to avoid forcing the user to put in 
more complex logic to deal with the partial write + event, and is set 
just for the amount of time it takes to perform the write (note that 
this ).



  At this point this method is doing three things:
  a) returns true/false if we can write data
  b) delegates a socket to the poller to write data and generate a 
event(WRITE) to the comet processor

  c) configures a write to be blocking or non blocking
  This is for sure not what I would expect of a simple API, if 
simple means less keystrokes than yes, but simple to me also means 
intuitive and easily understood.


So you have plenty of methods to do the same thing.

Given points 1-4, this is what is going to happen to every single 
developer
 I) They are going to use stream.write and event.isWriteable all the 
time, not realizing what it actually does
II) They are going to get confused when they receive an IOException 
for trying to perform a write, cause they used isWriteable and the 
socket went into non blocking mode


If that's what you want to believe ...

At this point, this 'simple' API, obviously not so simple, instead it 
becomes very complicated, as I would almost have to reverse engineer 
the code to truly understand what it does.
It may be simple to you and me, but that is because we are 
implementing it.


I really don't see what is complex, especially when you look at the 
code the user would write for the simple cases, where you don't even 
have to use any API besides stream.write:

- reply later
- wait for read events, and write data in response to it

The complex case deals with handling incomplete async writes if you 
don't simply drop connection.


so what does this mean to 'isReadable'? That I'm automatically 
registering for a READ event if it returns false? Maybe I don't want 
a READ event, I just want to see if any data has trickled in. so if I 
call sleep(), should I then call isReadable() to reregister for the 
read. how is this simpler than that register/unregister.


Read events always occur, unless you use sleep/callback. If this is 
not written clearly in the javadocs already, I need to change them.



Where does that leave us, well:
a) We are almost in sync on the implementation side of it


Not really, 

Re: Proposed simplification of CometEvent

2007-06-11 Thread Costin Manolache

For a separate opinion:

In the trunk version:
- the '...' and array return seem strange and generate GC ( not a big issue
those days, but still inconsistent with the
rest of tomcat )

- the API seems a bit over-complex - for example, why
setConfiguration(COMMET_BLOCKING) instead of setBlocking() ?
I agree that it less likely to break implementations by adding to the enom
instead of adding methods to the interface - not sure
why it's not an abstract class in the first place.

- please don't call the method configure(), it's commonly used with a
different meaning ( i.e. setting the port or general configuration).
setConnectionMode, etc. And using the enum doesn't sound consistent with
other APIs either.

- see bellow - I don't think I understand the benefits of mixing blocking
and non-blocking in this interface, it is quite confusing.

In the sandbox version:
- sleep() and setTimeout(int) - why not sleep(int millis) ? I think it's
confusing to have both and the interactions between them, in
particular setTimeout is marked optional ? It makes sense to have
setTimeout() as a general timeout.

- not sure I understand the use case for isReadable()/isWriteable() - when
will this be called ? My understanding was that when
the connection is readable, a callback will be generated with EventType ==
READ. Also it's very confusing to mix the 'blocking' in the
isReadable()/isWriteable() - it would be much cleaner to say that the
connection is always non-blocking, and add a method to switch to blocking
mode ( then use the regular servlet methods maybe ). Using the ComentEvent
for both is IMHO dangerous.

- will sleep() still allow callbacks ( and if not - what will happen with
them )? What's going to happen with callbacks if callback() is not called ?


In general ( both versions):
- it would be great to move it from o.a.catalina to org.apache.comet

Costin

On 6/11/07, Remy Maucherat [EMAIL PROTECTED] wrote:


Filip Hanik - Dev Lists wrote:
 Ok, let me see if I can summarize.

 1. Whether you write out the stored buffer using the Poller thread, or a
 Tomcat worker thread (flushed in Http11xxxProcessor) as described below
 I originally thought of this as async write, as we are simply doing a
 write with another one of our threads. Originally when we were talking
 non blocking writes, I was thinking along the lines of non blocking to
 where the Comet developer had to do that logic, just as he was writing a
 socket, possibly like (but not suggested) a
 CometEvent.nonBlockWrite(ByteBuffer).

 2. Do we need non blocking? with the methods of isWriteable and the
 ability to register(OP_WRITE)-event(WRITE), if the number of bytes you
 write is usually smaller than the socket buffer, chances are that most
 writes will be non blocking. I would even argue a large majority would
 be non blocking, and thus the implementation or the complexity thereof
 would not be needed. And with the ability to do async writes, means I
 can create my own thread pool/write queue to perform these writes.

You are writing the opposite thing to the previous email, and we are
back to non blocking is useless. The problem is that I understand
blocking IO as write this data, and return when it's done. If the
socket is in blocking mode, any write done by the servlet may block,
regardless of what isWriteable says. Of course, it's very unlikely,
which is why Comet in 6.0.x works.

 3. isWriteable - simple method, but I don't like that the method in
 itself performs actions like adding the socket to a poller etc.
   Instead isWriteable==true means that you can write on the socket,
 isWriteable==false you cannot. This method should be able to be invoked
 as many times as its wanted, and is thread safe and doesn't do anything
 funky underneath.

Ok, so you prefer a more complex API (if I follow just in case it was
useful). I started with an API which would expose all operations, and
looked into removing what was not explicitly useful.

 4. isWriteable - I'm also reading in that you are also suggesting that
 we use this method to declare if we want blocking or non blocking
writes.

No. The situation where write could (maybe) block is if the servlet
writes in a Tomcat thread. Typically, this is the reply-later design,
using the sleep/callback methods. The isWriteable method is not used,
since the servlet merely wants (in that common design) to send a
response as fast as possible, and typically this sort of response is not
too large and unlikely to cause IO problems. This blocking behavior is
allowed in that case to avoid forcing the user to put in more complex
logic to deal with the partial write + event, and is set just for the
amount of time it takes to perform the write (note that this ).

   At this point this method is doing three things:
   a) returns true/false if we can write data
   b) delegates a socket to the poller to write data and generate a
 event(WRITE) to the comet processor
   c) configures a write to be blocking or non blocking
   This is for 

Re: Proposed simplification of CometEvent

2007-06-08 Thread Filip Hanik - Dev Lists
If you don't care about this stuff, but still read the first line, do 
our community a favor and get involved :)


The API's are pretty much identical,

Remy: 
https://svn.apache.org/viewvc/tomcat/sandbox/comet/java/org/apache/catalina/CometEvent.java?view=markup
Filip: 
https://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/CometEvent.java?view=markup


There are a few differences

isReadable()
- Remy - same functionality as ServletInputStream.available()
- Filip - ServletInputStream.available() || 
InternalNioInputBuffer.hasData || 
InternalNioInputBuffer.nonBlockRead().hasData
ie, is readable in my API means that there is some data from the bottom 
layer of the API. Doesn't mean that it would actually result in data to 
a ServletInputStream.read(), but most cases it would. The benefit of 
this method is that it actually does check the socket for data in a non 
blocking way if the first two conditions have not been met.
API has been implemented in trunk. so isAvailable() is different, and 
both methods can be used for different purposes


isWriteable()
This functions the same way in both APIs. After playing with the API 
this function is useless unless you have true non blocking writes.
Why? Well, the function will always return true, unless there is 
another thread writing, but write is not thread safe, so another thread 
should never attempt to write.
And in a blocking way, isWriteable()-true : write(blocking) : 
isWriteable()-true, always.
However, in the blocking API, there is a true way to find out if we can 
write or not, and that is by calling CometEvent.register(OP_WRITE), this 
will actually check with the poller
to see if the network buffer is ready to receive more data and dispatch 
a worker thread.


callback()
- Remy - one time callback from the container on a Tomcat worker thread
- Filip - same functionality implemented, CometEvent.register(OP_CALLBACK)
I definitely like the register/unregister for events more than I like 
the one time functionality of callback()/sleep().

OP_CALLBACK currently is implemented and working in trunk.
Why do I like register more? Cause we can add new operations in the 
future without changing the API. This leads to more flexibility.
Currently OP_CALLBACK stays registered until it is unregister-ed. If 
we wanted to achieve callback() functionality, we can add a 
OP_CALLBACK_ONCE operation or simply change the behavior of existing 
callback, without changing the API.
it is also possible to retrieve the state of a comet connection by 
calling getRegisteredOps, something not available in the sandbox API.


sleep()
- Remy - deregister from the READ events
- Filip - same functionality exists, 
CometEvent.unregister(OP_READ,OP_WRITE,OP_CALLBACK) or simply 
CometEvent.unregister(OP_READ) if nothing else is registered.
Again, I think the trunk API is more flexible, and cleaner. sleep() is 
associated with Thread.sleep() in every programmers head. and doesn't 
really apply to an event based API.

This is implemented in trunk and working.


Conclusion, both APIs are almost identical. I believe the trunk API is 
more flexible and allows for additions of functionality in the future 
without changing the API.
Remy's initial -1 to the trunk was based on the implementation, having 
to synchronize etc. All that has been simplified and removed.


So therefor, the API's are almost identical, I would vote
sandbox API - -1 - API is simple but not extensible, names are not 
intuitive as they are not event oriented.
trunk API - +1 - API is equally simple, more geared towards event 
based API, more flexible, as I am sure new needs will need new 
operations and events


The only thing not working in trunk at this moment is non blocking, but 
after doing the research, this is a major surgery to try to do within 
the existing buffer/filter API
I'd rather delay such an attempt until we can reach consensus on the API 
and the simple stuff.


Looks like we are gonna have to have a pancake flipping contest :)

Filip


Remy Maucherat wrote:

Hi,

I've been working on additions to CometEvent to implement the 
additional Comet functionality that was agreed upon before creating 
the trunk branch. Although not functional at the moment, I consider 
it to be developed enough from an algorithmic standpoint to be 
proposed and reviewed (it is also important to not continue an API 
fork for too long, since otherwise it would be harder to merge, so 
some resolution is needed). I went through a few revisions of the API, 
as more tweaks appeared possible. The idea was to allow the extra 
functionality without adding complexity or incompatible changes, since 
this is most likely going to be an interim API.


The repository is at:
https://svn.apache.org/repos/asf/tomcat/sandbox/comet

It has the following changes over the 6.0.x branch:
- additions of four methods in CometEvent (sleep and callback, and the 
two flags isRead(Write)able)
- sleep delays request processing until either callback is 

Re: Proposed simplification of CometEvent

2007-06-08 Thread Remy Maucherat

Filip Hanik - Dev Lists wrote:
If you don't care about this stuff, but still read the first line, do 
our community a favor and get involved :)


I'm not sure I understand this. It could be interpreted in a derogatory way.


The API's are pretty much identical,


Yes, they are pretty much functionally identical. The problem is that 
the interpretation of the same thing you are proposing is 
overengineered, convoluted and very GC unfriendly. The sync was a funny 
choice which made me start working on a separate branch, since:

- you were ignoring my messages all of a sudden for some reason
- you started adding more and more stuff I disagreed with
It's ok to do that as part of a proposal (like I did), but it's not the 
right way if you do it in a regular branch.



callback()
- Remy - one time callback from the container on a Tomcat worker thread
- Filip - same functionality implemented, CometEvent.register(OP_CALLBACK)
I definitely like the register/unregister for events more than I like 
the one time functionality of callback()/sleep().

OP_CALLBACK currently is implemented and working in trunk.
Why do I like register more? Cause we can add new operations in the 
future without changing the API. This leads to more flexibility.
Currently OP_CALLBACK stays registered until it is unregister-ed. If 
we wanted to achieve callback() functionality, we can add a 
OP_CALLBACK_ONCE operation or simply change the behavior of existing 
callback, without changing the API.
it is also possible to retrieve the state of a comet connection by 
calling getRegisteredOps, something not available in the sandbox API.


sleep()
- Remy - deregister from the READ events
- Filip - same functionality exists, 
CometEvent.unregister(OP_READ,OP_WRITE,OP_CALLBACK) or simply 
CometEvent.unregister(OP_READ) if nothing else is registered.
Again, I think the trunk API is more flexible, and cleaner. sleep() is 
associated with Thread.sleep() in every programmers head. and doesn't 
really apply to an event based API.

This is implemented in trunk and working.


The connector should only care about IO, which only knows read and write 
(and error, but obviously this is a special case, and I don't see you 
registering for that).


Conclusion, both APIs are almost identical. I believe the trunk API is 
more flexible and allows for additions of functionality in the future 
without changing the API.
Remy's initial -1 to the trunk was based on the implementation, having 
to synchronize etc. All that has been simplified and removed.


I would like to understand what extensions are desirable or envisioned, 
since this this sort of extensions will make the connector 
implementation to skyrocket in terms of complexity. I think the 
connector should only care about IO, so this means: read, write, and a 
generic callback. The user will write a piece of code which can listen 
to any sort of event, and use the callback method: the callback is the 
extension point as far as I understand.


Another flaw IMO is that read and write do not behave the same as far as 
their registration go.


The trunk API also has the following additional methods and constructs:
- public enum CometConfiguration {COMET_BLOCKING, COMET_NON_BLOCKING};
- public void configure(CometConfiguration... options) throws 
IllegalStateException; (note: as I have discussed, it seems possible to 
abstract away blocking configuration from the user)

- public enum CometOperation {OP_CALLBACK, OP_READ, OP_WRITE};
- public CometOperation[] getRegisteredOps();
- the need to ask for a write event (it is quite crucial, and I found 
out it could easily be hidden away)
So, similarly, the configuration is extensible. I would like to 
understand what additional configuration should be exposed to the user 
(personally, I solved the configuration problem when I noticed blocking 
/ non blocking configuration was pointless).


I also dislike the thread checks you are using.

The last reason I would like to have a really simple (yet fully 
functional) API is to avoid having duplicate APIs. The Servlet API may 
tackle the Comet topic, and knowing Sun APIs, you may get the API of 
your dreams :D



So therefor, the API's are almost identical, I would vote
sandbox API - -1 - API is simple but not extensible, names are not 
intuitive as they are not event oriented.
trunk API - +1 - API is equally simple, more geared towards event 
based API, more flexible, as I am sure new needs will need new 
operations and events


I think the APIs are quite different in form, yet expose similar 
functionality (at the moment, I'm waiting for the OP_JMS ;) ). Since 
it's a user visible API, it's an important issue regardless of what you 
think. I have my own vote (hehe ;) ):

- sandbox - +1
- trunk - -1 (overenginneered, more complex, thread checks)

The only thing not working in trunk at this moment is non blocking, but 
after doing the research, this is a major surgery to try to do within 
the existing buffer/filter API



Re: Proposed simplification of CometEvent

2007-06-08 Thread Filip Hanik - Dev Lists

Remy Maucherat wrote:

Filip Hanik - Dev Lists wrote:
If you don't care about this stuff, but still read the first line, do 
our community a favor and get involved :)


I'm not sure I understand this. It could be interpreted in a 
derogatory way.

if it is just you and I, then its your -1 against my -1 and we get nowhere.
simply trying to invite folks to be a part of the decision making.



The API's are pretty much identical,


Yes, they are pretty much functionally identical. The problem is that 
the interpretation of the same thing you are proposing is 
overengineered, convoluted and very GC unfriendly. The sync was a 
funny choice which made me start working on a separate branch, since:

- you were ignoring my messages all of a sudden for some reason
no messages ignored. some messages were pure statements, and didn't 
invite for comments.

- you started adding more and more stuff I disagreed with

to the API? (CometEvent.java) like what?
It's ok to do that as part of a proposal (like I did), but it's not 
the right way if you do it in a regular branch.



callback()
- Remy - one time callback from the container on a Tomcat worker thread
- Filip - same functionality implemented, 
CometEvent.register(OP_CALLBACK)
I definitely like the register/unregister for events more than I like 
the one time functionality of callback()/sleep().

OP_CALLBACK currently is implemented and working in trunk.
Why do I like register more? Cause we can add new operations in the 
future without changing the API. This leads to more flexibility.
Currently OP_CALLBACK stays registered until it is unregister-ed. 
If we wanted to achieve callback() functionality, we can add a 
OP_CALLBACK_ONCE operation or simply change the behavior of existing 
callback, without changing the API.
it is also possible to retrieve the state of a comet connection by 
calling getRegisteredOps, something not available in the sandbox API.


sleep()
- Remy - deregister from the READ events
- Filip - same functionality exists, 
CometEvent.unregister(OP_READ,OP_WRITE,OP_CALLBACK) or simply 
CometEvent.unregister(OP_READ) if nothing else is registered.
Again, I think the trunk API is more flexible, and cleaner. sleep() 
is associated with Thread.sleep() in every programmers head. and 
doesn't really apply to an event based API.

This is implemented in trunk and working.


The connector should only care about IO, which only knows read and 
write (and error, but obviously this is a special case, and I don't 
see you registering for that).
But the connector must care, if you do a CALLBACK, you must ensure that 
you are not spawning a 2nd thread if a READ comes in on the socket.
otherwise, you are forcing the comet developers to synchronize, 
something in today's API, is done in such a way that if you do stuff on 
the Tomcat thread, you're safe.


Conclusion, both APIs are almost identical. I believe the trunk API 
is more flexible and allows for additions of functionality in the 
future without changing the API.
Remy's initial -1 to the trunk was based on the implementation, 
having to synchronize etc. All that has been simplified and removed.


I would like to understand what extensions are desirable or 
envisioned, since this this sort of extensions will make the connector 
implementation to skyrocket in terms of complexity. I think the 
connector should only care about IO, so this means: read, write, and a 
generic callback. The user will write a piece of code which can listen 
to any sort of event, and use the callback method: the callback is the 
extension point as far as I understand.


Another flaw IMO is that read and write do not behave the same as far 
as their registration go.


The trunk API also has the following additional methods and constructs:
- public enum CometConfiguration {COMET_BLOCKING, COMET_NON_BLOCKING};
- public void configure(CometConfiguration... options) throws 
IllegalStateException; (note: as I have discussed, it seems possible 
to abstract away blocking configuration from the user)

- public enum CometOperation {OP_CALLBACK, OP_READ, OP_WRITE};
- public CometOperation[] getRegisteredOps();
- the need to ask for a write event (it is quite crucial, and I found 
out it could easily be hidden away)
There is no need to ask for a WRITE, you can write anytime, 
asynchronously too. OP_WRITE is if you want to be sure that the network 
buffer is ready to receive data.
otherwise, I already pointed out the flaws in isWriteable and that 
isWriteable==true doesn't mean that it is writeable.
So, similarly, the configuration is extensible. I would like to 
understand what additional configuration should be exposed to the user 
(personally, I solved the configuration problem when I noticed 
blocking / non blocking configuration was pointless).
configure() can be removed, or taken out for a later consideration, have 
no problem with that.


I also dislike the thread checks you are using.
I can pull those out as well, since in my impl I able to 

Re: Proposed simplification of CometEvent

2007-06-08 Thread Remy Maucherat

Filip Hanik - Dev Lists wrote:

In my personal opinion I am no longer sure a non blocking write is needed.


Ok.

async - using more than one thread to do stuff
non blocking - a method call which returns immediately without, well, 
blocking


I think I did present understandable explanations, so if you don't 
bother reading (as usual ...), I suppose I should stop wasting my time.



I agree a consensus should have been reached *on month ago* :)
we'd be in the same shoes we are today. I still think a pancake flipping 
contest would be the way to go. although I might consider stone,paper 
and scissors too.


No problem with that, feel free to consider it any way you like. What I 
see in your response is that we actually agree on very little.


I'll try in order (one last time, most likely):

 The connector should only care about IO, which only knows read and
 write (and error, but obviously this is a special case, and I don't
 see you registering for that).
 But the connector must care, if you do a CALLBACK, you must ensure that
 you are not spawning a 2nd thread if a READ comes in on the socket.
 otherwise, you are forcing the comet developers to synchronize,
 something in today's API, is done in such a way that if you do stuff on
 the Tomcat thread, you're safe.

Well, not really, the callback goes all the way to the poller, using the 
same add lists, which allows ensuring that events are not sent in a 
concurrent way.


 Actually, this is very simple to implement. Read is obvious. For
 write, the algorithm for the flushBuffer method would be very similar
 to what it is now, but if a write returns 0, leftover bytes would be
 put in a ByteChunk. isWriteable, if called, will return false, and
 place the socket in the poller with write notifications.
 that's not non blocking, that's a async write, and I could ten times
 more easier implement it in an AbstractCometProcessor.java, then having
 to fiddle with pollers and everything else down the chain.
 non blocking is a different concept than async.

I made an effort to explain in detail algorithms, and you come back with 
definitions I do not understand and vague ideas (I have no idea what 
would be implemented in AbstractCometProcessor).


 does not work either. isWriteable (when blocking) only is in effect for
 other threads, but write is not thread safe, so this method is useless
 then.
 and during an async write, you have the same issue, async writes still
 should only be done on one thread.

? Ok, so the plan is that there's only one thread attempting to write on 
one particular connection. The lifeclyle seems very simple to me:

- check isWriteable
- write stuff
- repeat until isWriteable puts the socket in the add-write list for the 
poller, and returns false

- wait until you get a write event before writing again on the connection

Since this is non blocking IO, it is indeed possible and recommended to 
use a single thread for writing, thus maximizing scalability. If you 
advocate a design where the user would write using multiple threads, 
never sync anything, and hope it works, then I'd like to hear about a 
use case first :)


Rémy

-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Re: Proposed simplification of CometEvent

2007-06-08 Thread Remy Maucherat

Filip Hanik - Dev Lists wrote:
I think I did present understandable explanations, so if you don't 
bother reading (as usual ...), I suppose I should stop wasting my time.
throwing your hands in the air and saying you're not going to waste your 
time, is in your personal interest only and you are of course welcome to 
do anything you wish. Throwing in derogatory statements like the one 
above, wont help you achieve your goal, it will only risk you being 
taken less seriously, and it doesn't benefit you nor the community.


You are writing self conflicting statements in the previous emails, 
which makes discussion difficult.


Here it is now, where we (magically) agree on core definitions:
 async - using more than one thread to do stuff
 and that is what you are proposing, to dispatch the write to the poller
 thread.
 non blocking - a method call which returns immediately without, well,
 blocking
 yes

And in the previous email, it was:
 Actually, this is very simple to implement. Read is obvious. For
 write, the algorithm for the flushBuffer method would be very similar
 to what it is now, but if a write returns 0, leftover bytes 
would be

 put in a ByteChunk. isWriteable, if called, will return false, and
 place the socket in the poller with write notifications.
 that's not non blocking, that's a async write, and I could ten times
 more easier implement it in an AbstractCometProcessor.java, then having
 to fiddle with pollers and everything else down the chain.
 non blocking is a different concept than async.

(stars added to point out it was plainly obvious I was talking about non 
blocking write calls, I never talked at all about blocking IO - except 
to say they were most likely useless to the user, to which you said I 
am no longer sure a non blocking write is needed; at this point, I'd 
like you to explain to me how I could agree on anything you said)


I made an effort to explain in detail algorithms, and you come back 
with definitions I do not understand and vague ideas (I have no idea 
what would be implemented in AbstractCometProcessor).
ok, you suggest that a non block write is simply a dispatch of the 
writing to the poller in the event of the data written didn't fit in the 
network buffer, that sounds like multiple threads are indeed involved. 


No, I suggest the possibility, as is written in black and white, that 
rather than rely on a (un)register API, that the isWriteable call has 
the possibility to safely put the socket in the poller. This seems to be 
well understood now.


So this is just a terminology misunderstanding. What you are explaining 
is similar to the SEND_FILE way of doing it, there is still a thread on 
our side involved in writing the data. I do understand your solution, 
and it would still work with my API.


Not at all, the lifecycle I provided is very clear. Our thread is the 
event thread before it invokes the event. When a write event is sent, 
the following occurs:

- go out of the poller with the write notification
- dispatch to a worker thread
- in the Http11(Apr/Nio)Processor, flush leftover data (if any)
- if all data was flushed, invoke the adapter with a write event 
(isWriteable will now return true, but the servlet will wait before 
getting a write event to start dealing with writing on this connection), 
otherwise go back to the poller


Writes are done in two threads, but never concurrently. It is also 
possible to not care and not do any flush before going into the servlet 
(the servlet first write would do the flush), but it seemed more 
efficient to do so.


As I have described in a previous email, if the servlet does its writes 
during the processing of read and callback events, and the servlet is 
not using isWriteable, I think it would be fair if the write call blocks.



it would be like this
a) check isWriteable
b) write stuff possibly goto f)
c) check isWriteable, if true goto b) else goto d),
d) event.register(OP_WRITE)
e) wait for a WRITE event to come in
f) done


It's almost the same scenario, but the event.register(OP_WRITE) is done 
inside isWriteable. This allows simplifying a lot the API, since the 
only feature which remains is the ability to disable read events.


in your API, you are forcing the WRITE event notification, I may just 
not be interested in it, and that is why I like the trunk API better, it 


If you are not interested in the write notification, then don't process 
it in the servlet, and use a tight loop on isWriteable, it will work 
without any particular problem (but would not be very sensible). Another 
way is to discard messages, which seems uncommon in web land.


is event driven and it is the developer who controls what notifications 
are going to be coming or not. Since a WRITE event does take a thread 
out of the thread pool, that may not be desired.


Looks like a better argument to me, since you don't imply that the 
solution I proposed is unsafe ;)


In that case, I would like more concrete 

Proposed simplification of CometEvent

2007-06-07 Thread Remy Maucherat

Hi,

I've been working on additions to CometEvent to implement the additional 
Comet functionality that was agreed upon before creating the trunk 
branch. Although not functional at the moment, I consider it to be 
developed enough from an algorithmic standpoint to be proposed and 
reviewed (it is also important to not continue an API fork for too long, 
since otherwise it would be harder to merge, so some resolution is 
needed). I went through a few revisions of the API, as more tweaks 
appeared possible. The idea was to allow the extra functionality without 
adding complexity or incompatible changes, since this is most likely 
going to be an interim API.


The repository is at:
https://svn.apache.org/repos/asf/tomcat/sandbox/comet

It has the following changes over the 6.0.x branch:
- additions of four methods in CometEvent (sleep and callback, and the 
two flags isRead(Write)able)
- sleep delays request processing until either callback is called, or a 
timeout occurs
- callback allows waking up requests which are asleep or waiting for 
an IO event
- non blocking IO exclusively in Comet mode, since it now seems to me it 
is algorithmically equivalent to blocking IO; for read, it has been 
demonstrated previously; for write, it seems there should always be 
write events after a properly handled congestion (where the servlet uses 
isWriteable), since if the servlet does not, it will be best to simply 
fail-fast the connection using an IOException (the servlet would 
effectively only handle clients which are fast enough if using the 
Comet API like in Tomcat 6.0, which avoids a lot of issues)
- isRead(Write)able indicate if data may be read or written (since this 
is non blocking IO, reading or writing would read or write 0 bytes); if 
it is false and reading or writing is done, an IO exception will be thrown

- no additional data structures
- new ActionCode: ACTION_COMET_TIMEOUT (which is cleanup), 
ACTION_COMET_CALLBACK (called by the callback() method), 
ACTION_COMET_SLEEP (called by the sleep() method), ACTION_COMET_WRITE 
(called by the CometEvent.isWriteable method without the need for an 
explicit callback from the servlet - isWriteable knows the result of the 
last write, and the servlet is supposed to not attempt any further 
writing if isWriteable returns false)
- no additional features, like verification of caller threads (which I 
consider useless)


I hope I did not forget anything.

Comments ? / Votes ?

Rémy


-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Re: Proposed simplification of CometEvent

2007-06-07 Thread Yoav Shapira

Hi,

On 6/7/07, Remy Maucherat [EMAIL PROTECTED] wrote:

fail-fast the connection using an IOException (the servlet would
effectively only handle clients which are fast enough if using the
Comet API like in Tomcat 6.0, which avoids a lot of issues)


This is an interesting assumption, but I think it's valid for this type of API.


Comments ? / Votes ?


I like the callback approach especially, and otherwise I see no major
problems.  Cool improvements.

Yoav

-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Re: Proposed simplification of CometEvent

2007-06-07 Thread Remy Maucherat

Yoav Shapira wrote:

Hi,

On 6/7/07, Remy Maucherat [EMAIL PROTECTED] wrote:

fail-fast the connection using an IOException (the servlet would
effectively only handle clients which are fast enough if using the
Comet API like in Tomcat 6.0, which avoids a lot of issues)


This is an interesting assumption, but I think it's valid for this type 
of API.


Yes, it's a bit an assumption. Since there's no blocking or non 
blocking ? question mark, it simplifies significantly the documentation 
of the API.


The main issue is how to handle a write which would block, and would 
most probably cause problems when doing async writes (as others pointed 
out - Filip, I think), so in that case, if the Servlet chooses not to 
handle it using isWriteable - which makes sense in many cases -, I think 
the exception throwing is fine.


The only situation where it could cause real problems is if the write is 
done inside another event (like in the common reply later pattern), 
and I think it would most likely work well enough due to the existence 
of buffers at the servlet layer. It's quite easy to add back blocking 
mode if needed, and tricks could be used rather than rely on direct 
configuration. For example, while I think adding code to detect what is 
called asynchronously for error checking purposes is useless, it could 
be possible to detect if the problematic write is sync or async, and 
adjust blocking mode accordingly at the connector level rather than 
throwing the exception.


The idea is to make the API simpler overall than what it is in 6.0 
(despite the addition of 3 methods and 2 event types, I think it would 
be simpler to work with due to the sleep/callback methods which allow 
doing common things very easily), and avoid introducing heavier 
constructs and method calls.


Rémy

-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]