Niklas Therning (JIRA) a écrit :

Hi Niklas,

I'm switching to the ML because JIRA may have a problem with too many threads used ;)

[ http://issues.apache.org/jira/browse/DIRMINA-197?page=comments#action_12373020 ]
Niklas Therning commented on DIRMINA-197:
-----------------------------------------

You say that you only call bind/unbind?
Yep

There are no clients connecting at all?
I have wrote an injector that simulates clients. Right now, I just do N times Bind/Unbind.

If there are no clients I can't understand why a ThreadPoolFilter would be created in the first place.
Each Bind is issued by what we can call a Client. So it makes sense that a thread handle the request.

Maybe you could post your test code to clarify things?
yep, of course. Attached.

If there are clients connecting I think the problem could be that a new ThreadPoolFilter is created for each new session.
That's it.

You see, when a new session is created the ThreadModel, used when binding the 
Acceptor to the port, will be asked to modify the new session's filter chain. 
I've had a look at the code and it seems to me that the default ThreadModel 
implementation (PooledThreadModel) creates a new ThreadPoolFilter for each new 
session which it adds to the start of the session's chain. I don't think this 
is what was intended. It could be bug.
I don't know. However, I was expecting the thread to be destroyed when I unbind, as I'm closing the socket. Another solution is to create a threads pool to deal with all those sessions. I suppose that the PooledThreadModel is the perfect class for that, but ...

To verify that this is the problem you could implement your own ThreadModel and in its buildFilterChain() method you always add the same ThreadPoolFilter instance to the chain instead of creating a new every time like PooledThreadModel does.
Yeah, maybe. However, the PooledThreadModel, which is a subclass of ThreadModel is supposed to be a pool, but it only pools worker threads. I don't why if it's a bug in the design, or if it's done on purpose. Trustin might know !

You can set a non-default ThreadModel by specifying an IoServiceConfig when 
calling bind() on your acceptor.

All of this is only my guess though and I may have completely misunderstood how 
the new ThreadModel stuff work. :)
Me neither :) Mina is still a mistery to me. I never had time to deepen my knowledge of MINA.

Thanks a lot for the help !


package org.apache.directory.tester;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;

