Hi guys,

I'm still doing some experiment with the new chain (in mina-new-chain2 branch). It's not totally satisfactory, mainly for two reasons : - I have used a List to store the filters, so I have to propagate an integer index to jump from one filter to another. This is a bit ugly, as you have inex+1 all over the code. I will move to what was suggested by Steve Ulrich (passing a ChainIterator instead of an index will mask the ugly +1). - The current MINA code is so damn complex that it makes it an order of magnitude more complicated to fix than to rewrite it, but this is not something I want to jump in, yet. As an example, here is the stack you get when you receive a message and send back a response (just for you to realize how insane is the current code ...). And we only have three filters : mdc, codec and logging.

AbstractPollingIoProcessor$Processor.run()
 NioProcessor(AbstractPollingIoProcessor<T>).process()
   NioProcessor(AbstractPollingIoProcessor<T>).process(T)
     NioProcessor(AbstractPollingIoProcessor<T>).read(T)
     | DefaultIoFilterChain.fireMessageReceived(java.lang.Object)
| DefaultIoFilterChain.callNextMessageReceived(IoFilterChain$Entry, IoSession, Object) | DefaultIoFilterChain$HeadFilter(IoFilterAdapter).messageReceived(IoFilter$NextFilter, IoSession, Object) | DefaultIoFilterChain$EntryImpl$1.messageReceived(IoSession, Object) | DefaultIoFilterChain.callNextMessageReceived(IoFilterChain$Entry, IoSession, Object) | MdcInjectionFilter(CommonEventFilter).messageReceived(IoFilter$NextFilter, IoSession, Object)
     |             MdcInjectionFilter.filter(IoFilterEvent)
     |               IoFilterEvent.fire()
| DefaultIoFilterChain$EntryImpl$1.messageReceived(IoSession, Object) | DefaultIoFilterChain.callNextMessageReceived(IoFilterChain$Entry, IoSession, Object) | ProtocolCodecFilter.messageReceived(IoFilter$NextFilter, IoSession, Object) | | TextLineDecoder.decode(IoSession, IoBuffer, ProtocolDecoderOutput) | | TextLineDecoder.decodeAuto(TextLineDecoder$Context, IoSession, IoBuffer, ProtocolDecoderOutput)
     |                     | <-+
| | ProtocolCodecFilter$ProtocolDecoderOutputImpl.flush() | | DefaultIoFilterChain$EntryImpl$1.messageReceived(IoSession, Object) | | DefaultIoFilterChain.callNextMessageReceived(IoFilterChain$Entry, IoSession, Object) | | LoggingFilter.messageReceived(IoFilter$NextFilter, IoSession, Object) | | DefaultIoFilterChain$EntryImpl$1.messageReceived(IoSession, Object) | | DefaultIoFilterChain.callNextMessageReceived(IoFilterChain$Entry, IoSession, Object) | | DefaultIoFilterChain$TailFilter.messageReceived(IoFilter$NextFilter, IoSession, Object) | | ChatProtocolHandler.messageReceived(IoSession, Object) | | ChatProtocolHandler.broadcast(String) | | NioSocketSession(AbstractIoSession).write(Object) | | NioSocketSession(AbstractIoSession).write(Object, SocketAddress) | | DefaultIoFilterChain.fireFilterWrite(WriteRequest) | | DefaultIoFilterChain.callPreviousFilterWrite(IoFilterChain$Entry, IoSession, WriteRequest) | | DefaultIoFilterChain$TailFilter.filterWrite(IoFilter$NextFilter, IoSession, WriteRequest) | | DefaultIoFilterChain$EntryImpl$1.filterWrite(IoSession, WriteRequest) | | DefaultIoFilterChain.callPreviousFilterWrite(IoFilterChain$Entry, IoSession, WriteRequest) | | LoggingFilter(IoFilterAdapter).filterWrite(IoFilter$NextFilter, IoSession, WriteRequest) | | DefaultIoFilterChain$EntryImpl$1.filterWrite(IoSession, WriteRequest) | | DefaultIoFilterChain.callPreviousFilterWrite(IoFilterChain$Entry, IoSession, WriteRequest) | | ProtocolCodecFilter.filterWrite(IoFilter$NextFilter, IoSession, WriteRequest) | | | TextLineEncoder.encode(IoSession, Object, ProtocolEncoderOutput) | | | ProtocolCodecFilter$ProtocolEncoderOutputImpl(AbstractProtocolEncoderOutput).write(Object)
     |                     |                                       | <-+
| | | ProtocolCodecFilter$ProtocolEncoderOutputImpl.flushWithoutFuture() | | | DefaultIoFilterChain$EntryImpl$1.filterWrite(IoSession, WriteRequest) | | | DefaultIoFilterChain.callPreviousFilterWrite(IoFilterChain$Entry, IoSession, WriteRequest) | | | MdcInjectionFilter(CommonEventFilter).filterWrite(IoFilter$NextFilter, IoSession, WriteRequest) | | | MdcInjectionFilter.filter(IoFilterEvent) | | | IoFilterEvent.fire() | | | DefaultIoFilterChain$EntryImpl$1.filterWrite(IoSession, WriteRequest) | | | DefaultIoFilterChain.callPreviousFilterWrite(IoFilterChain$Entry, IoSession, WriteRequest) | | | DefaultIoFilterChain$HeadFilter.filterWrite(IoFilter$NextFilter, IoSession, WriteRequest) | | | SimpleIoProcessorPool<T>.flush(T) | | | NioProcessor(AbstractPollingIoProcessor<T>).flush(T) | | | NioProcessor.wakeup() | | | <-+ | | | <-+ | | | <-+ | | | <-+ | | | <-+ | | | <-+ | | | <-+ | | | <-+ | | | <-+
     |                     |                                       |   <-+
     |                     |                                       | <-+
