You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Yann Simon <ya...@gmail.com> on 2014/01/08 18:04:37 UTC

Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Hi,

I am trying to write a servlet that asynchronously read data from the
servlet request input stream.
I tested my servlet with tomcat 8.0.0-RC5.

the symptoms:
- I must synchronously read the input stream in onDataAvailable() so
that the upload works

what I expected:
I want to be more "reactive" (buzzword of the moment) and not read the
input stream until I am ready (=until the previous chunk is processed)
I though I could return from onDataAvailable() before having read all
the data, read the data in another thread. I expected
onDataAvailable() to be called again when I consumed all the data
(servletInputStream.isReady becomes false)
That way, I could implement back pressure on the browser as long as my
servlet has not finished its work with the actual chunk

But if I do that, neither onDataAvailable() nor onAllDataRead() is called again.

When I consume the input stream synchronously in onDataAvailable(), it
works as expected.

Am I misunderstanding the asynchron IO in Tomcat 8?

Thanks in advance for any ideas!
Yann

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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
2014-03-19 16:42 GMT+01:00 Mark Thomas <ma...@apache.org>:
> On 19/03/2014 15:36, Yann Simon wrote:
>> Hi,
>>
>> I have maybe found another problem:
>> onAllDataRead is called with the same thread that is calling input.read.
>>
>> I updated the sample to show the problem:
>> https://github.com/yanns/servlet31_async/commit/3c7618a51a8efd76956a6a29e27f350f7dbe835b
>>
>> The servlet displays a wrong size of the uploaded file.
>>
>> event.getSuppliedResponse().getOutputStream().print("Complete. Read "
>> + readListener.getRead());
>> sees a wrong value from readListener.getRead()
>>
>> If onAllDataRead was called with another thread, it would wait for the
>> synchronized (input) { } and display the right value.
>> Jetty for example displays the right size.
>> With Jetty:
>> [Thread 13] ReadListenerImpl: onDataAvailable
>> [Thread 13] onDataAvailable end
>> [Thread 22] read till now: 234
>> [Thread 14] onAllDataRead
>> (onAllDataRead is called after "read till now" with a different thread)
>>
>> With Tomcat:
>> [Thread 26] ReadListenerImpl: onDataAvailable
>> [Thread 26] onDataAvailable end
>> [Thread 27] onAllDataRead
>> [Thread 27] read till now: 234
>> (onAllDataRead is called defore "read till now" with the same thread)
>>
>> Can you check that?
>
> Tomcat version?

tomcat 8.0.3

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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Mark Thomas <ma...@apache.org>.
On 19/03/2014 15:36, Yann Simon wrote:
> Hi,
> 
> I have maybe found another problem:
> onAllDataRead is called with the same thread that is calling input.read.
> 
> I updated the sample to show the problem:
> https://github.com/yanns/servlet31_async/commit/3c7618a51a8efd76956a6a29e27f350f7dbe835b
> 
> The servlet displays a wrong size of the uploaded file.
> 
> event.getSuppliedResponse().getOutputStream().print("Complete. Read "
> + readListener.getRead());
> sees a wrong value from readListener.getRead()
> 
> If onAllDataRead was called with another thread, it would wait for the
> synchronized (input) { } and display the right value.
> Jetty for example displays the right size.
> With Jetty:
> [Thread 13] ReadListenerImpl: onDataAvailable
> [Thread 13] onDataAvailable end
> [Thread 22] read till now: 234
> [Thread 14] onAllDataRead
> (onAllDataRead is called after "read till now" with a different thread)
> 
> With Tomcat:
> [Thread 26] ReadListenerImpl: onDataAvailable
> [Thread 26] onDataAvailable end
> [Thread 27] onAllDataRead
> [Thread 27] read till now: 234
> (onAllDataRead is called defore "read till now" with the same thread)
> 
> Can you check that?

Tomcat version?

Mark


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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Daniel Mikusa <dm...@gopivotal.com>.
On Mar 25, 2014, at 12:16 PM, Yann Simon <ya...@gmail.com> wrote:

> 2014-03-25 16:36 GMT+01:00 Daniel Mikusa <dm...@gopivotal.com>:
>> On Mar 25, 2014, at 11:25 AM, Yann Simon <ya...@gmail.com> wrote:
>> 
>>> 2014-03-20 15:28 GMT+01:00 Yann Simon <ya...@gmail.com>:
>>>> Thanks for all your input, I think I have now an implementation that
>>>> works on Tomcat and Jetty.
>>>> 
>>>> By testing it, I've found something that can be an interesting
>>>> information for you.
>>>> 
>>>> The upload variant with forking a new thread is very very slow.
>>>> My non scientific tests by uploading a file from 1.4 GB:
>>>> - with tomca 8.0.3:
>>>> /upload2: 4.5 s
>>>> /upload (with new Thread): 2 mn
>> 
>> Have you looked closer to see where the time is being spent?  Perhaps with thread dumps, a debugger or a profiler?
> 
> I'll try.
> 
>> Also, have you tried with the 8.0.5 release that is up for vote?
> 
> I do not see this version anywhere.
> Is there already an alpha/beta/CR Version I can download?

http://markmail.org/message/mxxwzwgmmvrqe2pt

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


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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
2014-03-25 17:25 GMT+01:00 Caldarale, Charles R <Ch...@unisys.com>:
>> From: Yann Simon [mailto:yann.simon.fr@gmail.com]
>> Subject: Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener
>
>> > Also, have you tried with the 8.0.5 release that is up for vote?
>
>> I do not see this version anywhere.
>> Is there already an alpha/beta/CR Version I can download?
>
> It's staged here prior to actual release:
> https://dist.apache.org/repos/dist/dev/tomcat/tomcat-8/v8.0.5/
>
>  - Chuck

Thanks.

I still see the same issue with tomcat 8.0.5.
After a few tests:
- sampling only shows that more time is spent in
org.apache.tomcat.util.threads.TaskQueue.take()
- Profiling does not show anything interesting

If you have an idea of what I can check / test...

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


RE: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by "Caldarale, Charles R" <Ch...@unisys.com>.
> From: Yann Simon [mailto:yann.simon.fr@gmail.com] 
> Subject: Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

> > Also, have you tried with the 8.0.5 release that is up for vote?

> I do not see this version anywhere.
> Is there already an alpha/beta/CR Version I can download?

It's staged here prior to actual release:
https://dist.apache.org/repos/dist/dev/tomcat/tomcat-8/v8.0.5/

 - Chuck


THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY MATERIAL and is thus for use only by the intended recipient. If you received this in error, please contact the sender and delete the e-mail and its attachments from all computers.


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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
2014-03-25 16:36 GMT+01:00 Daniel Mikusa <dm...@gopivotal.com>:
> On Mar 25, 2014, at 11:25 AM, Yann Simon <ya...@gmail.com> wrote:
>
>> 2014-03-20 15:28 GMT+01:00 Yann Simon <ya...@gmail.com>:
>>> Thanks for all your input, I think I have now an implementation that
>>> works on Tomcat and Jetty.
>>>
>>> By testing it, I've found something that can be an interesting
>>> information for you.
>>>
>>> The upload variant with forking a new thread is very very slow.
>>> My non scientific tests by uploading a file from 1.4 GB:
>>> - with tomca 8.0.3:
>>> /upload2: 4.5 s
>>> /upload (with new Thread): 2 mn
>
> Have you looked closer to see where the time is being spent?  Perhaps with thread dumps, a debugger or a profiler?

I'll try.

> Also, have you tried with the 8.0.5 release that is up for vote?

I do not see this version anywhere.
Is there already an alpha/beta/CR Version I can download?

> Dan

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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Daniel Mikusa <dm...@gopivotal.com>.
On Mar 25, 2014, at 11:25 AM, Yann Simon <ya...@gmail.com> wrote:

> 2014-03-20 15:28 GMT+01:00 Yann Simon <ya...@gmail.com>:
>> Thanks for all your input, I think I have now an implementation that
>> works on Tomcat and Jetty.
>> 
>> By testing it, I've found something that can be an interesting
>> information for you.
>> 
>> The upload variant with forking a new thread is very very slow.
>> My non scientific tests by uploading a file from 1.4 GB:
>> - with tomca 8.0.3:
>> /upload2: 4.5 s
>> /upload (with new Thread): 2 mn

Have you looked closer to see where the time is being spent?  Perhaps with thread dumps, a debugger or a profiler?

Also, have you tried with the 8.0.5 release that is up for vote?

Dan

