001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.pool.impl; 019 020 import java.util.NoSuchElementException; 021 import java.util.Random; 022 023 import org.apache.commons.pool.BasePoolableObjectFactory; 024 import org.apache.commons.pool.ObjectPool; 025 import org.apache.commons.pool.PoolUtils; 026 import org.apache.commons.pool.PoolableObjectFactory; 027 import org.apache.commons.pool.TestBaseObjectPool; 028 import org.apache.commons.pool.VisitTracker; 029 import org.apache.commons.pool.VisitTrackerFactory; 030 031 /** 032 * @author Rodney Waldhoff 033 * @author Dirk Verbeeck 034 * @author Sandy McArthur 035 * @version $Revision: 1205211 $ $Date: 2011-11-22 15:47:57 -0700 (Tue, 22 Nov 2011) $ 036 */ 037 public class TestGenericObjectPool extends TestBaseObjectPool { 038 public TestGenericObjectPool(String testName) { 039 super(testName); 040 } 041 042 protected ObjectPool makeEmptyPool(int mincap) { 043 GenericObjectPool pool = new GenericObjectPool(new SimpleFactory()); 044 pool.setMaxActive(mincap); 045 pool.setMaxIdle(mincap); 046 return pool; 047 } 048 049 protected ObjectPool makeEmptyPool(final PoolableObjectFactory factory) { 050 return new GenericObjectPool(factory); 051 } 052 053 protected Object getNthObject(int n) { 054 return String.valueOf(n); 055 } 056 057 public void setUp() throws Exception { 058 super.setUp(); 059 pool = new GenericObjectPool(new SimpleFactory()); 060 } 061 062 public void tearDown() throws Exception { 063 super.tearDown(); 064 pool.clear(); 065 pool.close(); 066 pool = null; 067 } 068 069 public void testWhenExhaustedGrow() throws Exception { 070 pool.setMaxActive(1); 071 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_GROW); 072 Object obj1 = pool.borrowObject(); 073 assertNotNull(obj1); 074 Object obj2 = pool.borrowObject(); 075 assertNotNull(obj2); 076 pool.returnObject(obj2); 077 pool.returnObject(obj1); 078 pool.close(); 079 } 080 081 public void testWhenExhaustedFail() throws Exception { 082 pool.setMaxActive(1); 083 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL); 084 Object obj1 = pool.borrowObject(); 085 assertNotNull(obj1); 086 try { 087 pool.borrowObject(); 088 fail("Expected NoSuchElementException"); 089 } catch(NoSuchElementException e) { 090 // expected 091 } 092 pool.returnObject(obj1); 093 assertEquals(1, pool.getNumIdle()); 094 pool.close(); 095 } 096 097 public void testWhenExhaustedBlock() throws Exception { 098 pool.setMaxActive(1); 099 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); 100 pool.setMaxWait(10L); 101 Object obj1 = pool.borrowObject(); 102 assertNotNull(obj1); 103 try { 104 pool.borrowObject(); 105 fail("Expected NoSuchElementException"); 106 } catch(NoSuchElementException e) { 107 // expected 108 } 109 pool.returnObject(obj1); 110 pool.close(); 111 } 112 113 public void testWhenExhaustedBlockInterupt() throws Exception { 114 pool.setMaxActive(1); 115 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); 116 pool.setMaxWait(0); 117 Object obj1 = pool.borrowObject(); 118 119 // Make sure an object was obtained 120 assertNotNull(obj1); 121 122 // Create a separate thread to try and borrow another object 123 WaitingTestThread wtt = new WaitingTestThread(pool, 200); 124 wtt.start(); 125 // Give wtt time to start 126 Thread.sleep(200); 127 wtt.interrupt(); 128 129 // Give interupt time to take effect 130 Thread.sleep(200); 131 132 // Check thread was interrupted 133 assertTrue(wtt._thrown instanceof InterruptedException); 134 135 // Return object to the pool 136 pool.returnObject(obj1); 137 138 // Bug POOL-162 - check there is now an object in the pool 139 pool.setMaxWait(10L); 140 Object obj2 = null; 141 try { 142 obj2 = pool.borrowObject(); 143 assertNotNull(obj2); 144 } catch(NoSuchElementException e) { 145 // Not expected 146 fail("NoSuchElementException not expected"); 147 } 148 pool.returnObject(obj2); 149 pool.close(); 150 } 151 152 public void testWhenExhaustedBlockClosePool() throws Exception { 153 pool.setMaxActive(1); 154 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); 155 pool.setMaxWait(0); 156 Object obj1 = pool.borrowObject(); 157 158 // Make sure an object was obtained 159 assertNotNull(obj1); 160 161 // Create a separate thread to try and borrow another object 162 WaitingTestThread wtt = new WaitingTestThread(pool, 200); 163 wtt.start(); 164 // Give wtt time to start 165 Thread.sleep(200); 166 167 // close the pool (Bug POOL-189) 168 pool.close(); 169 170 // Give interrupt time to take effect 171 Thread.sleep(200); 172 173 // Check thread was interrupted 174 assertTrue(wtt._thrown instanceof IllegalStateException); 175 } 176 177 public void testEvictWhileEmpty() throws Exception { 178 pool.evict(); 179 pool.evict(); 180 pool.close(); 181 } 182 183 /** 184 * Tests addObject contention between ensureMinIdle triggered by 185 * the Evictor with minIdle > 0 and borrowObject. 186 */ 187 public void testEvictAddObjects() throws Exception { 188 SimpleFactory factory = new SimpleFactory(); 189 factory.setMakeLatency(300); 190 factory.setMaxActive(2); 191 GenericObjectPool pool = new GenericObjectPool(factory); 192 pool.setMaxActive(2); 193 pool.setMinIdle(1); 194 pool.borrowObject(); // numActive = 1, numIdle = 0 195 // Create a test thread that will run once and try a borrow after 196 // 150ms fixed delay 197 TestThread borrower = new TestThread(pool, 1, 150, false); 198 Thread borrowerThread = new Thread(borrower); 199 // Set evictor to run in 100 ms - will create idle instance 200 pool.setTimeBetweenEvictionRunsMillis(100); 201 borrowerThread.start(); // Off to the races 202 borrowerThread.join(); 203 assertTrue(!borrower.failed()); 204 pool.close(); 205 } 206 207 public void testEvictLIFO() throws Exception { 208 checkEvict(true); 209 } 210 211 public void testEvictFIFO() throws Exception { 212 checkEvict(false); 213 } 214 215 public void checkEvict(boolean lifo) throws Exception { 216 // yea this is hairy but it tests all the code paths in GOP.evict() 217 final SimpleFactory factory = new SimpleFactory(); 218 final GenericObjectPool pool = new GenericObjectPool(factory); 219 pool.setSoftMinEvictableIdleTimeMillis(10); 220 pool.setMinIdle(2); 221 pool.setTestWhileIdle(true); 222 pool.setLifo(lifo); 223 PoolUtils.prefill(pool, 5); 224 pool.evict(); 225 factory.setEvenValid(false); 226 factory.setOddValid(false); 227 factory.setThrowExceptionOnActivate(true); 228 pool.evict(); 229 PoolUtils.prefill(pool, 5); 230 factory.setThrowExceptionOnActivate(false); 231 factory.setThrowExceptionOnPassivate(true); 232 pool.evict(); 233 factory.setThrowExceptionOnPassivate(false); 234 factory.setEvenValid(true); 235 factory.setOddValid(true); 236 Thread.sleep(125); 237 pool.evict(); 238 assertEquals(2, pool.getNumIdle()); 239 } 240 241 /** 242 * Test to make sure evictor visits least recently used objects first, 243 * regardless of FIFO/LIFO 244 * 245 * JIRA: POOL-86 246 */ 247 public void testEvictionOrder() throws Exception { 248 checkEvictionOrder(false); 249 checkEvictionOrder(true); 250 } 251 252 private void checkEvictionOrder(boolean lifo) throws Exception { 253 SimpleFactory factory = new SimpleFactory(); 254 GenericObjectPool pool = new GenericObjectPool(factory); 255 pool.setNumTestsPerEvictionRun(2); 256 pool.setMinEvictableIdleTimeMillis(100); 257 pool.setLifo(lifo); 258 for (int i = 0; i < 5; i++) { 259 pool.addObject(); 260 Thread.sleep(100); 261 } 262 // Order, oldest to youngest, is "0", "1", ...,"4" 263 pool.evict(); // Should evict "0" and "1" 264 Object obj = pool.borrowObject(); 265 assertTrue("oldest not evicted", !obj.equals("0")); 266 assertTrue("second oldest not evicted", !obj.equals("1")); 267 // 2 should be next out for FIFO, 4 for LIFO 268 assertEquals("Wrong instance returned", lifo ? "4" : "2" , obj); 269 270 // Two eviction runs in sequence 271 factory = new SimpleFactory(); 272 pool = new GenericObjectPool(factory); 273 pool.setNumTestsPerEvictionRun(2); 274 pool.setMinEvictableIdleTimeMillis(100); 275 pool.setLifo(lifo); 276 for (int i = 0; i < 5; i++) { 277 pool.addObject(); 278 Thread.sleep(100); 279 } 280 pool.evict(); // Should evict "0" and "1" 281 pool.evict(); // Should evict "2" and "3" 282 obj = pool.borrowObject(); 283 assertEquals("Wrong instance remaining in pool", "4", obj); 284 } 285 286 /** 287 * Verifies that the evictor visits objects in expected order 288 * and frequency. 289 */ 290 public void testEvictorVisiting() throws Exception { 291 checkEvictorVisiting(true); 292 checkEvictorVisiting(false); 293 } 294 295 private void checkEvictorVisiting(boolean lifo) throws Exception { 296 VisitTrackerFactory factory = new VisitTrackerFactory(); 297 GenericObjectPool pool = new GenericObjectPool(factory); 298 pool.setNumTestsPerEvictionRun(2); 299 pool.setMinEvictableIdleTimeMillis(-1); 300 pool.setTestWhileIdle(true); 301 pool.setLifo(lifo); 302 pool.setTestOnReturn(false); 303 pool.setTestOnBorrow(false); 304 for (int i = 0; i < 8; i++) { 305 pool.addObject(); 306 } 307 pool.evict(); // Visit oldest 2 - 0 and 1 308 Object obj = pool.borrowObject(); 309 pool.returnObject(obj); 310 obj = pool.borrowObject(); 311 pool.returnObject(obj); 312 // borrow, return, borrow, return 313 // FIFO will move 0 and 1 to end 314 // LIFO, 7 out, then in, then out, then in 315 pool.evict(); // Should visit 2 and 3 in either case 316 for (int i = 0; i < 8; i++) { 317 VisitTracker tracker = (VisitTracker) pool.borrowObject(); 318 if (tracker.getId() >= 4) { 319 assertEquals("Unexpected instance visited " + tracker.getId(), 320 0, tracker.getValidateCount()); 321 } else { 322 assertEquals("Instance " + tracker.getId() + 323 " visited wrong number of times.", 324 1, tracker.getValidateCount()); 325 } 326 } 327 328 factory = new VisitTrackerFactory(); 329 pool = new GenericObjectPool(factory); 330 pool.setNumTestsPerEvictionRun(3); 331 pool.setMinEvictableIdleTimeMillis(-1); 332 pool.setTestWhileIdle(true); 333 pool.setLifo(lifo); 334 pool.setTestOnReturn(false); 335 pool.setTestOnBorrow(false); 336 for (int i = 0; i < 8; i++) { 337 pool.addObject(); 338 } 339 pool.evict(); // 0, 1, 2 340 pool.evict(); // 3, 4, 5 341 obj = pool.borrowObject(); 342 pool.returnObject(obj); 343 obj = pool.borrowObject(); 344 pool.returnObject(obj); 345 obj = pool.borrowObject(); 346 pool.returnObject(obj); 347 // borrow, return, borrow, return 348 // FIFO 3,4,5,6,7,0,1,2 349 // LIFO 7,6,5,4,3,2,1,0 350 // In either case, pointer should be at 6 351 pool.evict(); 352 // Should hit 6,7,0 - 0 for second time 353 for (int i = 0; i < 8; i++) { 354 VisitTracker tracker = (VisitTracker) pool.borrowObject(); 355 if (tracker.getId() != 0) { 356 assertEquals("Instance " + tracker.getId() + 357 " visited wrong number of times.", 358 1, tracker.getValidateCount()); 359 } else { 360 assertEquals("Instance " + tracker.getId() + 361 " visited wrong number of times.", 362 2, tracker.getValidateCount()); 363 } 364 } 365 // Randomly generate a pools with random numTests 366 // and make sure evictor cycles through elements appropriately 367 int[] smallPrimes = {2, 3, 5, 7}; 368 Random random = new Random(); 369 random.setSeed(System.currentTimeMillis()); 370 for (int i = 0; i < 4; i++) { 371 pool.setNumTestsPerEvictionRun(smallPrimes[i]); 372 for (int j = 0; j < 5; j++) { 373 pool = new GenericObjectPool(factory); 374 pool.setNumTestsPerEvictionRun(3); 375 pool.setMinEvictableIdleTimeMillis(-1); 376 pool.setTestWhileIdle(true); 377 pool.setLifo(lifo); 378 pool.setTestOnReturn(false); 379 pool.setTestOnBorrow(false); 380 pool.setMaxIdle(-1); 381 int instanceCount = 10 + random.nextInt(20); 382 pool.setMaxActive(instanceCount); 383 for (int k = 0; k < instanceCount; k++) { 384 pool.addObject(); 385 } 386 387 // Execute a random number of evictor runs 388 int runs = 10 + random.nextInt(50); 389 for (int k = 0; k < runs; k++) { 390 pool.evict(); 391 } 392 393 // Number of times evictor should have cycled through the pool 394 int cycleCount = (runs * pool.getNumTestsPerEvictionRun()) 395 / instanceCount; 396 397 // Look at elements and make sure they are visited cycleCount 398 // or cycleCount + 1 times 399 VisitTracker tracker = null; 400 int visitCount = 0; 401 for (int k = 0; k < instanceCount; k++) { 402 tracker = (VisitTracker) pool.borrowObject(); 403 assertTrue(pool.getNumActive() <= pool.getMaxActive()); 404 visitCount = tracker.getValidateCount(); 405 assertTrue(visitCount >= cycleCount && 406 visitCount <= cycleCount + 1); 407 } 408 } 409 } 410 } 411 412 public void testExceptionOnPassivateDuringReturn() throws Exception { 413 SimpleFactory factory = new SimpleFactory(); 414 GenericObjectPool pool = new GenericObjectPool(factory); 415 Object obj = pool.borrowObject(); 416 factory.setThrowExceptionOnPassivate(true); 417 pool.returnObject(obj); 418 assertEquals(0,pool.getNumIdle()); 419 pool.close(); 420 } 421 422 public void testExceptionOnDestroyDuringBorrow() throws Exception { 423 SimpleFactory factory = new SimpleFactory(); 424 factory.setThrowExceptionOnDestroy(true); 425 GenericObjectPool pool = new GenericObjectPool(factory); 426 pool.setTestOnBorrow(true); 427 pool.borrowObject(); 428 factory.setValid(false); // Make validation fail on next borrow attempt 429 try { 430 pool.borrowObject(); 431 fail("Expecting NoSuchElementException"); 432 } catch (NoSuchElementException ex) { 433 // expected 434 } 435 assertEquals(1, pool.getNumActive()); 436 assertEquals(0, pool.getNumIdle()); 437 } 438 439 public void testExceptionOnDestroyDuringReturn() throws Exception { 440 SimpleFactory factory = new SimpleFactory(); 441 factory.setThrowExceptionOnDestroy(true); 442 GenericObjectPool pool = new GenericObjectPool(factory); 443 pool.setTestOnReturn(true); 444 Object obj1 = pool.borrowObject(); 445 pool.borrowObject(); 446 factory.setValid(false); // Make validation fail 447 pool.returnObject(obj1); 448 assertEquals(1, pool.getNumActive()); 449 assertEquals(0, pool.getNumIdle()); 450 } 451 452 public void testExceptionOnActivateDuringBorrow() throws Exception { 453 SimpleFactory factory = new SimpleFactory(); 454 GenericObjectPool pool = new GenericObjectPool(factory); 455 Object obj1 = pool.borrowObject(); 456 Object obj2 = pool.borrowObject(); 457 pool.returnObject(obj1); 458 pool.returnObject(obj2); 459 factory.setThrowExceptionOnActivate(true); 460 factory.setEvenValid(false); 461 // Activation will now throw every other time 462 // First attempt throws, but loop continues and second succeeds 463 Object obj = pool.borrowObject(); 464 assertEquals(1, pool.getNumActive()); 465 assertEquals(0, pool.getNumIdle()); 466 467 pool.returnObject(obj); 468 factory.setValid(false); 469 // Validation will now fail on activation when borrowObject returns 470 // an idle instance, and then when attempting to create a new instance 471 try { 472 obj1 = pool.borrowObject(); 473 fail("Expecting NoSuchElementException"); 474 } catch (NoSuchElementException ex) { 475 // expected 476 } 477 assertEquals(0, pool.getNumActive()); 478 assertEquals(0, pool.getNumIdle()); 479 } 480 481 public void testSetFactoryWithActiveObjects() throws Exception { 482 GenericObjectPool pool = new GenericObjectPool(); 483 pool.setMaxIdle(10); 484 pool.setFactory(new SimpleFactory()); 485 Object obj = pool.borrowObject(); 486 assertNotNull(obj); 487 try { 488 pool.setFactory(null); 489 fail("Expected IllegalStateException"); 490 } catch(IllegalStateException e) { 491 // expected 492 } 493 try { 494 pool.setFactory(new SimpleFactory()); 495 fail("Expected IllegalStateException"); 496 } catch(IllegalStateException e) { 497 // expected 498 } 499 } 500 501 public void testSetFactoryWithNoActiveObjects() throws Exception { 502 GenericObjectPool pool = new GenericObjectPool(); 503 pool.setMaxIdle(10); 504 pool.setFactory(new SimpleFactory()); 505 Object obj = pool.borrowObject(); 506 pool.returnObject(obj); 507 assertEquals(1,pool.getNumIdle()); 508 pool.setFactory(new SimpleFactory()); 509 assertEquals(0,pool.getNumIdle()); 510 } 511 512 public void testNegativeMaxActive() throws Exception { 513 pool.setMaxActive(-1); 514 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL); 515 Object obj = pool.borrowObject(); 516 assertEquals(getNthObject(0),obj); 517 pool.returnObject(obj); 518 } 519 520 public void testMaxIdle() throws Exception { 521 pool.setMaxActive(100); 522 pool.setMaxIdle(8); 523 Object[] active = new Object[100]; 524 for(int i=0;i<100;i++) { 525 active[i] = pool.borrowObject(); 526 } 527 assertEquals(100,pool.getNumActive()); 528 assertEquals(0,pool.getNumIdle()); 529 for(int i=0;i<100;i++) { 530 pool.returnObject(active[i]); 531 assertEquals(99 - i,pool.getNumActive()); 532 assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle()); 533 } 534 } 535 536 public void testMaxIdleZero() throws Exception { 537 pool.setMaxActive(100); 538 pool.setMaxIdle(0); 539 Object[] active = new Object[100]; 540 for(int i=0;i<100;i++) { 541 active[i] = pool.borrowObject(); 542 } 543 assertEquals(100,pool.getNumActive()); 544 assertEquals(0,pool.getNumIdle()); 545 for(int i=0;i<100;i++) { 546 pool.returnObject(active[i]); 547 assertEquals(99 - i,pool.getNumActive()); 548 assertEquals(0, pool.getNumIdle()); 549 } 550 } 551 552 public void testMaxActive() throws Exception { 553 pool.setMaxActive(3); 554 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL); 555 556 pool.borrowObject(); 557 pool.borrowObject(); 558 pool.borrowObject(); 559 try { 560 pool.borrowObject(); 561 fail("Expected NoSuchElementException"); 562 } catch(NoSuchElementException e) { 563 // expected 564 } 565 } 566 567 public void testTimeoutNoLeak() throws Exception { 568 pool.setMaxActive(2); 569 pool.setMaxWait(10); 570 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); 571 Object obj = pool.borrowObject(); 572 Object obj2 = pool.borrowObject(); 573 try { 574 pool.borrowObject(); 575 fail("Expecting NoSuchElementException"); 576 } catch (NoSuchElementException ex) { 577 //xpected 578 } 579 pool.returnObject(obj2); 580 pool.returnObject(obj); 581 582 obj = pool.borrowObject(); 583 obj2 = pool.borrowObject(); 584 } 585 586 public void testMaxActiveZero() throws Exception { 587 pool.setMaxActive(0); 588 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL); 589 590 try { 591 pool.borrowObject(); 592 fail("Expected NoSuchElementException"); 593 } catch(NoSuchElementException e) { 594 // expected 595 } 596 } 597 598 public void testMaxActiveUnderLoad() { 599 // Config 600 int numThreads = 199; // And main thread makes a round 200. 601 int numIter = 20; 602 int delay = 25; 603 int maxActive = 10; 604 605 SimpleFactory factory = new SimpleFactory(); 606 factory.setMaxActive(maxActive); 607 pool.setFactory(factory); 608 pool.setMaxActive(maxActive); 609 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); 610 pool.setTimeBetweenEvictionRunsMillis(-1); 611 612 // Start threads to borrow objects 613 TestThread[] threads = new TestThread[numThreads]; 614 for(int i=0;i<numThreads;i++) { 615 // Factor of 2 on iterations so main thread does work whilst other 616 // threads are running. Factor of 2 on delay so average delay for 617 // other threads == actual delay for main thread 618 threads[i] = new TestThread(pool, numIter * 2, delay * 2); 619 Thread t = new Thread(threads[i]); 620 t.start(); 621 } 622 // Give the threads a chance to start doing some work 623 try { 624 Thread.sleep(5000); 625 } catch(InterruptedException e) { 626 // ignored 627 } 628 629 for (int i = 0; i < numIter; i++) { 630 Object obj = null; 631 try { 632 try { 633 Thread.sleep(delay); 634 } catch(InterruptedException e) { 635 // ignored 636 } 637 obj = pool.borrowObject(); 638 // Under load, observed _numActive > _maxActive 639 if (pool.getNumActive() > pool.getMaxActive()) { 640 throw new IllegalStateException("Too many active objects"); 641 } 642 try { 643 Thread.sleep(delay); 644 } catch(InterruptedException e) { 645 // ignored 646 } 647 } catch (Exception e) { 648 // Shouldn't happen 649 e.printStackTrace(); 650 fail("Exception on borrow"); 651 } finally { 652 if (obj != null) { 653 try { 654 pool.returnObject(obj); 655 } catch (Exception e) { 656 // Ignore 657 } 658 } 659 } 660 } 661 662 for(int i=0;i<numThreads;i++) { 663 while(!(threads[i]).complete()) { 664 try { 665 Thread.sleep(500L); 666 } catch(InterruptedException e) { 667 // ignored 668 } 669 } 670 if(threads[i].failed()) { 671 fail("Thread "+i+" failed: "+threads[i]._error.toString()); 672 } 673 } 674 } 675 676 public void testInvalidWhenExhaustedAction() throws Exception { 677 try { 678 pool.setWhenExhaustedAction(Byte.MAX_VALUE); 679 fail("Expected IllegalArgumentException"); 680 } catch(IllegalArgumentException e) { 681 // expected 682 } 683 684 try { 685 ObjectPool pool = new GenericObjectPool( 686 new SimpleFactory(), 687 GenericObjectPool.DEFAULT_MAX_ACTIVE, 688 Byte.MAX_VALUE, 689 GenericObjectPool.DEFAULT_MAX_WAIT, 690 GenericObjectPool.DEFAULT_MAX_IDLE, 691 false, 692 false, 693 GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, 694 GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN, 695 GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, 696 false 697 ); 698 assertNotNull(pool); 699 fail("Expected IllegalArgumentException"); 700 } catch(IllegalArgumentException e) { 701 // expected 702 } 703 } 704 705 public void testSettersAndGetters() throws Exception { 706 GenericObjectPool pool = new GenericObjectPool(); 707 { 708 pool.setFactory(new SimpleFactory()); 709 } 710 { 711 pool.setMaxActive(123); 712 assertEquals(123,pool.getMaxActive()); 713 } 714 { 715 pool.setMaxIdle(12); 716 assertEquals(12,pool.getMaxIdle()); 717 } 718 { 719 pool.setMaxWait(1234L); 720 assertEquals(1234L,pool.getMaxWait()); 721 } 722 { 723 pool.setMinEvictableIdleTimeMillis(12345L); 724 assertEquals(12345L,pool.getMinEvictableIdleTimeMillis()); 725 } 726 { 727 pool.setNumTestsPerEvictionRun(11); 728 assertEquals(11,pool.getNumTestsPerEvictionRun()); 729 } 730 { 731 pool.setTestOnBorrow(true); 732 assertTrue(pool.getTestOnBorrow()); 733 pool.setTestOnBorrow(false); 734 assertTrue(!pool.getTestOnBorrow()); 735 } 736 { 737 pool.setTestOnReturn(true); 738 assertTrue(pool.getTestOnReturn()); 739 pool.setTestOnReturn(false); 740 assertTrue(!pool.getTestOnReturn()); 741 } 742 { 743 pool.setTestWhileIdle(true); 744 assertTrue(pool.getTestWhileIdle()); 745 pool.setTestWhileIdle(false); 746 assertTrue(!pool.getTestWhileIdle()); 747 } 748 { 749 pool.setTimeBetweenEvictionRunsMillis(11235L); 750 assertEquals(11235L,pool.getTimeBetweenEvictionRunsMillis()); 751 } 752 { 753 pool.setSoftMinEvictableIdleTimeMillis(12135L); 754 assertEquals(12135L,pool.getSoftMinEvictableIdleTimeMillis()); 755 } 756 { 757 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); 758 assertEquals(GenericObjectPool.WHEN_EXHAUSTED_BLOCK,pool.getWhenExhaustedAction()); 759 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL); 760 assertEquals(GenericObjectPool.WHEN_EXHAUSTED_FAIL,pool.getWhenExhaustedAction()); 761 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_GROW); 762 assertEquals(GenericObjectPool.WHEN_EXHAUSTED_GROW,pool.getWhenExhaustedAction()); 763 } 764 } 765 766 public void testDefaultConfiguration() throws Exception { 767 GenericObjectPool pool = new GenericObjectPool(); 768 assertConfiguration(new GenericObjectPool.Config(),pool); 769 } 770 771 public void testConstructors() throws Exception { 772 { 773 GenericObjectPool pool = new GenericObjectPool(); 774 assertConfiguration(new GenericObjectPool.Config(),pool); 775 } 776 { 777 GenericObjectPool pool = new GenericObjectPool(new SimpleFactory()); 778 assertConfiguration(new GenericObjectPool.Config(),pool); 779 } 780 { 781 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 782 expected.maxActive = 2; 783 expected.maxIdle = 3; 784 expected.maxWait = 5L; 785 expected.minEvictableIdleTimeMillis = 7L; 786 expected.numTestsPerEvictionRun = 9; 787 expected.testOnBorrow = true; 788 expected.testOnReturn = true; 789 expected.testWhileIdle = true; 790 expected.timeBetweenEvictionRunsMillis = 11L; 791 expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; 792 GenericObjectPool pool = new GenericObjectPool(null,expected); 793 assertConfiguration(expected,pool); 794 } 795 { 796 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 797 expected.maxActive = 2; 798 GenericObjectPool pool = new GenericObjectPool(null,expected.maxActive); 799 assertConfiguration(expected,pool); 800 } 801 { 802 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 803 expected.maxActive = 2; 804 expected.maxWait = 5L; 805 expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; 806 GenericObjectPool pool = new GenericObjectPool(null,expected.maxActive,expected.whenExhaustedAction,expected.maxWait); 807 assertConfiguration(expected,pool); 808 } 809 { 810 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 811 expected.maxActive = 2; 812 expected.maxWait = 5L; 813 expected.testOnBorrow = true; 814 expected.testOnReturn = true; 815 expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; 816 GenericObjectPool pool = new GenericObjectPool(null,expected.maxActive,expected.whenExhaustedAction,expected.maxWait,expected.testOnBorrow,expected.testOnReturn); 817 assertConfiguration(expected,pool); 818 } 819 { 820 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 821 expected.maxActive = 2; 822 expected.maxIdle = 3; 823 expected.maxWait = 5L; 824 expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; 825 GenericObjectPool pool = new GenericObjectPool(null,expected.maxActive,expected.whenExhaustedAction,expected.maxWait,expected.maxIdle); 826 assertConfiguration(expected,pool); 827 } 828 { 829 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 830 expected.maxActive = 2; 831 expected.maxIdle = 3; 832 expected.maxWait = 5L; 833 expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; 834 expected.testOnBorrow = true; 835 expected.testOnReturn = true; 836 GenericObjectPool pool = new GenericObjectPool(null,expected.maxActive,expected.whenExhaustedAction,expected.maxWait,expected.maxIdle,expected.testOnBorrow,expected.testOnReturn); 837 assertConfiguration(expected,pool); 838 } 839 { 840 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 841 expected.maxActive = 2; 842 expected.maxIdle = 3; 843 expected.maxWait = 5L; 844 expected.minEvictableIdleTimeMillis = 7L; 845 expected.numTestsPerEvictionRun = 9; 846 expected.testOnBorrow = true; 847 expected.testOnReturn = true; 848 expected.testWhileIdle = true; 849 expected.timeBetweenEvictionRunsMillis = 11L; 850 expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; 851 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); 852 assertConfiguration(expected,pool); 853 } 854 { 855 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 856 expected.maxActive = 2; 857 expected.maxIdle = 3; 858 expected.minIdle = 1; 859 expected.maxWait = 5L; 860 expected.minEvictableIdleTimeMillis = 7L; 861 expected.numTestsPerEvictionRun = 9; 862 expected.testOnBorrow = true; 863 expected.testOnReturn = true; 864 expected.testWhileIdle = true; 865 expected.timeBetweenEvictionRunsMillis = 11L; 866 expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; 867 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); 868 assertConfiguration(expected,pool); 869 } 870 } 871 872 public void testSetConfig() throws Exception { 873 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 874 GenericObjectPool pool = new GenericObjectPool(); 875 assertConfiguration(expected,pool); 876 expected.maxActive = 2; 877 expected.maxIdle = 3; 878 expected.maxWait = 5L; 879 expected.minEvictableIdleTimeMillis = 7L; 880 expected.numTestsPerEvictionRun = 9; 881 expected.testOnBorrow = true; 882 expected.testOnReturn = true; 883 expected.testWhileIdle = true; 884 expected.timeBetweenEvictionRunsMillis = 11L; 885 expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; 886 pool.setConfig(expected); 887 assertConfiguration(expected,pool); 888 } 889 890 public void testDebugInfo() throws Exception { 891 GenericObjectPool pool = new GenericObjectPool(new SimpleFactory()); 892 pool.setMaxIdle(3); 893 assertNotNull(pool.debugInfo()); 894 Object obj = pool.borrowObject(); 895 assertNotNull(pool.debugInfo()); 896 pool.returnObject(obj); 897 assertNotNull(pool.debugInfo()); 898 } 899 900 public void testStartAndStopEvictor() throws Exception { 901 // set up pool without evictor 902 pool.setMaxIdle(6); 903 pool.setMaxActive(6); 904 pool.setNumTestsPerEvictionRun(6); 905 pool.setMinEvictableIdleTimeMillis(100L); 906 907 for(int j=0;j<2;j++) { 908 // populate the pool 909 { 910 Object[] active = new Object[6]; 911 for(int i=0;i<6;i++) { 912 active[i] = pool.borrowObject(); 913 } 914 for(int i=0;i<6;i++) { 915 pool.returnObject(active[i]); 916 } 917 } 918 919 // note that it stays populated 920 assertEquals("Should have 6 idle",6,pool.getNumIdle()); 921 922 // start the evictor 923 pool.setTimeBetweenEvictionRunsMillis(50L); 924 925 // wait a second (well, .2 seconds) 926 try { Thread.sleep(200L); } catch(InterruptedException e) { } 927 928 // assert that the evictor has cleared out the pool 929 assertEquals("Should have 0 idle",0,pool.getNumIdle()); 930 931 // stop the evictor 932 pool.startEvictor(0L); 933 } 934 } 935 936 public void testEvictionWithNegativeNumTests() throws Exception { 937 // when numTestsPerEvictionRun is negative, it represents a fraction of the idle objects to test 938 pool.setMaxIdle(6); 939 pool.setMaxActive(6); 940 pool.setNumTestsPerEvictionRun(-2); 941 pool.setMinEvictableIdleTimeMillis(50L); 942 pool.setTimeBetweenEvictionRunsMillis(100L); 943 944 Object[] active = new Object[6]; 945 for(int i=0;i<6;i++) { 946 active[i] = pool.borrowObject(); 947 } 948 for(int i=0;i<6;i++) { 949 pool.returnObject(active[i]); 950 } 951 952 try { Thread.sleep(100L); } catch(InterruptedException e) { } 953 assertTrue("Should at most 6 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 6); 954 try { Thread.sleep(100L); } catch(InterruptedException e) { } 955 assertTrue("Should at most 3 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 3); 956 try { Thread.sleep(100L); } catch(InterruptedException e) { } 957 assertTrue("Should be at most 2 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 2); 958 try { Thread.sleep(100L); } catch(InterruptedException e) { } 959 assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle()); 960 } 961 962 public void testEviction() throws Exception { 963 pool.setMaxIdle(500); 964 pool.setMaxActive(500); 965 pool.setNumTestsPerEvictionRun(100); 966 pool.setMinEvictableIdleTimeMillis(250L); 967 pool.setTimeBetweenEvictionRunsMillis(500L); 968 pool.setTestWhileIdle(true); 969 970 Object[] active = new Object[500]; 971 for(int i=0;i<500;i++) { 972 active[i] = pool.borrowObject(); 973 } 974 for(int i=0;i<500;i++) { 975 pool.returnObject(active[i]); 976 } 977 978 try { Thread.sleep(1000L); } catch(InterruptedException e) { } 979 assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500); 980 try { Thread.sleep(600L); } catch(InterruptedException e) { } 981 assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400); 982 try { Thread.sleep(600L); } catch(InterruptedException e) { } 983 assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300); 984 try { Thread.sleep(600L); } catch(InterruptedException e) { } 985 assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200); 986 try { Thread.sleep(600L); } catch(InterruptedException e) { } 987 assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100); 988 try { Thread.sleep(600L); } catch(InterruptedException e) { } 989 assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle()); 990 991 for(int i=0;i<500;i++) { 992 active[i] = pool.borrowObject(); 993 } 994 for(int i=0;i<500;i++) { 995 pool.returnObject(active[i]); 996 } 997 998 try { Thread.sleep(1000L); } catch(InterruptedException e) { } 999 assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500); 1000 try { Thread.sleep(600L); } catch(InterruptedException e) { } 1001 assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400); 1002 try { Thread.sleep(600L); } catch(InterruptedException e) { } 1003 assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300); 1004 try { Thread.sleep(600L); } catch(InterruptedException e) { } 1005 assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200); 1006 try { Thread.sleep(600L); } catch(InterruptedException e) { } 1007 assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100); 1008 try { Thread.sleep(600L); } catch(InterruptedException e) { } 1009 assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle()); 1010 } 1011 1012 public void testEvictionSoftMinIdle() throws Exception { 1013 GenericObjectPool pool = null; 1014 1015 class TimeTest extends BasePoolableObjectFactory { 1016 private final long createTime; 1017 public TimeTest() { 1018 createTime = System.currentTimeMillis(); 1019 } 1020 public Object makeObject() throws Exception { 1021 return new TimeTest(); 1022 } 1023 public long getCreateTime() { 1024 return createTime; 1025 } 1026 } 1027 1028 pool = new GenericObjectPool(new TimeTest()); 1029 1030 pool.setMaxIdle(5); 1031 pool.setMaxActive(5); 1032 pool.setNumTestsPerEvictionRun(5); 1033 pool.setMinEvictableIdleTimeMillis(3000L); 1034 pool.setSoftMinEvictableIdleTimeMillis(1000L); 1035 pool.setMinIdle(2); 1036 1037 Object[] active = new Object[5]; 1038 Long[] creationTime = new Long[5] ; 1039 for(int i=0;i<5;i++) { 1040 active[i] = pool.borrowObject(); 1041 creationTime[i] = new Long(((TimeTest)active[i]).getCreateTime()); 1042 } 1043 1044 for(int i=0;i<5;i++) { 1045 pool.returnObject(active[i]); 1046 } 1047 1048 // Soft evict all but minIdle(2) 1049 Thread.sleep(1500L); 1050 pool.evict(); 1051 assertEquals("Idle count different than expected.", 2, pool.getNumIdle()); 1052 1053 // Hard evict the rest. 1054 Thread.sleep(2000L); 1055 pool.evict(); 1056 assertEquals("Idle count different than expected.", 0, pool.getNumIdle()); 1057 } 1058 1059 public void testMinIdle() throws Exception { 1060 pool.setMaxIdle(500); 1061 pool.setMinIdle(5); 1062 pool.setMaxActive(10); 1063 pool.setNumTestsPerEvictionRun(0); 1064 pool.setMinEvictableIdleTimeMillis(50L); 1065 pool.setTimeBetweenEvictionRunsMillis(100L); 1066 pool.setTestWhileIdle(true); 1067 1068 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1069 assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5); 1070 1071 Object[] active = new Object[5]; 1072 active[0] = pool.borrowObject(); 1073 1074 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1075 assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5); 1076 1077 for(int i=1 ; i<5 ; i++) { 1078 active[i] = pool.borrowObject(); 1079 } 1080 1081 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1082 assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5); 1083 1084 for(int i=0 ; i<5 ; i++) { 1085 pool.returnObject(active[i]); 1086 } 1087 1088 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1089 assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10); 1090 } 1091 1092 public void testMinIdleMaxActive() throws Exception { 1093 pool.setMaxIdle(500); 1094 pool.setMinIdle(5); 1095 pool.setMaxActive(10); 1096 pool.setNumTestsPerEvictionRun(0); 1097 pool.setMinEvictableIdleTimeMillis(50L); 1098 pool.setTimeBetweenEvictionRunsMillis(100L); 1099 pool.setTestWhileIdle(true); 1100 1101 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1102 assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5); 1103 1104 Object[] active = new Object[10]; 1105 1106 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1107 assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5); 1108 1109 for(int i=0 ; i<5 ; i++) { 1110 active[i] = pool.borrowObject(); 1111 } 1112 1113 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1114 assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5); 1115 1116 for(int i=0 ; i<5 ; i++) { 1117 pool.returnObject(active[i]); 1118 } 1119 1120 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1121 assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10); 1122 1123 for(int i=0 ; i<10 ; i++) { 1124 active[i] = pool.borrowObject(); 1125 } 1126 1127 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1128 assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0); 1129 1130 for(int i=0 ; i<10 ; i++) { 1131 pool.returnObject(active[i]); 1132 } 1133 1134 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1135 assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10); 1136 } 1137 1138 /** 1139 * Kicks off <numThreads> test threads, each of which will go through 1140 * <iterations> borrow-return cycles with random delay times <= delay 1141 * in between. 1142 */ 1143 public void runTestThreads(int numThreads, int iterations, int delay) { 1144 TestThread[] threads = new TestThread[numThreads]; 1145 for(int i=0;i<numThreads;i++) { 1146 threads[i] = new TestThread(pool,iterations,delay); 1147 Thread t = new Thread(threads[i]); 1148 t.start(); 1149 } 1150 for(int i=0;i<numThreads;i++) { 1151 while(!(threads[i]).complete()) { 1152 try { 1153 Thread.sleep(500L); 1154 } catch(InterruptedException e) { 1155 // ignored 1156 } 1157 } 1158 if(threads[i].failed()) { 1159 fail("Thread "+i+" failed: "+threads[i]._error.toString()); 1160 } 1161 } 1162 } 1163 1164 public void testThreaded1() throws Exception { 1165 pool.setMaxActive(15); 1166 pool.setMaxIdle(15); 1167 pool.setMaxWait(1000L); 1168 runTestThreads(20, 100, 50); 1169 } 1170 1171 /** 1172 * Verifies that maxActive is not exceeded when factory destroyObject 1173 * has high latency, testOnReturn is set and there is high incidence of 1174 * validation failures. 1175 */ 1176 public void testMaxActiveInvariant() throws Exception { 1177 int maxActive = 15; 1178 SimpleFactory factory = new SimpleFactory(); 1179 factory.setEvenValid(false); // Every other validation fails 1180 factory.setDestroyLatency(100); // Destroy takes 100 ms 1181 factory.setMaxActive(maxActive); // (makes - destroys) bound 1182 factory.setValidationEnabled(true); 1183 pool = new GenericObjectPool(factory); 1184 pool.setMaxActive(maxActive); 1185 pool.setMaxIdle(-1); 1186 pool.setTestOnReturn(true); 1187 pool.setMaxWait(1000L); 1188 runTestThreads(5, 10, 50); 1189 } 1190 1191 public void testConcurrentBorrowAndEvict() throws Exception { 1192 1193 pool.setMaxActive(1); 1194 pool.addObject(); 1195 1196 for( int i=0; i<5000; i++) { 1197 ConcurrentBorrowAndEvictThread one = 1198 new ConcurrentBorrowAndEvictThread(true); 1199 ConcurrentBorrowAndEvictThread two = 1200 new ConcurrentBorrowAndEvictThread(false); 1201 1202 one.start(); 1203 two.start(); 1204 one.join(); 1205 two.join(); 1206 1207 pool.returnObject(one.obj); 1208 1209 /* Uncomment this for a progress indication 1210 if (i % 10 == 0) { 1211 System.out.println(i/10); 1212 } 1213 */ 1214 } 1215 } 1216 1217 private class ConcurrentBorrowAndEvictThread extends Thread { 1218 private boolean borrow; 1219 public Object obj; 1220 1221 public ConcurrentBorrowAndEvictThread(boolean borrow) { 1222 this.borrow = borrow; 1223 } 1224 1225 public void run() { 1226 try { 1227 if (borrow) { 1228 obj = pool.borrowObject(); 1229 } else { 1230 pool.evict(); 1231 } 1232 } catch (Exception e) { /* Ignore */} 1233 } 1234 } 1235 1236 static class TestThread implements Runnable { 1237 private final java.util.Random _random = new java.util.Random(); 1238 1239 // Thread config items 1240 private final ObjectPool _pool; 1241 private final int _iter; 1242 private final int _delay; 1243 private final boolean _randomDelay; 1244 private final Object _expectedObject; 1245 1246 private volatile boolean _complete = false; 1247 private volatile boolean _failed = false; 1248 private volatile Throwable _error; 1249 1250 public TestThread(ObjectPool pool) { 1251 this(pool, 100, 50, true, null); 1252 } 1253 1254 public TestThread(ObjectPool pool, int iter) { 1255 this(pool, iter, 50, true, null); 1256 } 1257 1258 public TestThread(ObjectPool pool, int iter, int delay) { 1259 this(pool, iter, delay, true, null); 1260 } 1261 1262 public TestThread(ObjectPool pool, int iter, int delay, 1263 boolean randomDelay) { 1264 this(pool, iter, delay, randomDelay, null); 1265 } 1266 1267 public TestThread(ObjectPool pool, int iter, int delay, 1268 boolean randomDelay, Object obj) { 1269 _pool = pool; 1270 _iter = iter; 1271 _delay = delay; 1272 _randomDelay = randomDelay; 1273 _expectedObject = obj; 1274 } 1275 1276 public boolean complete() { 1277 return _complete; 1278 } 1279 1280 public boolean failed() { 1281 return _failed; 1282 } 1283 1284 public void run() { 1285 for(int i=0;i<_iter;i++) { 1286 long delay = 1287 _randomDelay ? (long)_random.nextInt(_delay) : _delay; 1288 try { 1289 Thread.sleep(delay); 1290 } catch(InterruptedException e) { 1291 // ignored 1292 } 1293 Object obj = null; 1294 try { 1295 obj = _pool.borrowObject(); 1296 } catch(Exception e) { 1297 _error = e; 1298 _failed = true; 1299 _complete = true; 1300 break; 1301 } 1302 1303 if (_expectedObject != null && !_expectedObject.equals(obj)) { 1304 _error = new Throwable("Expected: "+_expectedObject+ " found: "+obj); 1305 _failed = true; 1306 _complete = true; 1307 break; 1308 } 1309 1310 try { 1311 Thread.sleep(delay); 1312 } catch(InterruptedException e) { 1313 // ignored 1314 } 1315 try { 1316 _pool.returnObject(obj); 1317 } catch(Exception e) { 1318 _error = e; 1319 _failed = true; 1320 _complete = true; 1321 break; 1322 } 1323 } 1324 _complete = true; 1325 } 1326 } 1327 1328 public void testFIFO() throws Exception { 1329 pool.setLifo(false); 1330 pool.addObject(); // "0" 1331 pool.addObject(); // "1" 1332 pool.addObject(); // "2" 1333 assertEquals("Oldest", "0", pool.borrowObject()); 1334 assertEquals("Middle", "1", pool.borrowObject()); 1335 assertEquals("Youngest", "2", pool.borrowObject()); 1336 assertEquals("new-3", "3", pool.borrowObject()); 1337 pool.returnObject("r"); 1338 assertEquals("returned", "r", pool.borrowObject()); 1339 assertEquals("new-4", "4", pool.borrowObject()); 1340 } 1341 1342 public void testLIFO() throws Exception { 1343 pool.setLifo(true); 1344 pool.addObject(); // "0" 1345 pool.addObject(); // "1" 1346 pool.addObject(); // "2" 1347 assertEquals("Youngest", "2", pool.borrowObject()); 1348 assertEquals("Middle", "1", pool.borrowObject()); 1349 assertEquals("Oldest", "0", pool.borrowObject()); 1350 assertEquals("new-3", "3", pool.borrowObject()); 1351 pool.returnObject("r"); 1352 assertEquals("returned", "r", pool.borrowObject()); 1353 assertEquals("new-4", "4", pool.borrowObject()); 1354 } 1355 1356 public void testAddObject() throws Exception { 1357 assertEquals("should be zero idle", 0, pool.getNumIdle()); 1358 pool.addObject(); 1359 assertEquals("should be one idle", 1, pool.getNumIdle()); 1360 assertEquals("should be zero active", 0, pool.getNumActive()); 1361 Object obj = pool.borrowObject(); 1362 assertEquals("should be zero idle", 0, pool.getNumIdle()); 1363 assertEquals("should be one active", 1, pool.getNumActive()); 1364 pool.returnObject(obj); 1365 assertEquals("should be one idle", 1, pool.getNumIdle()); 1366 assertEquals("should be zero active", 0, pool.getNumActive()); 1367 1368 ObjectPool op = new GenericObjectPool(); 1369 try { 1370 op.addObject(); 1371 fail("Expected IllegalStateException when there is no factory."); 1372 } catch (IllegalStateException ise) { 1373 //expected 1374 } 1375 op.close(); 1376 } 1377 1378 protected GenericObjectPool pool = null; 1379 1380 private void assertConfiguration(GenericObjectPool.Config expected, GenericObjectPool actual) throws Exception { 1381 assertEquals("testOnBorrow",expected.testOnBorrow,actual.getTestOnBorrow()); 1382 assertEquals("testOnReturn",expected.testOnReturn,actual.getTestOnReturn()); 1383 assertEquals("testWhileIdle",expected.testWhileIdle,actual.getTestWhileIdle()); 1384 assertEquals("whenExhaustedAction",expected.whenExhaustedAction,actual.getWhenExhaustedAction()); 1385 assertEquals("maxActive",expected.maxActive,actual.getMaxActive()); 1386 assertEquals("maxIdle",expected.maxIdle,actual.getMaxIdle()); 1387 assertEquals("maxWait",expected.maxWait,actual.getMaxWait()); 1388 assertEquals("minEvictableIdleTimeMillis",expected.minEvictableIdleTimeMillis,actual.getMinEvictableIdleTimeMillis()); 1389 assertEquals("numTestsPerEvictionRun",expected.numTestsPerEvictionRun,actual.getNumTestsPerEvictionRun()); 1390 assertEquals("timeBetweenEvictionRunsMillis",expected.timeBetweenEvictionRunsMillis,actual.getTimeBetweenEvictionRunsMillis()); 1391 } 1392 1393 public class SimpleFactory implements PoolableObjectFactory { 1394 public SimpleFactory() { 1395 this(true); 1396 } 1397 public SimpleFactory(boolean valid) { 1398 this(valid,valid); 1399 } 1400 public SimpleFactory(boolean evalid, boolean ovalid) { 1401 evenValid = evalid; 1402 oddValid = ovalid; 1403 } 1404 public synchronized void setValid(boolean valid) { 1405 setEvenValid(valid); 1406 setOddValid(valid); 1407 } 1408 public synchronized void setEvenValid(boolean valid) { 1409 evenValid = valid; 1410 } 1411 public synchronized void setOddValid(boolean valid) { 1412 oddValid = valid; 1413 } 1414 public synchronized void setThrowExceptionOnPassivate(boolean bool) { 1415 exceptionOnPassivate = bool; 1416 } 1417 public synchronized void setMaxActive(int maxActive) { 1418 this.maxActive = maxActive; 1419 } 1420 public synchronized void setDestroyLatency(long destroyLatency) { 1421 this.destroyLatency = destroyLatency; 1422 } 1423 public synchronized void setMakeLatency(long makeLatency) { 1424 this.makeLatency = makeLatency; 1425 } 1426 public synchronized void setValidateLatency(long validateLatency) { 1427 this.validateLatency = validateLatency; 1428 } 1429 public Object makeObject() { 1430 final long waitLatency; 1431 synchronized(this) { 1432 activeCount++; 1433 if (activeCount > maxActive) { 1434 throw new IllegalStateException( 1435 "Too many active instances: " + activeCount); 1436 } 1437 waitLatency = makeLatency; 1438 } 1439 if (waitLatency > 0) { 1440 doWait(waitLatency); 1441 } 1442 final int counter; 1443 synchronized(this) { 1444 counter = makeCounter++; 1445 } 1446 return String.valueOf(counter); 1447 } 1448 public void destroyObject(Object obj) throws Exception { 1449 final long waitLatency; 1450 final boolean hurl; 1451 synchronized(this) { 1452 waitLatency = destroyLatency; 1453 hurl = exceptionOnDestroy; 1454 } 1455 if (waitLatency > 0) { 1456 doWait(waitLatency); 1457 } 1458 synchronized(this) { 1459 activeCount--; 1460 } 1461 if (hurl) { 1462 throw new Exception(); 1463 } 1464 } 1465 public boolean validateObject(Object obj) { 1466 final boolean validate; 1467 final boolean evenTest; 1468 final boolean oddTest; 1469 final long waitLatency; 1470 final int counter; 1471 synchronized(this) { 1472 validate = enableValidation; 1473 evenTest = evenValid; 1474 oddTest = oddValid; 1475 counter = validateCounter++; 1476 waitLatency = validateLatency; 1477 } 1478 if (waitLatency > 0) { 1479 doWait(waitLatency); 1480 } 1481 if (validate) { 1482 return counter%2 == 0 ? evenTest : oddTest; 1483 } 1484 else { 1485 return true; 1486 } 1487 } 1488 public void activateObject(Object obj) throws Exception { 1489 final boolean hurl; 1490 final boolean evenTest; 1491 final boolean oddTest; 1492 final int counter; 1493 synchronized(this) { 1494 hurl = exceptionOnActivate; 1495 evenTest = evenValid; 1496 oddTest = oddValid; 1497 counter = validateCounter++; 1498 } 1499 if (hurl) { 1500 if (!(counter%2 == 0 ? evenTest : oddTest)) { 1501 throw new Exception(); 1502 } 1503 } 1504 } 1505 public void passivateObject(Object obj) throws Exception { 1506 final boolean hurl; 1507 synchronized(this) { 1508 hurl = exceptionOnPassivate; 1509 } 1510 if (hurl) { 1511 throw new Exception(); 1512 } 1513 } 1514 int makeCounter = 0; 1515 int validateCounter = 0; 1516 int activeCount = 0; 1517 boolean evenValid = true; 1518 boolean oddValid = true; 1519 boolean exceptionOnPassivate = false; 1520 boolean exceptionOnActivate = false; 1521 boolean exceptionOnDestroy = false; 1522 boolean enableValidation = true; 1523 long destroyLatency = 0; 1524 long makeLatency = 0; 1525 long validateLatency = 0; 1526 int maxActive = Integer.MAX_VALUE; 1527 1528 public synchronized boolean isThrowExceptionOnActivate() { 1529 return exceptionOnActivate; 1530 } 1531 1532 public synchronized void setThrowExceptionOnActivate(boolean b) { 1533 exceptionOnActivate = b; 1534 } 1535 1536 public synchronized void setThrowExceptionOnDestroy(boolean b) { 1537 exceptionOnDestroy = b; 1538 } 1539 1540 public synchronized boolean isValidationEnabled() { 1541 return enableValidation; 1542 } 1543 1544 public synchronized void setValidationEnabled(boolean b) { 1545 enableValidation = b; 1546 } 1547 1548 public synchronized int getMakeCounter() { 1549 return makeCounter; 1550 } 1551 1552 private void doWait(long latency) { 1553 try { 1554 Thread.sleep(latency); 1555 } catch (InterruptedException ex) { 1556 // ignore 1557 } 1558 } 1559 } 1560 protected boolean isLifo() { 1561 return true; 1562 } 1563 1564 protected boolean isFifo() { 1565 return false; 1566 } 1567 1568 /* 1569 * Note: This test relies on timing for correct execution. There *should* be 1570 * enough margin for this to work correctly on most (all?) systems but be 1571 * aware of this if you see a failure of this test. 1572 */ 1573 public void testBorrowObjectFairness() { 1574 // Config 1575 int numThreads = 30; 1576 int maxActive = 10; 1577 1578 SimpleFactory factory = new SimpleFactory(); 1579 factory.setMaxActive(maxActive); 1580 pool.setFactory(factory); 1581 pool.setMaxActive(maxActive); 1582 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); 1583 pool.setTimeBetweenEvictionRunsMillis(-1); 1584 1585 // Start threads to borrow objects 1586 TestThread[] threads = new TestThread[numThreads]; 1587 for(int i=0;i<numThreads;i++) { 1588 threads[i] = new TestThread(pool, 1, 2000, false, String.valueOf(i % maxActive)); 1589 Thread t = new Thread(threads[i]); 1590 t.start(); 1591 // Short delay to ensure threads start in correct order 1592 try { 1593 Thread.sleep(50); 1594 } catch (InterruptedException e) { 1595 fail(e.toString()); 1596 } 1597 } 1598 1599 // Wait for threads to finish 1600 for(int i=0;i<numThreads;i++) { 1601 while(!(threads[i]).complete()) { 1602 try { 1603 Thread.sleep(500L); 1604 } catch(InterruptedException e) { 1605 // ignored 1606 } 1607 } 1608 if(threads[i].failed()) { 1609 fail("Thread "+i+" failed: "+threads[i]._error.toString()); 1610 } 1611 } 1612 } 1613 1614 /** 1615 * On first borrow, first object fails validation, second object is OK. 1616 * Subsequent borrows are OK. This was POOL-152. 1617 */ 1618 public void testBrokenFactoryShouldNotBlockPool() { 1619 int maxActive = 1; 1620 1621 SimpleFactory factory = new SimpleFactory(); 1622 factory.setMaxActive(maxActive); 1623 pool.setFactory(factory); 1624 pool.setMaxActive(maxActive); 1625 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); 1626 pool.setTestOnBorrow(true); 1627 1628 // First borrow object will need to create a new object which will fail 1629 // validation. 1630 Object obj = null; 1631 Exception ex = null; 1632 factory.setValid(false); 1633 try { 1634 obj = pool.borrowObject(); 1635 } catch (Exception e) { 1636 ex = e; 1637 } 1638 // Failure expected 1639 assertNotNull(ex); 1640 assertTrue(ex instanceof NoSuchElementException); 1641 assertNull(obj); 1642 1643 // Configure factory to create valid objects so subsequent borrows work 1644 factory.setValid(true); 1645 1646 // Subsequent borrows should be OK 1647 try { 1648 obj = pool.borrowObject(); 1649 } catch (Exception e1) { 1650 fail(); 1651 } 1652 assertNotNull(obj); 1653 try { 1654 pool.returnObject(obj); 1655 } catch (Exception e) { 1656 fail(); 1657 } 1658 1659 } 1660 1661 /* 1662 * Very simple test thread that just tries to borrow an object from 1663 * the provided pool returns it after a wait 1664 */ 1665 static class WaitingTestThread extends Thread { 1666 private final GenericObjectPool _pool; 1667 private final long _pause; 1668 private Throwable _thrown; 1669 1670 private long preborrow; // just before borrow 1671 private long postborrow; // borrow returned 1672 private long postreturn; // after object was returned 1673 private long ended; 1674 private String objectId; 1675 1676 public WaitingTestThread(GenericObjectPool pool, long pause) { 1677 _pool = pool; 1678 _pause = pause; 1679 _thrown = null; 1680 } 1681 1682 public void run() { 1683 try { 1684 preborrow = System.currentTimeMillis(); 1685 Object obj = _pool.borrowObject(); 1686 objectId=obj.toString(); 1687 postborrow = System.currentTimeMillis(); 1688 Thread.sleep(_pause); 1689 _pool.returnObject(obj); 1690 postreturn = System.currentTimeMillis(); 1691 } catch (Exception e) { 1692 _thrown = e; 1693 } finally{ 1694 ended = System.currentTimeMillis(); 1695 } 1696 } 1697 } 1698 1699 private static final boolean DISPLAY_THREAD_DETAILS= 1700 Boolean.valueOf(System.getProperty("TestGenericObjectPool.display.thread.details", "false")).booleanValue(); 1701 // To pass this to a Maven test, use: 1702 // mvn test -DargLine="-DTestGenericObjectPool.display.thread.details=true" 1703 // @see http://jira.codehaus.org/browse/SUREFIRE-121 1704 1705 /* 1706 * Test multi-threaded pool access. 1707 * Multiple threads, but maxActive only allows half the threads to succeed. 1708 * 1709 * This test was prompted by Continuum build failures in the Commons DBCP test case: 1710 * TestPerUserPoolDataSource.testMultipleThreads2() 1711 * Let's see if the this fails on Continuum too! 1712 */ 1713 public void testMaxWaitMultiThreaded() throws Exception { 1714 final long maxWait = 500; // wait for connection 1715 final long holdTime = 2 * maxWait; // how long to hold connection 1716 final int threads = 10; // number of threads to grab the object initially 1717 SimpleFactory factory = new SimpleFactory(); 1718 GenericObjectPool pool = new GenericObjectPool(factory); 1719 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); 1720 pool.setMaxWait(maxWait); 1721 pool.setMaxActive(threads); 1722 // Create enough threads so half the threads will have to wait 1723 WaitingTestThread wtt[] = new WaitingTestThread[threads * 2]; 1724 for(int i=0; i < wtt.length; i++){ 1725 wtt[i] = new WaitingTestThread(pool,holdTime); 1726 } 1727 long origin = System.currentTimeMillis()-1000; 1728 for(int i=0; i < wtt.length; i++){ 1729 wtt[i].start(); 1730 } 1731 int failed = 0; 1732 for(int i=0; i < wtt.length; i++){ 1733 wtt[i].join(); 1734 if (wtt[i]._thrown != null){ 1735 failed++; 1736 } 1737 } 1738 if (DISPLAY_THREAD_DETAILS || wtt.length/2 != failed){ 1739 System.out.println( 1740 "MaxWait: "+maxWait 1741 +" HoldTime: "+holdTime 1742 + " MaxActive: "+threads 1743 +" Threads: "+wtt.length 1744 +" Failed: "+failed 1745 ); 1746 for(int i=0; i < wtt.length; i++){ 1747 WaitingTestThread wt = wtt[i]; 1748 System.out.println( 1749 "Preborrow: "+(wt.preborrow-origin) 1750 + " Postborrow: "+(wt.postborrow != 0 ? wt.postborrow-origin : -1) 1751 + " BorrowTime: "+(wt.postborrow != 0 ? wt.postborrow-wt.preborrow : -1) 1752 + " PostReturn: "+(wt.postreturn != 0 ? wt.postreturn-origin : -1) 1753 + " Ended: "+(wt.ended-origin) 1754 + " ObjId: "+wt.objectId 1755 ); 1756 } 1757 } 1758 assertEquals("Expected half the threads to fail",wtt.length/2,failed); 1759 } 1760 1761 /** 1762 * Test the following scenario: 1763 * Thread 1 borrows an instance 1764 * Thread 2 starts to borrow another instance before thread 1 returns its instance 1765 * Thread 1 returns its instance while thread 2 is validating its newly created instance 1766 * The test verifies that the instance created by Thread 2 is not leaked. 1767 */ 1768 public void testMakeConcurrentWithReturn() throws Exception { 1769 SimpleFactory factory = new SimpleFactory(); 1770 GenericObjectPool pool = new GenericObjectPool(factory); 1771 pool.setTestOnBorrow(true); 1772 factory.setValid(true); 1773 // Borrow and return an instance, with a short wait 1774 WaitingTestThread thread1 = new WaitingTestThread(pool, 200); 1775 thread1.start(); 1776 Thread.sleep(50); // wait for validation to succeed 1777 // Slow down validation and borrow an instance 1778 factory.setValidateLatency(400); 1779 Object instance = pool.borrowObject(); 1780 // Now make sure that we have not leaked an instance 1781 assertEquals(factory.getMakeCounter(), pool.getNumIdle() + 1); 1782 pool.returnObject(instance); 1783 assertEquals(factory.getMakeCounter(), pool.getNumIdle()); 1784 } 1785 }