You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@mina.apache.org by Emmanuel Lecharny <el...@gmail.com> on 2008/11/10 14:56:27 UTC
[MINA 2 new chain] Some feedback
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
Re: [MINA 2 new chain] Some feedback
Posted by Mark Webb <el...@gmail.com>.
I might need some beers just to cure the headache I get from looking
at that stack trace.
I agree that the "+1" is ugly and the ChainIterator is a much better
solution. Would a queue work in this situation?
--Mark
On Mon, Nov 10, 2008 at 8:56 AM, Emmanuel Lecharny <el...@gmail.com> wrote:
> 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
>
>
>