Me di cuenta al utilizar un grupo de conexiones LDAP que llamar al close()
en el contexto no parecía devolverlo al grupo, a pesar de la documentación sayingotherwise. Por lo tanto, cuando intento obtener un elemento del grupo cuando ya está en su tamaño máximo, se cuelga.¿Por qué no DirContext.close() devuelve la conexión LDAP al grupo?
Logré reducirlo a una caja mínima. Aunque creo que llamo al close()
en todos los objetos relevantes de manera determinista, parece depender de la recolección de basura para devolver objetos al grupo, lo cual es inesperado. ¿Por qué está pasando esto? ¿Hay algún otro objeto que deba cerrar?
En el siguiente fragmento de código:
- He configurado artificialmente el tamaño de grupo máximo a 1 para resaltar el problema.
- Obtengo
DirContext
del grupo (línea (2)), intento devolverlo al grupo (línea (4)), luego obtengo otro del grupo (línea (6)) que debería devolver el mismo , objeto devuelto - en su lugar, la segunda solicitud (línea (6)) se cuelga en alguna llamada interna al
Object.wait()
. Supongo que está esperando que un objeto agrupado esté disponible. - si desactiva la agrupación comentando (1), no se cuelga (¡pero quiero agrupar!).
- si hago un comentario (3) - una llamada al
SearchResults.next()
- funciona bien. - si elimino el comentario de la línea (5) para forzar la recolección de elementos no utilizados entre la llamada 'devolver a la agrupación' y la solicitud de un nuevo objeto al grupo, no se cuelga.
Como comentar la línea (3) hace que el problema desaparezca, quizás no estoy cerrando correctamente el valor de retorno y mantiene abierta la conexión agrupada. Sin embargo, el método results.next()
devuelve SearchResult
en este caso, que no tiene el método close
y no hay instrucciones en su documentación sobre cómo cerrarlo limpiamente.
El caso de prueba:
@Test
public void testHangs() throws NamingException {
System.setProperty("com.sun.jndi.ldap.connect.pool.debug", "fine");
System.setProperty("com.sun.jndi.ldap.connect.pool.maxsize", "1");
Hashtable<String,String> env = new Hashtable<String,String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_PRINCIPAL, user);
env.put(Context.SECURITY_CREDENTIALS, passwd);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.PROVIDER_URL, ldapUrl);
// use a connection pool
env.put("com.sun.jndi.ldap.connect.pool", "true"); // ----------------- (1)
// get a context from the pool.
DirContext context = new InitialDirContext(env); // -------------------- (2)
NamingEnumeration<SearchResult> results = context.search("", query, getSC());
// obviously the next two lines would normally be in a
// while(results.hasMore()) { ... = results.next(); } loop.
assertTrue(results.hasMore()); // this is only a problem when there are some results.
results.next(); // ----------------------------------------------------- (3)
// ensure the context is returned to the pool.
results.close();
context.close(); // ---------------------------------------------------- (4)
//System.gc(); // ------------------------------------------------------ (5)
new InitialDirContext(env); // hangs here! ---------------------------- (6)
}
Con el código tal como es, mi consola muestra:
Create [email protected][ldapad:389]
Use [email protected]
Mientras que si fuerzo al CG I, además, veo:
Release [email protected] <-- on GC
Use [email protected] <-- on new InitialDirContext
Gracias! Es frustrante que la documentación indique que para que el proveedor de LDAP administre adecuadamente las conexiones agrupadas, debe ser diligente al invocar Context.close() en contextos que ya no necesita, pero no explica cómo hacerlo de manera significativa. esto tampoco le dice qué objetos provistos pueden ellos mismos hacerse cargo de estos objetos que también necesitan cerrarse. – bacar
Si continúa el ciclo hasta que 'results.next()' devuelve falso, la conexión se cierra automáticamente. – EJP