DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT <http://nagoya.apache.org/bugzilla/show_bug.cgi?id=17990>. ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND INSERTED IN THE BUG DATABASE.
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=17990 Leaking DB connections - synch problem in GenericKeyedObjectPool.returnObject() Summary: Leaking DB connections - synch problem in GenericKeyedObjectPool.returnObject() Product: Commons Version: Nightly Builds Platform: PC OS/Version: Windows NT/2K Status: NEW Severity: Major Priority: Other Component: Pool AssignedTo: [EMAIL PROTECTED] ReportedBy: [EMAIL PROTECTED] I had a problem with "leaking" database connections, using Jdbc2PoolDataSource. I used both commons-dbcp and commons-pool builds from 10.03.2003. JDK was 1.3.1_07 and 1.4.1_02 on Windows 2K, Database was Oracle 8.7.1.3 on HPUX. The symptoms are: - after several minutes of test run value of _totalIdle field keeps increasing (as checked with debugger) - the number of open database connections keeps increasing (as observed on the database) After investigation, I discovered the problem was in GenericKeyedObjectPool.returnObject(). I belive the scenario was as follows: - after evictor removed idle connection, the pool was removed - then if a test thread wished to return a connection (returnObject()), it had to recreate the pool to return the connection to - unfortunately sometimes the pool was recreated by more than one thread - but only one stayed in _poolMap, others were discarded together with the connections. After some changes in synchronization of returnObject(), the problem disapeared. My version of GenericKeyedObjectPool.returnObject(): public void returnObject(Object key, Object obj) throws Exception { // if we need to validate this object, do so boolean success = true; // whether or not this object passed validation if((_testOnReturn && !_factory.validateObject(key, obj))) { success = false; try { _factory.destroyObject(key, obj); } catch(Exception e) { // ignored } } else { try { _factory.passivateObject(key, obj); } catch(Exception e) { success = false; } } boolean shouldDestroy = false; synchronized(this) { // grab the pool (list) of objects associated with the given key CursorableLinkedList pool = (CursorableLinkedList) (_poolMap.get (key)); // if it doesn't exist, create it if(null == pool) { pool = new CursorableLinkedList(); _poolMap.put(key, pool); _poolList.add(key); } // subtract one from the total and keyed active counts _totalActive--; Integer active = (Integer) (_activeMap.get(key)); if(null == active) { // do nothing, either null or zero is OK } else if(active.intValue() <= 1) { _activeMap.remove(key); } else { _activeMap.put(key, new Integer(active.intValue() - 1)); } // if there's no space in the pool, destroy the object // else if we passivated succesfully, return it to the pool if(_maxIdle > 0 && (pool.size() >= _maxIdle)) { shouldDestroy = true; } else if(success) { pool.addFirst(new ObjectTimestampPair(obj)); _totalIdle++; } notifyAll(); } if(shouldDestroy) { try { _factory.destroyObject(key, obj); } catch(Exception e) { // ignored? } } } Please verify this. --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
