Add config options of LDAP 'connection pooling'
With these config options user can enable LDAP 'connection pooling' for Helper.open() to improve the performance of LDAP server access. Change-Id: If1c7bb5a9f5824aaa0bd71e8419b91a8f588493d
This commit is contained in:
		| @@ -2369,6 +2369,91 @@ On Windows servers the registry key `HKEY_LOCAL_MACHINE\System\CurrentControlSet | |||||||
| must have the DWORD value `allowtgtsessionkey` set to 1 and the account must not | must have the DWORD value `allowtgtsessionkey` set to 1 and the account must not | ||||||
| have local administrator privileges. | have local administrator privileges. | ||||||
|  |  | ||||||
|  | [[ldap.useConnectionPooling]]ldap.useConnectionPooling:: | ||||||
|  | + | ||||||
|  | _(Optional)_ Enable the LDAP connection pooling or not. | ||||||
|  | + | ||||||
|  | If it is true, the LDAP service provider maintains a pool of (possibly) | ||||||
|  | previously used connections and assigns them to a Context instance as | ||||||
|  | needed. When a Context instance is done with a connection (closed or | ||||||
|  | garbage collected), the connection is returned to the pool for future use. | ||||||
|  | + | ||||||
|  | For details, see link:http://docs.oracle.com/javase/tutorial/jndi/ldap/pool.html[ | ||||||
|  | LDAP connection management (Pool)] and link:http://docs.oracle.com/javase/tutorial/jndi/ldap/config.html[ | ||||||
|  | LDAP connection management (Configuration)] | ||||||
|  | + | ||||||
|  | By default, false. | ||||||
|  |  | ||||||
|  | [[ldap.connectTimeout]]ldap.connectTimeout:: | ||||||
|  | + | ||||||
|  | _(Optional)_ Specify how long to wait for a pooled connection. | ||||||
|  | This is also used to specify a timeout period for establishment | ||||||
|  | of the LDAP connection. | ||||||
|  | + | ||||||
|  | The value is in the usual time-unit format like "1 s", "100 ms", | ||||||
|  | etc... | ||||||
|  | + | ||||||
|  | By default there is no timeout and Gerrit will wait indefinitely. | ||||||
|  |  | ||||||
|  | [[ldap.poolAuthentication]]ldap.poolAuthentication:: | ||||||
|  | + | ||||||
|  | _(Optional)_  A list of space-separated authentication types of | ||||||
|  | connections that may be pooled. Valid types are "none", "simple", | ||||||
|  | and "DIGEST-MD5". | ||||||
|  | + | ||||||
|  | Default is "none simple". | ||||||
|  |  | ||||||
|  | [[ldap.poolDebug]]ldap.poolDebug:: | ||||||
|  | + | ||||||
|  | _(Optional)_  A string that indicates the level of debug output | ||||||
|  | to produce. Valid values are "fine" (trace connection creation | ||||||
|  | and removal) and "all" (all debugging information). | ||||||
|  |  | ||||||
|  | [[ldap.poolInitsize]]ldap.poolInitsize:: | ||||||
|  | + | ||||||
|  | _(Optional)_ The string representation of an integer that | ||||||
|  | represents the number of connections per connection identity | ||||||
|  | to create when initially creating a connection for the identity. | ||||||
|  | + | ||||||
|  | Default is 1. | ||||||
|  |  | ||||||
|  | [[ldap.poolMaxsize]]ldap.poolMaxsize:: | ||||||
|  | + | ||||||
|  | _(Optional)_ The string representation of an integer that | ||||||
|  | represents the maximum number of connections per connection | ||||||
|  | identity that can be maintained concurrently. | ||||||
|  | + | ||||||
|  | Default is 0, means that there is no maximum size: A request for | ||||||
|  | a pooled connection will use an existing pooled idle connection | ||||||
|  | or a newly created pooled connection. | ||||||
|  |  | ||||||
|  | [[ldap.poolPrefsize]]ldap.poolPrefsize:: | ||||||
|  | + | ||||||
|  | _(Optional)_ The string representation of an integer that | ||||||
|  | represents the preferred number of connections per connection | ||||||
|  | identity that should be maintained concurrently. | ||||||
|  | + | ||||||
|  | Default is 0, means that there is no preferred size: A request | ||||||
|  | for a pooled connection will result in a newly created connection | ||||||
|  | only if no idle ones are available. | ||||||
|  |  | ||||||
|  | [[ldap.poolProtocol]]ldap.poolProtocol:: | ||||||
|  | + | ||||||
|  | _(Optional)_  A list of space-separated protocol types of | ||||||
|  | connections that may be pooled. Valid types are "plain" and "ssl". | ||||||
|  | + | ||||||
|  | Default is "plain". | ||||||
|  |  | ||||||
|  | [[ldap.poolTimeout]]ldap.poolTimeout:: | ||||||
|  | + | ||||||
|  | _(Optional)_ Specify how long an idle connection may remain | ||||||
|  | in the pool without being closed and removed from the pool. | ||||||
|  | + | ||||||
|  | The value is in the usual time-unit format like "1 s", "100 ms", | ||||||
|  | etc... | ||||||
|  | + | ||||||
|  | By default there is no timeout. | ||||||
|  |  | ||||||
| [[mimetype]] | [[mimetype]] | ||||||
| === Section mimetype | === Section mimetype | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,6 +17,7 @@ package com.google.gerrit.server.auth.ldap; | |||||||
| import com.google.common.base.Throwables; | import com.google.common.base.Throwables; | ||||||
| import com.google.common.cache.Cache; | import com.google.common.cache.Cache; | ||||||
| import com.google.common.collect.ImmutableSet; | import com.google.common.collect.ImmutableSet; | ||||||
|  | import com.google.common.collect.Maps; | ||||||
| import com.google.gerrit.common.data.ParameterizedString; | import com.google.gerrit.common.data.ParameterizedString; | ||||||
| import com.google.gerrit.reviewdb.client.AccountGroup; | import com.google.gerrit.reviewdb.client.AccountGroup; | ||||||
| import com.google.gerrit.server.account.AccountException; | import com.google.gerrit.server.account.AccountException; | ||||||
| @@ -37,6 +38,7 @@ import java.util.Collections; | |||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
| import java.util.HashSet; | import java.util.HashSet; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
| import java.util.Properties; | import java.util.Properties; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.concurrent.TimeUnit; | import java.util.concurrent.TimeUnit; | ||||||
| @@ -58,6 +60,42 @@ import javax.security.auth.login.LoginException; | |||||||
| @Singleton class Helper { | @Singleton class Helper { | ||||||
|   static final String LDAP_UUID = "ldap:"; |   static final String LDAP_UUID = "ldap:"; | ||||||
|  |  | ||||||
|  |   static private Map<String, String> getPoolProperties(Config config) { | ||||||
|  |     if (LdapRealm.optional(config, "useConnectionPooling", false)) { | ||||||
|  |       Map<String, String> r = Maps.newHashMap(); | ||||||
|  |       r.put("com.sun.jndi.ldap.connect.pool", "true"); | ||||||
|  |  | ||||||
|  |       String connectTimeout = LdapRealm.optional(config, "connectTimeout"); | ||||||
|  |       String poolDebug = LdapRealm.optional(config, "poolDebug"); | ||||||
|  |       String poolTimeout = LdapRealm.optional(config, "poolTimeout"); | ||||||
|  |  | ||||||
|  |       if (connectTimeout != null) { | ||||||
|  |         r.put("com.sun.jndi.ldap.connect.timeout", Long.toString(ConfigUtil | ||||||
|  |             .getTimeUnit(connectTimeout, 0, TimeUnit.MILLISECONDS))); | ||||||
|  |       } | ||||||
|  |       r.put("com.sun.jndi.ldap.connect.pool.authentication", | ||||||
|  |           LdapRealm.optional(config, "poolAuthentication", "none simple")); | ||||||
|  |       if (poolDebug != null) { | ||||||
|  |         r.put("com.sun.jndi.ldap.connect.pool.debug", poolDebug); | ||||||
|  |       } | ||||||
|  |       r.put("com.sun.jndi.ldap.connect.pool.initsize", | ||||||
|  |           String.valueOf(LdapRealm.optional(config, "poolInitsize", 1))); | ||||||
|  |       r.put("com.sun.jndi.ldap.connect.pool.maxsize", | ||||||
|  |           String.valueOf(LdapRealm.optional(config, "poolMaxsize", 0))); | ||||||
|  |       r.put("com.sun.jndi.ldap.connect.pool.prefsize", | ||||||
|  |           String.valueOf(LdapRealm.optional(config, "poolPrefsize", 0))); | ||||||
|  |       r.put("com.sun.jndi.ldap.connect.pool.protocol", | ||||||
|  |           LdapRealm.optional(config, "poolProtocol", "plain")); | ||||||
|  |       if (poolTimeout != null) { | ||||||
|  |         r.put("com.sun.jndi.ldap.connect.pool.timeout", Long | ||||||
|  |             .toString(ConfigUtil.getTimeUnit(poolTimeout, 0, | ||||||
|  |                 TimeUnit.MILLISECONDS))); | ||||||
|  |       } | ||||||
|  |       return r; | ||||||
|  |     } | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   private final Cache<String, ImmutableSet<String>> groupsByInclude; |   private final Cache<String, ImmutableSet<String>> groupsByInclude; | ||||||
|   private final Config config; |   private final Config config; | ||||||
|   private final String server; |   private final String server; | ||||||
| @@ -68,6 +106,7 @@ import javax.security.auth.login.LoginException; | |||||||
|   private final String authentication; |   private final String authentication; | ||||||
|   private volatile LdapSchema ldapSchema; |   private volatile LdapSchema ldapSchema; | ||||||
|   private final String readTimeOutMillis; |   private final String readTimeOutMillis; | ||||||
|  |   private final Map<String, String> connectionPoolConfig; | ||||||
|  |  | ||||||
|   @Inject |   @Inject | ||||||
|   Helper(@GerritServerConfig final Config config, |   Helper(@GerritServerConfig final Config config, | ||||||
| @@ -76,10 +115,11 @@ import javax.security.auth.login.LoginException; | |||||||
|     this.config = config; |     this.config = config; | ||||||
|     this.server = LdapRealm.optional(config, "server"); |     this.server = LdapRealm.optional(config, "server"); | ||||||
|     this.username = LdapRealm.optional(config, "username"); |     this.username = LdapRealm.optional(config, "username"); | ||||||
|     this.password = LdapRealm.optional(config, "password"); |     this.password = LdapRealm.optional(config, "password", ""); | ||||||
|     this.referral = LdapRealm.optional(config, "referral"); |     this.referral = LdapRealm.optional(config, "referral", "ignore"); | ||||||
|     this.sslVerify = config.getBoolean("ldap", "sslverify", true); |     this.sslVerify = config.getBoolean("ldap", "sslverify", true); | ||||||
|     this.authentication = LdapRealm.optional(config, "authentication"); |     this.authentication = | ||||||
|  |         LdapRealm.optional(config, "authentication", "simple"); | ||||||
|     String timeout = LdapRealm.optional(config, "readTimeout"); |     String timeout = LdapRealm.optional(config, "readTimeout"); | ||||||
|     if (timeout != null) { |     if (timeout != null) { | ||||||
|       readTimeOutMillis = |       readTimeOutMillis = | ||||||
| @@ -89,6 +129,7 @@ import javax.security.auth.login.LoginException; | |||||||
|       readTimeOutMillis = null; |       readTimeOutMillis = null; | ||||||
|     } |     } | ||||||
|     this.groupsByInclude = groupsByInclude; |     this.groupsByInclude = groupsByInclude; | ||||||
|  |     this.connectionPoolConfig = getPoolProperties(config); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private Properties createContextProperties() { |   private Properties createContextProperties() { | ||||||
| @@ -107,14 +148,17 @@ import javax.security.auth.login.LoginException; | |||||||
|  |  | ||||||
|   DirContext open() throws NamingException, LoginException { |   DirContext open() throws NamingException, LoginException { | ||||||
|     final Properties env = createContextProperties(); |     final Properties env = createContextProperties(); | ||||||
|     env.put(Context.SECURITY_AUTHENTICATION, authentication != null ? authentication : "simple"); |     if (connectionPoolConfig != null) { | ||||||
|     env.put(Context.REFERRAL, referral != null ? referral : "ignore"); |       env.putAll(connectionPoolConfig); | ||||||
|  |     } | ||||||
|  |     env.put(Context.SECURITY_AUTHENTICATION, authentication); | ||||||
|  |     env.put(Context.REFERRAL, referral); | ||||||
|     if ("GSSAPI".equals(authentication)) { |     if ("GSSAPI".equals(authentication)) { | ||||||
|       return kerberosOpen(env); |       return kerberosOpen(env); | ||||||
|     } else { |     } else { | ||||||
|       if (username != null) { |       if (username != null) { | ||||||
|         env.put(Context.SECURITY_PRINCIPAL, username); |         env.put(Context.SECURITY_PRINCIPAL, username); | ||||||
|         env.put(Context.SECURITY_CREDENTIALS, password != null ? password : ""); |         env.put(Context.SECURITY_CREDENTIALS, password); | ||||||
|       } |       } | ||||||
|       return new InitialDirContext(env); |       return new InitialDirContext(env); | ||||||
|     } |     } | ||||||
| @@ -146,8 +190,8 @@ import javax.security.auth.login.LoginException; | |||||||
|     final Properties env = createContextProperties(); |     final Properties env = createContextProperties(); | ||||||
|     env.put(Context.SECURITY_AUTHENTICATION, "simple"); |     env.put(Context.SECURITY_AUTHENTICATION, "simple"); | ||||||
|     env.put(Context.SECURITY_PRINCIPAL, dn); |     env.put(Context.SECURITY_PRINCIPAL, dn); | ||||||
|     env.put(Context.SECURITY_CREDENTIALS, password != null ? password : ""); |     env.put(Context.SECURITY_CREDENTIALS, password); | ||||||
|     env.put(Context.REFERRAL, referral != null ? referral : "ignore"); |     env.put(Context.REFERRAL, referral); | ||||||
|     try { |     try { | ||||||
|       return new InitialDirContext(env); |       return new InitialDirContext(env); | ||||||
|     } catch (NamingException e) { |     } catch (NamingException e) { | ||||||
|   | |||||||
| @@ -106,6 +106,22 @@ public class LdapRealm implements Realm { | |||||||
|     return config.getString("ldap", null, name); |     return config.getString("ldap", null, name); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   static int optional(Config config, String name, int defaultValue) { | ||||||
|  |     return config.getInt("ldap", name, defaultValue); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static String optional(Config config, String name, String defaultValue) { | ||||||
|  |     final String v = optional(config, name); | ||||||
|  |     if (Strings.isNullOrEmpty(v)) { | ||||||
|  |       return defaultValue; | ||||||
|  |     } | ||||||
|  |     return v; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static boolean optional(Config config, String name, boolean defaultValue) { | ||||||
|  |     return config.getBoolean("ldap", name, defaultValue); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   static String required(final Config config, final String name) { |   static String required(final Config config, final String name) { | ||||||
|     final String v = optional(config, name); |     final String v = optional(config, name); | ||||||
|     if (v == null || "".equals(v)) { |     if (v == null || "".equals(v)) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Bruce Zu
					Bruce Zu