Simon Trudeau wrote:
> Ok... Euhm...
>
> Saving the bytes from the buffer shouldn't be a big problem. So that
> should be ok. I am more worried about saving the connection information
> for later. What do I need to save? ThreadAttachment is nice but it is
> very much NOT thread safe! It contains things such as ByteBuffer and the
> likes which will get invalidated the next time a packet is processed by
> the ProtocolChain!
No, that's the idea. If you get a ThreadAttachment from a Thread, the
ByteBuffer will be detached from its thread (a new one will be created).
So you should not have any concurrency issues or any invalidation.
>
> Since I am connected to a server, there must be a channel (or something)
> establish and maintained between my client and server. I need to get a
> hold of that channel at a later point in time and send back my response.
>
> How do you typically do delayed processing like I intend on doing? How
> does Grizzly deal with burst? Without a delayed processing mechanism you
> cannot deal with request bursts without dropping packets. I am pretty
> sure (hoping :.)) that Grizzly has one! You might have the fastest NIO
> framework around but the applications built on top of it might just not
> keep up with the flow of requests!!! :.)
The way Grizzly works is the following (just to recap):
1. Client open a connection to Server
2. Server accept the connection
3. Server disable OP_READ operation (all upcoming packet are buffered by
the OS)
3. Server spawn a new Thread which execute the ProtocolChain
4. The first ProtocolFilter (read) reads the available bytes on the channel
5. The next Filter is invoked. The 'next" filter is usually parsing the
bytes, and decide:
5.1 If a response need to be send *and/or*
5.2 If it is time to get more bytes (enable OP_READ)
ctx.setRegistrationState(KeyRegistrationState.REGISTER); *or*
5.3 If the connection needs to be closed
ctx.setRegistrationState(KeyRegistrationState.CANCEL); *or*
5.4 If the connection needs to suspended
ctx.setRegistrationState(KeyRegistrationState.NONE);
If you set the KeyRegistrationState.NONE, you need to cache/store the
SelectionKey and then, let say 10 minutes after, get back that
SelectionKey and do:
5.5 Send the response ( key.channel().write() ) and
5.6 Either close the connection or re-enable the read operations.
During the suspended state, the OS will buffer some packets but
eventually will stop accepting them. Is that the problem you are
explaining? If you read all the packets without suspending, you might
run in a out of memory error if you need to buffer in memory all of them.
On the different note, I'm working right now on a
SuspendableProtocolFilter (should have it next week) that will make the
suspend() operation easier to handle.
A+
-- Jeanfrancois
>
> Simon
>
> -----Original Message-----
> From: Jeanfrancois.Arcand_at_Sun.COM [mailto:Jeanfrancois.Arcand_at_Sun.COM]
> Sent: March-12-08 1:42 PM
> To: users_at_grizzly.dev.java.net
> Subject: Re: [Q] Adding delays to protocol filter
>
>
>
> Simon Trudeau wrote:
>> Now I think that I understand what you mean! :.)
>>
>> **********
>> ctx.setKeyRegistrationState(Context.KeyRegistrationState.NONE);
>>
>> // Store those values somewhere:
>> SelectionKey key = ctx.getSelectionKey();
>> Selectorhandler sl = ctx.getSelectorHandler();
>> **********
>>
>>
>> In your explanation, the above make sense, but
>>
>>
>> **********
>> Once you have flushed the response,
>> just do:
>>
>> sl.getSelectionKeyHandler().register(key);
>>
>> So you can get other requests that are coming.
>> **********
>>
>> Cannot work since I register my key only after I have processed
> (during
>> a long time) the received packet, I won't be able to receive and queue
>> packets while I am processing! I need to keep the key (or a new key
>> maybe?) registered at all time so I can get all packets while my
>> application is processing.
>
> I see. Then you need some caching/buffering mechanism and store the read
>
> bytes. My solution doesn't stand :-)
>
>
>> It means that I might be receiving 5 requests but during that time I
>> might only be able to process 2!
>
> Right
>
>> So How should I set (maybe save) my selectionKey so I can reply to a
>> request even after many other requests have arrived and have been
> queued
>> (at the application level)?
>
> You can't save the SelectionKey, but instead you might want to use the
> ThreadAttachment and attach your ByteBuffer to it. Grizzly will re-use
> that ByteBuffer every time bytes are read. Once you have all your bytes,
>
> you just need to send the response. Take a look at the proposal I did
> (now implemented):
>
> http://www.nabble.com/-Proposal---vote--Adding-a-new-ThreadAttachment-fr
> o-partial-read-state-implementation-td11254764.html#a11254764
>
>
>> Also, is there one new Context object per packet received or is that
>> object shared among many packets (I know it can be shared when
> handling
>> truncated messages but are there other cases?).
>
> One per packet received.
>
> A+...pogne dans la neige a Montreal :-)
>
> -- jeanfrancois
>
>
>> Thanks,
>>
>>
>> Simon
>>
>> -----Original Message-----
>> From: Jeanfrancois.Arcand_at_Sun.COM [mailto:Jeanfrancois.Arcand_at_Sun.COM]
>
>> Sent: March-07-08 2:30 PM
>> To: users_at_grizzly.dev.java.net
>> Subject: Re: [Q] Adding delays to protocol filter
>>
>> Hi Simon,
>>
>> Simon Trudeau wrote:
>>> I want to test the performance of my application. To do so, I intend
>> on
>>> building an Echo server with delay. Basically, once my request
> reaches
>>> my server, I want to delay (simulate response processing) the sending
>> of
>>> a response. My first guess is to wrap the content of the execute
>> method
>>> of the EchoFilter inside a callable and have it executed by a
>> scheduled
>>> executor. Is that thread safe?
>> Yes you can, but make sure you call:
>>
>>
>> ctx.setKeyRegistrationState(
>> Context.KeyRegistrationState.NONE);
>>
>> // Store those values somewhere:
>> SelectionKey key = ctx.getSelectionKey();
>> Selectorhandler sl = ctx.getSelectorHandler();
>>
>>
>> inside you Filter, because if not, the key will be registered back and
>
>> it will gives unexpected result. Once you have flushed the response,
>> just do:
>>
>>
>> sl.getSelectionKeyHandler().register(key);
>>
>> So you can get other requests that are coming.
>>
>>
>>
>>>
>>>
>>> What happens to the context object if another packet arrives from the
>
>>> same connection while my server is waiting to send back the response?
>>>
>>>
>>>
>>> The issue I want to simulate is a fast producer (client), slow
>> consumer
>>> (server).
>> Right. Try the above :-)
>>
>> Thanks
>>
>> -- Jeanfrancois
>>
>>
>>>
>>>
>>> Can I just wrap
>>>
>>>
>>>
>>> *public* *boolean* execute(Context ctx) *throws* IOException {
>>>
>>> *final* WorkerThread workerThread =
>>> ((WorkerThread)Thread./currentThread/());
>>>
>>> ByteBuffer buffer = workerThread.getByteBuffer();
>>>
>>> buffer.flip();
>>>
>>> *if* (buffer.hasRemaining()) {
>>>
>>> // Depending on protocol perform echo
>>>
>>> SelectableChannel channel =
>> ctx.getSelectionKey().channel();
>>> *try* {
>>>
>>> *if* (ctx.getProtocol() == Controller.Protocol./TCP/)
>> {
>>> // TCP case
>>>
>>> OutputWriter./flushChannel/(channel, buffer);
>>>
>>> } *else* *if* (ctx.getProtocol() ==
>>> Controller.Protocol./UDP/) { // UDP case
>>>
>>> DatagramChannel datagramChannel =
>> (DatagramChannel)
>>> channel;
>>>
>>> SocketAddress address = (SocketAddress)
>>>
>>>
>>> ctx.getAttribute(ReadFilter./UDP_SOCKETADDRESS/);
>>>
>>> OutputWriter./flushChannel/(datagramChannel,
>>> address, buffer);
>>>
>>> }
>>>
>>> } *catch* (IOException ex) {
>>>
>>> // Store incoming data in byte[]
>>>
>>> *byte*[] data = *new* *byte*[buffer.remaining()];
>>>
>>> *int* position = buffer.position();
>>>
>>> buffer.get(data);
>>>
>>> buffer.position(position);
>>>
>>>
>>>
>>> Controller./logger/().log(Level./WARNING/,
>>>
>>> "Exception. Echo \"" + *new* String(data) +
>> "\"");
>>> *throw* ex;
>>>
>>> }
>>>
>>> }
>>>
>>>
>>>
>>> buffer.clear();
>>>
>>> *return* *false*;
>>>
>>> }
>>>
>>>
>>>
>>> Inside a callable and execute it from a Schedule Executor or are
> there
>>> states that will be messed up (the context maybe...?). What do you
>> think?
>>>
>>>
>>> Thanks,
>>>
>>>
>>>
>>> Simon
>>>
>>>
>>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>