>> 
>> - with jetty 9.1:
>> /upload2: 3.6 s
>> /upload (with new Thread): 4.1 s
>> 
>> I tested it by removing all Thread.sleep from
>> https://github.com/yanns/servlet31_async/blob/master/src/main/java/com/yann/ReadListenerImpl.java#L24
> 
> Should I fill an issue for this?
> 
>> 
>> Cheers,
>> Yann
>> 
>> 2014-03-20 9:36 GMT+01:00 Yann Simon <ya...@gmail.com>:
>>> One option I am trying is to ignore onAllDataRead and to use
>>> sevletInputStream.isFinished to know when the body is totally
>>> consumed:
>>> 
>>> https://github.com/yanns/servlet31_async/blob/master/src/main/java/com/yann/ReadListenerImpl.java#L55
>>> 
>>> Is it a dumb idea?
>>> 
>>> 2014-03-20 7:42 GMT+01:00 Yann Simon <ya...@gmail.com>:
>>>> Thanks Rémy and Mark for the quick feedback and explanations!
>>>> 
>>>> On Mar 19, 2014 6:40 PM, "Mark Thomas" <ma...@apache.org> wrote:
>>>>> 
>>>>> On 19/03/2014 17:04, Rémy Maucherat wrote:
>>>>>> 2014-03-19 17:47 GMT+01:00 Yann Simon <ya...@gmail.com>:
>>>>>> 
>>>>>>>> This is because you're forking a thread, it won't concurrently invoke
>>>>>>>> the
>>>>>>>> two events (which would be invalid).
>>>>>>> 
>>>>>>> Can you explain more please? I have difficulties to understand your
>>>>>>> sentence.
>>>>>>> 
>>>>>> 
>>>>>> It means the container has to wait until onReadPossible completes to
>>>>>> call
>>>>>> onDataAvailable.
>>>>> 
>>>>> I think Rémy meant Tomcat waits for onReadPossible() to complete before
>>>>> calling onAllDataRead()
>>>>> 
>>>>> If you look at the traces from the sample code, you'll see that the
>>>>> 
>>>>> onDataAvailable end
>>>>> 
>>>>> message always appears before
>>>>> 
>>>>> onAllDataRead
>>>>> 
>>>>> which is all you can rely on. You are seeing slightly odd behaviour
>>>>> because you are spawning a new thread to do the read. If you do that you
>>>>> have to handle the case that your new thread may trigger the
>>>>> onAllDataRead event and handle it appropriately. I don't see anything
>>>>> for Tomcat to do here.
>>>>> 
>>>>> Mark
>>>>> 
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>>>>> For additional commands, e-mail: users-help@tomcat.apache.org
>>>>> 
>>>> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
> 


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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
2014-03-20 15:28 GMT+01:00 Yann Simon <ya...@gmail.com>:
> Thanks for all your input, I think I have now an implementation that
> works on Tomcat and Jetty.
>
> By testing it, I've found something that can be an interesting
> information for you.
>
> The upload variant with forking a new thread is very very slow.
> My non scientific tests by uploading a file from 1.4 GB:
> - with tomca 8.0.3:
> /upload2: 4.5 s
> /upload (with new Thread): 2 mn
>
> - with jetty 9.1:
> /upload2: 3.6 s
> /upload (with new Thread): 4.1 s
>
> I tested it by removing all Thread.sleep from
> https://github.com/yanns/servlet31_async/blob/master/src/main/java/com/yann/ReadListenerImpl.java#L24

Should I fill an issue for this?

>
> Cheers,
> Yann
>
> 2014-03-20 9:36 GMT+01:00 Yann Simon <ya...@gmail.com>:
>> One option I am trying is to ignore onAllDataRead and to use
>> sevletInputStream.isFinished to know when the body is totally
>> consumed:
>>
>> https://github.com/yanns/servlet31_async/blob/master/src/main/java/com/yann/ReadListenerImpl.java#L55
>>
>> Is it a dumb idea?
>>
>> 2014-03-20 7:42 GMT+01:00 Yann Simon <ya...@gmail.com>:
>>> Thanks Rémy and Mark for the quick feedback and explanations!
>>>
>>> On Mar 19, 2014 6:40 PM, "Mark Thomas" <ma...@apache.org> wrote:
>>>>
>>>> On 19/03/2014 17:04, Rémy Maucherat wrote:
>>>> > 2014-03-19 17:47 GMT+01:00 Yann Simon <ya...@gmail.com>:
>>>> >
>>>> >>> This is because you're forking a thread, it won't concurrently invoke
>>>> >>> the
>>>> >>> two events (which would be invalid).
>>>> >>
>>>> >> Can you explain more please? I have difficulties to understand your
>>>> >> sentence.
>>>> >>
>>>> >
>>>> > It means the container has to wait until onReadPossible completes to
>>>> > call
>>>> > onDataAvailable.
>>>>
>>>> I think Rémy meant Tomcat waits for onReadPossible() to complete before
>>>> calling onAllDataRead()
>>>>
>>>> If you look at the traces from the sample code, you'll see that the
>>>>
>>>> onDataAvailable end
>>>>
>>>> message always appears before
>>>>
>>>> onAllDataRead
>>>>
>>>> which is all you can rely on. You are seeing slightly odd behaviour
>>>> because you are spawning a new thread to do the read. If you do that you
>>>> have to handle the case that your new thread may trigger the
>>>> onAllDataRead event and handle it appropriately. I don't see anything
>>>> for Tomcat to do here.
>>>>
>>>> Mark
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>>>> For additional commands, e-mail: users-help@tomcat.apache.org
>>>>
>>>

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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
Thanks for all your input, I think I have now an implementation that
works on Tomcat and Jetty.

By testing it, I've found something that can be an interesting
information for you.

The upload variant with forking a new thread is very very slow.
My non scientific tests by uploading a file from 1.4 GB:
- with tomca 8.0.3:
/upload2: 4.5 s
/upload (with new Thread): 2 mn

- with jetty 9.1:
/upload2: 3.6 s
/upload (with new Thread): 4.1 s

I tested it by removing all Thread.sleep from
https://github.com/yanns/servlet31_async/blob/master/src/main/java/com/yann/ReadListenerImpl.java#L24

Cheers,
Yann

2014-03-20 9:36 GMT+01:00 Yann Simon <ya...@gmail.com>:
> One option I am trying is to ignore onAllDataRead and to use
> sevletInputStream.isFinished to know when the body is totally
> consumed:
>
> https://github.com/yanns/servlet31_async/blob/master/src/main/java/com/yann/ReadListenerImpl.java#L55
>
> Is it a dumb idea?
>
> 2014-03-20 7:42 GMT+01:00 Yann Simon <ya...@gmail.com>:
>> Thanks Rémy and Mark for the quick feedback and explanations!
>>
>> On Mar 19, 2014 6:40 PM, "Mark Thomas" <ma...@apache.org> wrote:
>>>
>>> On 19/03/2014 17:04, Rémy Maucherat wrote:
>>> > 2014-03-19 17:47 GMT+01:00 Yann Simon <ya...@gmail.com>:
>>> >
>>> >>> This is because you're forking a thread, it won't concurrently invoke
>>> >>> the
>>> >>> two events (which would be invalid).
>>> >>
>>> >> Can you explain more please? I have difficulties to understand your
>>> >> sentence.
>>> >>
>>> >
>>> > It means the container has to wait until onReadPossible completes to
>>> > call
>>> > onDataAvailable.
>>>
>>> I think Rémy meant Tomcat waits for onReadPossible() to complete before
>>> calling onAllDataRead()
>>>
>>> If you look at the traces from the sample code, you'll see that the
>>>
>>> onDataAvailable end
>>>
>>> message always appears before
>>>
>>> onAllDataRead
>>>
>>> which is all you can rely on. You are seeing slightly odd behaviour
>>> because you are spawning a new thread to do the read. If you do that you
>>> have to handle the case that your new thread may trigger the
>>> onAllDataRead event and handle it appropriately. I don't see anything
>>> for Tomcat to do here.
>>>
>>> Mark
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>>> For additional commands, e-mail: users-help@tomcat.apache.org
>>>
>>

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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
One option I am trying is to ignore onAllDataRead and to use
sevletInputStream.isFinished to know when the body is totally
consumed:

https://github.com/yanns/servlet31_async/blob/master/src/main/java/com/yann/ReadListenerImpl.java#L55

Is it a dumb idea?

2014-03-20 7:42 GMT+01:00 Yann Simon <ya...@gmail.com>:
> Thanks Rémy and Mark for the quick feedback and explanations!
>
> On Mar 19, 2014 6:40 PM, "Mark Thomas" <ma...@apache.org> wrote:
>>
>> On 19/03/2014 17:04, Rémy Maucherat wrote:
>> > 2014-03-19 17:47 GMT+01:00 Yann Simon <ya...@gmail.com>:
>> >
>> >>> This is because you're forking a thread, it won't concurrently invoke
>> >>> the
>> >>> two events (which would be invalid).
>> >>
>> >> Can you explain more please? I have difficulties to understand your
>> >> sentence.
>> >>
>> >
>> > It means the container has to wait until onReadPossible completes to
>> > call
>> > onDataAvailable.
>>
>> I think Rémy meant Tomcat waits for onReadPossible() to complete before
>> calling onAllDataRead()
>>
>> If you look at the traces from the sample code, you'll see that the
>>
>> onDataAvailable end
>>
>> message always appears before
>>
>> onAllDataRead
>>
>> which is all you can rely on. You are seeing slightly odd behaviour
>> because you are spawning a new thread to do the read. If you do that you
>> have to handle the case that your new thread may trigger the
>> onAllDataRead event and handle it appropriately. I don't see anything
>> for Tomcat to do here.
>>
>> Mark
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>> For additional commands, e-mail: users-help@tomcat.apache.org
>>
>

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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
Thanks Rémy and Mark for the quick feedback and explanations!
On Mar 19, 2014 6:40 PM, "Mark Thomas" <ma...@apache.org> wrote:

> On 19/03/2014 17:04, Rémy Maucherat wrote:
> > 2014-03-19 17:47 GMT+01:00 Yann Simon <ya...@gmail.com>:
> >
> >>> This is because you're forking a thread, it won't concurrently invoke
> the
> >>> two events (which would be invalid).
> >>
> >> Can you explain more please? I have difficulties to understand your
> >> sentence.
> >>
> >
> > It means the container has to wait until onReadPossible completes to call
> > onDataAvailable.
>
> I think Rémy meant Tomcat waits for onReadPossible() to complete before
> calling onAllDataRead()
>
> If you look at the traces from the sample code, you'll see that the
>
> onDataAvailable end
>
> message always appears before
>
> onAllDataRead
>
> which is all you can rely on. You are seeing slightly odd behaviour
> because you are spawning a new thread to do the read. If you do that you
> have to handle the case that your new thread may trigger the
> onAllDataRead event and handle it appropriately. I don't see anything
> for Tomcat to do here.
>
> Mark
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>
>

Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Mark Thomas <ma...@apache.org>.
On 19/03/2014 17:04, Rémy Maucherat wrote:
> 2014-03-19 17:47 GMT+01:00 Yann Simon <ya...@gmail.com>:
> 
>>> This is because you're forking a thread, it won't concurrently invoke the
>>> two events (which would be invalid).
>>
>> Can you explain more please? I have difficulties to understand your
>> sentence.
>>
> 
> It means the container has to wait until onReadPossible completes to call
> onDataAvailable.

I think Rémy meant Tomcat waits for onReadPossible() to complete before
calling onAllDataRead()

If you look at the traces from the sample code, you'll see that the

onDataAvailable end

message always appears before

onAllDataRead

which is all you can rely on. You are seeing slightly odd behaviour
because you are spawning a new thread to do the read. If you do that you
have to handle the case that your new thread may trigger the
onAllDataRead event and handle it appropriately. I don't see anything
for Tomcat to do here.

Mark

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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Rémy Maucherat <re...@apache.org>.
2014-03-19 17:47 GMT+01:00 Yann Simon <ya...@gmail.com>:

> > This is because you're forking a thread, it won't concurrently invoke the
> > two events (which would be invalid).
>
> Can you explain more please? I have difficulties to understand your
> sentence.
>

It means the container has to wait until onReadPossible completes to call
onDataAvailable.

>
> >> I'd wish the specs to be much more precise for this sort of behavior,
> >> because it is now quite impossible to write a ReadListener that can
> >> run both on Jetty and Tomcat for example.
> >>
> >
> > Other async APIs like NIO2 are not any more "precise" on purpose about
> the
> > threading model, because this allows being flexible and have better
> > performance. You could use a semaphore to implement your desired
> behavior.
>
> Thx for the hint, I'll try that. But I doubt to find a solution that
> works on all containers.
>

I don't see how it could do worse than straight syncing.

Rémy

Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
2014-03-19 17:24 GMT+01:00 Rémy Maucherat <re...@apache.org>:
> 2014-03-19 17:10 GMT+01:00 Yann Simon <ya...@gmail.com>:
>
>> 2014-03-19 17:05 GMT+01:00 Rémy Maucherat <re...@apache.org>:
>> > 2014-03-19 16:36 GMT+01:00 Yann Simon <ya...@gmail.com>:
>> >
>> >> I have maybe found another problem:
>> >> onAllDataRead is called with the same thread that is calling input.read.
>> >>
>> >
>> > I am not aware of any requirement that says this is not allowed.
>> >
>> > Rémy
>>
>> You're right, the specs is not precise for this.
>> But doing so makes the ReadListener very difficult to use:
>> the onAllDataRead is called even before we had a chance to make
>> something with the data we just read.
>>
>
> This is because you're forking a thread, it won't concurrently invoke the
> two events (which would be invalid).

Can you explain more please? I have difficulties to understand your sentence.

>> I'd wish the specs to be much more precise for this sort of behavior,
>> because it is now quite impossible to write a ReadListener that can
>> run both on Jetty and Tomcat for example.
>>
>
> Other async APIs like NIO2 are not any more "precise" on purpose about the
> threading model, because this allows being flexible and have better
> performance. You could use a semaphore to implement your desired behavior.

Thx for the hint, I'll try that. But I doubt to find a solution that
works on all containers.

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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Rémy Maucherat <re...@apache.org>.
2014-03-19 17:10 GMT+01:00 Yann Simon <ya...@gmail.com>:

> 2014-03-19 17:05 GMT+01:00 Rémy Maucherat <re...@apache.org>:
> > 2014-03-19 16:36 GMT+01:00 Yann Simon <ya...@gmail.com>:
> >
> >> I have maybe found another problem:
> >> onAllDataRead is called with the same thread that is calling input.read.
> >>
> >
> > I am not aware of any requirement that says this is not allowed.
> >
> > Rémy
>
> You're right, the specs is not precise for this.
> But doing so makes the ReadListener very difficult to use:
> the onAllDataRead is called even before we had a chance to make
> something with the data we just read.
>

This is because you're forking a thread, it won't concurrently invoke the
two events (which would be invalid).

>
> I'd wish the specs to be much more precise for this sort of behavior,
> because it is now quite impossible to write a ReadListener that can
> run both on Jetty and Tomcat for example.
>

Other async APIs like NIO2 are not any more "precise" on purpose about the
threading model, because this allows being flexible and have better
performance. You could use a semaphore to implement your desired behavior.

Rémy

Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
2014-03-19 17:05 GMT+01:00 Rémy Maucherat <re...@apache.org>:
> 2014-03-19 16:36 GMT+01:00 Yann Simon <ya...@gmail.com>:
>
>> I have maybe found another problem:
>> onAllDataRead is called with the same thread that is calling input.read.
>>
>
> I am not aware of any requirement that says this is not allowed.
>
> Rémy

You're right, the specs is not precise for this.
But doing so makes the ReadListener very difficult to use:
the onAllDataRead is called even before we had a chance to make
something with the data we just read.

I'd wish the specs to be much more precise for this sort of behavior,
because it is now quite impossible to write a ReadListener that can
run both on Jetty and Tomcat for example.

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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Rémy Maucherat <re...@apache.org>.
2014-03-19 16:36 GMT+01:00 Yann Simon <ya...@gmail.com>:

> I have maybe found another problem:
> onAllDataRead is called with the same thread that is calling input.read.
>

I am not aware of any requirement that says this is not allowed.

Rémy

Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
Hi,

I have maybe found another problem:
onAllDataRead is called with the same thread that is calling input.read.

I updated the sample to show the problem:
https://github.com/yanns/servlet31_async/commit/3c7618a51a8efd76956a6a29e27f350f7dbe835b

The servlet displays a wrong size of the uploaded file.

event.getSuppliedResponse().getOutputStream().print("Complete. Read "
+ readListener.getRead());
sees a wrong value from readListener.getRead()

If onAllDataRead was called with another thread, it would wait for the
synchronized (input) { } and display the right value.
Jetty for example displays the right size.
With Jetty:
[Thread 13] ReadListenerImpl: onDataAvailable
[Thread 13] onDataAvailable end
[Thread 22] read till now: 234
[Thread 14] onAllDataRead
(onAllDataRead is called after "read till now" with a different thread)

With Tomcat:
[Thread 26] ReadListenerImpl: onDataAvailable
[Thread 26] onDataAvailable end
[Thread 27] onAllDataRead
[Thread 27] read till now: 234
(onAllDataRead is called defore "read till now" with the same thread)

Can you check that?

Thanks!
Yann

2014-02-01 15:13 GMT+01:00 Yann Simon <ya...@gmail.com>:
>
> On Jan 31, 2014 7:36 PM, "Mark Thomas" <ma...@apache.org> wrote:
>>
>> On 31/01/2014 11:52, Yann Simon wrote:
>> > On Jan 31, 2014 10:25 AM, "Mark Thomas" <ma...@apache.org> wrote:
>> >>
>> >> On 31/01/2014 07:58, Yann Simon wrote:
>> >>>>>> On Jan 30, 2014, at 11:18 AM, Yann Simon <ya...@gmail.com>
>> >>
>> >>> Jetty seems to allow this. Why not tomcat? Is there something in the
>> >>> specification about it. I could not find anything explicit.
>> >>
>> >> It could simply be a bug in Tomcat. I've had a quick look and I think I
>> >> might have a fix (thanks to Remy for the hint earlier in the thread)
>> >> but
>> >> the non-blocking code has proved tricky to get right and I want to do
>> >> some more testing. I should get to that later today.
>> >
>> > Thanks for the feedback!
>>
>> No problem. Thanks again for the test case.
>>
>> I've applied some changes to 8.0.x that will be in 8.0.2 onwards. Your
>> test case now completes for both options for BIO, NIO and APR/native
>> connectors.
>>
>> The 8.0.1 release is currently in progress so 8.0.2 is a little way off.
>> You can always build from source to get it sooner which should be fairly
>> painless. If you want to go down that route and you need some pointers
>> just ask here.
>
> Thanks for the quick fix! I'll test the new version when it is released and
> let you know.
>
> Yann
>
>>
>> Mark
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>> For additional commands, e-mail: users-help@tomcat.apache.org
>>

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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
On Jan 31, 2014 7:36 PM, "Mark Thomas" <ma...@apache.org> wrote:
>
> On 31/01/2014 11:52, Yann Simon wrote:
> > On Jan 31, 2014 10:25 AM, "Mark Thomas" <ma...@apache.org> wrote:
> >>
> >> On 31/01/2014 07:58, Yann Simon wrote:
> >>>>>> On Jan 30, 2014, at 11:18 AM, Yann Simon <ya...@gmail.com>
> >>
> >>> Jetty seems to allow this. Why not tomcat? Is there something in the
> >>> specification about it. I could not find anything explicit.
> >>
> >> It could simply be a bug in Tomcat. I've had a quick look and I think I
> >> might have a fix (thanks to Remy for the hint earlier in the thread)
but
> >> the non-blocking code has proved tricky to get right and I want to do
> >> some more testing. I should get to that later today.
> >
> > Thanks for the feedback!
>
> No problem. Thanks again for the test case.
>
> I've applied some changes to 8.0.x that will be in 8.0.2 onwards. Your
> test case now completes for both options for BIO, NIO and APR/native
> connectors.
>
> The 8.0.1 release is currently in progress so 8.0.2 is a little way off.
> You can always build from source to get it sooner which should be fairly
> painless. If you want to go down that route and you need some pointers
> just ask here.