import org.apache.directory.shared.asn1.ber.Asn1Decoder;
import org.apache.directory.shared.asn1.ber.IAsn1Container;
import org.apache.directory.shared.asn1.ber.tlv.TLVStateEnum;
import org.apache.directory.shared.asn1.codec.DecoderException;
import org.apache.directory.shared.asn1.codec.EncoderException;
import org.apache.directory.shared.ldap.codec.LdapDecoder;
import org.apache.directory.shared.ldap.codec.LdapMessage;
import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
import org.apache.directory.shared.ldap.codec.bind.BindRequest;
import org.apache.directory.shared.ldap.codec.bind.BindResponse;
import org.apache.directory.shared.ldap.codec.bind.LdapAuthentication;
import org.apache.directory.shared.ldap.codec.bind.SimpleAuthentication;
import org.apache.directory.shared.ldap.codec.extended.ExtendedResponse;
import org.apache.directory.shared.ldap.codec.unbind.UnBindRequest;
import org.apache.directory.shared.ldap.util.StringTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Agent 
{
    private static final Logger log = LoggerFactory.getLogger( Agent.class );
    private SocketChannel channel;
    private SocketAddress serverAddress;
        private OutputStream    serverOut;
        private InputStream     serverIn;
        private int messageId = 0;
    private IAsn1Container ldapMessageContainer = new LdapMessageContainer();
        private Asn1Decoder ldapDecoder = new LdapDecoder();
        
        public void bind( String host, int port, String rootdn, Name name, 
String password )
                throws Exception 
        {
                LdapMessage message = new LdapMessage();
                message.setMessageId( messageId++ );
                
                LdapMessage bind = new BindRequest();
                
                bind.setMessageId( messageId );
                ((BindRequest)bind).setVersion( 3 );
                SimpleAuthentication auth = new SimpleAuthentication();
                auth.setSimple( StringTools.getBytesUtf8( password ) );
                
                ((BindRequest)bind).setAuthentication( auth );
                ((BindRequest)bind).setName( name );
                message.setProtocolOP( bind );
                
                ByteBuffer bb = message.encode( null );
                bb.flip();
                
                serverAddress = new InetSocketAddress( host, port );

                channel = SocketChannel.open( serverAddress ); 

                channel.configureBlocking( true );
                
                channel.write( bb );
                bb.clear();
                
                while (true)
                {
                        int nbRead = channel.read( bb );
                        
                        if (nbRead == -1)
                        {
                                break;
                        }
                        else
                        {
                                bb.flip();
                        // Decode the PDU
                        ldapDecoder.decode( bb, ldapMessageContainer );
                                
                        if ( ldapMessageContainer.getState() == 
TLVStateEnum.PDU_DECODED )
                        {
                                LdapMessage messageResp = 
((LdapMessageContainer)ldapMessageContainer).getLdapMessage();
                                
                                if ( messageResp instanceof BindResponse )
                                {
                                        BindResponse resp = 
((LdapMessageContainer)ldapMessageContainer).getLdapMessage().getBindResponse();

                                        if 
(resp.getLdapResult().getResultCode() != 0 )
                                        {
                                                System.out.println( "Error : " 
+ resp.getLdapResult().getErrorMessage() );
                                        }
                                }
                                else if (messageResp instanceof 
ExtendedResponse )
                                {
                                        ExtendedResponse resp = 
((LdapMessageContainer)ldapMessageContainer).getLdapMessage().getExtendedResponse();
                                        
                                        if 
(resp.getLdapResult().getResultCode() != 0 )
                                        {
                                                System.out.println( "Error : " 
+ resp.getLdapResult().getErrorMessage() );
                                        }
                                }
                                
                                
                                //System.out.println( 
((LdapMessageContainer)ldapMessageContainer).getLdapMessage() );
                                
((LdapMessageContainer)ldapMessageContainer).clean();
                                break;
                        }
                        else
                        {
                                bb.flip();
                        }
                        }
                }
        }
        
        public void unbind() throws Exception 
        {
                LdapMessage message = new LdapMessage();
                message.setMessageId( messageId++ );
                
                LdapMessage unbind = new UnBindRequest();
                
                unbind.setMessageId( messageId );
                message.setProtocolOP( unbind );
                
                ByteBuffer bb = message.encode( null );
                bb.flip();
                
                channel.write( bb );
                bb.clear();
                channel.close();
        }

        /**
         * connect to server
         * 
         * @param host
         *            Description of Parameter
         * @param username
         *            Description of Parameter
         * @param password
         *            Description of Parameter
         * @exception NamingException
         *                Description of Exception
         */
        public DirContext bind( String host, String port, String rootdn, String 
username, String password )
                        throws NamingException {
                DirContext dirContext;
                Hashtable env = new Hashtable();
                env.put(Context.INITIAL_CONTEXT_FACTORY, 
"com.sun.jndi.ldap.LdapCtxFactory");
                env.put(Context.PROVIDER_URL, "ldap://"; + host + ":" + port + 
"/" + rootdn);
                env.put(Context.SECURITY_CREDENTIALS, password);
                env.put(Context.SECURITY_PRINCIPAL, username);
                
                log.debug ( "Binding ..." );
                
                dirContext = new InitialDirContext(env);
                
                log.debug ( "Bound!" );
                return dirContext;
        }

    private String decode( ByteBuffer buffer ) throws DecoderException
    {
        Asn1Decoder ldapDecoder = new LdapDecoder();

        // Allocate a LdapMessageContainer Container
        IAsn1Container ldapMessageContainer = new LdapMessageContainer();

        // Decode the PDU
        ldapDecoder.decode( buffer, ldapMessageContainer );

        // Check that everything is OK
        LdapMessage ldapMessage = ( (LdapMessageContainer) ldapMessageContainer 
).getLdapMessage();

        return ldapMessage.toString();
    }
    
        /**
         * disconnect from the server
         */
        public void unbind( DirContext dirContext ) {
                if (dirContext == null) {
                        log.info("Cannot disconnect null context");
                        return;
                }

                try {
                        log.debug ( "Unbinding ..." );
                        dirContext.close();
                        log.debug ( "Unbound !" );
                } catch (NamingException e) {
                        log.warn("Ldap client disconnect - ", e);
                }
        }
        
        