| | | DefaultIoFilterChain$EntryImpl$1.filterWrite(IoSession, WriteRequest) | | | DefaultIoFilterChain.callPreviousFilterWrite(IoFilterChain$Entry, IoSession, WriteRequest) | | | CommonEventFilter).filterWrite(IoFilter$NextFilter, IoSession, WriteRequest) | | | MdcInjectionFilter.filter(IoFilterEvent) | | | IoFilterEvent.fire() | | | DefaultIoFilterChain$EntryImpl$1.filterWrite(IoSession, WriteRequest) | | | DefaultIoFilterChain.callPreviousFilterWrite(IoFilterChain$Entry, IoSession, WriteRequest) | | | DefaultIoFilterChain$HeadFilter.filterWrite(IoFilter$NextFilter, IoSession, WriteRequest) | | | SimpleIoProcessorPool<T>.flush(T) | | | NioProcessor(org.apache.mina.core.polling.AbstractPollingIoProcessor<T>).flush(T) | | | <-+ | | | <-+ | | | <-+ | | | <-+ | | | <-+ | | | <-+ | | | <-+
     |                     |                                       |   <-+
     |                     |                                       | <-+
     |                     |                                       <-+
| | <-+ | | <-+ | | <-+ | | <-+ | | <-+ | | <-+ | | <-+ | | <-+ | | <-+ | | <-+ | | <-+ | | <-+ | | <-+ | | <-+ | | <-+ | | <-+ | | <-+ | | <-+ | | <-+ | <-+ | <-+ | <-+ | <-+ | <-+ | <-+ | <-+ | <-+ | <-+ | <-+ | <-+ <-+
   <-+
 <-+
 NioProcessor(AbstractPollingIoProcessor<T>).flush(long)
   NioProcessor(AbstractPollingIoProcessor<T>).flushNow(T, long)
NioProcessor(AbstractPollingIoProcessor<T>).writeBuffer(T, WriteRequest, boolean, int, long) | NioProcessor.write(NioSession, IoBuffer, int) // Actually write data into the socket
     <-+
NioProcessor(AbstractPollingIoProcessor<T>).fireMessageSent(T, WriteRequest) DefaultIoFilterChain.fireMessageSent(WriteRequest) DefaultIoFilterChain.callNextMessageSent(IoFilterChain$Entry, IoSession, WriteRequest) DefaultIoFilterChain$HeadFilter(IoFilterAdapter).messageSent(IoFilter$NextFilter, IoSession, WriteRequest) DefaultIoFilterChain.callNextMessageSent(IoFilterChain$Entry, IoSession, WriteRequest) MdcInjectionFilter(org.apache.mina.filter.util.CommonEventFilter).messageSent(IoFilter$NextFilter, IoSession, WriteRequest) MdcInjectionFilter.filter(IoFilterEvent) IoFilterEvent.fire() DefaultIoFilterChain$EntryImpl$1.messageSent(IoSession, WriteRequest) DefaultIoFilterChain.callNextMessageSent(IoFilterChain$Entry, IoSession, WriteRequest) ProtocolCodecFilter.messageSent(IoFilter$NextFilter, IoSession, WriteRequest) <-+ <-+
                     <-+
                   <-+
                 <-+
               <-+
             <-+
           <-+
         <-+
       <-+
     <-+
   <-+
 <-+
<-+

You can see that :
- for each filter, we have at least 3 lines in the stack, and we have 2 more filters : Head and Tail, which make a total of 15 lines, before we reach the Handler (in fact, 16 because we go through a two-step filter, the MDC filter). We should be able to get it done in 4 steps, max (which is what I currently get, except that I still have this extra MDC step) - The write chain is called twice : once in ProtocolCodecFilter$ProtocolEncoderOutputImpl.flushWithoutFuture(), for an extra 11 steps, and as the continuation of the write chain (which has already been followed into the flushWthoutFuture() method call), for 9 extra steps. I have no f**** idea why this call is necessary, so if anyone has an idea, please, feel free to tell me. (In my experiment, I have removed this last call, and it seems to be useless, but I'm not 100% sure). The only difference is that in the first case, we send a WriteRequest, when in the second case, we create a MessageSendRequest() object encapsulating the WriteRequest (no idea why...) - When all this 'usefull' chaining is done, we then call the chain again to inform (who ???) that the message has been sent. This seems to be overkilling...

Ok, now, whoever thinks that this is manageable and easy to debug, you have to offer me a bunch of beers next year in Amsterdam, and may be some of those special space cakes those who created this portion of code must have obviously abused while coding :) !

I will commit what I came to with the new chain approach, even if it's not -yet- working well : I still have some issues when closing the session, it seems that the 'close' message does not propagate well in the chat sample.

I will also try to draw a short desription, with some schema, on how a server is initialized and session are created, with all the parallel threads (but the IdleThread, which is totally a waste for socket).

Thanks !

--
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org


Reply via email to