mina-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Alan D. Cabrera" <l...@toolazydogs.com>
Subject Re: [MINA 3.0] filter chains
Date Sat, 27 Aug 2011 20:51:23 GMT

On Aug 26, 2011, at 7:35 PM, Emmanuel Lecharny wrote:

> On 8/27/11 2:04 AM, Alan D. Cabrera wrote:
>> On Aug 26, 2011, at 1:27 PM, Emmanuel Lecharny wrote:
>>> On 8/26/11 8:47 PM, Alan D. Cabrera wrote:
>>>> On Aug 26, 2011, at 11:03 AM, Emmanuel Lecharny wrote:
>>>>> On 8/26/11 7:22 PM, Alan D. Cabrera wrote:
>>>>>> On Aug 26, 2011, at 9:33 AM, Emmanuel Lecharny wrote:
>>>>>> What I have in mind is much more something like :
>>>>>> void messageReceived( context )
>>>>>> {
>>>>>>    ... // do something, updating the context, eventually setting
a status
>>>>>>   controller.callNextFilter( context, currentFilter );
>>>>>>    ... // do something after the call
>>>>>> }
>>>>>> and in controller :
>>>>>> void callNextFilter( Context context, Filter currentFilter )
>>>>>> {
>>>>>>    Status status = context.getStatus();
>>>>>>    Map<Status, Filter>    map = fsmMap.get( currentFilter );
>>>>>>    Filter nextFilter = map.get( status );
>>>>>>    nextFilter.messageReceived( context );
>>>>>> }
>>>>>> This strikes me as pretty complex, jmho.  Also, I don't like the
idea of forcing the filter to call the controller.callNextFilter() to make things work.
>>>>> the alternative would be something like :
>>>>> void messageReceived( context )
>>>>> {
>>>>>   ... // do something, updating the context, eventually setting a status
>>>>>  fsmMap.get( this ).get( status ).messageReceived( context );
>>>>>   ... // do something after the call
>>>>> }
>>>>> No controller, but a long list of chained call.
>>>> But we're still forcing the filter to participate in things that really should
be the domain of the controller not the filter.
>>> If we delegate the transition to the controller, then we can't have post actions...
Obviously, not having post actions makes it easier. (Post action are really important if we
want to do something when we come back from the application.)
>> I think we're getting to some interesting bits. Can you provide more exact detail?
> One very simple example, taken from the ProfilerFilter :
>    @Override
>    public void messageReceived(NextFilter nextFilter, IoSession session,
>            Object message) throws Exception {
>        if (profileMessageReceived) {
>            long start = timeNow();
>            nextFilter.messageReceived(session, message);
>            long end = timeNow();
>            messageReceivedTimerWorker.addNewDuration(end - start);
>        } else {
>            nextFilter.messageReceived(session, message);
>        }
>    }
> If you depend on the controller to call thenext filter, then you have no easy way to
compute the time it takes to process the action, as you won't be able to execute the post

This is a good use case, instrumentation of the protocol stack.  Something to think about.

What I still object to is forcing filters to participate via this code bit:

 fsmMap.get( this ).get( status ).messageReceived( context );

> Note that the decoding of multiple messages within one PDU won't be possible either without
being able to process post-actions. (see below)
>>> One clear exemple would be a decoder processing a PDU with more than one message
: you can't anymore loop on the PDU if you delegate the next call to the controller.
>> What is the format of this PDU and how is it presented to the FSM, i.e. in what kind
of pieces does it arrive?
> You get an array of bytes, containing potentially more than one message. The fact is
that you have no way to get a byte array from the socket as soon as a complete message has
been received : the socket does not know anything about messages.
> You just have to assume that the PDU you've got can be :
> - either a portion of a message, and you have to wait for more bytes in order to produce
a message
> - a full message, once decoded
> - more than one message you have to send to the handler one by one
> - some full messages plus a fraction of a message

I had/have the same understanding of how to crack a PDU and pass on translated messages. 
This can easily, and I think a fare bit cleaner, be accomplished using the mechanism that
I propose as well.

>>>> With that said I think that an FSM where we have, here letters are filters:
>>>> [outside filter] ->   {A ->   [state change decides to send to] ->
  B ->    [state change decides to send to]  ->   C} ->   [outside filter]
>>>> is very confusing.  What protocol would require that?  Just an honest question;
one does not come to my mind atm.
>>> all of them :) This is what we currently do in MINA.
>> I think that I am hearing a reply that explains that all the protocols are implemented
in this way.  I'm not hearing an explanation as to why it *must* be that way.
> simply because you can't move to the next filter unless you have transformed what you've
got from the previous filter. If we exclude all the utility filters (like the loggers), a
filter can only process a certain type of message, and produce another type of message. The
chain of filters is dictated by the transformation done at each step. One good example is
LDAP processing : in order to decode a LDAP message, you first have to decode the TLVs, then
you can decode the messages themselves. A LDAP chain would be something like :
> [outside filter] -> (bytes) -> { TLV decoder filter -> (TLVs) -> LDAP decoder
filter -> (LDAPmessages) } -> [outside filter]
> (add to this the fact that you may loop on the TLV filter *and* the LDAP filter, plus
the fact that you may have to wait for more bytes)
> Now, it makes *no sense* to exchange the filters. It will simply not work. It's the very
same for any protocol we will process with such a mechanism.
> In other words, the order the filters are executed is not random. It's fixed by design,
and does not change (as soon as we have ruled out the possibility to have a dynamic chain).
> Another way to see this mechanism is that it's a path from one point to another : you
may have many different paths, but for a set of bytes, you will always follow the same path.
The only way to follow two different paths is when you get two different sets of bytes.

I'm not sure that this needs to be a single FSM.  Why not

[outside filter] -> (bytes) -> [TLV decoder filter] -> (TLVs) -> [LDAP decoder
filter] -> (LDAPmessages) -> [outside filter]

I hear "looping" being a justification but it strikes me that using an FSM obfuscates things
needlessly as I believe that a simple filter will do.

Is there some code I can look at to see your above implementation?  I think here is a perfect
case for code bits to compare.


View raw message