Ok, I have a version that works better with the CompressionFilter.


Here is what I have changed :

- the session.write( <message> ) method will inject the original message into the WriteRequest

- any filterWrite filter that is going to create a new version of the message will store it in the same writeRequest, into a modifiedMessage field. (The WriteRequest impl thus holds 2 versions of the message, the odiginal one and the modified one)

- when the modified message is written to the remote peer (it's now an IoBuffer), messageSent will be called with the original message, or with the written IoBuffer flipped if the original message was a IoBuffer and was never modified.

The first test I did with the chat example seems to work pretty well. It's going through a TextLineCodecFactory codec filter, a CompressionFilter. I have to test it with the LoginFilter and the SslFilter.


All in all, the MINA code is much simpler and should be faster too, as we spare spurious calls to messageSent and filterWrite with an Empty message.


More to come soon.

On 22/03/2019 04:58, Emmanuel Lécharny wrote:
Hmmpphhhh....

I have traced the calls when a session.write( <blah> ) is done.


It's all a kind of a hack.


In order to be able to send the messageSent() event, the protocolFilter will call the nextFilter.filterWrite() method twice :

    public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
        Object message = writeRequest.getMessage();

        ...
            // Write all the encoded messages now
            while (!bufferQueue.isEmpty()) {
                Object encodedMessage = bufferQueue.poll();

                // Flush only when the buffer has remaining.
                if (!(encodedMessage instanceof IoBuffer) || ((IoBuffer) encodedMessage).hasRemaining()) {                     SocketAddress destination = writeRequest.getDestination();                     WriteRequest encodedWriteRequest = new EncodedWriteRequest(encodedMessage, null, destination);

                    nextFilter.filterWrite(session, encodedWriteRequest);
                }
            }

            // Call the next filter
            nextFilter.filterWrite(session, new MessageWriteRequest(writeRequest));

The first call we go down the chain with an IoBuffer containing the encoded message, the second call will use th e original message wrapped in a specific MessageWriteRequest instance, which will always return an empty IoBuffer when a getMessage() is called on it :

    private static class MessageWriteRequest extends WriteRequestWrapper {
        @Override
        public Object getMessage() {
            return EMPTY_BUFFER;
        }

It goes down the chain to the HeadFilter where it gets stacked to be written. But as it's an empty buffer, the flush() method will do nothing but initiate a call to messageSent() which will pop up to the handler. Actually, the messageSent() event will be issued twice, once with the encoded message, and it will be swallowed silently by the ProtocolCodecFilter :

    public void messageSent(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
        if (writeRequest instanceof EncodedWriteRequest) {
            return;

and a second time with the EMPTY buffer, which will bubble up to the IoHandler, with the original message.


This is overly complex, and leads to spurious CPU being consumed. It would be way smarter to encapsulate the original message in a WriteRequest instance, go though the filters with that, up to the encoder filter to feed a IoBuffer into this WriteRequest, which will be written to the remote peer, and when done, a messageSent event will be generated using the original message. If th eoriginal message is a IoBuffer that does not require encoding, then it's enough to keep the encoded message to null, up to the HeadFilter to find out that the original was never transformed so that it can write it, and let the IoProcessor generate a messageSent event after having flipped the original message to rest it back to its original position and limit. No reset, no mark, just a flip.


Reply via email to