You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by di...@apache.org on 2004/05/01 14:43:12 UTC

cvs commit: jakarta-commons/dbcp/src/test/org/apache/commons/dbcp TestAbandonedObjectPool.java

dirkv       2004/05/01 05:43:12

  Added:       dbcp/src/test/org/apache/commons/dbcp
                        TestAbandonedObjectPool.java
  Log:
  Bugzilla Bug 28579: NumActive can become incorrect when removeAbandoned=true
  - JUnit test written by Wayne Woodfield
  
  Revision  Changes    Path
  1.1                  jakarta-commons/dbcp/src/test/org/apache/commons/dbcp/TestAbandonedObjectPool.java
  
  Index: TestAbandonedObjectPool.java
  ===================================================================
  /*
   * Copyright 1999-2004 The Apache Software Foundation.
   * 
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   * 
   *      http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.commons.dbcp;
  
  import java.util.Vector;
  
  import junit.framework.Test;
  import junit.framework.TestCase;
  import junit.framework.TestSuite;
  
  import org.apache.commons.pool.PoolableObjectFactory;
  
  /**
   * TestCase for AbandonedObjectPool
   * 
   * @author Wayne Woodfield
   * @version $Revision: 1.1 $ $Date: 2004/05/01 12:43:12 $
   */
  public class TestAbandonedObjectPool extends TestCase {
      private AbandonedObjectPool pool = null;
      private AbandonedConfig config = null;
      
      public TestAbandonedObjectPool(String testName) {
          super(testName);
      }
  
      public static Test suite() {
          return new TestSuite(TestAbandonedObjectPool.class);
      }
  
      public void setUp() throws Exception {
          super.setUp();
  		config = new AbandonedConfig();
          
          // -- Uncomment the following line to enable logging -- 
          // config.setLogAbandoned(true);
          
  		config.setRemoveAbandoned(true);
  		config.setRemoveAbandonedTimeout(1);
          pool = new AbandonedObjectPool(new SimpleFactory(), config);
      }
  
      public void tearDown() throws Exception {
          super.tearDown();
          pool.close();
          pool = null;
      }
  
  	/**
  	* Tests fix for Bug 28579, a bug in AbandonedObjectPool that causes numActive to go negative
  	* in GenericObjectPool
  	*/
      public void testConcurrentInvalidation() throws Exception {
          final int POOL_SIZE = 30;
          pool.setMaxActive(POOL_SIZE);
          pool.setMaxIdle(POOL_SIZE);
          pool.setWhenExhaustedAction(AbandonedObjectPool.WHEN_EXHAUSTED_FAIL);
  
          // Exhaust the connection pool
          Vector vec = new Vector();
          for (int i = 0; i < POOL_SIZE; i++) {
              vec.add(pool.borrowObject());
          }
          
          // Abandon all borrowed objects
          for (int i = 0; i < vec.size(); i++) {
              ((PooledTestObject)vec.elementAt(i)).setAbandoned(true);
          }
  
          // Try launching a bunch of borrows concurrently.  Abandoned sweep will be triggered for each.
          final int CONCURRENT_BORROWS = 5;
          Thread[] threads = new Thread[CONCURRENT_BORROWS];
          for (int i = 0; i < CONCURRENT_BORROWS; i++) {
              threads[i] = new ConcurrentBorrower(vec);
              threads[i].start();
          }
  
          // Wait for all the threads to finish
          for (int i = 0; i < CONCURRENT_BORROWS; i++) {
              threads[i].join();
          }
          
          // Return all objects that have not been destroyed
          for (int i = 0; i < vec.size(); i++) {
              PooledTestObject pto = (PooledTestObject)vec.elementAt(i);
              if (pto.isActive()) {
                  pool.returnObject(pto);
              }
          }
          
          // Now, the number of open connections should be 0
          assertTrue("numActive should have been 0, was " + pool.getNumActive(), pool.getNumActive() == 0);
      }
      
      class ConcurrentBorrower extends Thread {
          private Vector _borrowed;
          
          public ConcurrentBorrower(Vector borrowed) {
              _borrowed = borrowed;
          }
          
          public void run() {
              try {
                  _borrowed.add(pool.borrowObject());
              } catch (Exception e) {
                  // expected in most cases
              }
          }
      }
      
      class SimpleFactory implements PoolableObjectFactory {
  
          public Object makeObject() {
              return new PooledTestObject(config);
          }
          
          public boolean validateObject(Object obj) { return true; }
          
          public void activateObject(Object obj) {
              ((PooledTestObject)obj).setActive(true);
          }
          
          public void passivateObject(Object obj) {
              ((PooledTestObject)obj).setActive(false);
          }
  
          public void destroyObject(Object obj) {
              ((PooledTestObject)obj).setActive(false);
              // destroying an object will often take a few milliseconds, especially when the object is a network connection
              try { Thread.sleep(30); }
              catch (InterruptedException e) { }
          }
      }
  }
  
  class PooledTestObject extends AbandonedTrace {
      private boolean active = false;
      private int _hash = 0;
      private boolean _abandoned = false;
  
      private static int hash = 1;
      
      public PooledTestObject(AbandonedConfig config) {
          super(config);
          _hash = hash++;
      }
      
      public synchronized void setActive(boolean b) {
          active = b;
      }
  
      public synchronized boolean isActive() {
          return active;
      }
      
      public int hashCode() {
          return _hash;
      }
      
      public void setAbandoned(boolean b) {
          _abandoned = b;
      }
      
      protected long getLastUsed() {
          if (_abandoned) {
              // Abandoned object sweep will occur no matter what the value of removeAbandonedTimeout,
              // because this indicates that this object was last used decades ago
              return 1;
          } else {
              // Abandoned object sweep won't clean up this object
              return 0;
          }
      }
      
      public boolean equals(Object obj) {
          if (!(obj instanceof PooledTestObject)) return false;
          return obj.hashCode() == hashCode();
      }
  }
  
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org