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.
>
> 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
>