Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 edu.illinois.enforcemop.examples.apache.pool; import java.util.NoSuchElementException; import java.util.Random; import org.apache.commons.pool.BasePoolableObjectFactory; import org.apache.commons.pool.ObjectPool; import org.apache.commons.pool.PoolUtils; import org.apache.commons.pool.PoolableObjectFactory; import org.apache.commons.pool.impl.GenericObjectPool; import org.junit.Test; import org.junit.Before; import org.junit.After; import static org.junit.Assert.*; /** * @author Rodney Waldhoff * @author Dirk Verbeeck * @author Sandy McArthur * @version $Revision: 901944 $ $Date: 2010-01-21 18:27:04 -0600 (Thu, 21 Jan * 2010) $ */ public class TestGenericObjectPool { public TestGenericObjectPool() { //super("TestGenericObjectPool"); } protected ObjectPool makeEmptyPool(int mincap) { GenericObjectPool pool = new GenericObjectPool(new SimpleFactory()); pool.setMaxActive(mincap); pool.setMaxIdle(mincap); return pool; } protected ObjectPool makeEmptyPool(final PoolableObjectFactory factory) { return new GenericObjectPool(factory); } protected Object getNthObject(int n) { return String.valueOf(n); } public void setUp() throws Exception { //super.setUp(); pool = new GenericObjectPool(new SimpleFactory()); } public void tearDown() throws Exception { //super.tearDown(); pool.clear(); pool.close(); pool = null; } @Test public void testWhenExhaustedBlockInterruptImproved() throws Exception { this.setUp(); pool.setMaxActive(1); pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); pool.setMaxWait(0); Object obj1 = pool.borrowObject(); // Make sure on object was obtained assertNotNull(obj1); // Create a separate thread to try and borrow another object NonWaitingTestThread nwtt = new NonWaitingTestThread(pool); nwtt.start(); // Give wtt time to start Thread.sleep(200); nwtt.interrupt(); // Give interupt time to take effect Thread.sleep(200); // Check thread was interrupted // assertTrue(wtt._thrown instanceof InterruptedException); // Return object to the pool pool.returnObject(obj1); // Bug POOL-162 - check there is now an object in the pool pool.setMaxWait(10L); Object obj2 = null; try { obj2 = pool.borrowObject(); assertNotNull(obj2); } catch (NoSuchElementException e) { // Not expected if (nwtt._thrown instanceof InterruptedException) { fail("NoSuchElementException not expected"); } } pool.returnObject(obj2); pool.close(); } @Test // @Schedule(name = "whenExhaustedBlockInterupt", value = "[beforeBorrow:afterBorrow]@borrowThread->beforeInterrupt@main,"+ // "afterThrow@borrowThread->beforeCheck@main") public void testWhenExhaustedBlockInterrupt() throws Exception { this.setUp(); pool.setMaxActive(1); pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); pool.setMaxWait(0); Object obj1 = pool.borrowObject(); // Make sure on object was obtained assertNotNull(obj1); // Create a separate thread to try and borrow another object WaitingTestThread wtt = new WaitingTestThread(pool, 200); wtt.setName("borrowThread"); wtt.start(); // Give wtt time to start Thread.sleep(200); wtt.interrupt(); // Give interupt time to take effect Thread.sleep(200); // Check thread was interrupted assertTrue(wtt._thrown instanceof InterruptedException); // Return object to the pool pool.returnObject(obj1); // Bug POOL-162 - check there is now an object in the pool pool.setMaxWait(10L); Object obj2 = null; try { obj2 = pool.borrowObject(); assertNotNull(obj2); } catch (NoSuchElementException e) { // Not expected fail("NoSuchElementException not expected"); } pool.returnObject(obj2); pool.close(); this.tearDown(); } public void testWhenExhaustedGrow() throws Exception { pool.setMaxActive(1); pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_GROW); Object obj1 = pool.borrowObject(); assertNotNull(obj1); Object obj2 = pool.borrowObject(); assertNotNull(obj2); pool.returnObject(obj2); pool.returnObject(obj1); pool.close(); } public void testWhenExhaustedFail() throws Exception { pool.setMaxActive(1); pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL); Object obj1 = pool.borrowObject(); assertNotNull(obj1); try { pool.borrowObject(); fail("Expected NoSuchElementException"); } catch (NoSuchElementException e) { // expected } pool.returnObject(obj1); assertEquals(1, pool.getNumIdle()); pool.close(); } public void testWhenExhaustedBlock() throws Exception { pool.setMaxActive(1); pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); pool.setMaxWait(10L); Object obj1 = pool.borrowObject(); assertNotNull(obj1); try { pool.borrowObject(); fail("Expected NoSuchElementException"); } catch (NoSuchElementException e) { // expected } pool.returnObject(obj1); pool.close(); } public void testEvictWhileEmpty() throws Exception { pool.evict(); pool.evict(); pool.close(); } /** * Tests addObject contention between ensureMinIdle triggered by the Evictor * with minIdle > 0 and borrowObject. */ public void testEvictAddObjects() throws Exception { SimpleFactory factory = new SimpleFactory(); factory.setMakeLatency(300); factory.setMaxActive(2); GenericObjectPool pool = new GenericObjectPool(factory); pool.setMaxActive(2); pool.setMinIdle(1); pool.borrowObject(); // numActive = 1, numIdle = 0 // Create a test thread that will run once and try a borrow after // 150ms fixed delay TestThread borrower = new TestThread(pool, 1, 150, false); Thread borrowerThread = new Thread(borrower); // Set evictor to run in 100 ms - will create idle instance pool.setTimeBetweenEvictionRunsMillis(100); borrowerThread.start(); // Off to the races borrowerThread.join(); assertTrue(!borrower.failed()); pool.close(); } public void testEvictLIFO() throws Exception { checkEvict(true); } public void testEvictFIFO() throws Exception { checkEvict(false); } public void checkEvict(boolean lifo) throws Exception { // yea this is hairy but it tests all the code paths in GOP.evict() final SimpleFactory factory = new SimpleFactory(); final GenericObjectPool pool = new GenericObjectPool(factory); pool.setSoftMinEvictableIdleTimeMillis(10); pool.setMinIdle(2); pool.setTestWhileIdle(true); pool.setLifo(lifo); PoolUtils.prefill(pool, 5); pool.evict(); factory.setEvenValid(false); factory.setOddValid(false); factory.setThrowExceptionOnActivate(true); pool.evict(); PoolUtils.prefill(pool, 5); factory.setThrowExceptionOnActivate(false); factory.setThrowExceptionOnPassivate(true); pool.evict(); factory.setThrowExceptionOnPassivate(false); factory.setEvenValid(true); factory.setOddValid(true); Thread.sleep(125); pool.evict(); assertEquals(2, pool.getNumIdle()); } /** * Test to make sure evictor visits least recently used objects first, * regardless of FIFO/LIFO * * JIRA: POOL-86 */ public void testEvictionOrder() throws Exception { checkEvictionOrder(false); checkEvictionOrder(true); } private void checkEvictionOrder(boolean lifo) throws Exception { SimpleFactory factory = new SimpleFactory(); GenericObjectPool pool = new GenericObjectPool(factory); pool.setNumTestsPerEvictionRun(2); pool.setMinEvictableIdleTimeMillis(100); pool.setLifo(lifo); for (int i = 0; i < 5; i++) { pool.addObject(); Thread.sleep(100); } // Order, oldest to youngest, is "0", "1", ...,"4" pool.evict(); // Should evict "0" and "1" Object obj = pool.borrowObject(); assertTrue("oldest not evicted", !obj.equals("0")); assertTrue("second oldest not evicted", !obj.equals("1")); // 2 should be next out for FIFO, 4 for LIFO assertEquals("Wrong instance returned", lifo ? "4" : "2", obj); // Two eviction runs in sequence factory = new SimpleFactory(); pool = new GenericObjectPool(factory); pool.setNumTestsPerEvictionRun(2); pool.setMinEvictableIdleTimeMillis(100); pool.setLifo(lifo); for (int i = 0; i < 5; i++) { pool.addObject(); Thread.sleep(100); } pool.evict(); // Should evict "0" and "1" pool.evict(); // Should evict "2" and "3" obj = pool.borrowObject(); assertEquals("Wrong instance remaining in pool", "4", obj); } /** * Verifies that the evictor visits objects in expected order and frequency. */ public void testEvictorVisiting() throws Exception { checkEvictorVisiting(true); checkEvictorVisiting(false); } private void checkEvictorVisiting(boolean lifo) throws Exception { VisitTrackerFactory factory = new VisitTrackerFactory(); GenericObjectPool pool = new GenericObjectPool(factory); pool.setNumTestsPerEvictionRun(2); pool.setMinEvictableIdleTimeMillis(-1); pool.setTestWhileIdle(true); pool.setLifo(lifo); pool.setTestOnReturn(false); pool.setTestOnBorrow(false); for (int i = 0; i < 8; i++) { pool.addObject(); } pool.evict(); // Visit oldest 2 - 0 and 1 Object obj = pool.borrowObject(); pool.returnObject(obj); obj = pool.borrowObject(); pool.returnObject(obj); // borrow, return, borrow, return // FIFO will move 0 and 1 to end // LIFO, 7 out, then in, then out, then in pool.evict(); // Should visit 2 and 3 in either case for (int i = 0; i < 8; i++) { VisitTracker tracker = (VisitTracker) pool.borrowObject(); if (tracker.getId() >= 4) { assertEquals("Unexpected instance visited " + tracker.getId(), 0, tracker.getValidateCount()); } else { assertEquals("Instance " + tracker.getId() + " visited wrong number of times.", 1, tracker.getValidateCount()); } } factory = new VisitTrackerFactory(); pool = new GenericObjectPool(factory); pool.setNumTestsPerEvictionRun(3); pool.setMinEvictableIdleTimeMillis(-1); pool.setTestWhileIdle(true); pool.setLifo(lifo); pool.setTestOnReturn(false); pool.setTestOnBorrow(false); for (int i = 0; i < 8; i++) { pool.addObject(); } pool.evict(); // 0, 1, 2 pool.evict(); // 3, 4, 5 obj = pool.borrowObject(); pool.returnObject(obj); obj = pool.borrowObject(); pool.returnObject(obj); obj = pool.borrowObject(); pool.returnObject(obj); // borrow, return, borrow, return // FIFO 3,4,5,6,7,0,1,2 // LIFO 7,6,5,4,3,2,1,0 // In either case, pointer should be at 6 pool.evict(); // Should hit 6,7,0 - 0 for second time for (int i = 0; i < 8; i++) { VisitTracker tracker = (VisitTracker) pool.borrowObject(); if (tracker.getId() != 0) { assertEquals("Instance " + tracker.getId() + " visited wrong number of times.", 1, tracker.getValidateCount()); } else { assertEquals("Instance " + tracker.getId() + " visited wrong number of times.", 2, tracker.getValidateCount()); } } // Randomly generate a pools with random numTests // and make sure evictor cycles through elements appropriately int[] smallPrimes = { 2, 3, 5, 7 }; Random random = new Random(); random.setSeed(System.currentTimeMillis()); for (int i = 0; i < 4; i++) { pool.setNumTestsPerEvictionRun(smallPrimes[i]); for (int j = 0; j < 5; j++) { pool = new GenericObjectPool(factory); pool.setNumTestsPerEvictionRun(3); pool.setMinEvictableIdleTimeMillis(-1); pool.setTestWhileIdle(true); pool.setLifo(lifo); pool.setTestOnReturn(false); pool.setTestOnBorrow(false); pool.setMaxIdle(-1); int instanceCount = 10 + random.nextInt(20); pool.setMaxActive(instanceCount); for (int k = 0; k < instanceCount; k++) { pool.addObject(); } // Execute a random number of evictor runs int runs = 10 + random.nextInt(50); for (int k = 0; k < runs; k++) { pool.evict(); } // Number of times evictor should have cycled through the pool int cycleCount = (runs * pool.getNumTestsPerEvictionRun()) / instanceCount; // Look at elements and make sure they are visited cycleCount // or cycleCount + 1 times VisitTracker tracker = null; int visitCount = 0; for (int k = 0; k < instanceCount; k++) { tracker = (VisitTracker) pool.borrowObject(); assertTrue(pool.getNumActive() <= pool.getMaxActive()); visitCount = tracker.getValidateCount(); assertTrue(visitCount >= cycleCount && visitCount <= cycleCount + 1); } } } } public void testExceptionOnPassivateDuringReturn() throws Exception { SimpleFactory factory = new SimpleFactory(); GenericObjectPool pool = new GenericObjectPool(factory); Object obj = pool.borrowObject(); factory.setThrowExceptionOnPassivate(true); pool.returnObject(obj); assertEquals(0, pool.getNumIdle()); pool.close(); } public void testExceptionOnDestroyDuringBorrow() throws Exception { SimpleFactory factory = new SimpleFactory(); factory.setThrowExceptionOnDestroy(true); GenericObjectPool pool = new GenericObjectPool(factory); pool.setTestOnBorrow(true); pool.borrowObject(); factory.setValid(false); // Make validation fail on next borrow attempt try { pool.borrowObject(); fail("Expecting NoSuchElementException"); } catch (NoSuchElementException ex) { // expected } assertEquals(1, pool.getNumActive()); assertEquals(0, pool.getNumIdle()); } public void testExceptionOnDestroyDuringReturn() throws Exception { SimpleFactory factory = new SimpleFactory(); factory.setThrowExceptionOnDestroy(true); GenericObjectPool pool = new GenericObjectPool(factory); pool.setTestOnReturn(true); Object obj1 = pool.borrowObject(); pool.borrowObject(); factory.setValid(false); // Make validation fail pool.returnObject(obj1); assertEquals(1, pool.getNumActive()); assertEquals(0, pool.getNumIdle()); } public void testExceptionOnActivateDuringBorrow() throws Exception { SimpleFactory factory = new SimpleFactory(); GenericObjectPool pool = new GenericObjectPool(factory); Object obj1 = pool.borrowObject(); Object obj2 = pool.borrowObject(); pool.returnObject(obj1); pool.returnObject(obj2); factory.setThrowExceptionOnActivate(true); factory.setEvenValid(false); // Activation will now throw every other time // First attempt throws, but loop continues and second succeeds Object obj = pool.borrowObject(); assertEquals(1, pool.getNumActive()); assertEquals(0, pool.getNumIdle()); pool.returnObject(obj); factory.setValid(false); // Validation will now fail on activation when borrowObject returns // an idle instance, and then when attempting to create a new instance try { obj1 = pool.borrowObject(); fail("Expecting NoSuchElementException"); } catch (NoSuchElementException ex) { // expected } assertEquals(0, pool.getNumActive()); assertEquals(0, pool.getNumIdle()); } public void testSetFactoryWithActiveObjects() throws Exception { GenericObjectPool pool = new GenericObjectPool(); pool.setMaxIdle(10); pool.setFactory(new SimpleFactory()); Object obj = pool.borrowObject(); assertNotNull(obj); try { pool.setFactory(null); fail("Expected IllegalStateException"); } catch (IllegalStateException e) { // expected } try { pool.setFactory(new SimpleFactory()); fail("Expected IllegalStateException"); } catch (IllegalStateException e) { // expected } } public void testSetFactoryWithNoActiveObjects() throws Exception { GenericObjectPool pool = new GenericObjectPool(); pool.setMaxIdle(10); pool.setFactory(new SimpleFactory()); Object obj = pool.borrowObject(); pool.returnObject(obj); assertEquals(1, pool.getNumIdle()); pool.setFactory(new SimpleFactory()); assertEquals(0, pool.getNumIdle()); } public void testNegativeMaxActive() throws Exception { pool.setMaxActive(-1); pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL); Object obj = pool.borrowObject(); assertEquals(getNthObject(0), obj); pool.returnObject(obj); } public void testMaxIdle() throws Exception { pool.setMaxActive(100); pool.setMaxIdle(8); Object[] active = new Object[100]; for (int i = 0; i < 100; i++) { active[i] = pool.borrowObject(); } assertEquals(100, pool.getNumActive()); assertEquals(0, pool.getNumIdle()); for (int i = 0; i < 100; i++) { pool.returnObject(active[i]); assertEquals(99 - i, pool.getNumActive()); assertEquals((i < 8 ? i + 1 : 8), pool.getNumIdle()); } } public void testMaxIdleZero() throws Exception { pool.setMaxActive(100); pool.setMaxIdle(0); Object[] active = new Object[100]; for (int i = 0; i < 100; i++) { active[i] = pool.borrowObject(); } assertEquals(100, pool.getNumActive()); assertEquals(0, pool.getNumIdle()); for (int i = 0; i < 100; i++) { pool.returnObject(active[i]); assertEquals(99 - i, pool.getNumActive()); assertEquals(0, pool.getNumIdle()); } } public void testMaxActive() throws Exception { pool.setMaxActive(3); pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL); pool.borrowObject(); pool.borrowObject(); pool.borrowObject(); try { pool.borrowObject(); fail("Expected NoSuchElementException"); } catch (NoSuchElementException e) { // expected } } public void testTimeoutNoLeak() throws Exception { pool.setMaxActive(2); pool.setMaxWait(10); pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); Object obj = pool.borrowObject(); Object obj2 = pool.borrowObject(); try { pool.borrowObject(); fail("Expecting NoSuchElementException"); } catch (NoSuchElementException ex) { // xpected } pool.returnObject(obj2); pool.returnObject(obj); obj = pool.borrowObject(); obj2 = pool.borrowObject(); } public void testMaxActiveZero() throws Exception { pool.setMaxActive(0); pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL); try { pool.borrowObject(); fail("Expected NoSuchElementException"); } catch (NoSuchElementException e) { // expected } } public void testMaxActiveUnderLoad() { // Config int numThreads = 199; // And main thread makes a round 200. int numIter = 20; int delay = 25; int maxActive = 10; SimpleFactory factory = new SimpleFactory(); factory.setMaxActive(maxActive); pool.setFactory(factory); pool.setMaxActive(maxActive); pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); pool.setTimeBetweenEvictionRunsMillis(-1); // Start threads to borrow objects TestThread[] threads = new TestThread[numThreads]; for (int i = 0; i < numThreads; i++) { // Factor of 2 on iterations so main thread does work whilst other // threads are running. Factor of 2 on delay so average delay for // other threads == actual delay for main thread threads[i] = new TestThread(pool, numIter * 2, delay * 2); Thread t = new Thread(threads[i]); t.start(); } // Give the threads a chance to start doing some work try { Thread.sleep(5000); } catch (InterruptedException e) { // ignored } for (int i = 0; i < numIter; i++) { Object obj = null; try { try { Thread.sleep(delay); } catch (InterruptedException e) { // ignored } obj = pool.borrowObject(); // Under load, observed _numActive > _maxActive if (pool.getNumActive() > pool.getMaxActive()) { throw new IllegalStateException("Too many active objects"); } try { Thread.sleep(delay); } catch (InterruptedException e) { // ignored } } catch (Exception e) { // Shouldn't happen e.printStackTrace(); fail("Exception on borrow"); } finally { if (obj != null) { try { pool.returnObject(obj); } catch (Exception e) { // Ignore } } } } for (int i = 0; i < numThreads; i++) { while (!(threads[i]).complete()) { try { Thread.sleep(500L); } catch (InterruptedException e) { // ignored } } if (threads[i].failed()) { fail("Thread " + i + " failed: " + threads[i]._error.toString()); } } } public void testInvalidWhenExhaustedAction() throws Exception { try { pool.setWhenExhaustedAction(Byte.MAX_VALUE); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { // expected } try { ObjectPool pool = new GenericObjectPool(new SimpleFactory(), GenericObjectPool.DEFAULT_MAX_ACTIVE, Byte.MAX_VALUE, GenericObjectPool.DEFAULT_MAX_WAIT, GenericObjectPool.DEFAULT_MAX_IDLE, false, false, GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN, GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, false); assertNotNull(pool); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { // expected } } public void testSettersAndGetters() throws Exception { GenericObjectPool pool = new GenericObjectPool(); { pool.setFactory(new SimpleFactory()); } { pool.setMaxActive(123); assertEquals(123, pool.getMaxActive()); } { pool.setMaxIdle(12); assertEquals(12, pool.getMaxIdle()); } { pool.setMaxWait(1234L); assertEquals(1234L, pool.getMaxWait()); } { pool.setMinEvictableIdleTimeMillis(12345L); assertEquals(12345L, pool.getMinEvictableIdleTimeMillis()); } { pool.setNumTestsPerEvictionRun(11); assertEquals(11, pool.getNumTestsPerEvictionRun()); } { pool.setTestOnBorrow(true); assertTrue(pool.getTestOnBorrow()); pool.setTestOnBorrow(false); assertTrue(!pool.getTestOnBorrow()); } { pool.setTestOnReturn(true); assertTrue(pool.getTestOnReturn()); pool.setTestOnReturn(false); assertTrue(!pool.getTestOnReturn()); } { pool.setTestWhileIdle(true); assertTrue(pool.getTestWhileIdle()); pool.setTestWhileIdle(false); assertTrue(!pool.getTestWhileIdle()); } { pool.setTimeBetweenEvictionRunsMillis(11235L); assertEquals(11235L, pool.getTimeBetweenEvictionRunsMillis()); } { pool.setSoftMinEvictableIdleTimeMillis(12135L); assertEquals(12135L, pool.getSoftMinEvictableIdleTimeMillis()); } { pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); assertEquals(GenericObjectPool.WHEN_EXHAUSTED_BLOCK, pool.getWhenExhaustedAction()); pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL); assertEquals(GenericObjectPool.WHEN_EXHAUSTED_FAIL, pool.getWhenExhaustedAction()); pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_GROW); assertEquals(GenericObjectPool.WHEN_EXHAUSTED_GROW, pool.getWhenExhaustedAction()); } } public void testDefaultConfiguration() throws Exception { GenericObjectPool pool = new GenericObjectPool(); assertConfiguration(new GenericObjectPool.Config(), pool); } public void testConstructors() throws Exception { { GenericObjectPool pool = new GenericObjectPool(); assertConfiguration(new GenericObjectPool.Config(), pool); } { GenericObjectPool pool = new GenericObjectPool(new SimpleFactory()); assertConfiguration(new GenericObjectPool.Config(), pool); } { GenericObjectPool.Config expected = new GenericObjectPool.Config(); expected.maxActive = 2; expected.maxIdle = 3; expected.maxWait = 5L; expected.minEvictableIdleTimeMillis = 7L; expected.numTestsPerEvictionRun = 9; expected.testOnBorrow = true; expected.testOnReturn = true; expected.testWhileIdle = true; expected.timeBetweenEvictionRunsMillis = 11L; expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; GenericObjectPool pool = new GenericObjectPool(null, expected); assertConfiguration(expected, pool); } { GenericObjectPool.Config expected = new GenericObjectPool.Config(); expected.maxActive = 2; GenericObjectPool pool = new GenericObjectPool(null, expected.maxActive); assertConfiguration(expected, pool); } { GenericObjectPool.Config expected = new GenericObjectPool.Config(); expected.maxActive = 2; expected.maxWait = 5L; expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; GenericObjectPool pool = new GenericObjectPool(null, expected.maxActive, expected.whenExhaustedAction, expected.maxWait); assertConfiguration(expected, pool); } { GenericObjectPool.Config expected = new GenericObjectPool.Config(); expected.maxActive = 2; expected.maxWait = 5L; expected.testOnBorrow = true; expected.testOnReturn = true; expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; GenericObjectPool pool = new GenericObjectPool(null, expected.maxActive, expected.whenExhaustedAction, expected.maxWait, expected.testOnBorrow, expected.testOnReturn); assertConfiguration(expected, pool); } { GenericObjectPool.Config expected = new GenericObjectPool.Config(); expected.maxActive = 2; expected.maxIdle = 3; expected.maxWait = 5L; expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; GenericObjectPool pool = new GenericObjectPool(null, expected.maxActive, expected.whenExhaustedAction, expected.maxWait, expected.maxIdle); assertConfiguration(expected, pool); } { GenericObjectPool.Config expected = new GenericObjectPool.Config(); expected.maxActive = 2; expected.maxIdle = 3; expected.maxWait = 5L; expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; expected.testOnBorrow = true; expected.testOnReturn = true; GenericObjectPool pool = new GenericObjectPool(null, expected.maxActive, expected.whenExhaustedAction, expected.maxWait, expected.maxIdle, expected.testOnBorrow, expected.testOnReturn); assertConfiguration(expected, pool); } { GenericObjectPool.Config expected = new GenericObjectPool.Config(); expected.maxActive = 2; expected.maxIdle = 3; expected.maxWait = 5L; expected.minEvictableIdleTimeMillis = 7L; expected.numTestsPerEvictionRun = 9; expected.testOnBorrow = true; expected.testOnReturn = true; expected.testWhileIdle = true; expected.timeBetweenEvictionRunsMillis = 11L; expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; GenericObjectPool pool = new GenericObjectPool(null, expected.maxActive, expected.whenExhaustedAction, expected.maxWait, expected.maxIdle, expected.testOnBorrow, expected.testOnReturn, expected.timeBetweenEvictionRunsMillis, expected.numTestsPerEvictionRun, expected.minEvictableIdleTimeMillis, expected.testWhileIdle); assertConfiguration(expected, pool); } { GenericObjectPool.Config expected = new GenericObjectPool.Config(); expected.maxActive = 2; expected.maxIdle = 3; expected.minIdle = 1; expected.maxWait = 5L; expected.minEvictableIdleTimeMillis = 7L; expected.numTestsPerEvictionRun = 9; expected.testOnBorrow = true; expected.testOnReturn = true; expected.testWhileIdle = true; expected.timeBetweenEvictionRunsMillis = 11L; expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; GenericObjectPool pool = new GenericObjectPool(null, expected.maxActive, expected.whenExhaustedAction, expected.maxWait, expected.maxIdle, expected.minIdle, expected.testOnBorrow, expected.testOnReturn, expected.timeBetweenEvictionRunsMillis, expected.numTestsPerEvictionRun, expected.minEvictableIdleTimeMillis, expected.testWhileIdle); assertConfiguration(expected, pool); } } public void testSetConfig() throws Exception { GenericObjectPool.Config expected = new GenericObjectPool.Config(); GenericObjectPool pool = new GenericObjectPool(); assertConfiguration(expected, pool); expected.maxActive = 2; expected.maxIdle = 3; expected.maxWait = 5L; expected.minEvictableIdleTimeMillis = 7L; expected.numTestsPerEvictionRun = 9; expected.testOnBorrow = true; expected.testOnReturn = true; expected.testWhileIdle = true; expected.timeBetweenEvictionRunsMillis = 11L; expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; pool.setConfig(expected); assertConfiguration(expected, pool); } public void testEvictionWithNegativeNumTests() throws Exception { // when numTestsPerEvictionRun is negative, it represents a fraction of the // idle objects to test pool.setMaxIdle(6); pool.setMaxActive(6); pool.setNumTestsPerEvictionRun(-2); pool.setMinEvictableIdleTimeMillis(50L); pool.setTimeBetweenEvictionRunsMillis(100L); Object[] active = new Object[6]; for (int i = 0; i < 6; i++) { active[i] = pool.borrowObject(); } for (int i = 0; i < 6; i++) { pool.returnObject(active[i]); } try { Thread.sleep(100L); } catch (InterruptedException e) { } assertTrue("Should at most 6 idle, found " + pool.getNumIdle(), pool.getNumIdle() <= 6); try { Thread.sleep(100L); } catch (InterruptedException e) { } assertTrue("Should at most 3 idle, found " + pool.getNumIdle(), pool.getNumIdle() <= 3); try { Thread.sleep(100L); } catch (InterruptedException e) { } assertTrue("Should be at most 2 idle, found " + pool.getNumIdle(), pool.getNumIdle() <= 2); try { Thread.sleep(100L); } catch (InterruptedException e) { } assertEquals("Should be zero idle, found " + pool.getNumIdle(), 0, pool.getNumIdle()); } public void testEviction() throws Exception { pool.setMaxIdle(500); pool.setMaxActive(500); pool.setNumTestsPerEvictionRun(100); pool.setMinEvictableIdleTimeMillis(250L); pool.setTimeBetweenEvictionRunsMillis(500L); pool.setTestWhileIdle(true); Object[] active = new Object[500]; for (int i = 0; i < 500; i++) { active[i] = pool.borrowObject(); } for (int i = 0; i < 500; i++) { pool.returnObject(active[i]); } try { Thread.sleep(1000L); } catch (InterruptedException e) { } assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(), pool.getNumIdle() < 500); try { Thread.sleep(600L); } catch (InterruptedException e) { } assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(), pool.getNumIdle() < 400); try { Thread.sleep(600L); } catch (InterruptedException e) { } assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(), pool.getNumIdle() < 300); try { Thread.sleep(600L); } catch (InterruptedException e) { } assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(), pool.getNumIdle() < 200); try { Thread.sleep(600L); } catch (InterruptedException e) { } assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(), pool.getNumIdle() < 100); try { Thread.sleep(600L); } catch (InterruptedException e) { } assertEquals("Should be zero idle, found " + pool.getNumIdle(), 0, pool.getNumIdle()); for (int i = 0; i < 500; i++) { active[i] = pool.borrowObject(); } for (int i = 0; i < 500; i++) { pool.returnObject(active[i]); } try { Thread.sleep(1000L); } catch (InterruptedException e) { } assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(), pool.getNumIdle() < 500); try { Thread.sleep(600L); } catch (InterruptedException e) { } assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(), pool.getNumIdle() < 400); try { Thread.sleep(600L); } catch (InterruptedException e) { } assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(), pool.getNumIdle() < 300); try { Thread.sleep(600L); } catch (InterruptedException e) { } assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(), pool.getNumIdle() < 200); try { Thread.sleep(600L); } catch (InterruptedException e) { } assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(), pool.getNumIdle() < 100); try { Thread.sleep(600L); } catch (InterruptedException e) { } assertEquals("Should be zero idle, found " + pool.getNumIdle(), 0, pool.getNumIdle()); } public void testEvictionSoftMinIdle() throws Exception { GenericObjectPool pool = null; class TimeTest extends BasePoolableObjectFactory { private final long createTime; public TimeTest() { createTime = System.currentTimeMillis(); } public Object makeObject() throws Exception { return new TimeTest(); } public long getCreateTime() { return createTime; } } pool = new GenericObjectPool(new TimeTest()); pool.setMaxIdle(5); pool.setMaxActive(5); pool.setNumTestsPerEvictionRun(5); pool.setMinEvictableIdleTimeMillis(3000L); pool.setSoftMinEvictableIdleTimeMillis(1000L); pool.setMinIdle(2); Object[] active = new Object[5]; Long[] creationTime = new Long[5]; for (int i = 0; i < 5; i++) { active[i] = pool.borrowObject(); creationTime[i] = new Long(((TimeTest) active[i]).getCreateTime()); } for (int i = 0; i < 5; i++) { pool.returnObject(active[i]); } // Soft evict all but minIdle(2) Thread.sleep(1500L); pool.evict(); assertEquals("Idle count different than expected.", 2, pool.getNumIdle()); // Hard evict the rest. Thread.sleep(2000L); pool.evict(); assertEquals("Idle count different than expected.", 0, pool.getNumIdle()); } public void testMinIdle() throws Exception { pool.setMaxIdle(500); pool.setMinIdle(5); pool.setMaxActive(10); pool.setNumTestsPerEvictionRun(0); pool.setMinEvictableIdleTimeMillis(50L); pool.setTimeBetweenEvictionRunsMillis(100L); pool.setTestWhileIdle(true); try { Thread.sleep(150L); } catch (InterruptedException e) { } assertTrue("Should be 5 idle, found " + pool.getNumIdle(), pool.getNumIdle() == 5); Object[] active = new Object[5]; active[0] = pool.borrowObject(); try { Thread.sleep(150L); } catch (InterruptedException e) { } assertTrue("Should be 5 idle, found " + pool.getNumIdle(), pool.getNumIdle() == 5); for (int i = 1; i < 5; i++) { active[i] = pool.borrowObject(); } try { Thread.sleep(150L); } catch (InterruptedException e) { } assertTrue("Should be 5 idle, found " + pool.getNumIdle(), pool.getNumIdle() == 5); for (int i = 0; i < 5; i++) { pool.returnObject(active[i]); } try { Thread.sleep(150L); } catch (InterruptedException e) { } assertTrue("Should be 10 idle, found " + pool.getNumIdle(), pool.getNumIdle() == 10); } public void testMinIdleMaxActive() throws Exception { pool.setMaxIdle(500); pool.setMinIdle(5); pool.setMaxActive(10); pool.setNumTestsPerEvictionRun(0); pool.setMinEvictableIdleTimeMillis(50L); pool.setTimeBetweenEvictionRunsMillis(100L); pool.setTestWhileIdle(true); try { Thread.sleep(150L); } catch (InterruptedException e) { } assertTrue("Should be 5 idle, found " + pool.getNumIdle(), pool.getNumIdle() == 5); Object[] active = new Object[10]; try { Thread.sleep(150L); } catch (InterruptedException e) { } assertTrue("Should be 5 idle, found " + pool.getNumIdle(), pool.getNumIdle() == 5); for (int i = 0; i < 5; i++) { active[i] = pool.borrowObject(); } try { Thread.sleep(150L); } catch (InterruptedException e) { } assertTrue("Should be 5 idle, found " + pool.getNumIdle(), pool.getNumIdle() == 5); for (int i = 0; i < 5; i++) { pool.returnObject(active[i]); } try { Thread.sleep(150L); } catch (InterruptedException e) { } assertTrue("Should be 10 idle, found " + pool.getNumIdle(), pool.getNumIdle() == 10); for (int i = 0; i < 10; i++) { active[i] = pool.borrowObject(); } try { Thread.sleep(150L); } catch (InterruptedException e) { } assertTrue("Should be 0 idle, found " + pool.getNumIdle(), pool.getNumIdle() == 0); for (int i = 0; i < 10; i++) { pool.returnObject(active[i]); } try { Thread.sleep(150L); } catch (InterruptedException e) { } assertTrue("Should be 10 idle, found " + pool.getNumIdle(), pool.getNumIdle() == 10); } /** * Kicks off <numThreads> test threads, each of which will go through * <iterations> borrow-return cycles with random delay times <= delay in * between. */ public void runTestThreads(int numThreads, int iterations, int delay) { TestThread[] threads = new TestThread[numThreads]; for (int i = 0; i < numThreads; i++) { threads[i] = new TestThread(pool, iterations, delay); Thread t = new Thread(threads[i]); t.start(); } for (int i = 0; i < numThreads; i++) { while (!(threads[i]).complete()) { try { Thread.sleep(500L); } catch (InterruptedException e) { // ignored } } if (threads[i].failed()) { fail("Thread " + i + " failed: " + threads[i]._error.toString()); } } } public void testThreaded1() throws Exception { pool.setMaxActive(15); pool.setMaxIdle(15); pool.setMaxWait(1000L); runTestThreads(20, 100, 50); } /** * Verifies that maxActive is not exceeded when factory destroyObject has high * latency, testOnReturn is set and there is high incidence of validation * failures. */ public void testMaxActiveInvariant() throws Exception { int maxActive = 15; SimpleFactory factory = new SimpleFactory(); factory.setEvenValid(false); // Every other validation fails factory.setDestroyLatency(100); // Destroy takes 100 ms factory.setMaxActive(maxActive); // (makes - destroys) bound factory.setValidationEnabled(true); pool = new GenericObjectPool(factory); pool.setMaxActive(maxActive); pool.setMaxIdle(-1); pool.setTestOnReturn(true); pool.setMaxWait(1000L); runTestThreads(5, 10, 50); } static class TestThread implements Runnable { private final java.util.Random _random = new java.util.Random(); // Thread config items private final ObjectPool _pool; private final int _iter; private final int _delay; private final boolean _randomDelay; private final Object _expectedObject; private volatile boolean _complete = false; private volatile boolean _failed = false; private volatile Throwable _error; public TestThread(ObjectPool pool) { this(pool, 100, 50, true, null); } public TestThread(ObjectPool pool, int iter) { this(pool, iter, 50, true, null); } public TestThread(ObjectPool pool, int iter, int delay) { this(pool, iter, delay, true, null); } public TestThread(ObjectPool pool, int iter, int delay, boolean randomDelay) { this(pool, iter, delay, randomDelay, null); } public TestThread(ObjectPool pool, int iter, int delay, boolean randomDelay, Object obj) { _pool = pool; _iter = iter; _delay = delay; _randomDelay = randomDelay; _expectedObject = obj; } public boolean complete() { return _complete; } public boolean failed() { return _failed; } public void run() { for (int i = 0; i < _iter; i++) { long delay = _randomDelay ? (long) _random.nextInt(_delay) : _delay; try { Thread.sleep(delay); } catch (InterruptedException e) { // ignored } Object obj = null; try { obj = _pool.borrowObject(); } catch (Exception e) { _error = e; _failed = true; _complete = true; break; } if (_expectedObject != null && !_expectedObject.equals(obj)) { _error = new Throwable("Expected: " + _expectedObject + " found: " + obj); _failed = true; _complete = true; break; } try { Thread.sleep(delay); } catch (InterruptedException e) { // ignored } try { _pool.returnObject(obj); } catch (Exception e) { _error = e; _failed = true; _complete = true; break; } } _complete = true; } } public void testFIFO() throws Exception { pool.setLifo(false); pool.addObject(); // "0" pool.addObject(); // "1" pool.addObject(); // "2" assertEquals("Oldest", "0", pool.borrowObject()); assertEquals("Middle", "1", pool.borrowObject()); assertEquals("Youngest", "2", pool.borrowObject()); assertEquals("new-3", "3", pool.borrowObject()); pool.returnObject("r"); assertEquals("returned", "r", pool.borrowObject()); assertEquals("new-4", "4", pool.borrowObject()); } public void testLIFO() throws Exception { pool.setLifo(true); pool.addObject(); // "0" pool.addObject(); // "1" pool.addObject(); // "2" assertEquals("Youngest", "2", pool.borrowObject()); assertEquals("Middle", "1", pool.borrowObject()); assertEquals("Oldest", "0", pool.borrowObject()); assertEquals("new-3", "3", pool.borrowObject()); pool.returnObject("r"); assertEquals("returned", "r", pool.borrowObject()); assertEquals("new-4", "4", pool.borrowObject()); } public void testAddObject() throws Exception { assertEquals("should be zero idle", 0, pool.getNumIdle()); pool.addObject(); assertEquals("should be one idle", 1, pool.getNumIdle()); assertEquals("should be zero active", 0, pool.getNumActive()); Object obj = pool.borrowObject(); assertEquals("should be zero idle", 0, pool.getNumIdle()); assertEquals("should be one active", 1, pool.getNumActive()); pool.returnObject(obj); assertEquals("should be one idle", 1, pool.getNumIdle()); assertEquals("should be zero active", 0, pool.getNumActive()); ObjectPool op = new GenericObjectPool(); try { op.addObject(); fail("Expected IllegalStateException when there is no factory."); } catch (IllegalStateException ise) { // expected } op.close(); } protected GenericObjectPool pool = null; private void assertConfiguration(GenericObjectPool.Config expected, GenericObjectPool actual) throws Exception { assertEquals("testOnBorrow", expected.testOnBorrow, actual.getTestOnBorrow()); assertEquals("testOnReturn", expected.testOnReturn, actual.getTestOnReturn()); assertEquals("testWhileIdle", expected.testWhileIdle, actual.getTestWhileIdle()); assertEquals("whenExhaustedAction", expected.whenExhaustedAction, actual.getWhenExhaustedAction()); assertEquals("maxActive", expected.maxActive, actual.getMaxActive()); assertEquals("maxIdle", expected.maxIdle, actual.getMaxIdle()); assertEquals("maxWait", expected.maxWait, actual.getMaxWait()); assertEquals("minEvictableIdleTimeMillis", expected.minEvictableIdleTimeMillis, actual.getMinEvictableIdleTimeMillis()); assertEquals("numTestsPerEvictionRun", expected.numTestsPerEvictionRun, actual.getNumTestsPerEvictionRun()); assertEquals("timeBetweenEvictionRunsMillis", expected.timeBetweenEvictionRunsMillis, actual.getTimeBetweenEvictionRunsMillis()); } public class SimpleFactory implements PoolableObjectFactory { public SimpleFactory() { this(true); } public SimpleFactory(boolean valid) { this(valid, valid); } public SimpleFactory(boolean evalid, boolean ovalid) { evenValid = evalid; oddValid = ovalid; } void setValid(boolean valid) { setEvenValid(valid); setOddValid(valid); } void setEvenValid(boolean valid) { evenValid = valid; } void setOddValid(boolean valid) { oddValid = valid; } public void setThrowExceptionOnPassivate(boolean bool) { exceptionOnPassivate = bool; } public void setMaxActive(int maxActive) { this.maxActive = maxActive; } public void setDestroyLatency(long destroyLatency) { this.destroyLatency = destroyLatency; } public void setMakeLatency(long makeLatency) { this.makeLatency = makeLatency; } public Object makeObject() { synchronized (this) { activeCount++; if (activeCount > maxActive) { throw new IllegalStateException("Too many active instances: " + activeCount); } } if (makeLatency > 0) { doWait(makeLatency); } return String.valueOf(makeCounter++); } public void destroyObject(Object obj) throws Exception { if (destroyLatency > 0) { doWait(destroyLatency); } synchronized (this) { activeCount--; } if (exceptionOnDestroy) { throw new Exception(); } } public boolean validateObject(Object obj) { if (enableValidation) { return validateCounter++ % 2 == 0 ? evenValid : oddValid; } else { return true; } } public void activateObject(Object obj) throws Exception { if (exceptionOnActivate) { if (!(validateCounter++ % 2 == 0 ? evenValid : oddValid)) { throw new Exception(); } } } public void passivateObject(Object obj) throws Exception { if (exceptionOnPassivate) { throw new Exception(); } } int makeCounter = 0; int validateCounter = 0; int activeCount = 0; boolean evenValid = true; boolean oddValid = true; boolean exceptionOnPassivate = false; boolean exceptionOnActivate = false; boolean exceptionOnDestroy = false; boolean enableValidation = true; long destroyLatency = 0; long makeLatency = 0; int maxActive = Integer.MAX_VALUE; public boolean isThrowExceptionOnActivate() { return exceptionOnActivate; } public void setThrowExceptionOnActivate(boolean b) { exceptionOnActivate = b; } public void setThrowExceptionOnDestroy(boolean b) { exceptionOnDestroy = b; } public boolean isValidationEnabled() { return enableValidation; } public void setValidationEnabled(boolean b) { enableValidation = b; } private void doWait(long latency) { try { Thread.sleep(latency); } catch (InterruptedException ex) { // ignore } } } protected boolean isLifo() { return true; } protected boolean isFifo() { return false; } /* * Note: This test relies on timing for correct execution. There *should* be * enough margin for this to work correctly on most (all?) systems but be * aware of this if you see a failure of this test. */ public void testBorrowObjectFairness() { // Config int numThreads = 30; int maxActive = 10; SimpleFactory factory = new SimpleFactory(); factory.setMaxActive(maxActive); pool.setFactory(factory); pool.setMaxActive(maxActive); pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); pool.setTimeBetweenEvictionRunsMillis(-1); // Start threads to borrow objects TestThread[] threads = new TestThread[numThreads]; for (int i = 0; i < numThreads; i++) { threads[i] = new TestThread(pool, 1, 2000, false, String.valueOf(i % maxActive)); Thread t = new Thread(threads[i]); t.start(); // Short delay to ensure threads start in correct order try { Thread.sleep(50); } catch (InterruptedException e) { fail(e.toString()); } } // Wait for threads to finish for (int i = 0; i < numThreads; i++) { while (!(threads[i]).complete()) { try { Thread.sleep(500L); } catch (InterruptedException e) { // ignored } } if (threads[i].failed()) { fail("Thread " + i + " failed: " + threads[i]._error.toString()); } } } /** * On first borrow, first object fails validation, second object is OK. * Subsequent borrows are OK. This was POOL-152. */ public void testBrokenFactoryShouldNotBlockPool() { int maxActive = 1; SimpleFactory factory = new SimpleFactory(); factory.setMaxActive(maxActive); pool.setFactory(factory); pool.setMaxActive(maxActive); pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); pool.setTestOnBorrow(true); // First borrow object will need to create a new object which will fail // validation. Object obj = null; Exception ex = null; factory.setValid(false); try { obj = pool.borrowObject(); } catch (Exception e) { ex = e; } // Failure expected assertNotNull(ex); assertTrue(ex instanceof NoSuchElementException); assertNull(obj); // Configure factory to create valid objects so subsequent borrows work factory.setValid(true); // Subsequent borrows should be OK try { obj = pool.borrowObject(); } catch (Exception e1) { fail(); } assertNotNull(obj); try { pool.returnObject(obj); } catch (Exception e) { fail(); } } /* * Very simple test thread that just tries to borrow an object from the * provided pool returns it after a wait */ static class WaitingTestThread extends Thread { private final GenericObjectPool _pool; private final long _pause; private Throwable _thrown; private long preborrow; // just before borrow private long postborrow; // borrow returned private long postreturn; // after object was returned private long ended; private String objectId; public WaitingTestThread(GenericObjectPool pool, long pause) { _pool = pool; _pause = pause; _thrown = null; } public void run() { try { preborrow = System.currentTimeMillis(); Object obj = _pool.borrowObject(); objectId = obj.toString(); postborrow = System.currentTimeMillis(); Thread.sleep(_pause); _pool.returnObject(obj); postreturn = System.currentTimeMillis(); } catch (Exception e) { _thrown = e; } finally { ended = System.currentTimeMillis(); } } } static class NonWaitingTestThread extends Thread { private final GenericObjectPool _pool; private Throwable _thrown; private String objectId; private long preborrow; // just before borrow private long postborrow; // borrow returned private long postreturn; // after object was returned private long ended; private boolean interrupted = false; public NonWaitingTestThread(GenericObjectPool pool) { _pool = pool; _thrown = null; } public void intep() { this.interrupted = true; } public void run() { try { // preborrow = System.currentTimeMillis(); Object obj = _pool.borrowObject(); objectId = obj.toString(); // if(this.interrupted) // throw new InterruptedException(); // postborrow = System.currentTimeMillis(); // Thread.sleep(10); _pool.returnObject(obj); // postreturn = System.currentTimeMillis(); } catch (Exception e) { _thrown = e; } finally { ended = System.currentTimeMillis(); } } } private static final boolean DISPLAY_THREAD_DETAILS = Boolean .valueOf(System.getProperty("TestGenericObjectPool.display.thread.details", "false")).booleanValue(); // To pass this to a Maven test, use: // mvn test -DargLine="-DTestGenericObjectPool.display.thread.details=true" // @see http://jira.codehaus.org/browse/SUREFIRE-121 /* * Test multi-threaded pool access. Multiple threads, but maxActive only * allows half the threads to succeed. * * This test was prompted by Continuum build failures in the Commons DBCP test * case: TestPerUserPoolDataSource.testMultipleThreads2() Let's see if the * this fails on Continuum too! */ public void testMaxWaitMultiThreaded() throws Exception { final long maxWait = 500; // wait for connection final long holdTime = 2 * maxWait; // how long to hold connection final int threads = 10; // number of threads to grab the object initially SimpleFactory factory = new SimpleFactory(); GenericObjectPool pool = new GenericObjectPool(factory); pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); pool.setMaxWait(maxWait); pool.setMaxActive(threads); // Create enough threads so half the threads will have to wait WaitingTestThread wtt[] = new WaitingTestThread[threads * 2]; for (int i = 0; i < wtt.length; i++) { wtt[i] = new WaitingTestThread(pool, holdTime); } long origin = System.currentTimeMillis() - 1000; for (int i = 0; i < wtt.length; i++) { wtt[i].start(); } int failed = 0; for (int i = 0; i < wtt.length; i++) { wtt[i].join(); if (wtt[i]._thrown != null) { failed++; } } if (DISPLAY_THREAD_DETAILS || wtt.length / 2 != failed) { System.out.println("MaxWait: " + maxWait + " HoldTime: " + holdTime + " MaxActive: " + threads + " Threads: " + wtt.length + " Failed: " + failed); for (int i = 0; i < wtt.length; i++) { WaitingTestThread wt = wtt[i]; System.out.println("Preborrow: " + (wt.preborrow - origin) + " Postborrow: " + (wt.postborrow != 0 ? wt.postborrow - origin : -1) + " BorrowTime: " + (wt.postborrow != 0 ? wt.postborrow - wt.preborrow : -1) + " PostReturn: " + (wt.postreturn != 0 ? wt.postreturn - origin : -1) + " Ended: " + (wt.ended - origin) + " ObjId: " + wt.objectId); } } assertEquals("Expected half the threads to fail", wtt.length / 2, failed); } public static void main(String[] args) { TestGenericObjectPool t = new TestGenericObjectPool(); try { t.setUp(); t.testWhenExhaustedBlockInterruptImproved(); t.tearDown(); } catch (Exception e) { e.printStackTrace(); } } }