Emmanuel Lecharny wrote:
MINA uses IoProcessor to handle incoming requests. When you instanciate the server, more than one of these objects are created, so you can process more than one request at the same time. Each of those IoProcessor has its own selector, but then, you should consider that the processing of one request is done in one single thread, ie the IoProcessor thread. More than that, each session is associated with a single IoProcessor object, so it can't be processed by another IoProcessor instance.

That being said, you may need to decouple the processing from the IO handling. For instance, assuming that you may have a lot of small and fast requests to process, plus from time to time one big expensive and CPU consuming request, you may want to free the IoProcessor as fast as possible for the small requests to be processed quickly. This is what the Executor filter is good for. When you add such a filter in the chain, it simply enqueue all the requests and ask a thread pool to process them, letting the IoProcessor doing its job quickly.

In any case, when the request has been processed, the response is written into a queue by the executor thread, AFAICT. As the write is done at the end of the processing (in your IoHanlder implementation), it's still traversing the chain using the thread selected by the executor filter, up to the point the request is written to the queue. Then the execution stack is unfold. It seems a bit complex, and it might have been a bit better to separate the incoming and outgoing chains, but at least, it does the job.

I hope I brought some faint light about the way MINA is working from the inside out. Just tell me if it's enough for waht you need.

Thanks !

Thanks for the detailed explanation, Emmanuel. I actually understood most of this pretty well already, though, as I've been digging through the code quite extensively to try to understand what was going on.


But a) if I'm reading the code correctly, it looks like what you wrote is not exactly correct, and b) I'm not sure you understood what I was trying to communicate in my last message - that the way MINA is coded, having a thread pool executor for write operations is completely useless, since the write thread pool will *never* get used to actually perform socket IO.

Let me explain.  Let's say you have a filter chain like so:

DefaultIoFilterChainBuilder filterChainBuilder = protocolAcceptor.getFilterChain(); filterChainBuilder.addLast("codec", new ProtocolCodecFilter(codecFactory));
                threadPool = new OrderedThreadPoolExecutor();
filterChainBuilder.addLast("writer thread pool", new ExecutorFilter(threadPool, IoEventType.WRITE));
                protocolAcceptor.setHandler(protocolHandler);

So the intention here is that after the codec does its work (i.e., processes an incoming message and generates a response) the actual write operation (i.e., actually physically writing the IoBuffer bytes out to the socket) should get performed in a threadPool thread.

But that does not happen. Instead, the write operation gets performed in the IoProcessor thread. And then, later, although the filter chain does invoke filterWrite() and messageSent() on the ExecutorFilter, that winds up essentially being a NO-OP, since there is nothing downstream from the executor filter that is doing any socket IO. So the whole concept of a writer thread pool is not possible to implement the way MINA is coded.


I guess what I'm finding unexpected about the way MINA is coded is this:

I would expect that messages/method-calls would traverse down the filter chain and then, finally, after the final (tail) filter in the chain is executed, then MINA would write the output out to the socket.

But according to DefaultIoFilterChain.HeadFilter, it looks like the *head* of the filter chain, not the tail, is what's writing the output out to the socket:

    private class HeadFilter extends IoFilterAdapter {
        @SuppressWarnings("unchecked")
        @Override
        public void filterWrite(NextFilter nextFilter, IoSession session,
                WriteRequest writeRequest) throws Exception {
...
            s.getWriteRequestQueue().offer(s, writeRequest);



I don't quite understand this. And as a matter of fact, it seems like this could cause some VERY unexpected behavior.

For example, say I wanted to add a org.apache.mina.filter.util.WriteRequestFilter at the end of my filter chain which alters the outgoing message before it gets sent. But this would not work! Since the message gets queued for send at the *head* of the filter chain, any changes I make to the message at the tail of the chain would have no effect.


In any case, the bottom line is: it looks like my efforts to try to get MINA to send messages out through the socket in a different thread cannot be successful. No matter how I configure things, MINA will always do the socket IO in the IoAcceptor thread.

It's easy to verify this, by the way: Try adding a "write thread pool" to your filter chain like I described above. Then, in the messageReceived() method of your protocol handler, where you write your response, include the following code:

                WriteFuture writeFuture = session.write(responseStr);
                writeFuture.addListener(
                        new IoFutureListener<WriteFuture>() {
                                public void operationComplete(WriteFuture 
future) {
System.out.println("message write occurred in thread: "+Thread.currentThread().getName());
                                }
                        }
                );

On my machine, the output always occurs in thread "NioProcessor-1", instead of one of the executor filter threads.


I hope I was clearer this time and that this makes some sense to you.

Can you shed any light on what's happening here and/or why the write request is getting queued in the head filter?

Thanks,

DR

Reply via email to