Thanks for the quick fix! I'll test the new version when it is released and
let you know.

Yann

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

Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Mark Thomas <ma...@apache.org>.
On 31/01/2014 11:52, Yann Simon wrote:
> On Jan 31, 2014 10:25 AM, "Mark Thomas" <ma...@apache.org> wrote:
>>
>> On 31/01/2014 07:58, Yann Simon wrote:
>>>>>> On Jan 30, 2014, at 11:18 AM, Yann Simon <ya...@gmail.com>
>>
>>> Jetty seems to allow this. Why not tomcat? Is there something in the
>>> specification about it. I could not find anything explicit.
>>
>> It could simply be a bug in Tomcat. I've had a quick look and I think I
>> might have a fix (thanks to Remy for the hint earlier in the thread) but
>> the non-blocking code has proved tricky to get right and I want to do
>> some more testing. I should get to that later today.
> 
> Thanks for the feedback!

No problem. Thanks again for the test case.

I've applied some changes to 8.0.x that will be in 8.0.2 onwards. Your
test case now completes for both options for BIO, NIO and APR/native
connectors.

The 8.0.1 release is currently in progress so 8.0.2 is a little way off.
You can always build from source to get it sooner which should be fairly
painless. If you want to go down that route and you need some pointers
just ask here.

Mark


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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
On Jan 31, 2014 10:25 AM, "Mark Thomas" <ma...@apache.org> wrote:
>
> On 31/01/2014 07:58, Yann Simon wrote:
> >>>> On Jan 30, 2014, at 11:18 AM, Yann Simon <ya...@gmail.com>
>
> > Jetty seems to allow this. Why not tomcat? Is there something in the
> > specification about it. I could not find anything explicit.
>
> It could simply be a bug in Tomcat. I've had a quick look and I think I
> might have a fix (thanks to Remy for the hint earlier in the thread) but
> the non-blocking code has proved tricky to get right and I want to do
> some more testing. I should get to that later today.

Thanks for the feedback!
>
> Mark
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>

Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Mark Thomas <ma...@apache.org>.
On 31/01/2014 07:58, Yann Simon wrote:
>>>> On Jan 30, 2014, at 11:18 AM, Yann Simon <ya...@gmail.com>

>>>>> I wrote a sample app to demonstrate the problem:
>>>>> https://github.com/yanns/servlet31_async

Thanks for the sample. That always makes looking at these things a lot
easier.

> Maybe it is too simplified in my head but I though if tomcat permits to
> exit the onDataAvailable immediately and to read the input afterwards, as I
> am doing in the sample app, then it is possible.

The Servlet specification is not always as clearly written as it could
be. As one of the EG members, that is partly my fault.

I wasn't too involved in the the non-blocking discussions as other EG
members were for more experienced than me with non-blocking at the time.
I don't recall anything that would not permit what you are trying to do
but I'd need to double check that. I'd need to check the archives to see
if there was anything there that didn't make the specification document.

> Jetty seems to allow this. Why not tomcat? Is there something in the
> specification about it. I could not find anything explicit.

It could simply be a bug in Tomcat. I've had a quick look and I think I
might have a fix (thanks to Remy for the hint earlier in the thread) but
the non-blocking code has proved tricky to get right and I want to do
some more testing. I should get to that later today.

Mark


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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
On Jan 30, 2014 11:02 PM, "Daniel Mikusa" <dm...@gopivotal.com> wrote:
>
> On Jan 30, 2014, at 3:38 PM, Yann Simon <ya...@gmail.com> wrote:
>
> > 2014-01-30 Daniel Mikusa <dm...@gopivotal.com>:
> >> On Jan 30, 2014, at 11:18 AM, Yann Simon <ya...@gmail.com>
wrote:
> >>
> >>> Hi,
> >>>
> >>> I wrote a sample app to demonstrate the problem:
> >>> https://github.com/yanns/servlet31_async
> >>>
> >>> You can generate an exploded war with maven: mvn war:exploded
> >>> I deployed the application in tomcat 8.0.0-RC10.
> >>>
> >>> The 2 upload form does work.
> >>> The 1st upload form uses a new thread in , and that does not work.
> >>>
https://github.com/yanns/servlet31_async/blob/master/src/main/java/com/yann/ReadListenerImpl.java#L22
> >>
> >> I’m not sure I see the point of the code here.  If you force it to
block with Thread.sleep() you’re going to tie up the thread that you’ve
created and you’re going to be back to having threads sitting around and
doing nothing.  If that’s the case, you may as well save yourself some
trouble and use the blocking apis.
> >
> > This sample application is only a simple way to show what I want to
> > achieve with a more complex application that I mentioned at the
> > beginning of the thread:
> >
https://github.com/yanns/play2-war-plugin/blob/servlet31/project-code/core/servlet31/src/main/scala/play/core/server/servlet31/RequestHandler31.scala#L80
>
> I haven’t looked at your code.  I’m not a Scala guy, so I can’t begin to
comment on that.  What you’ve described below sounds feasible though.
 Including some notes below.
>
> > Let me try to explain the use case:
> > let's say we want to save the uploaded file chunk by chunk in a
> > database, for which we have an asynchronous API.
> > - we receive the first chunk, that we can read synchronously in
> > onDataAvailable, no problem so far
>
> Ok.  Because this is our first call to onDataAvailable, the container is
going to handle that for us.  Question.  Are we reading until isReady()
returns false here?  or are we existing onDataAvailable with data that
still needs to be read?  This is important to know so we know who’s
responsibility it is to continue the reading process.

Yes by reading a chunk I mean reading on input until isReady returns false.
>
> > - we trigger the saving of this chunk in the database, and of course,
> > we do not wait for the completion of the operation
>
> Ok
>
> > - we receive the signal that a new chunk is available - the container
> > call onDataAvailable
>
> This is not quite correct.  The container won’t call onDataAvailable
here, unless you read all of the data that was available in the first step
(i.e. read till isReady() returns false).  It’s not specified, but it
doesn’t sound like that’s your intent here.
Yes I read all data available in the first step.
>
> > - we cannot push this chunk into the database, as the first operation
> > is not completed
>
> Ok.  At this point, you’re going to have to either buffer data or stop
reading.  It sounds like you want to do the later, so you’re going to need
to make sure something in your code starts reading again when your code can
process more data, since the container is not going to handle the call back.
>
> > - we asynchronously wait for the completion of the database operation.
> > We do not read any data so that the container push the pressure back
> > to the browser, telling it to slowdown. We do not want to block any
> > thread here. That's why we must exit the onDataAvailable without
> > having read any data.
>
> Sounds OK, but you’re now responsible for making sure that the rest of
the data is consumed.  If you don’t do this, the request will appear to
hang until it times out.
>
> > - when the database says us that it is ready for a new operation (by a
> > callback, or an event), then we can read the second chunk and trigger
> > the save operation in the database
>
> Once the database write is complete, you’re just going to need to call
onDataAvailable manually some how.  The container won’t do it because you
previously exited before isReady() returned false.
>
> > This a what I simulated with the new Thread and Thread.sleep.
> > In reality, there are no "new Thread" - it just simulates that at some
> > point later, the database driver informs us that the database is ready
> > for a new operation.
> > There are no Thread.sleep neither - it just simulates a slow database
> > to check the back-pressure mechanism that the container should do on
> > the browser.
>
> Ok, I understand what you’re going for here.
>
> > Also, if you said that I must consume the chunks synchronously in
> > onDataAvailable, I can simply not implement this double triggering
> > (from browser and from database) without blocking any thread. For me,
> > it means that I cannot totally use the asynchronous IO mechanism of
> > the OS.
>
> The non-blocking API that Servlet 3.1 exposes is pretty flexible, but
things get complicated quick.  I don’t see any reason why you couldn’t do
what you’ve described.  It’s just going to be complicated.  You’re going to
have to know when the container will call onDataAvailable and when you need
to call it.

Maybe it is too simplified in my head but I though if tomcat permits to
exit the onDataAvailable immediately and to read the input afterwards, as I
am doing in the sample app, then it is possible.

Jetty seems to allow this. Why not tomcat? Is there something in the
specification about it. I could not find anything explicit.