/***************************************************************************
         * Filter the data in the ldap directory for the given search base
         * 
         * @param search
         *            base where the search should start
         * @param search
         *            filter filter this value from the base
         
**************************************************************************/
        public NamingEnumeration searchTest(DirContext dirContext, 
                                String searchBase, 
                                String searchFilter, 
                                int scope, 
                                long countlim,
                                int timelim, 
                                String[] attrs, 
                                boolean retobj, 
                                boolean deref) throws NamingException {
                SearchControls searchcontrols = null;
                searchcontrols = new SearchControls();
                searchcontrols.setSearchScope(scope);
                NamingEnumeration answer = dirContext.search(searchBase, 
searchFilter, searchcontrols);
                return answer;
        }
}
package org.apache.directory.tester;

import javax.naming.InvalidNameException;
import javax.naming.Name;
import javax.naming.NamingEnumeration;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

import org.apache.directory.shared.ldap.codec.bind.LdapAuthentication;
import org.apache.directory.shared.ldap.codec.bind.SimpleAuthentication;
import org.apache.directory.shared.ldap.name.LdapDN;
import org.apache.directory.shared.ldap.util.StringTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Injector extends Thread {
    private static final Logger log = LoggerFactory.getLogger( Injector.class );
        private static int nbSearches;
        static Object lock = new Object();
        static int nbTh = 0;
    
    static 
    {
        try
        {
                final Name name = new LdapDN( "uid=admin,ou=system" );
        }
        catch (Exception e)
        {
                
        }
    }

    public void run()
    {
        Agent ldapAgent = new Agent();
                LdapAuthentication simple = new SimpleAuthentication();
                ( (SimpleAuthentication)simple ).setSimple( 
StringTools.getBytesUtf8( "secret" ) );
                
                long t0 = System.currentTimeMillis();
                System.out.println( this.currentThread().getId() + " starts " );
                
                try
                {
                        for (int j= 0; j < nbSearches; j++ )
                        {
                                if ( j%100 == 0 )
                                {
                                        System.out.println(j);
                                }
                                
                                log.debug( "(" + j + ")Searching..." );
                                ldapAgent.bind( "localhost", 10389, "", new 
LdapDN( "uid=admin,ou=system" ), "secret" );
                        
                                /*
                                DirContext context = null;

                                for (int j= 0; j < nbSearches; j++ )
                                {
                                        if ( j%100 == 0 )
                                        {
                                                System.out.println(j);
                                        }
                                        
                                        log.debug( "(" + j + ")Searching..." );
                                        NamingEnumeration res = 
ldapAgent.searchTest( context, "ou=users,ou=system", "(cn=ele*)", 
SearchControls.SUBTREE_SCOPE, 0L, 0, new String[]{}, false, false );
                                        log.debug( "Found !" );
                                        
                                        if ( log.isDebugEnabled() )
                                        {
                                                if ( ( res == null ) || ( 
res.hasMore() == false ) )
                                                {
                                                        log.debug( "(" + j + 
")Not found..." + ( res == null ? "Null" : "no elem" ) );
                                                }
                                                else
                                                {
                                                        while ( ( res != null ) 
&& ( res.hasMore() ) )
                                                        {
                                                                SearchResult sr 
= (SearchResult)res.next();
                                                                
                                                                log.debug( "(" 
+ j + ")Found name = " + sr.getName() );
                                                        }
                                                }
                                        }
                                }
                                */
                                
                                ldapAgent.unbind();
                        }
                }
                catch ( Exception e)
                {
                        e.printStackTrace();
                }

                System.out.println( this.currentThread().getId() + " ends : " + 
( System.currentTimeMillis() - t0 ) );
    }
    
        /**
         * @param args
         */
        public static void main(String[] args) throws Exception 
        {
                // TODO Auto-generated method stub
                Agent ldapAgent = new Agent();
                
                LdapAuthentication simple = new SimpleAuthentication();
                ( (SimpleAuthentication)simple ).setSimple( 
StringTools.getBytesUtf8( "secret" ) );
                
                Name name = new LdapDN( "uid=admin,ou=system" );
                
                int nbThreads = 1;
                long t0 = System.currentTimeMillis();
                nbSearches = 10000;
                
                System.out.println( "Test starts ");

                for (int i = 0; i < nbThreads; i++ )
                {
                        
                        Injector in = new Injector();
                        in.start();
                }
                
                System.out.println( "Test ends : " + ( 
System.currentTimeMillis() - t0 ) );
        }
}

Reply via email to