Hi Harsha,
Harsha Godugu wrote:
> resend..
>
> ----- Original Message -----
> From: Harsha Godugu <Harsha.Godugu_at_Sun.COM>
> Date: Wednesday, October 24, 2007 3:37 pm
> Subject: Re: Meeting Minutes, Oct 24, 2007
> To: dev_at_grizzly.dev.java.net
>
>
>> Hi Jeanfrancois,
>>
>> Thanks for the quick response. I've my comments inlined.
>>
>> However, at present I do not have any roadblocks in Grizzly for Corba
>> work, as I'm using the workaround.
I would really like to see your design as I think the role given to the
CallBackHandler is not the proper one (bad docs probably). I would have
never expected to write server side support in CallbackHandler. I'm not
sure I fully understand what's happening :-)
One I found strange is that I didn't faced the problem you are
describing (I will double check for sure) in Sailfin. In any case, do
you mind filling a bug with a little test case that demonstrate the
problem? That way we can fix it properly if there is a bug in the
Context logic.
Thanks
-- Jeanfrancois
>>
>> thanks,
>> Harsha
>>
>> ----- Original Message -----
>> From: Jeanfrancois Arcand <Jeanfrancois.Arcand_at_Sun.COM>
>> Date: Wednesday, October 24, 2007 3:06 pm
>> Subject: Re: Meeting Minutes, Oct 24, 2007
>> To: dev_at_grizzly.dev.java.net
>>
>>
>>> Hi Harsha,
>>>
>>> Harsha Godugu wrote:
>>>> ----- Original Message -----
>>>> From: Jeanfrancois Arcand <Jeanfrancois.Arcand_at_Sun.COM>
>>>> Date: Wednesday, October 24, 2007 2:23 pm
>>>> Subject: Re: Meeting Minutes, Oct 24, 2007
>>>> To: dev_at_grizzly.dev.java.net
>>>>
>>>>
>>>>> 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)?
>>>> Yes. Any even thats other than read.
>>> So OP_WRITE (not OP_CONNECT I suppose).
>>>
>>>>> 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.
>>>> Yes.
>>> OK so you read bytes inside the CallbackHandler and then invoke the
>>> ReadFilter. That's explain why the ReadFilter cannot read bytes.
>>> Should
>>> you avoid calling the ReadFilter in that case?
>>>
>>>>> 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.
>>>> To be clear, here is how the over-ridden method looks like: in TCPSelectorHandler.java
>>>>
>>>> public boolean onReadInterest(final SelectionKey key, final
>>> Context ctx) thr
>>>> ows IOException {
>>>>
>>>> //return super.onReadInterest(key, ctx);
>>>> key.interestOps(key.interestOps() & (~SelectionKey.OP_READ));
>>>> key.attach(createCB(ctx.getController()));
>>>> {
>>>> final Context context = ctx.getController().pollContext(key);
>>>> context.setSelectionKey(key);
>>>> context.setCurrentOpType(Context.OpType.OP_READ);
>>>> invokeCallbackHandler(context);
>>>> return false;
>>>> }
>>>> }
>>>>
>>>> This works for both on client side and serveside, as far as the
>>> protocol filters are concerned.
>>>> Please note that, the way we wanted to invoke protocol filter
>> (read)
>>> is :
>>>> i) to use the same filter on both client and server side
>>>> ii) to use the read filter ONLY when there is signal
>> from
>>> selector that there is a READ op.
>>>
>>> yes same as Sailfin (SIP protocol :-)). I'm trying to understand why
>> I
>>> didn't have to override the method.
>>>
>>>> In order to avoid falling into the protocol (read) chain, in case
>>> of NON READ operation, the above overriden method
>>>> returns false ALWAYS. This is a special case may be.
>>> Yes.
>>>
>>>>
>>>> Please correct me in the following lines:
>>>>
>>>> Grizzly's protocol filters are aimed at handling processing
>>> requirements of data (read/write/process) irrespective if what the
>>> selector signals of any event type on designated channel.
>>>
>>>
>>> False :-) The ReadFilter is for read operations, not for write (both
>>> TCP
>>> and UDP).
>> Thats what I was expecting. A read filter for read operations. But it
>> does not seem like, from the code as I mentioned.
>> Sorry, its very complex to describe in an email. But, i will try.
>>
>>> The worker threads process each callable in the queue, by checking
>> the
>>> callback handler first.
>>>
>>> Only if you need to use the client side of Grizzly. If you aren't
>>> using
>>> the client side (like opening a connection to a remote server), then
>>> the
>>> CallbackHandler should not be used (as an example, the Grizzly http
>>> server isn't using CallbackHandler, as it it a server side
>> component).
>>
>> This was the constraint for Grizzly a long time ago.
>> Ok, I will ask you the other way. I've a filter and parser. I wanted
>> to use it (the SAME code, logic ) on both client and server. If I use
>> readFilters on the serverside and
>> callbackhandlers on the client side, I BUMP into multiple reads out
>> of which some of the reads are FALSE and the parser gets into a LOOP.
>>
>> Please read again, my first email and the description and Context.java
>> file, in the context of a single filter acting as server and client
>> in the same process.
>>
>>> Sailfin (SIP) use the client side to connect to remote client.
>>>
>>> Is Corba needs to connect (meaning opening a new connection)? My
>>> understanding was no, you don't.
>> Yes. On the client side.
>>
>>> If that's the case, then you should
>>> not
>>> use CallBackHandler. Does it make sense?
>>>
>>> If none found, then, for the case of read filter, we go and read
>>> on
>>> a channel as quickly as possible. Grizzly makes an attempt to read.
>>>
>>> The ProtocolChain (and its ProtocolFilter) will always be called
>> when
>>> there is either an OP_READ or OP_WRITE. If you use Grizzly client,
>>> then
>>> you decide by yourself (inside the CallbackHandler) to invoke the
>>> ProtocolChain. In your case, when CallbackHandler.onWrite() is
>> called,
>>> you should not call the ProtocolChain as the ReadFilter will be invoked.
>>>
>>>
>>>> Is that correct?
>>>>
>>>> Corba's parser is so sensitive that, when controls falls here, it
>>> ASSUMES that the underlying channel is ready to read. If it DID
>> not
>>> read any bytes (zero count) then, the parser assumes that, the
>>> previous read is unsuccessful and hence gives back control to
>>> Grizzly's read filter to re-try the read, by setting the parser
>>> boolean isExpectingMoreData to true. For this reason, if there
>>> happened a non-read, which might be of no interest, at that time, if
>>> the control falls into
>>>> filter then attempts to READ (unnecessary read) quickly and then
>>> returns ZERO count and invokes parser with that bytebuffer with zero
>>> fresh bytes, then parser assumes, wrongly that, the underlying
>>> channel is ready to read and the first read was unsuccessful. This
>>> was the scenario that I bumped into recenlty.
>>> But if you execute a read inside the CallbackHandler, then for sure
>>> the
>>> ReadFilter will always fail. This is the part I don't understand. If
>>> you
>>> know the read will fail (or if ou are handling an OP_WRITE), why
>>> invoking the ProtocolChain/ReadFilter?
>> I do not belive read is failing AFTER making the changes mentioned
>> here. Before. these changes, I was getting into multiple reads.
>> Some of the reads were FALSE reads. Then I digged into this part of
>> code in Grizzly. And then, came up with these suggestions.
>> The logic is, we will have a protocol parser executed in a Callback
>> handler for reads alone, when a read occurs.
>>
>>
>>> Sorry for asking so many questions, but I really want to understand
>> Sure. Pl. feel free. I too want to make sure I'm doing the right approach.
>>
>> Please note that, all this discussion started (2 weeks ago) and
>> arrived at a workaround mainly due to the fact I was seeing mutliple
>> reads from Grizzly. In order to overcome that, I came up with the workaround.
>>
>> You are aslo right on the part that, we do not have to use ReadFilter
>> at all. I can just use a callback handler for the channel(s), and upon
>> read event,
>> I can directly call, the parser. But, the motive behind is, we wanted
>> to use very less code of our own and use Grizzly to the full
>> potential. That's what
>> Ken C. has been preaching me :-) .
>>
>> thanks,
>> Harsha
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>