Hi,
I was thinking about something like that, but more developer friendly, for example :
* Have an annotation on my RequestProcessor like @ASync
* And modify the main handler :
public service( Request req, Response res )
{
RequestProcessor rp = find( req, res );
if( hasAsyncAnnotation(rp) )
{
req.getInputStream( false );
}
res.suspend( ... )
executor.execute( rp );
}
As I don't really understand the problem you point me out, will this code be affected by the same problem ?
Thanks
David
De : Oleksiy Stashok [mailto:oleksiy.stashok_at_oracle.com]
Envoyé : mardi 9 août 2011 14:41
À : users_at_grizzly.java.net
Objet : Re: From Grizzly 1.9.x to 2.x
Sorry, pls. ignore my last email, the proposed workaround may cause thread racing, when 2 threads try to work with InputStream, which is not thread-safe.
The workaround, which would work - is to move current UploadTask.run(...) method logic to UploadTask.prepare(...) method, so it would be called from the HttpHandler.handle(...) thread.
Thanks.
WBR,
Alexey.
On 08/09/2011 02:25 PM, Oleksiy Stashok wrote:
Hi David,
Thanks for your explanations. It's clear now.
As you suggest, I open a Improvement issue on the Grizzly's JIRA here :
http://java.net/jira/browse/GRIZZLY-1056
Just one comment : I set the priority to "Major". You may be not agree on that, but it is for my use case.
I may be the only one that use Grizzly like that, so I would understand if you decide to change the priority.
No problem.
I can explain briefly how I works with Grizzly :
I have a main handler that serve all request and do unconditionally :
- Suspend the response
- Given the url, find a "RequestProcessor" and delegate the processing to a thread pool
It was made like that because it allow us to serve many request in parallel without increasing the Grizzly worker thread (that consume lot of memory in Grizzly 1.9.x)
As the request processor is a interface, the main handler don't have any knowledge about what it want to do.
It was made to be generic and pluggable for future needs.
We have also put some service facilities for RequestProcessor implementor that allow them to download a file with a simple line of code, for example :
DonwloadManager.download( request, response, inputstream ) -> it serve the resource input stream to the client in an async manner.
And this is inside the Download/Upload Manager I would like to use the new async read/write of Grizzly 2.
From a functional point of view, it fit perfectly well.
But as it already suspend and run inside my request processor thread, it not possible.
So, sorry to bother you with all my stuff, my goal was just to try to argument why I put the priority to "Major"
As I've mentioned on issue tracker, it's not a problem to work with NIO Streams from the custom thread. The problem is that Grizzly needs to understand that you want to work with InputStream in non-blocking mode, before you exit HttpHandler.handle(...) method.
Just as workaround you can add
RequestProcessor.prepare(Request, Response) method and call it before delegating Request/Response processing to a custom thread, and in Download/UploadManager implement prepare(...) method as:
-------------
public void prepare(Request request, Response response) throws IOException {
request.getInputStream(false);
}
-------------
Once Grizzly understands you want to use InputStream in non-blocking mode - the rest of your code should work.
Thanks.
WBR,
Alexey.
Thanks all for your help
Regards
David
De : Ryan Lubke [mailto:ryan.lubke_at_oracle.com]
Envoyé : lundi 8 août 2011 21:25
À : users_at_grizzly.java.net<mailto:users_at_grizzly.java.net>
Objet : Re: From Grizzly 1.9.x to 2.x
On 8/8/11 11:57 AM, Ryan Lubke wrote:
On 8/8/11 8:47 AM, Gay David (Annecy) wrote:
Hi Alexey,
Yep, I think I got it. See my attached sample test case.
It use Grizzly 2.1.2-SNAPSHOT checkout from yesterday.
If you run it like that, it works.
But if you modified the class UploadTask like that :
//--- Constructor ----------------------------------------------------------
public UploadTask( Request req, Response res ) throws FileNotFoundException
{
this.req = req;
this.res = res;
//this.channel = Channels.newChannel( new FileOutputStream(new File("toto-"+COUNT.getAndIncrement()+".data")) );
this.channel = Channels.newChannel( new NullOutputStream() );
this.error = null;
// Get the non-blocking input stream from the Grizzly thread : IT WORKS
///this.is = req.getInputStream( false );
}
//--- Runnable implementation ----------------------------------------------
@Override
public void run()
{
// Get the non-blocking input stream from the thread pool : IT DOES NOT WORKS !
this.is = req.getInputStream( false );
is.notifyAvailable( this, PREFERRED_SIZE );
}
Then, it doesn't work. As I don't know why, I think the only difference is that the getInputStream() call is made in the Grizzly thread in the constructor, while the the same call is made from my executor thread poll. It's not obvious for me what's happen in the Grizzly code.
So my questions :
Is my theory correct ?
Yes. In the working case, the HttpServerFilter is properly configured for async operations when AsyncHandler.service(). This is true because, like you said, getInputStream() was called within the constructor of UploadTask, so the HttpServerFilter had the correct state. When you called getInputStream() within the run() method, AsyncHandler.service() had already exited. Since the async state wasn't present at that time, the HttpServerFilter will only operate in blocking mode.
Is it a mistake to call the getInputStream() from thread other than the Grizzly ones ?
I think the rule of thumb is that getInputStream() must be called before exiting the service() method of your handler.
Or, is it a limitation/bug of the current version ? If so, do you want me to open an issue ?
It's a limitation (albeit a minor one). I think we should document this and move on.
After further discussion, we've documented the limitation, but we'll try to resolve this in the next release.
Please do log an issue.
Thanks,
-rl
Thanks
David
De : Oleksiy Stashok [mailto:oleksiy.stashok_at_oracle.com]
Envoyé : lundi 8 août 2011 13:45
À : users_at_grizzly.java.net<mailto:users_at_grizzly.java.net>
Objet : Re: From Grizzly 1.9.x to 2.x
Hi David,
the issue is probably in the ReadHander registration code, not in actual ReadHandler.
Can you pls. share more code, may be working (or better say non-working) sample?
Thanks.
WBR,
Alexey.