> Hope that helps.
>
> Dan
>
>
> >
> > I hope I made my goals clear.
> >
> > Cheers,
> > Yann
> >
> >>
> >> Here’s what I’d suggest to make this work.
> >>
> >>  - in onDataAvailable read as much data as possible
> >>  - if you read until input.isReady() is false then just exit the
function.  The container will call back when more data can be read.
> >>  - if you need to stop reading for some reason but input.isReady() is
still true, use a thread pool to schedule your own call back to
onDataAvailable at some point in the future.  You can then continue reading
at that point in time.
> >>  - Repeat until you’ve read all the data.
> >>
> >> You still need additional threads with this approach, but it’s not one
to one.  A small thread pool can service many requests because the thread
is only active when data is being read.
> >>
> >> Here’s an example of this in action.
> >>
> >>
http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DataRateLimitedServlet.java
> >>
> >> Dan
> >>
> >>>
> >>> The "onDataAvailable" is called only one time.
> >>>
> >>> With jetty, it does work (mvn jetty:run)
> >>>
> >>> I hope this can help.
> >>>
> >>> Yann
> >>>
> >>> 2014-01-08 Yann Simon <ya...@gmail.com>:
> >>>> 2014/1/8 Daniel Mikusa <dm...@gopivotal.com>:
> >>>>> On Jan 8, 2014, at 12:04 PM, Yann Simon <ya...@gmail.com>
wrote:
> >>>>>
> >>>>>> Hi,
> >>>>>>
> >>>>>> I am trying to write a servlet that asynchronously read data from
the
> >>>>>> servlet request input stream.
> >>>>>> I tested my servlet with tomcat 8.0.0-RC5.
> >>>>>
> >>>>> If possible, you might want to try 8.0.0-RC10 or trunk and see if
you're getting the same behavior.
> >>>>>
> >>>>>>
> >>>>>> the symptoms:
> >>>>>> - I must synchronously read the input stream in onDataAvailable()
so
> >>>>>> that the upload works
> >>>>>>
> >>>>>> what I expected:
> >>>>>> I want to be more "reactive" (buzzword of the moment) and not read
the
> >>>>>> input stream until I am ready (=until the previous chunk is
processed)
> >>>>>> I though I could return from onDataAvailable() before having read
all
> >>>>>> the data, read the data in another thread.
> >>>>>
> >>>>> Do you have a code sample?  It would help to see what you're doing.
> >>>>>
> >>>>>> I expected onDataAvailable() to be called again when I consumed
all the data
> >>>>>> (servletInputStream.isReady becomes false)
> >>>>>
> >>>>> Generally this sounds OK.  When you call
ServletInputStream.isReady() and it returns false, that should trigger the
container to call onDataAvailable() when more data is available to be read.
 If you return from onDataAvailable() and ServletInputStream.isReady() is
still true the container won't call onDataAvailable() again.  You'll be
responsible for calling it when you're ready to read more.
> >>>>>
> >>>>>> That way, I could implement back pressure on the browser as long
as my
> >>>>>> servlet has not finished its work with the actual chunk
> >>>>>>
> >>>>>> But if I do that, neither onDataAvailable() nor onAllDataRead() is
called again.
> >>>>>
> >>>>> Again, a code sample would be helpful.  Debugging non-blocking IO
is tricky.  If you can include a sample Servlet or test case, it would
greatly increase your chance of getting feedback.
> >>>>
> >>>> Thanks for the quick answer!
> >>>>
> >>>> I have a code sample, but it may be too complicated to help debugging
> >>>> the problem.
> >>>> It is written in Scala. Its purpose is to provide a servlet that runs
> >>>> asynchronous action from Playframework (http://www.playframework.com/
)
> >>>>
> >>>>
https://github.com/yanns/play2-war-plugin/blob/servlet31/project-code/core/servlet31/src/main/scala/play/core/server/servlet31/RequestHandler31.scala#L74
> >>>>
> >>>> The line 80 (iteratee = iteratee.pureFlatFold ) use a closure that
> >>>> consumes the input stream asynchronously in another thread.
> >>>>
> >>>> I'll try to take the time to write a much simpler code sample in
Java.
> >>>>
> >>>>>
> >>>>> Dan
> >>>>>
> >>>>>>
> >>>>>> When I consume the input stream synchronously in
onDataAvailable(), it
> >>>>>> works as expected.
> >>>>>>
> >>>>>> Am I misunderstanding the asynchron IO in Tomcat 8?
> >>>>>>
> >>>>>> Thanks in advance for any ideas!
> >>>>>> Yann
> >>>>>>
> >>>>>>
---------------------------------------------------------------------
> >>>>>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> >>>>>> For additional commands, e-mail: users-help@tomcat.apache.org
> >>>>>>
> >>>>>
> >>>>>
> >>>>>
---------------------------------------------------------------------
> >>>>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> >>>>> For additional commands, e-mail: users-help@tomcat.apache.org
> >>>>>
> >>>
> >>> ---------------------------------------------------------------------
> >>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> >>> For additional commands, e-mail: users-help@tomcat.apache.org
> >>>
> >>
> >>
> >> ---------------------------------------------------------------------
> >> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> >> For additional commands, e-mail: users-help@tomcat.apache.org
> >>
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> > For additional commands, e-mail: users-help@tomcat.apache.org
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>

Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Daniel Mikusa <dm...@gopivotal.com>.
On Jan 30, 2014, at 3:38 PM, Yann Simon <ya...@gmail.com> wrote:

> 2014-01-30 Daniel Mikusa <dm...@gopivotal.com>:
>> On Jan 30, 2014, at 11:18 AM, Yann Simon <ya...@gmail.com> wrote:
>> 
>>> Hi,
>>> 
>>> I wrote a sample app to demonstrate the problem:
>>> https://github.com/yanns/servlet31_async
>>> 
>>> You can generate an exploded war with maven: mvn war:exploded
>>> I deployed the application in tomcat 8.0.0-RC10.
>>> 
>>> The 2 upload form does work.
>>> The 1st upload form uses a new thread in , and that does not work.
>>> https://github.com/yanns/servlet31_async/blob/master/src/main/java/com/yann/ReadListenerImpl.java#L22
>> 
>> I’m not sure I see the point of the code here.  If you force it to block with Thread.sleep() you’re going to tie up the thread that you’ve created and you’re going to be back to having threads sitting around and doing nothing.  If that’s the case, you may as well save yourself some trouble and use the blocking apis.
> 
> This sample application is only a simple way to show what I want to
> achieve with a more complex application that I mentioned at the
> beginning of the thread:
> https://github.com/yanns/play2-war-plugin/blob/servlet31/project-code/core/servlet31/src/main/scala/play/core/server/servlet31/RequestHandler31.scala#L80

I haven’t looked at your code.  I’m not a Scala guy, so I can’t begin to comment on that.  What you’ve described below sounds feasible though.  Including some notes below.

> Let me try to explain the use case:
> let's say we want to save the uploaded file chunk by chunk in a
> database, for which we have an asynchronous API.
> - we receive the first chunk, that we can read synchronously in
> onDataAvailable, no problem so far

Ok.  Because this is our first call to onDataAvailable, the container is going to handle that for us.  Question.  Are we reading until isReady() returns false here?  or are we existing onDataAvailable with data that still needs to be read?  This is important to know so we know who’s responsibility it is to continue the reading process.

> - we trigger the saving of this chunk in the database, and of course,
> we do not wait for the completion of the operation

Ok

> - we receive the signal that a new chunk is available - the container
> call onDataAvailable

This is not quite correct.  The container won’t call onDataAvailable here, unless you read all of the data that was available in the first step (i.e. read till isReady() returns false).  It’s not specified, but it doesn’t sound like that’s your intent here.

> - we cannot push this chunk into the database, as the first operation
> is not completed

Ok.  At this point, you’re going to have to either buffer data or stop reading.  It sounds like you want to do the later, so you’re going to need to make sure something in your code starts reading again when your code can process more data, since the container is not going to handle the call back.

> - we asynchronously wait for the completion of the database operation.
> We do not read any data so that the container push the pressure back
> to the browser, telling it to slowdown. We do not want to block any
> thread here. That's why we must exit the onDataAvailable without
> having read any data.

Sounds OK, but you’re now responsible for making sure that the rest of the data is consumed.  If you don’t do this, the request will appear to hang until it times out.

> - when the database says us that it is ready for a new operation (by a
> callback, or an event), then we can read the second chunk and trigger
> the save operation in the database

Once the database write is complete, you’re just going to need to call onDataAvailable manually some how.  The container won’t do it because you previously exited before isReady() returned false.

> This a what I simulated with the new Thread and Thread.sleep.
> In reality, there are no "new Thread" - it just simulates that at some
> point later, the database driver informs us that the database is ready
> for a new operation.
> There are no Thread.sleep neither - it just simulates a slow database
> to check the back-pressure mechanism that the container should do on
> the browser.

Ok, I understand what you’re going for here.

> Also, if you said that I must consume the chunks synchronously in
> onDataAvailable, I can simply not implement this double triggering
> (from browser and from database) without blocking any thread. For me,
> it means that I cannot totally use the asynchronous IO mechanism of
> the OS.

The non-blocking API that Servlet 3.1 exposes is pretty flexible, but things get complicated quick.  I don’t see any reason why you couldn’t do what you’ve described.  It’s just going to be complicated.  You’re going to have to know when the container will call onDataAvailable and when you need to call it.  

