dev@grizzly.java.net

Re: Meeting Minutes, Oct 24, 2007

From: Jeanfrancois Arcand <Jeanfrancois.Arcand_at_Sun.COM>
Date: Wed, 24 Oct 2007 17:23:40 -0400

Harsha Godugu wrote:
> Thanks Charlie for the meeting minutes. Of all, the one interest to me, in this email is about the read filters. So, I'm erasing the rest of the line, to just to focus on read filters.
>>> Charlie asked about how during default ReadFilter works once it
>>> receives an OP_READ event until it re-enables interest ops on the
>>> SelectionKey. In particular, under what circumstances does default
>>> ReadFilter do multiple reads?
>>>
>>> Looking a ReadFilter.execute(), we see:
>>>
>> // As soon as bytes are ready, invoke the next ProtocolFilter.
>> while (channel.isOpen() && (count = channel.read(byteBuffer)) == 0){
>> // Avoid calling the Selector.
>> if (++loop > 2){
>> if (ctx.getKeyRegistrationState() !=
>> Context.KeyRegistrationState.NONE){
>> ctx.setAttribute(ProtocolFilter.SUCCESSFUL_READ, Boolean.FALSE);
>> invokeNextFilter = false;
>> }
>> break;
>> }
>> }
>>>
>>> Hence, we see that Grizzly will read once if it there are bytes read
>>> from the channel. It will try a total of 3 times before giving up.
>>> Also notice that if it reads 3 times and has found no bytes have
>> been
>>> read, the 'invokeNextFilter' is set to false. So this means if bytes
>>> had been read, the next Filter in the chain is invoked. If not, the
>>> ReadFilter will not invoke the next Filter. In both cases, when the
>>> chain of filters have finished executing, the interest op will be
>>> re-enabled on the SelectionKey
>
> Let's go back a step and get little context.
>
> In corba the requirement is to use the same protocol filter on both client and serve side, so that when there is a need to parse the received bytes, we can use the same filter and parser mechanism. That requirement lead us to use the filter from the callback handler mechanism in Grizzly. That means, when there is read event, it will invoke the read filter that reads the available bytes and then gives control to the parser. Thats fine until this stage. In order accomplish this, we all know that, we need to add the given protocol filter (in this case read filter) to the protocol chain.
>
> We accomplish invoking the filters from callback handler by the code like the following:
> public void onRead(IOEvent<Context> ioEvent) {
> try {
> Context ctx = ioEvent.attachment();
> SelectionKey key = ioEvent.attachment().getSelectionKey();
> // disable OP_READ on key before doing anything else
> key.interestOps(key.interestOps() & (~SelectionKey.OP_READ));
> ctx.getProtocolChain().execute(ioEvent.attachment());
> ...
> ..
> //enable read op here or other place once reading is done
> }
> }
>
> Now, the issue/bug (to me at-least) is, take a look at the following code from : Context.java which is the heat of the Grizzly protocol filters and callback handlers. The method we are interested in here is:
>
> public Object call() throws Exception {
> // we are interested in the if /else block
> if (ioEvent != null && (attachment instanceof CallbackHandler)){
> ... ...
> // not copied entire code for saving space.
> } else {
> SelectionKey currentKey = key;
> selectorHandler.getSelectionKeyHandler().process(currentKey);
> try {
> protocolChain.execute(this);
> } finally {
> selectorHandler.getSelectionKeyHandler().postProcess(currentKey);
> }
> }
>
> }
>
> From the code above, we note that, if there is a callback handler, the control (while in a worker thread, does not matter here) falls into the protocol chain and then handles the read event in the protocol filter (here its is read filter) . That's fine no problems there. The issue is around the ELSE block.
>
> Assume the scenario of, a non read event.. during that time

Here you means a write event? You can always query the Context to learn
what is the type of OP currently processed (OP_READ or OP_WRITE).

the IF condition fails and then gets into ELSE case and executes the
protocol filter (read filter). This where, I was referring multiple
reads.
>
> Now imagine a case, we have a read filter, getting invoked through the callback handler on a connection.
  The filters get executed by default whenever a target callable is
added to the worker queue.
  Each time a worker thread executes the callable, it check for the
callback handler and read event.

Can you elaborate on the type of event here? You means a write event as
well (like above)?


  If there is no read event, it fallse to else block as I mentioned
above and executes the read filter.

Are you reading bytes inside the CallbackHandler? If yes, then it will
explain why you are reading 0 bytes.

   This where I was seeing multiple reads. I worked around this by
overriding the following method in TCPSelectorHandler.java
>
> public boolean onReadInterest(final SelectionKey key, final Context ctx) throws IOException {
> // code to add a callback handler
> // return always false, so that, we do not fall into the protocol chain
> }
>
> With the above change , I do NOT see multiple reads through the read filter.

If you override that method, then your CallbackHandler will never be
invoked. So why using CallbackHandler then? For handling the OP_WRITE?
That would make sense if true, but I suspect you should make a clear
distinction between OP_READ and OP_WRITE.

Thanks

-- Jeanfrancois


>
> Harsha.
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>