При использовании пула подключений LDAP я заметил, что вызов close()
в контексте не возвращает его в пул, несмотря на то, что в документации говоритсяиначе . Таким образом, когда я пытаюсь получить элемент из пула, когда он уже имеет максимальный размер, он зависает.
Мне удалось сузить его до минимального случая. Несмотря на то, что я полагаю, что вызываю close()
для всех соответствующих объектов детерминистически, кажется, что он полагается на сборку мусора, чтобы фактически вернуть объекты в пул, что неожиданно. Почему это происходит? Есть ли какой-то другой объект, который я должен закрыть?
Во фрагменте кода ниже:
DirContext
из пула (строка (2 )), пытаюсь вернуть его в пул (строка (4 )), затем получаю еще один из пула (строка (6 )), которая должна возвращать тот же возвращаемый объект.Object.wait()
. Я предполагаю, что он ждет, пока объект из пула станет доступным.SearchResults.next()
-это работает нормально.Поскольку закомментирование строки (3 )устраняет проблему, возможно, я неправильно закрываю возвращаемое значение, и это держит соединение в пуле открытым. Однако,метод results.next()
возвращаетSearchResult
в этом случае, у которого нет метода close
и в его документации нет руководства о том, как его закрыть.
Тестовый случай:
@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 env = new Hashtable();
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 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)
}
С кодом как есть моя консоль показывает:
Create com.sun.jndi.ldap.LdapClient@1a7bf11[ldapad:389]
Use com.sun.jndi.ldap.LdapClient@1a7bf11
В то время как если я форсирую сборщик мусора, я дополнительно вижу:
Release com.sun.jndi.ldap.LdapClient@93dee9 <-- on GC
Use com.sun.jndi.ldap.LdapClient@93dee9 <-- on new InitialDirContext