Hope that helps.

Dan


> 
> I hope I made my goals clear.
> 
> Cheers,
> Yann
> 
>> 
>> Here’s what I’d suggest to make this work.
>> 
>>  - in onDataAvailable read as much data as possible
>>  - if you read until input.isReady() is false then just exit the function.  The container will call back when more data can be read.
>>  - if you need to stop reading for some reason but input.isReady() is still true, use a thread pool to schedule your own call back to onDataAvailable at some point in the future.  You can then continue reading at that point in time.
>>  - Repeat until you’ve read all the data.
>> 
>> You still need additional threads with this approach, but it’s not one to one.  A small thread pool can service many requests because the thread is only active when data is being read.
>> 
>> Here’s an example of this in action.
>> 
>>  http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DataRateLimitedServlet.java
>> 
>> Dan
>> 
>>> 
>>> The "onDataAvailable" is called only one time.
>>> 
>>> With jetty, it does work (mvn jetty:run)
>>> 
>>> I hope this can help.
>>> 
>>> Yann
>>> 
>>> 2014-01-08 Yann Simon <ya...@gmail.com>:
>>>> 2014/1/8 Daniel Mikusa <dm...@gopivotal.com>:
>>>>> On Jan 8, 2014, at 12:04 PM, Yann Simon <ya...@gmail.com> wrote:
>>>>> 
>>>>>> Hi,
>>>>>> 
>>>>>> I am trying to write a servlet that asynchronously read data from the
>>>>>> servlet request input stream.
>>>>>> I tested my servlet with tomcat 8.0.0-RC5.
>>>>> 
>>>>> If possible, you might want to try 8.0.0-RC10 or trunk and see if you're getting the same behavior.
>>>>> 
>>>>>> 
>>>>>> the symptoms:
>>>>>> - I must synchronously read the input stream in onDataAvailable() so
>>>>>> that the upload works
>>>>>> 
>>>>>> what I expected:
>>>>>> I want to be more "reactive" (buzzword of the moment) and not read the
>>>>>> input stream until I am ready (=until the previous chunk is processed)
>>>>>> I though I could return from onDataAvailable() before having read all
>>>>>> the data, read the data in another thread.
>>>>> 
>>>>> Do you have a code sample?  It would help to see what you're doing.
>>>>> 
>>>>>> I expected onDataAvailable() to be called again when I consumed all the data
>>>>>> (servletInputStream.isReady becomes false)
>>>>> 
>>>>> Generally this sounds OK.  When you call ServletInputStream.isReady() and it returns false, that should trigger the container to call onDataAvailable() when more data is available to be read.  If you return from onDataAvailable() and ServletInputStream.isReady() is still true the container won't call onDataAvailable() again.  You'll be responsible for calling it when you're ready to read more.
>>>>> 
>>>>>> That way, I could implement back pressure on the browser as long as my
>>>>>> servlet has not finished its work with the actual chunk
>>>>>> 
>>>>>> But if I do that, neither onDataAvailable() nor onAllDataRead() is called again.
>>>>> 
>>>>> Again, a code sample would be helpful.  Debugging non-blocking IO is tricky.  If you can include a sample Servlet or test case, it would greatly increase your chance of getting feedback.
>>>> 
>>>> Thanks for the quick answer!
>>>> 
>>>> I have a code sample, but it may be too complicated to help debugging
>>>> the problem.
>>>> It is written in Scala. Its purpose is to provide a servlet that runs
>>>> asynchronous action from Playframework (http://www.playframework.com/)
>>>> 
>>>> https://github.com/yanns/play2-war-plugin/blob/servlet31/project-code/core/servlet31/src/main/scala/play/core/server/servlet31/RequestHandler31.scala#L74
>>>> 
>>>> The line 80 (iteratee = iteratee.pureFlatFold ) use a closure that
>>>> consumes the input stream asynchronously in another thread.
>>>> 
>>>> I'll try to take the time to write a much simpler code sample in Java.
>>>> 
>>>>> 
>>>>> Dan
>>>>> 
>>>>>> 
>>>>>> When I consume the input stream synchronously in onDataAvailable(), it
>>>>>> works as expected.
>>>>>> 
>>>>>> Am I misunderstanding the asynchron IO in Tomcat 8?
>>>>>> 
>>>>>> Thanks in advance for any ideas!
>>>>>> Yann
>>>>>> 
>>>>>> ---------------------------------------------------------------------
>>>>>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>>>>>> For additional commands, e-mail: users-help@tomcat.apache.org
>>>>>> 
>>>>> 
>>>>> 
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>>>>> For additional commands, e-mail: users-help@tomcat.apache.org
>>>>> 
>>> 
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>>> For additional commands, e-mail: users-help@tomcat.apache.org
>>> 
>> 
>> 
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>> For additional commands, e-mail: users-help@tomcat.apache.org
>> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
> 


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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
2014-01-30 Daniel Mikusa <dm...@gopivotal.com>:
> On Jan 30, 2014, at 11:18 AM, Yann Simon <ya...@gmail.com> wrote:
>
>> Hi,
>>
>> I wrote a sample app to demonstrate the problem:
>> https://github.com/yanns/servlet31_async
>>
>> You can generate an exploded war with maven: mvn war:exploded
>> I deployed the application in tomcat 8.0.0-RC10.
>>
>> The 2 upload form does work.
>> The 1st upload form uses a new thread in , and that does not work.
>> https://github.com/yanns/servlet31_async/blob/master/src/main/java/com/yann/ReadListenerImpl.java#L22
>
> I’m not sure I see the point of the code here.  If you force it to block with Thread.sleep() you’re going to tie up the thread that you’ve created and you’re going to be back to having threads sitting around and doing nothing.  If that’s the case, you may as well save yourself some trouble and use the blocking apis.

This sample application is only a simple way to show what I want to
achieve with a more complex application that I mentioned at the
beginning of the thread:
https://github.com/yanns/play2-war-plugin/blob/servlet31/project-code/core/servlet31/src/main/scala/play/core/server/servlet31/RequestHandler31.scala#L80

Let me try to explain the use case:
let's say we want to save the uploaded file chunk by chunk in a
database, for which we have an asynchronous API.
- we receive the first chunk, that we can read synchronously in
onDataAvailable, no problem so far
- we trigger the saving of this chunk in the database, and of course,
we do not wait for the completion of the operation
- we receive the signal that a new chunk is available - the container
call onDataAvailable
- we cannot push this chunk into the database, as the first operation
is not completed
- we asynchronously wait for the completion of the database operation.
We do not read any data so that the container push the pressure back
to the browser, telling it to slowdown. We do not want to block any
thread here. That's why we must exit the onDataAvailable without
having read any data.
- when the database says us that it is ready for a new operation (by a
callback, or an event), then we can read the second chunk and trigger
the save operation in the database

This a what I simulated with the new Thread and Thread.sleep.
In reality, there are no "new Thread" - it just simulates that at some
point later, the database driver informs us that the database is ready
for a new operation.
There are no Thread.sleep neither - it just simulates a slow database
to check the back-pressure mechanism that the container should do on
the browser.

Also, if you said that I must consume the chunks synchronously in
onDataAvailable, I can simply not implement this double triggering
(from browser and from database) without blocking any thread. For me,
it means that I cannot totally use the asynchronous IO mechanism of
the OS.

I hope I made my goals clear.

Cheers,
Yann

>
> Here’s what I’d suggest to make this work.
>
>   - in onDataAvailable read as much data as possible
>   - if you read until input.isReady() is false then just exit the function.  The container will call back when more data can be read.
>   - if you need to stop reading for some reason but input.isReady() is still true, use a thread pool to schedule your own call back to onDataAvailable at some point in the future.  You can then continue reading at that point in time.
>   - Repeat until you’ve read all the data.
>
> You still need additional threads with this approach, but it’s not one to one.  A small thread pool can service many requests because the thread is only active when data is being read.
>
> Here’s an example of this in action.
>
>   http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DataRateLimitedServlet.java
>
> Dan
>
>>
>> The "onDataAvailable" is called only one time.
>>
>> With jetty, it does work (mvn jetty:run)
>>
>> I hope this can help.
>>
>> Yann
>>
>> 2014-01-08 Yann Simon <ya...@gmail.com>:
>>> 2014/1/8 Daniel Mikusa <dm...@gopivotal.com>:
>>>> On Jan 8, 2014, at 12:04 PM, Yann Simon <ya...@gmail.com> wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> I am trying to write a servlet that asynchronously read data from the
>>>>> servlet request input stream.
>>>>> I tested my servlet with tomcat 8.0.0-RC5.
>>>>
>>>> If possible, you might want to try 8.0.0-RC10 or trunk and see if you're getting the same behavior.
>>>>
>>>>>
>>>>> the symptoms:
>>>>> - I must synchronously read the input stream in onDataAvailable() so
>>>>> that the upload works
>>>>>
>>>>> what I expected:
>>>>> I want to be more "reactive" (buzzword of the moment) and not read the
>>>>> input stream until I am ready (=until the previous chunk is processed)
>>>>> I though I could return from onDataAvailable() before having read all
>>>>> the data, read the data in another thread.
>>>>
>>>> Do you have a code sample?  It would help to see what you're doing.
>>>>
>>>>> I expected onDataAvailable() to be called again when I consumed all the data
>>>>> (servletInputStream.isReady becomes false)
>>>>
>>>> Generally this sounds OK.  When you call ServletInputStream.isReady() and it returns false, that should trigger the container to call onDataAvailable() when more data is available to be read.  If you return from onDataAvailable() and ServletInputStream.isReady() is still true the container won't call onDataAvailable() again.  You'll be responsible for calling it when you're ready to read more.
>>>>
>>>>> That way, I could implement back pressure on the browser as long as my
>>>>> servlet has not finished its work with the actual chunk
>>>>>
>>>>> But if I do that, neither onDataAvailable() nor onAllDataRead() is called again.
>>>>
>>>> Again, a code sample would be helpful.  Debugging non-blocking IO is tricky.  If you can include a sample Servlet or test case, it would greatly increase your chance of getting feedback.
>>>
>>> Thanks for the quick answer!
>>>
>>> I have a code sample, but it may be too complicated to help debugging
>>> the problem.
>>> It is written in Scala. Its purpose is to provide a servlet that runs
>>> asynchronous action from Playframework (http://www.playframework.com/)
>>>
>>> https://github.com/yanns/play2-war-plugin/blob/servlet31/project-code/core/servlet31/src/main/scala/play/core/server/servlet31/RequestHandler31.scala#L74
>>>
>>> The line 80 (iteratee = iteratee.pureFlatFold ) use a closure that
>>> consumes the input stream asynchronously in another thread.
>>>
>>> I'll try to take the time to write a much simpler code sample in Java.
>>>
>>>>
>>>> Dan
>>>>
>>>>>
>>>>> When I consume the input stream synchronously in onDataAvailable(), it
>>>>> works as expected.
>>>>>
>>>>> Am I misunderstanding the asynchron IO in Tomcat 8?
>>>>>
>>>>> Thanks in advance for any ideas!
>>>>> Yann
>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>>>>> For additional commands, e-mail: users-help@tomcat.apache.org
>>>>>
>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>>>> For additional commands, e-mail: users-help@tomcat.apache.org
>>>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>> For additional commands, e-mail: users-help@tomcat.apache.org
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>

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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Daniel Mikusa <dm...@gopivotal.com>.
On Jan 30, 2014, at 11:18 AM, Yann Simon <ya...@gmail.com> wrote:

> Hi,
> 
> I wrote a sample app to demonstrate the problem:
> https://github.com/yanns/servlet31_async
> 
> You can generate an exploded war with maven: mvn war:exploded
> I deployed the application in tomcat 8.0.0-RC10.
> 
> The 2 upload form does work.
> The 1st upload form uses a new thread in , and that does not work.
> https://github.com/yanns/servlet31_async/blob/master/src/main/java/com/yann/ReadListenerImpl.java#L22

I’m not sure I see the point of the code here.  If you force it to block with Thread.sleep() you’re going to tie up the thread that you’ve created and you’re going to be back to having threads sitting around and doing nothing.  If that’s the case, you may as well save yourself some trouble and use the blocking apis.

Here’s what I’d suggest to make this work.

  - in onDataAvailable read as much data as possible
  - if you read until input.isReady() is false then just exit the function.  The container will call back when more data can be read.
  - if you need to stop reading for some reason but input.isReady() is still true, use a thread pool to schedule your own call back to onDataAvailable at some point in the future.  You can then continue reading at that point in time.
  - Repeat until you’ve read all the data.

You still need additional threads with this approach, but it’s not one to one.  A small thread pool can service many requests because the thread is only active when data is being read.

Here’s an example of this in action.

  http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DataRateLimitedServlet.java

Dan

> 
> The "onDataAvailable" is called only one time.
> 
> With jetty, it does work (mvn jetty:run)
> 
> I hope this can help.
> 
> Yann
> 
> 2014-01-08 Yann Simon <ya...@gmail.com>:
>> 2014/1/8 Daniel Mikusa <dm...@gopivotal.com>:
>>> On Jan 8, 2014, at 12:04 PM, Yann Simon <ya...@gmail.com> wrote:
>>> 
>>>> Hi,
>>>> 
>>>> I am trying to write a servlet that asynchronously read data from the
>>>> servlet request input stream.
>>>> I tested my servlet with tomcat 8.0.0-RC5.
>>> 
>>> If possible, you might want to try 8.0.0-RC10 or trunk and see if you're getting the same behavior.
>>> 
>>>> 
>>>> the symptoms:
>>>> - I must synchronously read the input stream in onDataAvailable() so
>>>> that the upload works
>>>> 
>>>> what I expected:
>>>> I want to be more "reactive" (buzzword of the moment) and not read the
>>>> input stream until I am ready (=until the previous chunk is processed)
>>>> I though I could return from onDataAvailable() before having read all
>>>> the data, read the data in another thread.
>>> 
>>> Do you have a code sample?  It would help to see what you're doing.
>>> 
>>>> I expected onDataAvailable() to be called again when I consumed all the data
>>>> (servletInputStream.isReady becomes false)
>>> 
>>> Generally this sounds OK.  When you call ServletInputStream.isReady() and it returns false, that should trigger the container to call onDataAvailable() when more data is available to be read.  If you return from onDataAvailable() and ServletInputStream.isReady() is still true the container won't call onDataAvailable() again.  You'll be responsible for calling it when you're ready to read more.
>>> 
>>>> That way, I could implement back pressure on the browser as long as my
>>>> servlet has not finished its work with the actual chunk
>>>> 
>>>> But if I do that, neither onDataAvailable() nor onAllDataRead() is called again.
>>> 
>>> Again, a code sample would be helpful.  Debugging non-blocking IO is tricky.  If you can include a sample Servlet or test case, it would greatly increase your chance of getting feedback.
>> 
>> Thanks for the quick answer!
>> 
>> I have a code sample, but it may be too complicated to help debugging
>> the problem.
>> It is written in Scala. Its purpose is to provide a servlet that runs
>> asynchronous action from Playframework (http://www.playframework.com/)
>> 
>> https://github.com/yanns/play2-war-plugin/blob/servlet31/project-code/core/servlet31/src/main/scala/play/core/server/servlet31/RequestHandler31.scala#L74
>> 
>> The line 80 (iteratee = iteratee.pureFlatFold ) use a closure that
>> consumes the input stream asynchronously in another thread.
>> 
>> I'll try to take the time to write a much simpler code sample in Java.
>> 
>>> 
>>> Dan
>>> 
>>>> 
>>>> When I consume the input stream synchronously in onDataAvailable(), it
>>>> works as expected.
>>>> 
>>>> Am I misunderstanding the asynchron IO in Tomcat 8?
>>>> 
>>>> Thanks in advance for any ideas!
>>>> Yann
>>>> 
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>>>> For additional commands, e-mail: users-help@tomcat.apache.org
>>>> 
>>> 
>>> 
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>>> For additional commands, e-mail: users-help@tomcat.apache.org
>>> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
> 


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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Rémy Maucherat <re...@apache.org>.
2014-01-30 Yann Simon <ya...@gmail.com>:

> It means we cannot write real asynchronous reactive applications with
> servlet 3.1... disappointing.
>
> onDataAvailable is already something asynchronous, so starting an
asynchronous operation from it to do the same thing you're supposed to do
is not going to make things more asynchronous.

Unless you really are careful to do things exactly like in your example,
async reads is going to produce thread safety problems.

About the specific example, I'd say it doesn't work because the NIO
connector doesn't do anything to add the channel to its "poller" when ready
flips unless it is already in that state when the container thread returns,
but the APR connector does (so it would likely work).

Rémy

Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
2014-01-30 Rémy Maucherat <re...@apache.org>:
> 2014-01-30 Yann Simon <ya...@gmail.com>:
>
>> Hi,
>>
>> I wrote a sample app to demonstrate the problem:
>> https://github.com/yanns/servlet31_async
>>
>> You can generate an exploded war with maven: mvn war:exploded
>> I deployed the application in tomcat 8.0.0-RC10.
>>
>> The 2 upload form does work.
>> The 1st upload form uses a new thread in , and that does not work.
>>
>> https://github.com/yanns/servlet31_async/blob/master/src/main/java/com/yann/ReadListenerImpl.java#L22
>>
>> The "onDataAvailable" is called only one time.
>>
>> With jetty, it does work (mvn jetty:run)
>>
>> I hope this can help.
>>
>
> You must read data until the ready flag flips, and you must do it in the
> onDataAvailable invocation (= synchronously). Asynchronous reads is not the
> threading and sync model that was chosen by the specification, so you
> should simply not do that. I doubt it will reliably work in any container
> since it is almost certain you can run in thread safety issues.
>
> Rémy

Thx for the explanation.
What is the part of the specification that is saying that
onDataAvailbale must be consumed synchronously?
Is it the last sentence "The Servlet container must access methods in
ReadListener in a thread safe manner." from:

"The ReadListener provides the following callback methods for non blocking IO -
■ ReadListener
■ onDataAvailable() . The onDataAvailable method is invoked on the
ReadListener when data is available to read from the incoming request
stream. The container will invoke the method the first time when data is
available to read. The container will subsequently invoke the onDataAvailable
method if and only if isReady method on ServletInputStream , described
below, returns false .
■ onAllDataRead() . The onAllDataRead method is invoked when you have
finished reading all the data for the ServletRequest for which the listener was
registered.
■ onError(Throwable t) . The onError method is invoked if there is any error or
exception that occurs while processing the request.
The Servlet container must access methods in ReadListener in a thread
safe manner."

It means we cannot write real asynchronous reactive applications with
servlet 3.1... disappointing.

Yann

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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Rémy Maucherat <re...@apache.org>.
2014-01-30 Yann Simon <ya...@gmail.com>:

> Hi,
>
> I wrote a sample app to demonstrate the problem:
> https://github.com/yanns/servlet31_async
>
> You can generate an exploded war with maven: mvn war:exploded
> I deployed the application in tomcat 8.0.0-RC10.
>
> The 2 upload form does work.
> The 1st upload form uses a new thread in , and that does not work.
>
> https://github.com/yanns/servlet31_async/blob/master/src/main/java/com/yann/ReadListenerImpl.java#L22
>
> The "onDataAvailable" is called only one time.
>
> With jetty, it does work (mvn jetty:run)
>
> I hope this can help.
>

You must read data until the ready flag flips, and you must do it in the
onDataAvailable invocation (= synchronously). Asynchronous reads is not the
threading and sync model that was chosen by the specification, so you
should simply not do that. I doubt it will reliably work in any container
since it is almost certain you can run in thread safety issues.

Rémy

Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
Hi,

I wrote a sample app to demonstrate the problem:
https://github.com/yanns/servlet31_async

You can generate an exploded war with maven: mvn war:exploded
I deployed the application in tomcat 8.0.0-RC10.

The 2 upload form does work.
The 1st upload form uses a new thread in , and that does not work.
https://github.com/yanns/servlet31_async/blob/master/src/main/java/com/yann/ReadListenerImpl.java#L22

The "onDataAvailable" is called only one time.

With jetty, it does work (mvn jetty:run)

I hope this can help.

Yann

2014-01-08 Yann Simon <ya...@gmail.com>:
> 2014/1/8 Daniel Mikusa <dm...@gopivotal.com>:
>> On Jan 8, 2014, at 12:04 PM, Yann Simon <ya...@gmail.com> wrote:
>>
>>> Hi,
>>>
>>> I am trying to write a servlet that asynchronously read data from the
>>> servlet request input stream.
>>> I tested my servlet with tomcat 8.0.0-RC5.
>>
>> If possible, you might want to try 8.0.0-RC10 or trunk and see if you're getting the same behavior.
>>
>>>
>>> the symptoms:
>>> - I must synchronously read the input stream in onDataAvailable() so
>>> that the upload works
>>>
>>> what I expected:
>>> I want to be more "reactive" (buzzword of the moment) and not read the
>>> input stream until I am ready (=until the previous chunk is processed)
>>> I though I could return from onDataAvailable() before having read all
>>> the data, read the data in another thread.
>>
>> Do you have a code sample?  It would help to see what you're doing.
>>
>>> I expected onDataAvailable() to be called again when I consumed all the data
>>> (servletInputStream.isReady becomes false)
>>
>> Generally this sounds OK.  When you call ServletInputStream.isReady() and it returns false, that should trigger the container to call onDataAvailable() when more data is available to be read.  If you return from onDataAvailable() and ServletInputStream.isReady() is still true the container won't call onDataAvailable() again.  You'll be responsible for calling it when you're ready to read more.
>>
>>> That way, I could implement back pressure on the browser as long as my
>>> servlet has not finished its work with the actual chunk
>>>
>>> But if I do that, neither onDataAvailable() nor onAllDataRead() is called again.
>>
>> Again, a code sample would be helpful.  Debugging non-blocking IO is tricky.  If you can include a sample Servlet or test case, it would greatly increase your chance of getting feedback.
>
> Thanks for the quick answer!
>
> I have a code sample, but it may be too complicated to help debugging
> the problem.
> It is written in Scala. Its purpose is to provide a servlet that runs
> asynchronous action from Playframework (http://www.playframework.com/)
>
> https://github.com/yanns/play2-war-plugin/blob/servlet31/project-code/core/servlet31/src/main/scala/play/core/server/servlet31/RequestHandler31.scala#L74
>
> The line 80 (iteratee = iteratee.pureFlatFold ) use a closure that
> consumes the input stream asynchronously in another thread.
>
> I'll try to take the time to write a much simpler code sample in Java.
>
>>
>> Dan
>>
>>>
>>> When I consume the input stream synchronously in onDataAvailable(), it
>>> works as expected.
>>>
>>> Am I misunderstanding the asynchron IO in Tomcat 8?
>>>
>>> Thanks in advance for any ideas!
>>> Yann
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>>> For additional commands, e-mail: users-help@tomcat.apache.org
>>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>> For additional commands, e-mail: users-help@tomcat.apache.org
>>

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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Yann Simon <ya...@gmail.com>.
2014/1/8 Daniel Mikusa <dm...@gopivotal.com>:
> On Jan 8, 2014, at 12:04 PM, Yann Simon <ya...@gmail.com> wrote:
>
>> Hi,
>>
>> I am trying to write a servlet that asynchronously read data from the
>> servlet request input stream.
>> I tested my servlet with tomcat 8.0.0-RC5.
>
> If possible, you might want to try 8.0.0-RC10 or trunk and see if you're getting the same behavior.
>
>>
>> the symptoms:
>> - I must synchronously read the input stream in onDataAvailable() so
>> that the upload works
>>
>> what I expected:
>> I want to be more "reactive" (buzzword of the moment) and not read the
>> input stream until I am ready (=until the previous chunk is processed)
>> I though I could return from onDataAvailable() before having read all
>> the data, read the data in another thread.
>
> Do you have a code sample?  It would help to see what you're doing.
>
>> I expected onDataAvailable() to be called again when I consumed all the data
>> (servletInputStream.isReady becomes false)
>
> Generally this sounds OK.  When you call ServletInputStream.isReady() and it returns false, that should trigger the container to call onDataAvailable() when more data is available to be read.  If you return from onDataAvailable() and ServletInputStream.isReady() is still true the container won't call onDataAvailable() again.  You'll be responsible for calling it when you're ready to read more.
>
>> That way, I could implement back pressure on the browser as long as my
>> servlet has not finished its work with the actual chunk
>>
>> But if I do that, neither onDataAvailable() nor onAllDataRead() is called again.
>
> Again, a code sample would be helpful.  Debugging non-blocking IO is tricky.  If you can include a sample Servlet or test case, it would greatly increase your chance of getting feedback.

Thanks for the quick answer!

I have a code sample, but it may be too complicated to help debugging
the problem.
It is written in Scala. Its purpose is to provide a servlet that runs
asynchronous action from Playframework (http://www.playframework.com/)

https://github.com/yanns/play2-war-plugin/blob/servlet31/project-code/core/servlet31/src/main/scala/play/core/server/servlet31/RequestHandler31.scala#L74

The line 80 (iteratee = iteratee.pureFlatFold ) use a closure that
consumes the input stream asynchronously in another thread.

I'll try to take the time to write a much simpler code sample in Java.

>
> Dan
>
>>
>> When I consume the input stream synchronously in onDataAvailable(), it
>> works as expected.
>>
>> Am I misunderstanding the asynchron IO in Tomcat 8?
>>
>> Thanks in advance for any ideas!
>> Yann
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>> For additional commands, e-mail: users-help@tomcat.apache.org
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>

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


Re: Tomcat 8.0.0-RC5: asynchron IO and back pressure with ReadListener

Posted by Daniel Mikusa <dm...@gopivotal.com>.
On Jan 8, 2014, at 12:04 PM, Yann Simon <ya...@gmail.com> wrote:

> Hi,
> 
> I am trying to write a servlet that asynchronously read data from the
> servlet request input stream.
> I tested my servlet with tomcat 8.0.0-RC5.

If possible, you might want to try 8.0.0-RC10 or trunk and see if you're getting the same behavior.

> 
> the symptoms:
> - I must synchronously read the input stream in onDataAvailable() so
> that the upload works
> 
> what I expected:
> I want to be more "reactive" (buzzword of the moment) and not read the
> input stream until I am ready (=until the previous chunk is processed)
> I though I could return from onDataAvailable() before having read all
> the data, read the data in another thread.

Do you have a code sample?  It would help to see what you're doing.

> I expected onDataAvailable() to be called again when I consumed all the data
> (servletInputStream.isReady becomes false)

Generally this sounds OK.  When you call ServletInputStream.isReady() and it returns false, that should trigger the container to call onDataAvailable() when more data is available to be read.  If you return from onDataAvailable() and ServletInputStream.isReady() is still true the container won't call onDataAvailable() again.  You'll be responsible for calling it when you're ready to read more.

> That way, I could implement back pressure on the browser as long as my
> servlet has not finished its work with the actual chunk
> 
> But if I do that, neither onDataAvailable() nor onAllDataRead() is called again.

Again, a code sample would be helpful.  Debugging non-blocking IO is tricky.  If you can include a sample Servlet or test case, it would greatly increase your chance of getting feedback.

Dan

> 
> When I consume the input stream synchronously in onDataAvailable(), it
> works as expected.
> 
> Am I misunderstanding the asynchron IO in Tomcat 8?
> 
> Thanks in advance for any ideas!
> Yann
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
> 


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