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