1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.pool2.impl;
19
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertFalse;
22 import static org.junit.jupiter.api.Assertions.assertNotEquals;
23 import static org.junit.jupiter.api.Assertions.assertNotNull;
24 import static org.junit.jupiter.api.Assertions.assertNotSame;
25 import static org.junit.jupiter.api.Assertions.assertSame;
26 import static org.junit.jupiter.api.Assertions.assertThrows;
27 import static org.junit.jupiter.api.Assertions.assertTrue;
28 import static org.junit.jupiter.api.Assertions.fail;
29
30 import java.lang.management.ManagementFactory;
31 import java.time.Duration;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.HashSet;
35 import java.util.List;
36 import java.util.NoSuchElementException;
37 import java.util.Objects;
38 import java.util.Random;
39 import java.util.Set;
40 import java.util.Timer;
41 import java.util.TimerTask;
42 import java.util.concurrent.ConcurrentHashMap;
43 import java.util.concurrent.ExecutionException;
44 import java.util.concurrent.ExecutorService;
45 import java.util.concurrent.Executors;
46 import java.util.concurrent.Future;
47 import java.util.concurrent.Semaphore;
48 import java.util.concurrent.ThreadFactory;
49 import java.util.concurrent.TimeUnit;
50 import java.util.concurrent.atomic.AtomicInteger;
51
52 import javax.management.MBeanServer;
53 import javax.management.ObjectName;
54
55 import org.apache.commons.lang3.exception.ExceptionUtils;
56 import org.apache.commons.pool2.AbstractTestKeyedObjectPool;
57 import org.apache.commons.pool2.BaseKeyedPooledObjectFactory;
58 import org.apache.commons.pool2.DestroyMode;
59 import org.apache.commons.pool2.KeyedObjectPool;
60 import org.apache.commons.pool2.KeyedPooledObjectFactory;
61 import org.apache.commons.pool2.PooledObject;
62 import org.apache.commons.pool2.VisitTracker;
63 import org.apache.commons.pool2.VisitTrackerFactory;
64 import org.apache.commons.pool2.Waiter;
65 import org.apache.commons.pool2.WaiterFactory;
66 import org.junit.jupiter.api.AfterEach;
67 import org.junit.jupiter.api.BeforeEach;
68 import org.junit.jupiter.api.Test;
69 import org.junit.jupiter.api.Timeout;
70 import org.junit.jupiter.params.ParameterizedTest;
71 import org.junit.jupiter.params.provider.EnumSource;
72
73
74
75 public class TestGenericKeyedObjectPool extends AbstractTestKeyedObjectPool {
76
77 private static final class DaemonThreadFactory implements ThreadFactory {
78 @Override
79 public Thread newThread(final Runnable r) {
80 final Thread t = new Thread(r);
81 t.setDaemon(true);
82 return t;
83 }
84 }
85
86 private static final class DummyFactory extends BaseKeyedPooledObjectFactory<Object, Object> {
87 @Override
88 public Object create(final Object key) {
89 return null;
90 }
91 @Override
92 public PooledObject<Object> wrap(final Object value) {
93 return new DefaultPooledObject<>(value);
94 }
95 }
96
97
98
99
100
101
102 private static final class HashSetFactory
103 extends BaseKeyedPooledObjectFactory<String, HashSet<String>> {
104 @Override
105 public HashSet<String> create(final String key) {
106 return new HashSet<>();
107 }
108 @Override
109 public PooledObject<HashSet<String>> wrap(final HashSet<String> value) {
110 return new DefaultPooledObject<>(value);
111 }
112 }
113
114
115
116
117 static class InvalidateThread implements Runnable {
118
119 private final String obj;
120 private final KeyedObjectPool<String, String> pool;
121 private final String key;
122 private boolean done;
123
124 public InvalidateThread(final KeyedObjectPool<String, String> pool, final String key, final String obj) {
125 this.obj = obj;
126 this.pool = pool;
127 this.key = key;
128 }
129
130 public boolean complete() {
131 return done;
132 }
133
134 @Override
135 public void run() {
136 try {
137 pool.invalidateObject(key, obj);
138 } catch (final IllegalStateException ex) {
139
140 } catch (final Exception ex) {
141 fail("Unexpected exception " + ex.toString());
142 } finally {
143 done = true;
144 }
145 }
146 }
147
148 private static final class ObjectFactory
149 extends BaseKeyedPooledObjectFactory<Integer, Object> {
150
151 @Override
152 public Object create(final Integer key) {
153 return new Object();
154 }
155
156 @Override
157 public PooledObject<Object> wrap(final Object value) {
158 return new DefaultPooledObject<>(value);
159 }
160 }
161
162 public static class SimpleFactory<K> implements KeyedPooledObjectFactory<K, String> {
163 volatile int counter;
164 final boolean valid;
165 int activeCount;
166 int validateCounter;
167 boolean evenValid = true;
168 boolean oddValid = true;
169 boolean enableValidation;
170
171 long destroyLatency;
172 long makeLatency;
173 long validateLatency;
174 volatile int maxTotalPerKey = Integer.MAX_VALUE;
175 boolean exceptionOnPassivate;
176 boolean exceptionOnActivate;
177 boolean exceptionOnDestroy;
178 boolean exceptionOnValidate;
179
180 boolean exceptionOnCreate;
181
182 public SimpleFactory() {
183 this(true);
184 }
185
186 public SimpleFactory(final boolean valid) {
187 this.valid = valid;
188 }
189
190 @Override
191 public void activateObject(final K key, final PooledObject<String> obj) throws Exception {
192 if (exceptionOnActivate && !(validateCounter++ % 2 == 0 ? evenValid : oddValid)) {
193 throw new Exception();
194 }
195 }
196
197 @Override
198 public void destroyObject(final K key, final PooledObject<String> obj) throws Exception {
199 doWait(destroyLatency);
200 synchronized(this) {
201 activeCount--;
202 }
203 if (exceptionOnDestroy) {
204 throw new Exception();
205 }
206 }
207
208 private void doWait(final long latency) {
209 Waiter.sleepQuietly(latency);
210 }
211
212 @Override
213 public PooledObject<String> makeObject(final K key) throws Exception {
214 if (exceptionOnCreate) {
215 throw new Exception();
216 }
217 doWait(makeLatency);
218 String out = null;
219 synchronized(this) {
220 activeCount++;
221 if (activeCount > maxTotalPerKey) {
222 throw new IllegalStateException(
223 "Too many active instances: " + activeCount);
224 }
225 out = String.valueOf(key) + String.valueOf(counter++);
226 }
227 return new DefaultPooledObject<>(out);
228 }
229
230 @Override
231 public void passivateObject(final K key, final PooledObject<String> obj) throws Exception {
232 if (exceptionOnPassivate) {
233 throw new Exception();
234 }
235 }
236
237 public void setDestroyLatency(final long destroyLatency) {
238 this.destroyLatency = destroyLatency;
239 }
240
241 void setEvenValid(final boolean valid) {
242 evenValid = valid;
243 }
244
245 public void setMakeLatency(final long makeLatency) {
246 this.makeLatency = makeLatency;
247 }
248
249 public void setMaxTotalPerKey(final int maxTotalPerKey) {
250 this.maxTotalPerKey = maxTotalPerKey;
251 }
252
253 public void setThrowExceptionOnActivate(final boolean b) {
254 exceptionOnActivate = b;
255 }
256
257 public void setThrowExceptionOnDestroy(final boolean b) {
258 exceptionOnDestroy = b;
259 }
260
261 public void setThrowExceptionOnPassivate(final boolean b) {
262 exceptionOnPassivate = b;
263 }
264
265 public void setThrowExceptionOnValidate(final boolean b) {
266 exceptionOnValidate = b;
267 }
268
269 void setValid(final boolean valid) {
270 evenValid = valid;
271 oddValid = valid;
272 }
273
274 public void setValidateLatency(final long validateLatency) {
275 this.validateLatency = validateLatency;
276 }
277
278 public void setValidationEnabled(final boolean b) {
279 enableValidation = b;
280 }
281
282 @Override
283 public boolean validateObject(final K key, final PooledObject<String> obj) {
284 doWait(validateLatency);
285 if (exceptionOnValidate) {
286 throw new RuntimeException("validation failed");
287 }
288 if (enableValidation) {
289 return validateCounter++ % 2 == 0 ? evenValid : oddValid;
290 }
291 return valid;
292 }
293 }
294
295 private static final class SimplePerKeyFactory extends BaseKeyedPooledObjectFactory<Object, Object> {
296 final ConcurrentHashMap<Object, AtomicInteger> map = new ConcurrentHashMap<>();
297
298 @Override
299 public Object create(final Object key) {
300 final int counter = map.computeIfAbsent(key, k -> new AtomicInteger(-1)).incrementAndGet();
301 return String.valueOf(key) + String.valueOf(counter);
302 }
303
304 @Override
305 public PooledObject<Object> wrap(final Object value) {
306 return new DefaultPooledObject<>(value);
307 }
308 }
309
310
311
312
313
314 static class SimpleTestThread<T> implements Runnable {
315 private final KeyedObjectPool<String, T> pool;
316 private final String key;
317
318 public SimpleTestThread(final KeyedObjectPool<String, T> pool, final String key) {
319 this.pool = pool;
320 this.key = key;
321 }
322
323 @Override
324 public void run() {
325 try {
326 pool.returnObject(key, pool.borrowObject(key));
327 } catch (final Exception e) {
328
329 }
330 }
331 }
332
333
334
335
336 private static final class SlowEvictionPolicy<T> extends DefaultEvictionPolicy<T> {
337 private final long delay;
338
339
340
341
342
343
344 public SlowEvictionPolicy(final long delay) {
345 this.delay = delay;
346 }
347
348 @Override
349 public boolean evict(final EvictionConfig config, final PooledObject<T> underTest,
350 final int idleCount) {
351 Waiter.sleepQuietly(delay);
352 return super.evict(config, underTest, idleCount);
353 }
354 }
355
356 static class TestThread<T> implements Runnable {
357 private final Random random = new Random();
358
359
360 private final KeyedObjectPool<String, T> pool;
361
362 private final int iter;
363
364 private final int startDelay;
365
366 private final int holdTime;
367
368 private final boolean randomDelay;
369
370 private final T expectedObject;
371
372 private final String key;
373
374 private volatile boolean complete;
375 private volatile boolean failed;
376 private volatile Exception exception;
377
378 public TestThread(final KeyedObjectPool<String, T> pool) {
379 this(pool, 100, 50, 50, true, null, null);
380 }
381
382 public TestThread(final KeyedObjectPool<String, T> pool, final int iter) {
383 this(pool, iter, 50, 50, true, null, null);
384 }
385
386 public TestThread(final KeyedObjectPool<String, T> pool, final int iter, final int delay) {
387 this(pool, iter, delay, delay, true, null, null);
388 }
389
390 public TestThread(final KeyedObjectPool<String, T> pool, final int iter, final int startDelay,
391 final int holdTime, final boolean randomDelay, final T expectedObject, final String key) {
392 this.pool = pool;
393 this.iter = iter;
394 this.startDelay = startDelay;
395 this.holdTime = holdTime;
396 this.randomDelay = randomDelay;
397 this.expectedObject = expectedObject;
398 this.key = key;
399
400 }
401
402 public boolean complete() {
403 return complete;
404 }
405
406 public boolean failed() {
407 return failed;
408 }
409
410 @Override
411 public void run() {
412 for (int i = 0; i < iter; i++) {
413 final String actualKey = key == null ? String.valueOf(random.nextInt(3)) : key;
414 Waiter.sleepQuietly(randomDelay ? random.nextInt(startDelay) : startDelay);
415 T obj = null;
416 try {
417 obj = pool.borrowObject(actualKey);
418 } catch (final Exception e) {
419 exception = e;
420 failed = true;
421 complete = true;
422 break;
423 }
424
425 if (expectedObject != null && !expectedObject.equals(obj)) {
426 exception = new Exception("Expected: " + expectedObject + " found: " + obj);
427 failed = true;
428 complete = true;
429 break;
430 }
431
432 Waiter.sleepQuietly(randomDelay ? random.nextInt(holdTime) : holdTime);
433 try {
434 pool.returnObject(actualKey, obj);
435 } catch (final Exception e) {
436 exception = e;
437 failed = true;
438 complete = true;
439 break;
440 }
441 }
442 complete = true;
443 }
444 }
445
446
447
448
449
450 static class WaitingTestThread extends Thread {
451 private final KeyedObjectPool<String, String> pool;
452 private final String key;
453 private final long pause;
454 private Throwable thrown;
455
456 private long preBorrowMillis;
457 private long postBorrowMillis;
458 private long postReturnMillis;
459 private long endedMillis;
460 private String objectId;
461
462 public WaitingTestThread(final KeyedObjectPool<String, String> pool, final String key, final long pause) {
463 this.pool = pool;
464 this.key = key;
465 this.pause = pause;
466 this.thrown = null;
467 }
468
469 @Override
470 public void run() {
471 try {
472 preBorrowMillis = System.currentTimeMillis();
473 final String obj = pool.borrowObject(key);
474 objectId = obj;
475 postBorrowMillis = System.currentTimeMillis();
476 Thread.sleep(pause);
477 pool.returnObject(key, obj);
478 postReturnMillis = System.currentTimeMillis();
479 } catch (final Exception e) {
480 thrown = e;
481 } finally{
482 endedMillis = System.currentTimeMillis();
483 }
484 }
485 }
486
487 private static final Integer KEY_ZERO = Integer.valueOf(0);
488
489 private static final Integer KEY_ONE = Integer.valueOf(1);
490
491 private static final Integer KEY_TWO = Integer.valueOf(2);
492
493 private static final boolean DISPLAY_THREAD_DETAILS=
494 Boolean.getBoolean("TestGenericKeyedObjectPool.display.thread.details");
495
496
497
498
499
500 private GenericKeyedObjectPool<String, String> gkoPool;
501
502
503 private SimpleFactory<String> simpleFactory;
504
505 private void checkEvictionOrder(final boolean lifo) throws Exception {
506 final SimpleFactory<Integer> intFactory = new SimpleFactory<>();
507 try (final GenericKeyedObjectPool<Integer, String> intPool = new GenericKeyedObjectPool<>(intFactory)) {
508 intPool.setNumTestsPerEvictionRun(2);
509 intPool.setMinEvictableIdleTime(Duration.ofMillis(100));
510 intPool.setLifo(lifo);
511
512 for (int i = 0; i < 3; i++) {
513 final Integer key = Integer.valueOf(i);
514 for (int j = 0; j < 5; j++) {
515 intPool.addObject(key);
516 }
517 }
518
519
520 Thread.sleep(200);
521
522
523
524
525
526
527
528
529 intPool.evict();
530 assertEquals(3, intPool.getNumIdle(KEY_ZERO));
531 final String objZeroA = intPool.borrowObject(KEY_ZERO);
532 assertTrue(lifo ? objZeroA.equals("04") : objZeroA.equals("02"));
533 assertEquals(2, intPool.getNumIdle(KEY_ZERO));
534 final String objZeroB = intPool.borrowObject(KEY_ZERO);
535 assertEquals("03", objZeroB);
536 assertEquals(1, intPool.getNumIdle(KEY_ZERO));
537
538 intPool.evict();
539 assertEquals(0, intPool.getNumIdle(KEY_ZERO));
540 assertEquals(4, intPool.getNumIdle(KEY_ONE));
541 final String objOneA = intPool.borrowObject(KEY_ONE);
542 assertTrue(lifo ? objOneA.equals("19") : objOneA.equals("16"));
543 assertEquals(3, intPool.getNumIdle(KEY_ONE));
544 final String objOneB = intPool.borrowObject(KEY_ONE);
545 assertTrue(lifo ? objOneB.equals("18") : objOneB.equals("17"));
546 assertEquals(2, intPool.getNumIdle(KEY_ONE));
547
548 intPool.evict();
549 assertEquals(0, intPool.getNumIdle(KEY_ONE));
550 intPool.evict();
551 assertEquals(3, intPool.getNumIdle(KEY_TWO));
552 final String objTwoA = intPool.borrowObject(KEY_TWO);
553 assertTrue(lifo ? objTwoA.equals("214") : objTwoA.equals("212"));
554 assertEquals(2, intPool.getNumIdle(KEY_TWO));
555 intPool.evict();
556 assertEquals(0, intPool.getNumIdle(KEY_TWO));
557
558 intPool.evict();
559
560 intPool.returnObject(KEY_ZERO, objZeroA);
561 intPool.returnObject(KEY_ZERO, objZeroB);
562 intPool.returnObject(KEY_ONE, objOneA);
563 intPool.returnObject(KEY_ONE, objOneB);
564 intPool.returnObject(KEY_TWO, objTwoA);
565
566 intPool.clear();
567
568
569 intPool.setMinEvictableIdleTime(Duration.ofMillis(500));
570 intFactory.counter = 0;
571 for (int i = 0; i < 3; i++) {
572 final Integer key = Integer.valueOf(i);
573 for (int j = 0; j < 5; j++) {
574 intPool.addObject(key);
575 }
576 Thread.sleep(200);
577 }
578
579
580 intPool.evict();
581 assertEquals(3, intPool.getNumIdle(KEY_ZERO));
582 intPool.evict();
583 assertEquals(1, intPool.getNumIdle(KEY_ZERO));
584 intPool.evict();
585 assertEquals(0, intPool.getNumIdle(KEY_ZERO));
586 assertEquals(5, intPool.getNumIdle(KEY_ONE));
587 assertEquals(5, intPool.getNumIdle(KEY_TWO));
588 intPool.evict();
589 assertEquals(5, intPool.getNumIdle(KEY_ONE));
590 assertEquals(5, intPool.getNumIdle(KEY_TWO));
591 intPool.evict();
592 assertEquals(5, intPool.getNumIdle(KEY_ONE));
593 assertEquals(5, intPool.getNumIdle(KEY_TWO));
594 intPool.evict();
595 assertEquals(5, intPool.getNumIdle(KEY_ONE));
596 assertEquals(5, intPool.getNumIdle(KEY_TWO));
597 intPool.evict();
598 assertEquals(5, intPool.getNumIdle(KEY_ONE));
599 assertEquals(5, intPool.getNumIdle(KEY_TWO));
600 intPool.evict();
601 assertEquals(5, intPool.getNumIdle(KEY_ONE));
602 assertEquals(5, intPool.getNumIdle(KEY_TWO));
603 Thread.sleep(200);
604 intPool.evict();
605 assertEquals(3, intPool.getNumIdle(KEY_ONE));
606 assertEquals(5, intPool.getNumIdle(KEY_TWO));
607 final String obj = intPool.borrowObject(KEY_ONE);
608 if (lifo) {
609 assertEquals("19", obj);
610 } else {
611 assertEquals("15", obj);
612 }
613 }
614 }
615
616 private void checkEvictorVisiting(final boolean lifo) throws Exception {
617 VisitTrackerFactory<Integer> trackerFactory = new VisitTrackerFactory<>();
618 try (GenericKeyedObjectPool<Integer, VisitTracker<Integer>> intPool = new GenericKeyedObjectPool<>(
619 trackerFactory)) {
620 intPool.setNumTestsPerEvictionRun(2);
621 intPool.setMinEvictableIdleTime(Duration.ofMillis(-1));
622 intPool.setTestWhileIdle(true);
623 intPool.setLifo(lifo);
624 intPool.setTestOnReturn(false);
625 intPool.setTestOnBorrow(false);
626 for (int i = 0; i < 3; i++) {
627 trackerFactory.resetId();
628 final Integer key = Integer.valueOf(i);
629 for (int j = 0; j < 8; j++) {
630 intPool.addObject(key);
631 }
632 }
633 intPool.evict();
634 VisitTracker<Integer> obj = intPool.borrowObject(KEY_ZERO);
635 intPool.returnObject(KEY_ZERO, obj);
636 obj = intPool.borrowObject(KEY_ZERO);
637 intPool.returnObject(KEY_ZERO, obj);
638
639
640
641 intPool.evict();
642 for (int i = 0; i < 8; i++) {
643 final VisitTracker<Integer> tracker = intPool.borrowObject(KEY_ZERO);
644 if (tracker.getId() >= 4) {
645 assertEquals(0, tracker.getValidateCount(), "Unexpected instance visited " + tracker.getId());
646 } else {
647 assertEquals(1,
648 tracker.getValidateCount(),"Instance " + tracker.getId() + " visited wrong number of times.");
649 }
650 }
651
652
653 intPool.setNumTestsPerEvictionRun(3);
654
655 intPool.evict();
656 intPool.evict();
657
658 obj = intPool.borrowObject(KEY_ONE);
659 intPool.returnObject(KEY_ONE, obj);
660 obj = intPool.borrowObject(KEY_ONE);
661 intPool.returnObject(KEY_ONE, obj);
662 obj = intPool.borrowObject(KEY_ONE);
663 intPool.returnObject(KEY_ONE, obj);
664
665
666
667
668 intPool.evict();
669
670
671 intPool.evict();
672
673
674 intPool.evict();
675
676
677 intPool.evict();
678
679
680 for (int i = 0; i < 8; i++) {
681 final VisitTracker<Integer> tracker = intPool.borrowObject(KEY_ONE);
682 if (lifo && tracker.getId() > 1 || !lifo && tracker.getId() > 2) {
683 assertEquals(1, tracker.getValidateCount(), "Instance " + tracker.getId() + " visited wrong number of times.");
684 } else {
685 assertEquals(2, tracker.getValidateCount(), "Instance " + tracker.getId() + " visited wrong number of times.");
686 }
687 }
688 }
689
690
691
692 final int[] smallPrimes = { 2, 3, 5, 7 };
693 final Random random = new Random();
694 random.setSeed(System.currentTimeMillis());
695 for (int i = 0; i < smallPrimes.length; i++) {
696 for (int j = 0; j < 5; j++) {
697
698
699 trackerFactory = new VisitTrackerFactory<>();
700 try (GenericKeyedObjectPool<Integer, VisitTracker<Integer>> intPool = new GenericKeyedObjectPool<>(
701 trackerFactory)) {
702 intPool.setMaxIdlePerKey(-1);
703 intPool.setMaxTotalPerKey(-1);
704 intPool.setNumTestsPerEvictionRun(smallPrimes[i]);
705 intPool.setMinEvictableIdleTime(Duration.ofMillis(-1));
706 intPool.setTestWhileIdle(true);
707 intPool.setLifo(lifo);
708 intPool.setTestOnReturn(false);
709 intPool.setTestOnBorrow(false);
710
711 final int zeroLength = 10 + random.nextInt(20);
712 for (int k = 0; k < zeroLength; k++) {
713 intPool.addObject(KEY_ZERO);
714 }
715 final int oneLength = 10 + random.nextInt(20);
716 for (int k = 0; k < oneLength; k++) {
717 intPool.addObject(KEY_ONE);
718 }
719 final int twoLength = 10 + random.nextInt(20);
720 for (int k = 0; k < twoLength; k++) {
721 intPool.addObject(KEY_TWO);
722 }
723
724
725 final int runs = 10 + random.nextInt(50);
726 for (int k = 0; k < runs; k++) {
727 intPool.evict();
728 }
729
730
731 final int totalInstances = zeroLength + oneLength + twoLength;
732
733
734 final int cycleCount = runs * intPool.getNumTestsPerEvictionRun() / totalInstances;
735
736
737
738 VisitTracker<Integer> tracker = null;
739 int visitCount = 0;
740 for (int k = 0; k < zeroLength; k++) {
741 tracker = intPool.borrowObject(KEY_ZERO);
742 visitCount = tracker.getValidateCount();
743 if (visitCount < cycleCount || visitCount > cycleCount + 1) {
744 fail(formatSettings("ZERO", "runs", runs, "lifo", lifo, "i", i, "j", j, "k", k,
745 "visitCount", visitCount, "cycleCount", cycleCount, "totalInstances",
746 totalInstances, zeroLength, oneLength, twoLength));
747 }
748 }
749 for (int k = 0; k < oneLength; k++) {
750 tracker = intPool.borrowObject(KEY_ONE);
751 visitCount = tracker.getValidateCount();
752 if (visitCount < cycleCount || visitCount > cycleCount + 1) {
753 fail(formatSettings("ONE", "runs", runs, "lifo", lifo, "i", i, "j", j, "k", k, "visitCount",
754 visitCount, "cycleCount", cycleCount, "totalInstances", totalInstances, zeroLength,
755 oneLength, twoLength));
756 }
757 }
758 final int[] visits = new int[twoLength];
759 for (int k = 0; k < twoLength; k++) {
760 tracker = intPool.borrowObject(KEY_TWO);
761 visitCount = tracker.getValidateCount();
762 visits[k] = visitCount;
763 if (visitCount < cycleCount || visitCount > cycleCount + 1) {
764 final StringBuilder sb = new StringBuilder("Visits:");
765 for (int l = 0; l <= k; l++) {
766 sb.append(visits[l]).append(' ');
767 }
768 fail(formatSettings("TWO " + sb.toString(), "runs", runs, "lifo", lifo, "i", i, "j", j, "k",
769 k, "visitCount", visitCount, "cycleCount", cycleCount, "totalInstances",
770 totalInstances, zeroLength, oneLength, twoLength));
771 }
772 }
773 }
774 }
775 }
776 }
777
778 private String formatSettings(final String title, final String s, final int i, final String s0, final boolean b0, final String s1, final int i1, final String s2, final int i2, final String s3, final int i3,
779 final String s4, final int i4, final String s5, final int i5, final String s6, final int i6, final int zeroLength, final int oneLength, final int twoLength){
780 final StringBuilder sb = new StringBuilder(80);
781 sb.append(title).append(' ');
782 sb.append(s).append('=').append(i).append(' ');
783 sb.append(s0).append('=').append(b0).append(' ');
784 sb.append(s1).append('=').append(i1).append(' ');
785 sb.append(s2).append('=').append(i2).append(' ');
786 sb.append(s3).append('=').append(i3).append(' ');
787 sb.append(s4).append('=').append(i4).append(' ');
788 sb.append(s5).append('=').append(i5).append(' ');
789 sb.append(s6).append('=').append(i6).append(' ');
790 sb.append("Lengths=").append(zeroLength).append(',').append(oneLength).append(',').append(twoLength).append(' ');
791 return sb.toString();
792 }
793
794 @Override
795 protected Object getNthObject(final Object key, final int n) {
796 return String.valueOf(key) + String.valueOf(n);
797 }
798
799 @Override
800 protected boolean isFifo() {
801 return false;
802 }
803
804 @Override
805 protected boolean isLifo() {
806 return true;
807 }
808
809 @SuppressWarnings("unchecked")
810 @Override
811 protected <E extends Exception> KeyedObjectPool<Object, Object> makeEmptyPool(final int minCapacity) {
812 final KeyedPooledObjectFactory<Object, Object> perKeyFactory = new SimplePerKeyFactory();
813 final GenericKeyedObjectPool<Object, Object> perKeyPool = new GenericKeyedObjectPool<>(perKeyFactory);
814 perKeyPool.setMaxTotalPerKey(minCapacity);
815 perKeyPool.setMaxIdlePerKey(minCapacity);
816 return (KeyedObjectPool<Object, Object>) perKeyPool;
817 }
818
819 @Override
820 protected <E extends Exception> KeyedObjectPool<Object, Object> makeEmptyPool(final KeyedPooledObjectFactory<Object, Object> fac) {
821 return new GenericKeyedObjectPool<>(fac);
822 }
823
824 @Override
825 protected Object makeKey(final int n) {
826 return String.valueOf(n);
827 }
828
829
830
831
832
833
834
835
836
837
838
839
840 public <T> void runTestThreads(final int numThreads, final int iterations, final int delay,
841 final GenericKeyedObjectPool<String, T> gkopPool) {
842 final ArrayList<TestThread<T>> threads = new ArrayList<>();
843 for (int i = 0; i < numThreads; i++) {
844 final TestThread<T> testThread = new TestThread<>(gkopPool, iterations, delay);
845 threads.add(testThread);
846 final Thread t = new Thread(testThread);
847 t.start();
848 }
849 for (final TestThread<T> testThread : threads) {
850 while (!testThread.complete()) {
851 Waiter.sleepQuietly(500L);
852 }
853 if (testThread.failed()) {
854 fail("Thread failed: " + threads.indexOf(testThread) + "\n" + ExceptionUtils.getStackTrace(testThread.exception));
855 }
856 }
857 }
858
859 @BeforeEach
860 public void setUp() {
861 simpleFactory = new SimpleFactory<>();
862 gkoPool = new GenericKeyedObjectPool<>(simpleFactory);
863 }
864
865 @AfterEach
866 public void tearDownJmx() throws Exception {
867 super.tearDown();
868 final ObjectName jmxName = gkoPool.getJmxName();
869 final String poolName = Objects.toString(jmxName, null);
870 gkoPool.clear();
871 gkoPool.close();
872 gkoPool = null;
873 simpleFactory = null;
874
875 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
876 final Set<ObjectName> result = mbs.queryNames(new ObjectName(
877 "org.apache.commoms.pool2:type=GenericKeyedObjectPool,*"),
878 null);
879
880 final int registeredPoolCount = result.size();
881 final StringBuilder msg = new StringBuilder("Current pool is: ");
882 msg.append(poolName);
883 msg.append(" Still open pools are: ");
884 for (final ObjectName name : result) {
885
886 msg.append(name.toString());
887 msg.append(" created via\n");
888 msg.append(mbs.getAttribute(name, "CreationStackTrace"));
889 msg.append('\n');
890 mbs.unregisterMBean(name);
891 }
892 assertEquals(0, registeredPoolCount, msg.toString());
893 }
894
895 @Test
896 public void testAppendStats() {
897 assertFalse(gkoPool.getMessageStatistics());
898 assertEquals("foo", gkoPool.appendStats("foo"));
899 try (final GenericKeyedObjectPool<?, ?> pool = new GenericKeyedObjectPool<>(new SimpleFactory<>())) {
900 pool.setMessagesStatistics(true);
901 assertNotEquals("foo", pool.appendStats("foo"));
902 pool.setMessagesStatistics(false);
903 assertEquals("foo", pool.appendStats("foo"));
904 }
905 }
906
907 @Test
908 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
909 public void testBlockedKeyDoesNotBlockPool() throws Exception {
910 gkoPool.setBlockWhenExhausted(true);
911 gkoPool.setMaxWaitMillis(5000);
912 gkoPool.setMaxTotalPerKey(1);
913 gkoPool.setMaxTotal(-1);
914 gkoPool.borrowObject("one");
915 final long startMillis = System.currentTimeMillis();
916
917 final Runnable simple = new SimpleTestThread<>(gkoPool, "one");
918 new Thread(simple).start();
919
920
921
922 Thread.sleep(1000);
923 gkoPool.borrowObject("two");
924 final long endMillis = System.currentTimeMillis();
925
926
927
928
929 assertTrue(endMillis - startMillis < 4000,
930 "Elapsed time: " + (endMillis - startMillis) + " should be less than 4000");
931
932 }
933
934
935
936
937
938
939 @SuppressWarnings("rawtypes")
940 @Test
941 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
942 public void testBorrowObjectFairness() throws Exception {
943
944 final int numThreads = 40;
945 final int maxTotal = 40;
946
947 final GenericKeyedObjectPoolConfig<String> config = new GenericKeyedObjectPoolConfig<>();
948 config.setMaxTotalPerKey(maxTotal);
949 config.setFairness(true);
950 config.setLifo(false);
951 config.setMaxIdlePerKey(maxTotal);
952
953 gkoPool = new GenericKeyedObjectPool<>(simpleFactory, config);
954
955
956 final String[] objects = new String[maxTotal];
957 for (int i = 0; i < maxTotal; i++) {
958 objects[i] = gkoPool.borrowObject("0");
959 }
960
961
962 final TestThread[] threads = new TestThread[numThreads];
963 for (int i = 0; i < numThreads; i++) {
964 threads[i] = new TestThread<>(gkoPool, 1, 0, 2000, false, "0" + String.valueOf(i % maxTotal), "0");
965 final Thread t = new Thread(threads[i]);
966 t.start();
967
968 try {
969 Thread.sleep(10);
970 } catch (final InterruptedException e) {
971 fail(e.toString());
972 }
973 }
974
975
976 for (int i = 0; i < maxTotal; i++) {
977 gkoPool.returnObject("0", objects[i]);
978 }
979
980
981 for (int i = 0; i < numThreads; i++) {
982 while (!threads[i].complete()) {
983 Waiter.sleepQuietly(500L);
984 }
985 if (threads[i].failed()) {
986 fail("Thread " + i + " failed: " + ExceptionUtils.getStackTrace(threads[i].exception));
987 }
988 }
989 }
990
991
992
993
994
995
996
997 @Test
998 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
999 public void testClear() throws Exception {
1000 gkoPool.setMaxTotal(2);
1001 gkoPool.setMaxTotalPerKey(2);
1002 gkoPool.setBlockWhenExhausted(false);
1003 gkoPool.addObject("one");
1004 gkoPool.addObject("one");
1005 assertEquals(2, gkoPool.getNumIdle());
1006 gkoPool.clear("one");
1007 assertEquals(0, gkoPool.getNumIdle());
1008 assertEquals(0, gkoPool.getNumIdle("one"));
1009 final String obj1 = gkoPool.borrowObject("one");
1010 final String obj2 = gkoPool.borrowObject("one");
1011 gkoPool.returnObject("one", obj1);
1012 gkoPool.returnObject("one", obj2);
1013 gkoPool.clear();
1014 assertEquals(0, gkoPool.getNumIdle());
1015 assertEquals(0, gkoPool.getNumIdle("one"));
1016 gkoPool.borrowObject("one");
1017 gkoPool.borrowObject("one");
1018 gkoPool.close();
1019 }
1020
1021
1022
1023
1024
1025
1026 @Test
1027 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
1028 public void testClearOldest() throws Exception {
1029
1030 final WaiterFactory<String> waiterFactory = new WaiterFactory<>(0, 20, 0, 0, 0, 0, 50, 5, 0);
1031 try (final GenericKeyedObjectPool<String, Waiter> waiterPool = new GenericKeyedObjectPool<>(waiterFactory)) {
1032 waiterPool.setMaxTotalPerKey(5);
1033 waiterPool.setMaxTotal(50);
1034 waiterPool.setLifo(false);
1035
1036 for (int i = 0; i < 10; i++) {
1037 final String key = Integer.toString(i);
1038 for (int j = 0; j < 5; j++) {
1039 waiterPool.addObject(key);
1040 }
1041
1042 Thread.sleep(20);
1043 }
1044
1045
1046
1047 final SimpleTestThread<Waiter> t2 = new SimpleTestThread<>(waiterPool, "51");
1048 final Thread thread2 = new Thread(t2);
1049 thread2.start();
1050 Thread.sleep(50);
1051 final Waiter waiter = waiterPool.borrowObject("1");
1052 Thread.sleep(200);
1053 waiterPool.returnObject("1", waiter);
1054 }
1055 }
1056
1057
1058
1059
1060
1061
1062
1063 @Test
1064 public void testClearReuseCapacity() throws Exception {
1065 gkoPool.setMaxTotalPerKey(6);
1066 gkoPool.setMaxTotal(6);
1067 gkoPool.setMaxWait(Duration.ofSeconds(5));
1068
1069 final ArrayList<Thread> testThreads = new ArrayList<>();
1070 testThreads.add(new Thread(new SimpleTestThread<>(gkoPool, "one")));
1071 testThreads.add(new Thread(new SimpleTestThread<>(gkoPool, "two")));
1072 testThreads.add(new Thread(new SimpleTestThread<>(gkoPool, "two")));
1073 testThreads.add(new Thread(new SimpleTestThread<>(gkoPool, "three")));
1074 testThreads.add(new Thread(new SimpleTestThread<>(gkoPool, "three")));
1075 testThreads.add(new Thread(new SimpleTestThread<>(gkoPool, "three")));
1076
1077 final String four = gkoPool.borrowObject("four");
1078 final String four2 = gkoPool.borrowObject("four");
1079 final String five = gkoPool.borrowObject("five");
1080 final String five2 = gkoPool.borrowObject("five");
1081 final String six = gkoPool.borrowObject("six");
1082 final String six2 = gkoPool.borrowObject("six");
1083 Thread.sleep(100);
1084
1085 for (final Thread t : testThreads) {
1086 t.start();
1087 }
1088 Thread.sleep(100);
1089
1090
1091 gkoPool.returnObject("four", four);
1092 gkoPool.returnObject("four", four2);
1093 gkoPool.clear("four");
1094 Thread.sleep(20);
1095 assertTrue(!testThreads.get(3).isAlive() || !testThreads.get(4).isAlive() || !testThreads.get(5).isAlive());
1096
1097 gkoPool.returnObject("five", five);
1098 gkoPool.returnObject("five", five2);
1099 gkoPool.clear("five");
1100 Thread.sleep(20);
1101
1102 gkoPool.returnObject("six", six);
1103 gkoPool.returnObject("six", six2);
1104 gkoPool.clear("six");
1105 Thread.sleep(20);
1106 for (final Thread t : testThreads) {
1107 assertFalse(t.isAlive());
1108 }
1109 }
1110
1111
1112
1113
1114 @Test
1115 @Timeout(value = 10000, unit = TimeUnit.MILLISECONDS)
1116 public void testClearUnblocksWaiters() throws Exception {
1117 final GenericKeyedObjectPoolConfig<Integer> config = new GenericKeyedObjectPoolConfig<>();
1118 config.setMaxTotalPerKey(1);
1119 config.setMaxTotal(1);
1120 config.setMaxWait(Duration.ofMillis(500));
1121 final GenericKeyedObjectPool<Integer, Integer> testPool = new GenericKeyedObjectPool<>(
1122 new KeyedPooledObjectFactory<Integer, Integer>() {
1123 @Override
1124 public void activateObject(final Integer key, final PooledObject<Integer> p) {
1125
1126 }
1127
1128 @Override
1129 public void destroyObject(final Integer key, final PooledObject<Integer> p)
1130 throws InterruptedException {
1131 Thread.sleep(10);
1132 }
1133
1134 @Override
1135 public PooledObject<Integer> makeObject(final Integer key) {
1136 return new DefaultPooledObject<>(10);
1137 }
1138
1139 @Override
1140 public void passivateObject(final Integer key, final PooledObject<Integer> p) {
1141
1142 }
1143
1144 @Override
1145 public boolean validateObject(final Integer key, final PooledObject<Integer> p) {
1146 return true;
1147 }
1148 }, config);
1149 final Integer borrowKey = 10;
1150 final int iterations = 100;
1151 final ExecutorService executor = Executors.newFixedThreadPool(2);
1152 final Thread t = new Thread(() -> {
1153 try {
1154 for (int i = 0; i < iterations; i++) {
1155 final Integer integer = testPool.borrowObject(borrowKey);
1156 testPool.returnObject(borrowKey, integer);
1157 Thread.sleep(10);
1158 }
1159
1160 } catch (final Exception e) {
1161 fail(e);
1162 }
1163 });
1164 final Thread t2 = new Thread(() -> {
1165 try {
1166 for (int i = 0; i < iterations; i++) {
1167 testPool.clear(borrowKey);
1168 Thread.sleep(10);
1169 }
1170 } catch (final Exception e) {
1171 fail(e);
1172 }
1173 });
1174 final Future<?> f1 = executor.submit(t);
1175 final Future<?> f2 = executor.submit(t2);
1176 f2.get();
1177 f1.get();
1178 }
1179
1180
1181 @Test
1182 public void testClientWaitStats() throws Exception {
1183 final SimpleFactory<String> factory = new SimpleFactory<>();
1184
1185 factory.setMakeLatency(200);
1186 try (final GenericKeyedObjectPool<String, String> pool = new GenericKeyedObjectPool<>(factory,
1187 new GenericKeyedObjectPoolConfig<>())) {
1188 final String s = pool.borrowObject("one");
1189
1190
1191 assertTrue(pool.getMaxBorrowWaitTimeMillis() >= 100);
1192 assertTrue(pool.getMeanBorrowWaitTimeMillis() >= 100);
1193 pool.returnObject("one", s);
1194 pool.borrowObject("one");
1195
1196 assertTrue(pool.getMaxBorrowWaitTimeMillis() > 100);
1197 assertTrue(pool.getMeanBorrowWaitTimeMillis() < 200);
1198 assertTrue(pool.getMeanBorrowWaitTimeMillis() > 20);
1199 }
1200 }
1201
1202
1203
1204
1205
1206
1207 @Test
1208 public void testConcurrentBorrowAndClear() throws Exception {
1209 final int threadCount = 64;
1210 final int taskCount = 64;
1211 final int addCount = 1;
1212 final int borrowCycles = 1024;
1213 final int clearCycles = 1024;
1214 final boolean useYield = true;
1215
1216 testConcurrentBorrowAndClear(threadCount, taskCount, addCount, borrowCycles, clearCycles, useYield);
1217 }
1218
1219
1220
1221
1222
1223
1224 private void testConcurrentBorrowAndClear(final int threadCount, final int taskCount, final int addCount, final int borrowCycles, final int clearCycles,
1225 final boolean useYield) throws Exception {
1226 final GenericKeyedObjectPoolConfig<String> config = new GenericKeyedObjectPoolConfig<>();
1227 final int maxTotalPerKey = borrowCycles + 1;
1228 config.setMaxTotalPerKey(threadCount);
1229 config.setMaxIdlePerKey(threadCount);
1230 config.setMaxTotal(maxTotalPerKey * threadCount);
1231 config.setBlockWhenExhausted(false);
1232
1233 gkoPool = new GenericKeyedObjectPool<>(simpleFactory, config);
1234 final String key = "0";
1235 gkoPool.addObjects(Arrays.asList(key), threadCount);
1236
1237
1238 final ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);
1239 final List<Future<?>> futures = new ArrayList<>();
1240 try {
1241 for (int t = 0; t < taskCount; t++) {
1242 futures.add(threadPool.submit(() -> {
1243 for (int i = 0; i < clearCycles; i++) {
1244 if (useYield) {
1245 Thread.yield();
1246 }
1247 gkoPool.clear(key, true);
1248 try {
1249 gkoPool.addObjects(Arrays.asList(key), addCount);
1250 } catch (final Exception e) {
1251 fail(e);
1252 }
1253 }
1254 }));
1255 futures.add(threadPool.submit(() -> {
1256 try {
1257 for (int i = 0; i < borrowCycles; i++) {
1258 if (useYield) {
1259 Thread.yield();
1260 }
1261 final String pooled = gkoPool.borrowObject(key);
1262 gkoPool.returnObject(key, pooled);
1263 }
1264 } catch (final Exception e) {
1265 fail(e);
1266 }
1267 }));
1268 }
1269 futures.forEach(f -> {
1270 try {
1271 f.get();
1272 } catch (InterruptedException | ExecutionException e) {
1273 fail(e);
1274 }
1275 });
1276 } finally {
1277 threadPool.shutdownNow();
1278 }
1279 }
1280
1281
1282
1283
1284
1285
1286 @Test
1287 public void testConcurrentBorrowAndClear_JiraComment17741156() throws Exception {
1288 final int threadCount = 2;
1289 final int taskCount = 2;
1290 final int addCount = 1;
1291 final int borrowCycles = 5_000;
1292 final int clearCycles = 5_000;
1293 final boolean useYield = false;
1294
1295 testConcurrentBorrowAndClear(threadCount, taskCount, addCount, borrowCycles, clearCycles, useYield);
1296 }
1297
1298
1299
1300
1301
1302
1303
1304 @Test
1305 public void testConcurrentInvalidate() throws Exception {
1306
1307 final int nObjects = 1000;
1308 final String key = "one";
1309 gkoPool.setMaxTotal(nObjects);
1310 gkoPool.setMaxTotalPerKey(nObjects);
1311 gkoPool.setMaxIdlePerKey(nObjects);
1312 final String [] obj = new String[nObjects];
1313 for (int i = 0; i < nObjects; i++) {
1314 obj[i] = gkoPool.borrowObject(key);
1315 }
1316 for (int i = 0; i < nObjects; i++) {
1317 if (i % 2 == 0) {
1318 gkoPool.returnObject(key, obj[i]);
1319 }
1320 }
1321 final int nThreads = 20;
1322 final int nIterations = 60;
1323 final InvalidateThread[] threads = new InvalidateThread[nThreads];
1324
1325 final ArrayList<Integer> targets = new ArrayList<>();
1326 final Random random = new Random();
1327 for (int j = 0; j < nIterations; j++) {
1328
1329 Integer targ = Integer.valueOf(random.nextInt(nObjects));
1330 while (targets.contains(targ)) {
1331 targ = Integer.valueOf(random.nextInt(nObjects));
1332 }
1333 targets.add(targ);
1334
1335 for (int i = 0; i < nThreads; i++) {
1336 threads[i] = new InvalidateThread(gkoPool, key, obj[targ.intValue()]);
1337 }
1338 for (int i = 0; i < nThreads; i++) {
1339 new Thread(threads[i]).start();
1340 }
1341 boolean done = false;
1342 while (!done) {
1343 done = true;
1344 for (int i = 0; i < nThreads; i++) {
1345 done = done && threads[i].complete();
1346 }
1347 Thread.sleep(100);
1348 }
1349 }
1350 assertEquals(nIterations, gkoPool.getDestroyedCount());
1351 }
1352
1353 @Test
1354 public void testConstructorNullFactory() {
1355
1356 assertThrows(IllegalArgumentException.class,
1357 () -> new GenericKeyedObjectPool<>(null));
1358 }
1359
1360 @SuppressWarnings("deprecation")
1361 @Test
1362 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
1363 public void testConstructors() {
1364
1365
1366 final int maxTotalPerKey = 1;
1367 final int minIdle = 2;
1368 final Duration maxWaitDuration = Duration.ofMillis(3);
1369 final long maxWaitMillis = maxWaitDuration.toMillis();
1370 final int maxIdle = 4;
1371 final int maxTotal = 5;
1372 final long minEvictableIdleTimeMillis = 6;
1373 final int numTestsPerEvictionRun = 7;
1374 final boolean testOnBorrow = true;
1375 final boolean testOnReturn = true;
1376 final boolean testWhileIdle = true;
1377 final long timeBetweenEvictionRunsMillis = 8;
1378 final boolean blockWhenExhausted = false;
1379 final boolean lifo = false;
1380 final KeyedPooledObjectFactory<Object, Object> dummyFactory = new DummyFactory();
1381
1382 try (GenericKeyedObjectPool<Object, Object> objPool = new GenericKeyedObjectPool<>(dummyFactory)) {
1383 assertEquals(GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY, objPool.getMaxTotalPerKey());
1384 assertEquals(GenericKeyedObjectPoolConfig.DEFAULT_MAX_IDLE_PER_KEY, objPool.getMaxIdlePerKey());
1385 assertEquals(BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS, objPool.getMaxWaitMillis());
1386 assertEquals(GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY, objPool.getMinIdlePerKey());
1387 assertEquals(GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL, objPool.getMaxTotal());
1388
1389 assertEquals(BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
1390 objPool.getMinEvictableIdleTimeMillis());
1391 assertEquals(BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME,
1392 objPool.getMinEvictableIdleTime());
1393 assertEquals(BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME,
1394 objPool.getMinEvictableIdleDuration());
1395
1396 assertEquals(BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN, objPool.getNumTestsPerEvictionRun());
1397 assertEquals(Boolean.valueOf(BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW),
1398 Boolean.valueOf(objPool.getTestOnBorrow()));
1399 assertEquals(Boolean.valueOf(BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN),
1400 Boolean.valueOf(objPool.getTestOnReturn()));
1401 assertEquals(Boolean.valueOf(BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE),
1402 Boolean.valueOf(objPool.getTestWhileIdle()));
1403
1404 assertEquals(BaseObjectPoolConfig.DEFAULT_DURATION_BETWEEN_EVICTION_RUNS,
1405 objPool.getDurationBetweenEvictionRuns());
1406 assertEquals(BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
1407 objPool.getTimeBetweenEvictionRunsMillis());
1408 assertEquals(BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS,
1409 objPool.getTimeBetweenEvictionRuns());
1410
1411 assertEquals(Boolean.valueOf(BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED),
1412 Boolean.valueOf(objPool.getBlockWhenExhausted()));
1413 assertEquals(Boolean.valueOf(BaseObjectPoolConfig.DEFAULT_LIFO), Boolean.valueOf(objPool.getLifo()));
1414 }
1415
1416 final GenericKeyedObjectPoolConfig<Object> config = new GenericKeyedObjectPoolConfig<>();
1417 config.setLifo(lifo);
1418 config.setMaxTotalPerKey(maxTotalPerKey);
1419 config.setMaxIdlePerKey(maxIdle);
1420 config.setMinIdlePerKey(minIdle);
1421 config.setMaxTotal(maxTotal);
1422 config.setMaxWait(maxWaitDuration);
1423 config.setMinEvictableIdleDuration(Duration.ofMillis(minEvictableIdleTimeMillis));
1424 config.setMinEvictableIdleTime(Duration.ofMillis(minEvictableIdleTimeMillis));
1425 config.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
1426 config.setTestOnBorrow(testOnBorrow);
1427 config.setTestOnReturn(testOnReturn);
1428 config.setTestWhileIdle(testWhileIdle);
1429 config.setTimeBetweenEvictionRuns(Duration.ofMillis(timeBetweenEvictionRunsMillis));
1430 config.setBlockWhenExhausted(blockWhenExhausted);
1431 try (GenericKeyedObjectPool<Object, Object> objPool = new GenericKeyedObjectPool<>(dummyFactory, config)) {
1432 assertEquals(maxTotalPerKey, objPool.getMaxTotalPerKey());
1433 assertEquals(maxIdle, objPool.getMaxIdlePerKey());
1434 assertEquals(maxWaitDuration, objPool.getMaxWaitDuration());
1435 assertEquals(maxWaitMillis, objPool.getMaxWaitMillis());
1436 assertEquals(minIdle, objPool.getMinIdlePerKey());
1437 assertEquals(maxTotal, objPool.getMaxTotal());
1438 assertEquals(minEvictableIdleTimeMillis, objPool.getMinEvictableIdleDuration().toMillis());
1439 assertEquals(minEvictableIdleTimeMillis, objPool.getMinEvictableIdleTimeMillis());
1440 assertEquals(minEvictableIdleTimeMillis, objPool.getMinEvictableIdleTime().toMillis());
1441 assertEquals(numTestsPerEvictionRun, objPool.getNumTestsPerEvictionRun());
1442 assertEquals(Boolean.valueOf(testOnBorrow), Boolean.valueOf(objPool.getTestOnBorrow()));
1443 assertEquals(Boolean.valueOf(testOnReturn), Boolean.valueOf(objPool.getTestOnReturn()));
1444 assertEquals(Boolean.valueOf(testWhileIdle), Boolean.valueOf(objPool.getTestWhileIdle()));
1445 assertEquals(timeBetweenEvictionRunsMillis, objPool.getDurationBetweenEvictionRuns().toMillis());
1446 assertEquals(timeBetweenEvictionRunsMillis, objPool.getTimeBetweenEvictionRunsMillis());
1447 assertEquals(timeBetweenEvictionRunsMillis, objPool.getTimeBetweenEvictionRuns().toMillis());
1448 assertEquals(Boolean.valueOf(blockWhenExhausted), Boolean.valueOf(objPool.getBlockWhenExhausted()));
1449 assertEquals(Boolean.valueOf(lifo), Boolean.valueOf(objPool.getLifo()));
1450 }
1451 }
1452
1453
1454
1455
1456
1457 @Test
1458 public void testContructorEvictionConfig() throws Exception {
1459 final GenericKeyedObjectPoolConfig<String> config = new GenericKeyedObjectPoolConfig<>();
1460 config.setTimeBetweenEvictionRuns(Duration.ofMillis(500));
1461 config.setMinEvictableIdleDuration(Duration.ofMillis(50));
1462 config.setNumTestsPerEvictionRun(5);
1463 try (final GenericKeyedObjectPool<String, String> p = new GenericKeyedObjectPool<>(simpleFactory, config)) {
1464 for (int i = 0; i < 5; i++) {
1465 p.addObject("one");
1466 }
1467 Waiter.sleepQuietly(100);
1468 assertEquals(5, p.getNumIdle("one"));
1469 Waiter.sleepQuietly(500);
1470 assertEquals(0, p.getNumIdle("one"));
1471 }
1472 }
1473
1474
1475
1476
1477
1478
1479
1480 @Test
1481 public void testEqualsIndiscernible() throws Exception {
1482 final HashSetFactory factory = new HashSetFactory();
1483 try (final GenericKeyedObjectPool<String, HashSet<String>> pool = new GenericKeyedObjectPool<>(factory,
1484 new GenericKeyedObjectPoolConfig<>())) {
1485 final HashSet<String> s1 = pool.borrowObject("a");
1486 final HashSet<String> s2 = pool.borrowObject("a");
1487 pool.returnObject("a", s1);
1488 pool.returnObject("a", s2);
1489 }
1490 }
1491
1492 @Test
1493 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
1494 public void testEviction() throws Exception {
1495 gkoPool.setMaxIdlePerKey(500);
1496 gkoPool.setMaxTotalPerKey(500);
1497 gkoPool.setNumTestsPerEvictionRun(100);
1498 gkoPool.setMinEvictableIdleTime(Duration.ofMillis(250));
1499 gkoPool.setDurationBetweenEvictionRuns(Duration.ofMillis(500));
1500
1501 final String[] active = new String[500];
1502 for (int i = 0; i < 500; i++) {
1503 active[i] = gkoPool.borrowObject("");
1504 }
1505 for (int i = 0; i < 500; i++) {
1506 gkoPool.returnObject("", active[i]);
1507 }
1508
1509 Waiter.sleepQuietly(1000L);
1510 assertTrue(gkoPool.getNumIdle("") < 500, "Should be less than 500 idle, found " + gkoPool.getNumIdle(""));
1511 Waiter.sleepQuietly(600L);
1512 assertTrue(gkoPool.getNumIdle("") < 400, "Should be less than 400 idle, found " + gkoPool.getNumIdle(""));
1513 Waiter.sleepQuietly(600L);
1514 assertTrue(gkoPool.getNumIdle("") < 300, "Should be less than 300 idle, found " + gkoPool.getNumIdle(""));
1515 Waiter.sleepQuietly(600L);
1516 assertTrue(gkoPool.getNumIdle("") < 200, "Should be less than 200 idle, found " + gkoPool.getNumIdle(""));
1517 Waiter.sleepQuietly(600L);
1518 assertTrue(gkoPool.getNumIdle("") < 100, "Should be less than 100 idle, found " + gkoPool.getNumIdle(""));
1519 Waiter.sleepQuietly(600L);
1520 assertEquals(0, gkoPool.getNumIdle(""), "Should be zero idle, found " + gkoPool.getNumIdle(""));
1521
1522 for (int i = 0; i < 500; i++) {
1523 active[i] = gkoPool.borrowObject("");
1524 }
1525 for (int i = 0; i < 500; i++) {
1526 gkoPool.returnObject("", active[i]);
1527 }
1528
1529 Waiter.sleepQuietly(1000L);
1530 assertTrue(gkoPool.getNumIdle("") < 500, "Should be less than 500 idle, found " + gkoPool.getNumIdle(""));
1531 Waiter.sleepQuietly(600L);
1532 assertTrue(gkoPool.getNumIdle("") < 400, "Should be less than 400 idle, found " + gkoPool.getNumIdle(""));
1533 Waiter.sleepQuietly(600L);
1534 assertTrue(gkoPool.getNumIdle("") < 300, "Should be less than 300 idle, found " + gkoPool.getNumIdle(""));
1535 Waiter.sleepQuietly(600L);
1536 assertTrue(gkoPool.getNumIdle("") < 200, "Should be less than 200 idle, found " + gkoPool.getNumIdle(""));
1537 Waiter.sleepQuietly(600L);
1538 assertTrue(gkoPool.getNumIdle("") < 100, "Should be less than 100 idle, found " + gkoPool.getNumIdle(""));
1539 Waiter.sleepQuietly(600L);
1540 assertEquals(0, gkoPool.getNumIdle(""), "Should be zero idle, found " + gkoPool.getNumIdle(""));
1541 }
1542
1543 @Test
1544 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
1545 public void testEviction2() throws Exception {
1546 gkoPool.setMaxIdlePerKey(500);
1547 gkoPool.setMaxTotalPerKey(500);
1548 gkoPool.setNumTestsPerEvictionRun(100);
1549 gkoPool.setMinEvictableIdleTime(Duration.ofMillis(500));
1550 gkoPool.setTimeBetweenEvictionRuns(Duration.ofMillis(500));
1551
1552 final String[] active = new String[500];
1553 final String[] active2 = new String[500];
1554 for (int i = 0; i < 500; i++) {
1555 active[i] = gkoPool.borrowObject("");
1556 active2[i] = gkoPool.borrowObject("2");
1557 }
1558 for (int i = 0; i < 500; i++) {
1559 gkoPool.returnObject("", active[i]);
1560 gkoPool.returnObject("2", active2[i]);
1561 }
1562
1563 Waiter.sleepQuietly(1100L);
1564 assertTrue(gkoPool.getNumIdle() < 1000, "Should be less than 1000 idle, found " + gkoPool.getNumIdle());
1565 final long sleepMillisPart2 = 600L;
1566 Waiter.sleepQuietly(sleepMillisPart2);
1567 assertTrue(gkoPool.getNumIdle() < 900, "Should be less than 900 idle, found " + gkoPool.getNumIdle());
1568 Waiter.sleepQuietly(sleepMillisPart2);
1569 assertTrue(gkoPool.getNumIdle() < 800, "Should be less than 800 idle, found " + gkoPool.getNumIdle());
1570 Waiter.sleepQuietly(sleepMillisPart2);
1571 assertTrue(gkoPool.getNumIdle() < 700, "Should be less than 700 idle, found " + gkoPool.getNumIdle());
1572 Waiter.sleepQuietly(sleepMillisPart2);
1573 assertTrue(gkoPool.getNumIdle() < 600, "Should be less than 600 idle, found " + gkoPool.getNumIdle());
1574 Waiter.sleepQuietly(sleepMillisPart2);
1575 assertTrue(gkoPool.getNumIdle() < 500, "Should be less than 500 idle, found " + gkoPool.getNumIdle());
1576 Waiter.sleepQuietly(sleepMillisPart2);
1577 assertTrue(gkoPool.getNumIdle() < 400, "Should be less than 400 idle, found " + gkoPool.getNumIdle());
1578 Waiter.sleepQuietly(sleepMillisPart2);
1579 assertTrue(gkoPool.getNumIdle() < 300, "Should be less than 300 idle, found " + gkoPool.getNumIdle());
1580 Waiter.sleepQuietly(sleepMillisPart2);
1581 assertTrue(gkoPool.getNumIdle() < 200, "Should be less than 200 idle, found " + gkoPool.getNumIdle());
1582 Waiter.sleepQuietly(sleepMillisPart2);
1583 assertTrue(gkoPool.getNumIdle() < 100, "Should be less than 100 idle, found " + gkoPool.getNumIdle());
1584 Waiter.sleepQuietly(sleepMillisPart2);
1585 assertEquals(0, gkoPool.getNumIdle(), "Should be zero idle, found " + gkoPool.getNumIdle());
1586 }
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596 @Test
1597 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
1598 public void testEvictionOrder() throws Exception {
1599 checkEvictionOrder(false);
1600 checkEvictionOrder(true);
1601 }
1602
1603
1604 @Test
1605 public void testEvictorClearOldestRace() throws Exception {
1606 gkoPool.setMinEvictableIdleTime(Duration.ofMillis(100));
1607 gkoPool.setNumTestsPerEvictionRun(1);
1608
1609
1610
1611 gkoPool.setEvictionPolicy(new SlowEvictionPolicy<>(1000));
1612
1613
1614 final String val = gkoPool.borrowObject("foo");
1615
1616
1617 gkoPool.addObject("foo");
1618
1619
1620 Thread.sleep(1000);
1621
1622
1623 gkoPool.setTimeBetweenEvictionRuns(Duration.ofMillis(10));
1624
1625
1626 Thread.sleep(100);
1627 gkoPool.clearOldest();
1628
1629
1630 Thread.sleep(1500);
1631
1632
1633 gkoPool.returnObject("foo", val);
1634 }
1635
1636
1637
1638
1639
1640
1641
1642 @Test
1643 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
1644 public void testEvictorVisiting() throws Exception {
1645 checkEvictorVisiting(true);
1646 checkEvictorVisiting(false);
1647 }
1648
1649 @Test
1650 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
1651 public void testExceptionInValidationDuringEviction() throws Exception {
1652 gkoPool.setMaxIdlePerKey(1);
1653 gkoPool.setMinEvictableIdleTime(Duration.ZERO);
1654 gkoPool.setTestWhileIdle(true);
1655
1656 final String obj = gkoPool.borrowObject("one");
1657 gkoPool.returnObject("one", obj);
1658
1659 simpleFactory.setThrowExceptionOnValidate(true);
1660 assertThrows(RuntimeException.class, gkoPool::evict);
1661 assertEquals(0, gkoPool.getNumActive());
1662 assertEquals(0, gkoPool.getNumIdle());
1663 }
1664
1665 @Test
1666 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
1667 public void testExceptionOnActivateDuringBorrow() throws Exception {
1668 final String obj1 = gkoPool.borrowObject("one");
1669 final String obj2 = gkoPool.borrowObject("one");
1670 gkoPool.returnObject("one", obj1);
1671 gkoPool.returnObject("one", obj2);
1672 simpleFactory.setThrowExceptionOnActivate(true);
1673 simpleFactory.setEvenValid(false);
1674
1675
1676 final String obj = gkoPool.borrowObject("one");
1677 assertEquals(1, gkoPool.getNumActive("one"));
1678 assertEquals(0, gkoPool.getNumIdle("one"));
1679 assertEquals(1, gkoPool.getNumActive());
1680 assertEquals(0, gkoPool.getNumIdle());
1681
1682 gkoPool.returnObject("one", obj);
1683 simpleFactory.setValid(false);
1684
1685
1686 assertThrows(NoSuchElementException.class, () -> gkoPool.borrowObject("one"));
1687 assertEquals(0, gkoPool.getNumActive("one"));
1688 assertEquals(0, gkoPool.getNumIdle("one"));
1689 assertEquals(0, gkoPool.getNumActive());
1690 assertEquals(0, gkoPool.getNumIdle());
1691 }
1692
1693 @Test
1694 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
1695 public void testExceptionOnDestroyDuringBorrow() throws Exception {
1696 simpleFactory.setThrowExceptionOnDestroy(true);
1697 simpleFactory.setValidationEnabled(true);
1698 gkoPool.setTestOnBorrow(true);
1699 gkoPool.borrowObject("one");
1700 simpleFactory.setValid(false);
1701 assertThrows(NoSuchElementException.class, () -> gkoPool.borrowObject("one"));
1702 assertEquals(1, gkoPool.getNumActive("one"));
1703 assertEquals(0, gkoPool.getNumIdle("one"));
1704 assertEquals(1, gkoPool.getNumActive());
1705 assertEquals(0, gkoPool.getNumIdle());
1706 }
1707
1708 @Test
1709 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
1710 public void testExceptionOnDestroyDuringReturn() throws Exception {
1711 simpleFactory.setThrowExceptionOnDestroy(true);
1712 simpleFactory.setValidationEnabled(true);
1713 gkoPool.setTestOnReturn(true);
1714 final String obj1 = gkoPool.borrowObject("one");
1715 gkoPool.borrowObject("one");
1716 simpleFactory.setValid(false);
1717 gkoPool.returnObject("one", obj1);
1718 assertEquals(1, gkoPool.getNumActive("one"));
1719 assertEquals(0, gkoPool.getNumIdle("one"));
1720 assertEquals(1, gkoPool.getNumActive());
1721 assertEquals(0, gkoPool.getNumIdle());
1722 }
1723
1724 @Test
1725 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
1726 public void testExceptionOnPassivateDuringReturn() throws Exception {
1727 final String obj = gkoPool.borrowObject("one");
1728 simpleFactory.setThrowExceptionOnPassivate(true);
1729 gkoPool.returnObject("one", obj);
1730 assertEquals(0, gkoPool.getNumIdle());
1731 gkoPool.close();
1732 }
1733
1734 @Test
1735 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
1736 public void testFIFO() throws Exception {
1737 gkoPool.setLifo(false);
1738 final String key = "key";
1739 gkoPool.addObject(key);
1740 gkoPool.addObject(key);
1741 gkoPool.addObject(key);
1742 assertEquals("key0", gkoPool.borrowObject(key), "Oldest");
1743 assertEquals("key1", gkoPool.borrowObject(key), "Middle");
1744 assertEquals("key2", gkoPool.borrowObject(key), "Youngest");
1745 final String s = gkoPool.borrowObject(key);
1746 assertEquals("key3", s, "new-3");
1747 gkoPool.returnObject(key, s);
1748 assertEquals(s, gkoPool.borrowObject(key), "returned");
1749 assertEquals("key4", gkoPool.borrowObject(key), "new-4");
1750 }
1751
1752 @Test
1753 @Timeout(value = 60, unit = TimeUnit.SECONDS)
1754 public void testGetKeys() throws Exception {
1755 gkoPool.addObject("one");
1756 assertEquals(1, gkoPool.getKeys().size());
1757 gkoPool.addObject("two");
1758 assertEquals(2, gkoPool.getKeys().size());
1759 gkoPool.clear("one");
1760 assertEquals(1, gkoPool.getKeys().size());
1761 assertEquals("two", gkoPool.getKeys().get(0));
1762 gkoPool.clear();
1763 }
1764
1765 @Test
1766 public void testGetStatsString() {
1767 assertNotNull(gkoPool.getStatsString());
1768 }
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778 @Test
1779 public void testInvalidateFreesCapacity() throws Exception {
1780 final SimpleFactory<String> factory = new SimpleFactory<>();
1781 try (final GenericKeyedObjectPool<String, String> pool = new GenericKeyedObjectPool<>(factory)) {
1782 pool.setMaxTotalPerKey(2);
1783 pool.setMaxWaitMillis(500);
1784
1785 final WaitingTestThread thread1 = new WaitingTestThread(pool, "one", 5000);
1786 thread1.start();
1787
1788 final String obj = pool.borrowObject("one");
1789
1790 final WaitingTestThread thread2 = new WaitingTestThread(pool, "one", 100);
1791 thread2.start();
1792
1793 Thread.sleep(20);
1794 pool.invalidateObject("one", obj);
1795 Thread.sleep(600);
1796 if (thread2.thrown != null) {
1797 fail(thread2.thrown.toString());
1798 }
1799 }
1800 }
1801
1802 @Test
1803 public void testInvalidateFreesCapacityForOtherKeys() throws Exception {
1804 gkoPool.setMaxTotal(1);
1805 gkoPool.setMaxWait(Duration.ofMillis(500));
1806 final Thread borrower = new Thread(new SimpleTestThread<>(gkoPool, "two"));
1807 final String obj = gkoPool.borrowObject("one");
1808 borrower.start();
1809 Thread.sleep(100);
1810 gkoPool.invalidateObject("one", obj);
1811 Thread.sleep(20);
1812 assertFalse(borrower.isAlive());
1813 }
1814
1815 @Test
1816 public void testInvalidateMissingKey() throws Exception {
1817 assertThrows(IllegalStateException.class, () -> gkoPool.invalidateObject("UnknownKey", "Ignored"));
1818 }
1819
1820 @ParameterizedTest
1821 @EnumSource(DestroyMode.class)
1822 public void testInvalidateMissingKeyForDestroyMode(final DestroyMode destroyMode) throws Exception {
1823 assertThrows(IllegalStateException.class, () -> gkoPool.invalidateObject("UnknownKey", "Ignored", destroyMode));
1824 }
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834 @Test
1835 public void testInvalidateWaiting()
1836 throws Exception {
1837
1838 final GenericKeyedObjectPoolConfig<Object> config = new GenericKeyedObjectPoolConfig<>();
1839 config.setMaxTotal(2);
1840 config.setBlockWhenExhausted(true);
1841 config.setMinIdlePerKey(0);
1842 config.setMaxWait(Duration.ofMillis(-1));
1843 config.setNumTestsPerEvictionRun(Integer.MAX_VALUE);
1844 config.setTestOnBorrow(true);
1845 config.setTestOnReturn(false);
1846 config.setTestWhileIdle(true);
1847 config.setTimeBetweenEvictionRuns(Duration.ofMillis(-1));
1848
1849 try (final GenericKeyedObjectPool<Integer, Object> pool = new GenericKeyedObjectPool<>(new ObjectFactory(), config)) {
1850
1851
1852 pool.borrowObject(Integer.valueOf(1));
1853 final Object object2 = pool.borrowObject(Integer.valueOf(1));
1854
1855
1856 final ExecutorService executorService = Executors.newSingleThreadExecutor(new DaemonThreadFactory());
1857 final Semaphore signal = new Semaphore(0);
1858 final Future<Exception> result = executorService.submit(() -> {
1859 try {
1860 signal.release();
1861 final Object object3 = pool.borrowObject(Integer.valueOf(1));
1862 pool.returnObject(Integer.valueOf(1), object3);
1863 signal.release();
1864 } catch (final Exception e1) {
1865 return e1;
1866 } catch (final Throwable e2) {
1867 return new Exception(e2);
1868 }
1869
1870 return null;
1871 });
1872
1873
1874 assertTrue(signal.tryAcquire(5, TimeUnit.SECONDS));
1875
1876
1877 Thread.sleep(500);
1878
1879 pool.invalidateObject(Integer.valueOf(1), object2);
1880
1881 assertTrue(signal.tryAcquire(2, TimeUnit.SECONDS),"Call to invalidateObject did not unblock pool waiters.");
1882
1883 if (result.get() != null) {
1884 throw new AssertionError(result.get());
1885 }
1886 }
1887 }
1888
1889
1890
1891
1892 @Test
1893 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
1894 public void testJmxRegistration() {
1895 final ObjectName oname = gkoPool.getJmxName();
1896 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
1897 final Set<ObjectName> result = mbs.queryNames(oname, null);
1898 assertEquals(1, result.size());
1899 }
1900
1901 @Test
1902 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
1903 public void testLIFO() throws Exception {
1904 gkoPool.setLifo(true);
1905 final String key = "key";
1906 gkoPool.addObject(key);
1907 gkoPool.addObject(key);
1908 gkoPool.addObject(key);
1909 assertEquals("key2", gkoPool.borrowObject(key), "Youngest");
1910 assertEquals("key1", gkoPool.borrowObject(key), "Middle");
1911 assertEquals("key0", gkoPool.borrowObject(key), "Oldest");
1912 final String s = gkoPool.borrowObject(key);
1913 assertEquals("key3", s, "new-3");
1914 gkoPool.returnObject(key, s);
1915 assertEquals(s, gkoPool.borrowObject(key), "returned");
1916 assertEquals("key4", gkoPool.borrowObject(key), "new-4");
1917 }
1918
1919
1920
1921
1922
1923
1924
1925 @Test
1926 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
1927 public void testLivenessPerKey() throws Exception {
1928 gkoPool.setMaxIdlePerKey(3);
1929 gkoPool.setMaxTotal(3);
1930 gkoPool.setMaxTotalPerKey(3);
1931 gkoPool.setMaxWaitMillis(3000);
1932
1933
1934 final WaitingTestThread t1 = new WaitingTestThread(gkoPool, "1", 100);
1935 final WaitingTestThread t2 = new WaitingTestThread(gkoPool, "1", 100);
1936 final WaitingTestThread t3 = new WaitingTestThread(gkoPool, "1", 100);
1937 t1.start();
1938 t2.start();
1939 t3.start();
1940
1941
1942
1943 gkoPool.borrowObject("2");
1944 }
1945
1946
1947
1948
1949
1950
1951
1952
1953 @Test
1954 public void testMakeObjectException() throws Exception {
1955 final SimpleFactory<String> factory = new SimpleFactory<>();
1956 try (final GenericKeyedObjectPool<String, String> pool = new GenericKeyedObjectPool<>(factory)) {
1957 pool.setMaxTotalPerKey(1);
1958 pool.setBlockWhenExhausted(false);
1959 factory.exceptionOnCreate = true;
1960 assertThrows(Exception.class, () -> pool.borrowObject("One"));
1961 factory.exceptionOnCreate = false;
1962 pool.borrowObject("One");
1963 }
1964 }
1965
1966
1967
1968
1969 @Test
1970 @Timeout(value = 200000, unit = TimeUnit.MILLISECONDS)
1971 public void testMaxActivePerKeyExceeded() {
1972 final WaiterFactory<String> waiterFactory = new WaiterFactory<>(0, 20, 0, 0, 0, 0, 8, 5, 0);
1973
1974
1975 try (final GenericKeyedObjectPool<String, Waiter> waiterPool = new GenericKeyedObjectPool<>(waiterFactory)) {
1976 waiterPool.setMaxTotalPerKey(5);
1977 waiterPool.setMaxTotal(8);
1978 waiterPool.setTestOnBorrow(true);
1979 waiterPool.setMaxIdlePerKey(5);
1980 waiterPool.setMaxWaitMillis(-1);
1981 runTestThreads(20, 300, 250, waiterPool);
1982 }
1983 }
1984
1985 @Test
1986 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
1987 public void testMaxIdle() throws Exception {
1988 gkoPool.setMaxTotalPerKey(100);
1989 gkoPool.setMaxIdlePerKey(8);
1990 final String[] active = new String[100];
1991 for (int i = 0; i < 100; i++) {
1992 active[i] = gkoPool.borrowObject("");
1993 }
1994 assertEquals(100, gkoPool.getNumActive(""));
1995 assertEquals(0, gkoPool.getNumIdle(""));
1996 for (int i = 0; i < 100; i++) {
1997 gkoPool.returnObject("", active[i]);
1998 assertEquals(99 - i, gkoPool.getNumActive(""));
1999 assertEquals(i < 8 ? i + 1 : 8, gkoPool.getNumIdle(""));
2000 }
2001
2002 for (int i = 0; i < 100; i++) {
2003 active[i] = gkoPool.borrowObject("a");
2004 }
2005 assertEquals(100, gkoPool.getNumActive("a"));
2006 assertEquals(0, gkoPool.getNumIdle("a"));
2007 for (int i = 0; i < 100; i++) {
2008 gkoPool.returnObject("a", active[i]);
2009 assertEquals(99 - i, gkoPool.getNumActive("a"));
2010 assertEquals(i < 8 ? i + 1 : 8, gkoPool.getNumIdle("a"));
2011 }
2012
2013
2014 assertEquals(16, gkoPool.getNumIdle());
2015
2016 assertEquals(8, gkoPool.getNumIdle(""));
2017 assertEquals(8, gkoPool.getNumIdle("a"));
2018
2019 }
2020
2021 @Test
2022 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
2023 public void testMaxTotal() throws Exception {
2024 gkoPool.setMaxTotalPerKey(2);
2025 gkoPool.setMaxTotal(3);
2026 gkoPool.setBlockWhenExhausted(false);
2027
2028 final String o1 = gkoPool.borrowObject("a");
2029 assertNotNull(o1);
2030 final String o2 = gkoPool.borrowObject("a");
2031 assertNotNull(o2);
2032 final String o3 = gkoPool.borrowObject("b");
2033 assertNotNull(o3);
2034 assertThrows(NoSuchElementException.class, () -> gkoPool.borrowObject("c"));
2035
2036 assertEquals(0, gkoPool.getNumIdle());
2037
2038 gkoPool.returnObject("b", o3);
2039 assertEquals(1, gkoPool.getNumIdle());
2040 assertEquals(1, gkoPool.getNumIdle("b"));
2041
2042 final Object o4 = gkoPool.borrowObject("b");
2043 assertNotNull(o4);
2044 assertEquals(0, gkoPool.getNumIdle());
2045 assertEquals(0, gkoPool.getNumIdle("b"));
2046
2047 gkoPool.setMaxTotal(4);
2048 final Object o5 = gkoPool.borrowObject("b");
2049 assertNotNull(o5);
2050
2051 assertEquals(2, gkoPool.getNumActive("a"));
2052 assertEquals(2, gkoPool.getNumActive("b"));
2053 assertEquals(gkoPool.getMaxTotal(),
2054 gkoPool.getNumActive("b") + gkoPool.getNumActive("b"));
2055 assertEquals(gkoPool.getNumActive(),
2056 gkoPool.getMaxTotal());
2057 }
2058
2059
2060
2061
2062
2063
2064 @Test
2065 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
2066 public void testMaxTotalInvariant() {
2067 final int maxTotal = 15;
2068 simpleFactory.setEvenValid(false);
2069 simpleFactory.setDestroyLatency(100);
2070 simpleFactory.setMaxTotalPerKey(maxTotal);
2071 simpleFactory.setValidationEnabled(true);
2072 gkoPool.setMaxTotal(maxTotal);
2073 gkoPool.setMaxIdlePerKey(-1);
2074 gkoPool.setTestOnReturn(true);
2075 gkoPool.setMaxWaitMillis(10000L);
2076 runTestThreads(5, 10, 50, gkoPool);
2077 }
2078
2079 @Test
2080 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
2081 public void testMaxTotalLRU() throws Exception {
2082 gkoPool.setMaxTotalPerKey(2);
2083 gkoPool.setMaxTotal(3);
2084
2085 final String o1 = gkoPool.borrowObject("a");
2086 assertNotNull(o1);
2087 gkoPool.returnObject("a", o1);
2088 Thread.sleep(25);
2089
2090 final String o2 = gkoPool.borrowObject("b");
2091 assertNotNull(o2);
2092 gkoPool.returnObject("b", o2);
2093 Thread.sleep(25);
2094
2095 final String o3 = gkoPool.borrowObject("c");
2096 assertNotNull(o3);
2097 gkoPool.returnObject("c", o3);
2098 Thread.sleep(25);
2099
2100 final String o4 = gkoPool.borrowObject("a");
2101 assertNotNull(o4);
2102 gkoPool.returnObject("a", o4);
2103 Thread.sleep(25);
2104
2105 assertSame(o1, o4);
2106
2107
2108 final String o5 = gkoPool.borrowObject("d");
2109 assertNotNull(o5);
2110 gkoPool.returnObject("d", o5);
2111 Thread.sleep(25);
2112
2113
2114
2115 final String o6 = gkoPool.borrowObject("b");
2116 assertNotNull(o6);
2117 gkoPool.returnObject("b", o6);
2118
2119 assertNotSame(o1, o6);
2120 assertNotSame(o2, o6);
2121
2122
2123 final String o7 = gkoPool.borrowObject("a");
2124 assertNotNull(o7);
2125 gkoPool.returnObject("a", o7);
2126
2127 assertSame(o4, o7);
2128 }
2129
2130 @Test
2131 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
2132 public void testMaxTotalPerKey() throws Exception {
2133 gkoPool.setMaxTotalPerKey(3);
2134 gkoPool.setBlockWhenExhausted(false);
2135
2136 gkoPool.borrowObject("");
2137 gkoPool.borrowObject("");
2138 gkoPool.borrowObject("");
2139 assertThrows(NoSuchElementException.class, () -> gkoPool.borrowObject(""));
2140 }
2141
2142 @Test
2143 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
2144 public void testMaxTotalPerKeyZero() {
2145 gkoPool.setMaxTotalPerKey(0);
2146 gkoPool.setBlockWhenExhausted(false);
2147
2148 assertThrows(NoSuchElementException.class, () -> gkoPool.borrowObject("a"));
2149 }
2150
2151
2152
2153
2154
2155
2156
2157 @Test
2158 public void testMaxTotalWithThreads() throws Exception {
2159
2160 gkoPool.setMaxTotalPerKey(2);
2161 gkoPool.setMaxTotal(1);
2162
2163 final int holdTime = 2000;
2164
2165 final TestThread<String> testA = new TestThread<>(gkoPool, 1, 0, holdTime, false, null, "a");
2166 final TestThread<String> testB = new TestThread<>(gkoPool, 1, 0, holdTime, false, null, "b");
2167
2168 final Thread threadA = new Thread(testA);
2169 final Thread threadB = new Thread(testB);
2170
2171 threadA.start();
2172 threadB.start();
2173
2174 Thread.sleep(holdTime * 2);
2175
2176
2177 boolean threadRunning = true;
2178 int count = 0;
2179 while (threadRunning && count < 15) {
2180 threadRunning = threadA.isAlive();
2181 threadRunning = threadB.isAlive();
2182 Thread.sleep(200);
2183 count++;
2184 }
2185 assertFalse(threadA.isAlive());
2186 assertFalse(threadB.isAlive());
2187
2188 assertFalse(testA.failed);
2189 assertFalse(testB.failed);
2190 }
2191
2192 @Test
2193 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
2194 public void testMaxTotalZero() {
2195 gkoPool.setMaxTotal(0);
2196 gkoPool.setBlockWhenExhausted(false);
2197
2198 assertThrows(NoSuchElementException.class, () -> gkoPool.borrowObject("a"));
2199 }
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209 @Test
2210 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
2211 public void testMaxWaitMultiThreaded() throws Exception {
2212 final long maxWait = 500;
2213 final long holdTime = 4 * maxWait;
2214 final int keyCount = 4;
2215 final int threadsPerKey = 5;
2216 gkoPool.setBlockWhenExhausted(true);
2217 gkoPool.setMaxWaitMillis(maxWait);
2218 gkoPool.setMaxTotalPerKey(threadsPerKey);
2219
2220 final WaitingTestThread[] wtt = new WaitingTestThread[keyCount * threadsPerKey * 2];
2221 for (int i = 0; i < wtt.length; i++) {
2222 wtt[i] = new WaitingTestThread(gkoPool, Integer.toString(i % keyCount), holdTime);
2223 }
2224 final long originMillis = System.currentTimeMillis() - 1000;
2225 for (final WaitingTestThread element : wtt) {
2226 element.start();
2227 }
2228 int failed = 0;
2229 for (final WaitingTestThread element : wtt) {
2230 element.join();
2231 if (element.thrown != null){
2232 failed++;
2233 }
2234 }
2235 if (DISPLAY_THREAD_DETAILS || wtt.length/2 != failed){
2236 System.out.println(
2237 "MaxWait: " + maxWait +
2238 " HoldTime: " + holdTime +
2239 " KeyCount: " + keyCount +
2240 " MaxActive: " + threadsPerKey +
2241 " Threads: " + wtt.length +
2242 " Failed: " + failed
2243 );
2244 for (final WaitingTestThread wt : wtt) {
2245 System.out.println(
2246 "Preborrow: " + (wt.preBorrowMillis - originMillis) +
2247 " Postborrow: " + (wt.postBorrowMillis != 0 ? wt.postBorrowMillis - originMillis : -1) +
2248 " BorrowTime: " + (wt.postBorrowMillis != 0 ? wt.postBorrowMillis - wt.preBorrowMillis : -1) +
2249 " PostReturn: " + (wt.postReturnMillis != 0 ? wt.postReturnMillis - originMillis : -1) +
2250 " Ended: " + (wt.endedMillis - originMillis) +
2251 " Key: " + wt.key +
2252 " ObjId: " + wt.objectId
2253 );
2254 }
2255 }
2256 assertEquals(wtt.length / 2, failed, "Expected half the threads to fail");
2257 }
2258
2259 @Test
2260 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
2261 public void testMinIdle() throws Exception {
2262 gkoPool.setMaxIdlePerKey(500);
2263 gkoPool.setMinIdlePerKey(5);
2264 gkoPool.setMaxTotalPerKey(10);
2265 gkoPool.setNumTestsPerEvictionRun(0);
2266 gkoPool.setMinEvictableIdleTime(Duration.ofMillis(50));
2267 gkoPool.setTimeBetweenEvictionRuns(Duration.ofMillis(100));
2268 gkoPool.setTestWhileIdle(true);
2269
2270
2271 final String key = "A";
2272
2273 gkoPool.preparePool(key);
2274
2275 Waiter.sleepQuietly(150L);
2276 assertEquals(5, gkoPool.getNumIdle(), "Should be 5 idle, found " + gkoPool.getNumIdle());
2277
2278 final String[] active = new String[5];
2279 active[0] = gkoPool.borrowObject(key);
2280
2281 Waiter.sleepQuietly(150L);
2282 assertEquals(5, gkoPool.getNumIdle(), "Should be 5 idle, found " + gkoPool.getNumIdle());
2283
2284 for (int i = 1; i < 5; i++) {
2285 active[i] = gkoPool.borrowObject(key);
2286 }
2287
2288 Waiter.sleepQuietly(150L);
2289 assertEquals(5, gkoPool.getNumIdle(), "Should be 5 idle, found " + gkoPool.getNumIdle());
2290
2291 for (int i = 0; i < 5; i++) {
2292 gkoPool.returnObject(key, active[i]);
2293 }
2294
2295 Waiter.sleepQuietly(150L);
2296 assertEquals(10, gkoPool.getNumIdle(), "Should be 10 idle, found " + gkoPool.getNumIdle());
2297 }
2298
2299 @Test
2300 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
2301 public void testMinIdleMaxTotalPerKey() throws Exception {
2302 gkoPool.setMaxIdlePerKey(500);
2303 gkoPool.setMinIdlePerKey(5);
2304 gkoPool.setMaxTotalPerKey(10);
2305 gkoPool.setNumTestsPerEvictionRun(0);
2306 gkoPool.setMinEvictableIdleTime(Duration.ofMillis(50));
2307 gkoPool.setTimeBetweenEvictionRuns(Duration.ofMillis(100));
2308 gkoPool.setTestWhileIdle(true);
2309
2310 final String key = "A";
2311
2312 gkoPool.preparePool(key);
2313 assertEquals(5, gkoPool.getNumIdle(), "Should be 5 idle, found " +
2314 gkoPool.getNumIdle());
2315
2316 Waiter.sleepQuietly(150L);
2317 assertEquals(5, gkoPool.getNumIdle(), "Should be 5 idle, found " + gkoPool.getNumIdle());
2318
2319 final String[] active = new String[10];
2320
2321 Waiter.sleepQuietly(150L);
2322 assertEquals(5, gkoPool.getNumIdle(), "Should be 5 idle, found " + gkoPool.getNumIdle());
2323
2324 for(int i=0 ; i<5 ; i++) {
2325 active[i] = gkoPool.borrowObject(key);
2326 }
2327
2328 Waiter.sleepQuietly(150L);
2329 assertEquals(5, gkoPool.getNumIdle(), "Should be 5 idle, found " + gkoPool.getNumIdle());
2330
2331 for(int i=0 ; i<5 ; i++) {
2332 gkoPool.returnObject(key, active[i]);
2333 }
2334
2335 Waiter.sleepQuietly(150L);
2336 assertEquals(10, gkoPool.getNumIdle(), "Should be 10 idle, found " + gkoPool.getNumIdle());
2337
2338 for(int i=0 ; i<10 ; i++) {
2339 active[i] = gkoPool.borrowObject(key);
2340 }
2341
2342 Waiter.sleepQuietly(150L);
2343 assertEquals(0, gkoPool.getNumIdle(), "Should be 0 idle, found " + gkoPool.getNumIdle());
2344
2345 for(int i=0 ; i<10 ; i++) {
2346 gkoPool.returnObject(key, active[i]);
2347 }
2348
2349 Waiter.sleepQuietly(150L);
2350 assertEquals(10, gkoPool.getNumIdle(), "Should be 10 idle, found " + gkoPool.getNumIdle());
2351 }
2352
2353 @Test
2354 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
2355 public void testMinIdleNoPreparePool() throws Exception {
2356 gkoPool.setMaxIdlePerKey(500);
2357 gkoPool.setMinIdlePerKey(5);
2358 gkoPool.setMaxTotalPerKey(10);
2359 gkoPool.setNumTestsPerEvictionRun(0);
2360 gkoPool.setMinEvictableIdleTime(Duration.ofMillis(50));
2361 gkoPool.setTimeBetweenEvictionRuns(Duration.ofMillis(100));
2362 gkoPool.setTestWhileIdle(true);
2363
2364
2365 final String key = "A";
2366
2367 Waiter.sleepQuietly(150L);
2368 assertEquals(0, gkoPool.getNumIdle(), "Should be 0 idle, found " + gkoPool.getNumIdle());
2369
2370 final Object active = gkoPool.borrowObject(key);
2371 assertNotNull(active);
2372
2373 Waiter.sleepQuietly(150L);
2374 assertEquals(5, gkoPool.getNumIdle(), "Should be 5 idle, found " + gkoPool.getNumIdle());
2375 }
2376
2377
2378
2379
2380
2381
2382
2383 @Test
2384 public void testMultipleReturn() throws Exception {
2385 final WaiterFactory<String> factory = new WaiterFactory<>(0, 0, 0, 0, 0, 0);
2386 try (final GenericKeyedObjectPool<String, Waiter> pool = new GenericKeyedObjectPool<>(factory)) {
2387 pool.setTestOnReturn(true);
2388 final Waiter waiter = pool.borrowObject("a");
2389 pool.returnObject("a", waiter);
2390 assertEquals(1, waiter.getValidationCount());
2391 assertEquals(1, waiter.getPassivationCount());
2392 try {
2393 pool.returnObject("a", waiter);
2394 fail("Expecting IllegalStateException from multiple return");
2395 } catch (final IllegalStateException ex) {
2396
2397 assertEquals(1, waiter.getValidationCount());
2398 assertEquals(1, waiter.getPassivationCount());
2399 }
2400 }
2401 }
2402
2403
2404
2405
2406
2407
2408
2409 @Test
2410 public void testMutable() throws Exception {
2411 final HashSetFactory factory = new HashSetFactory();
2412 try (final GenericKeyedObjectPool<String, HashSet<String>> pool = new GenericKeyedObjectPool<>(factory,
2413 new GenericKeyedObjectPoolConfig<>())) {
2414 final HashSet<String> s1 = pool.borrowObject("a");
2415 final HashSet<String> s2 = pool.borrowObject("a");
2416 s1.add("One");
2417 s2.add("One");
2418 pool.returnObject("a", s1);
2419 pool.returnObject("a", s2);
2420 }
2421 }
2422
2423 @Test
2424 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
2425 public void testNegativeMaxTotalPerKey() throws Exception {
2426 gkoPool.setMaxTotalPerKey(-1);
2427 gkoPool.setBlockWhenExhausted(false);
2428 final String obj = gkoPool.borrowObject("");
2429 assertEquals("0", obj);
2430 gkoPool.returnObject("", obj);
2431 }
2432
2433
2434
2435
2436 @Test
2437 @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS)
2438 public void testNPEOnFactoryNull() {
2439
2440 final DisconnectingWaiterFactory<String> factory = new DisconnectingWaiterFactory<>(
2441 () -> null,
2442 DisconnectingWaiterFactory.DEFAULT_DISCONNECTED_LIFECYCLE_ACTION,
2443 DisconnectingWaiterFactory.DEFAULT_DISCONNECTED_VALIDATION_ACTION
2444 );
2445
2446 try (final GenericKeyedObjectPool<String, Waiter> pool = new GenericKeyedObjectPool<>(factory)) {
2447 final String key = "one";
2448 pool.setTestOnBorrow(true);
2449 pool.setMaxTotal(-1);
2450 pool.setMinIdlePerKey(1);
2451
2452 factory.disconnect();
2453 assertThrows(NullPointerException.class, () -> pool.borrowObject(key));
2454 assertThrows(NullPointerException.class, () -> pool.addObject(key));
2455 assertThrows(NullPointerException.class, pool::ensureMinIdle);
2456 }
2457 }
2458
2459 @Test
2460 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
2461 public void testNumActiveNumIdle2() throws Exception {
2462 assertEquals(0, gkoPool.getNumActive());
2463 assertEquals(0, gkoPool.getNumIdle());
2464 assertEquals(0, gkoPool.getNumActive("A"));
2465 assertEquals(0, gkoPool.getNumIdle("A"));
2466 assertEquals(0, gkoPool.getNumActive("B"));
2467 assertEquals(0, gkoPool.getNumIdle("B"));
2468
2469 final String objA0 = gkoPool.borrowObject("A");
2470 final String objB0 = gkoPool.borrowObject("B");
2471
2472 assertEquals(2, gkoPool.getNumActive());
2473 assertEquals(0, gkoPool.getNumIdle());
2474 assertEquals(1, gkoPool.getNumActive("A"));
2475 assertEquals(0, gkoPool.getNumIdle("A"));
2476 assertEquals(1, gkoPool.getNumActive("B"));
2477 assertEquals(0, gkoPool.getNumIdle("B"));
2478
2479 final String objA1 = gkoPool.borrowObject("A");
2480 final String objB1 = gkoPool.borrowObject("B");
2481
2482 assertEquals(4, gkoPool.getNumActive());
2483 assertEquals(0, gkoPool.getNumIdle());
2484 assertEquals(2, gkoPool.getNumActive("A"));
2485 assertEquals(0, gkoPool.getNumIdle("A"));
2486 assertEquals(2, gkoPool.getNumActive("B"));
2487 assertEquals(0, gkoPool.getNumIdle("B"));
2488
2489 gkoPool.returnObject("A", objA0);
2490 gkoPool.returnObject("B", objB0);
2491
2492 assertEquals(2, gkoPool.getNumActive());
2493 assertEquals(2, gkoPool.getNumIdle());
2494 assertEquals(1, gkoPool.getNumActive("A"));
2495 assertEquals(1, gkoPool.getNumIdle("A"));
2496 assertEquals(1, gkoPool.getNumActive("B"));
2497 assertEquals(1, gkoPool.getNumIdle("B"));
2498
2499 gkoPool.returnObject("A", objA1);
2500 gkoPool.returnObject("B", objB1);
2501
2502 assertEquals(0, gkoPool.getNumActive());
2503 assertEquals(4, gkoPool.getNumIdle());
2504 assertEquals(0, gkoPool.getNumActive("A"));
2505 assertEquals(2, gkoPool.getNumIdle("A"));
2506 assertEquals(0, gkoPool.getNumActive("B"));
2507 assertEquals(2, gkoPool.getNumIdle("B"));
2508 }
2509
2510 @Test
2511 public void testReturnObjectThrowsIllegalStateException() {
2512 try (final GenericKeyedObjectPool<String, String> pool = new GenericKeyedObjectPool<>(new SimpleFactory<>())) {
2513 assertThrows(IllegalStateException.class,
2514 () -> pool.returnObject("Foo", "Bar"));
2515 }
2516 }
2517
2518 @Test
2519 public void testReturnObjectWithBlockWhenExhausted() throws Exception {
2520 gkoPool.setBlockWhenExhausted(true);
2521 gkoPool.setMaxTotal(1);
2522
2523
2524 final String obj = gkoPool.borrowObject("0");
2525 gkoPool.returnObject("0", obj);
2526
2527
2528 final TestThread<String> testA = new TestThread<>(gkoPool, 1, 0, 500, false, null, "0");
2529 final TestThread<String> testB = new TestThread<>(gkoPool, 1, 0, 0, false, null, "1");
2530 final Thread threadA = new Thread(testA);
2531 final Thread threadB = new Thread(testB);
2532 threadA.start();
2533 threadB.start();
2534 threadA.join();
2535 threadB.join();
2536 }
2537
2538 @Test
2539 public void testReturnObjectWithoutBlockWhenExhausted() throws Exception {
2540 gkoPool.setBlockWhenExhausted(false);
2541
2542
2543 final String obj = gkoPool.borrowObject("0");
2544 gkoPool.returnObject("0", obj);
2545 }
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555 @Test
2556 public void testReturnToHead() throws Exception {
2557 final SimpleFactory<String> factory = new SimpleFactory<>();
2558 factory.setValidateLatency(100);
2559 factory.setValid(true);
2560 try (final GenericKeyedObjectPool<String, String> pool = new GenericKeyedObjectPool<>(factory)) {
2561 pool.setMaxWaitMillis(1000);
2562 pool.setTestWhileIdle(true);
2563 pool.setMaxTotalPerKey(2);
2564 pool.setNumTestsPerEvictionRun(1);
2565 pool.setTimeBetweenEvictionRuns(Duration.ofMillis(500));
2566
2567
2568 pool.addObject("one");
2569 pool.addObject("one");
2570
2571
2572
2573 Thread.sleep(800);
2574
2575
2576
2577 Thread.sleep(250);
2578 final String o1 = pool.borrowObject("one");
2579 final String o2 = pool.borrowObject("one");
2580 pool.returnObject("one", o1);
2581 pool.returnObject("one", o2);
2582 }
2583 }
2584
2585 @Test
2586 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
2587 public void testSettersAndGetters() {
2588 {
2589 gkoPool.setMaxTotalPerKey(123);
2590 assertEquals(123, gkoPool.getMaxTotalPerKey());
2591 }
2592 {
2593 gkoPool.setMaxIdlePerKey(12);
2594 assertEquals(12, gkoPool.getMaxIdlePerKey());
2595 }
2596 {
2597 gkoPool.setMaxWaitMillis(1234L);
2598 assertEquals(1234L, gkoPool.getMaxWaitMillis());
2599 }
2600 {
2601 gkoPool.setMinEvictableIdleTimeMillis(12345L);
2602 assertEquals(12345L, gkoPool.getMinEvictableIdleTimeMillis());
2603 }
2604 {
2605 gkoPool.setMinEvictableIdleTime(Duration.ofMillis(12345L));
2606 assertEquals(12345L, gkoPool.getMinEvictableIdleTime().toMillis());
2607 }
2608 {
2609 gkoPool.setMinEvictableIdleTime(Duration.ofMillis(12345L));
2610 assertEquals(12345L, gkoPool.getMinEvictableIdleDuration().toMillis());
2611 }
2612 {
2613 gkoPool.setNumTestsPerEvictionRun(11);
2614 assertEquals(11, gkoPool.getNumTestsPerEvictionRun());
2615 }
2616 {
2617 gkoPool.setTestOnBorrow(true);
2618 assertTrue(gkoPool.getTestOnBorrow());
2619 gkoPool.setTestOnBorrow(false);
2620 assertFalse(gkoPool.getTestOnBorrow());
2621 }
2622 {
2623 gkoPool.setTestOnReturn(true);
2624 assertTrue(gkoPool.getTestOnReturn());
2625 gkoPool.setTestOnReturn(false);
2626 assertFalse(gkoPool.getTestOnReturn());
2627 }
2628 {
2629 gkoPool.setTestWhileIdle(true);
2630 assertTrue(gkoPool.getTestWhileIdle());
2631 gkoPool.setTestWhileIdle(false);
2632 assertFalse(gkoPool.getTestWhileIdle());
2633 }
2634 {
2635 gkoPool.setTimeBetweenEvictionRunsMillis(11235L);
2636 assertEquals(11235L, gkoPool.getDurationBetweenEvictionRuns().toMillis());
2637 assertEquals(11235L, gkoPool.getTimeBetweenEvictionRuns().toMillis());
2638 assertEquals(11235L, gkoPool.getTimeBetweenEvictionRunsMillis());
2639 }
2640 {
2641 gkoPool.setTimeBetweenEvictionRuns(Duration.ofMillis(11235L));
2642 assertEquals(11235L, gkoPool.getDurationBetweenEvictionRuns().toMillis());
2643 assertEquals(11235L, gkoPool.getTimeBetweenEvictionRuns().toMillis());
2644 assertEquals(11235L, gkoPool.getTimeBetweenEvictionRunsMillis());
2645 }
2646 {
2647 gkoPool.setBlockWhenExhausted(true);
2648 assertTrue(gkoPool.getBlockWhenExhausted());
2649 gkoPool.setBlockWhenExhausted(false);
2650 assertFalse(gkoPool.getBlockWhenExhausted());
2651 }
2652 }
2653
2654 @Test
2655 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
2656 public void testThreaded1() {
2657 gkoPool.setMaxTotalPerKey(15);
2658 gkoPool.setMaxIdlePerKey(15);
2659 gkoPool.setMaxWaitMillis(1000L);
2660 runTestThreads(20, 100, 50, gkoPool);
2661 }
2662
2663
2664 @Test
2665 public void testValidateOnCreate() throws Exception {
2666 gkoPool.setTestOnCreate(true);
2667 simpleFactory.setValidationEnabled(true);
2668 gkoPool.addObject("one");
2669 assertEquals(1, simpleFactory.validateCounter);
2670 }
2671
2672 @Test
2673 public void testValidateOnCreateFailure() throws Exception {
2674 gkoPool.setTestOnCreate(true);
2675 gkoPool.setTestOnBorrow(false);
2676 gkoPool.setMaxTotal(2);
2677 simpleFactory.setValidationEnabled(true);
2678 simpleFactory.setValid(false);
2679
2680 gkoPool.addObject("one");
2681 gkoPool.addObject("one");
2682 assertEquals(0, gkoPool.getNumIdle());
2683 assertEquals(0, gkoPool.getNumActive());
2684 simpleFactory.setValid(true);
2685 final String obj = gkoPool.borrowObject("one");
2686 assertNotNull(obj);
2687 gkoPool.addObject("one");
2688
2689 assertEquals(1, gkoPool.getNumIdle());
2690 assertEquals(1, gkoPool.getNumActive());
2691 }
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701 @Test
2702 public void testValidationFailureOnReturnFreesCapacity()
2703 throws Exception {
2704 final SimpleFactory<String> factory = new SimpleFactory<>();
2705 factory.setValid(false);
2706 factory.setValidationEnabled(true);
2707 try (final GenericKeyedObjectPool<String, String> pool = new GenericKeyedObjectPool<>(factory)) {
2708 pool.setMaxTotalPerKey(2);
2709 pool.setMaxWaitMillis(1500);
2710 pool.setTestOnReturn(true);
2711 pool.setTestOnBorrow(false);
2712
2713 final WaitingTestThread thread1 = new WaitingTestThread(pool, "one", 5000);
2714 thread1.start();
2715
2716 final WaitingTestThread thread2 = new WaitingTestThread(pool, "one", 500);
2717 thread2.start();
2718 Thread.sleep(50);
2719
2720 final String obj = pool.borrowObject("one");
2721 pool.returnObject("one", obj);
2722 }
2723 }
2724
2725
2726 @Test
2727 public void testValidationOnCreateOnly() throws Exception {
2728 simpleFactory.enableValidation = true;
2729
2730 gkoPool.setMaxTotal(1);
2731 gkoPool.setTestOnCreate(true);
2732 gkoPool.setTestOnBorrow(false);
2733 gkoPool.setTestOnReturn(false);
2734 gkoPool.setTestWhileIdle(false);
2735
2736 final String o1 = gkoPool.borrowObject("KEY");
2737 assertEquals("KEY0", o1);
2738 final Timer t = new Timer();
2739 t.schedule(
2740 new TimerTask() {
2741 @Override
2742 public void run() {
2743 gkoPool.returnObject("KEY", o1);
2744 }
2745 }, 3000);
2746
2747 final String o2 = gkoPool.borrowObject("KEY");
2748 assertEquals("KEY0", o2);
2749
2750 assertEquals(1, simpleFactory.validateCounter);
2751 }
2752
2753 @Test
2754 public void testWaiterCounts() throws Exception {
2755 final String[] keys = {"one", "two", "three"};
2756 final String[] objects = new String[keys.length];
2757 gkoPool.setMaxTotalPerKey(1);
2758 gkoPool.setBlockWhenExhausted(true);
2759
2760 assertTrue(gkoPool.getNumWaitersByKey().isEmpty());
2761 assertEquals(0, gkoPool.getNumWaiters());
2762
2763
2764 for (int i = 0; i < keys.length; i++) {
2765 objects[i] = gkoPool.borrowObject(keys[i]);
2766 }
2767
2768
2769
2770 final WaitingTestThread[] waiters = new WaitingTestThread[6];
2771 for (int i = 0; i < 3; i++) {
2772 for (int j = 0; j < i + 1; j++) {
2773 waiters[i + j] = new WaitingTestThread(gkoPool, keys[i], 100);
2774 waiters[i + j].start();
2775 }
2776 }
2777 Thread.sleep(10);
2778
2779
2780 assertEquals(6, gkoPool.getNumWaiters());
2781 for (int i = 0; i < 3; i++) {
2782 assertEquals(i + 1, gkoPool.getNumWaitersByKey().get(keys[i]).intValue());
2783 }
2784
2785
2786 for (int i = 0; i < 3; i++) {
2787 gkoPool.returnObject(keys[i], objects[i]);
2788 }
2789
2790 Thread.sleep(10);
2791
2792
2793 assertEquals(3, gkoPool.getNumWaiters());
2794 for (int i = 0; i < 3; i++) {
2795 assertEquals(i, gkoPool.getNumWaitersByKey().get(keys[i]).intValue());
2796 }
2797
2798
2799 for (int i = 0; i < 5; i++) {
2800 waiters[i].join();
2801 }
2802
2803
2804 assertEquals(0, gkoPool.getNumWaiters());
2805 for (int i = 0; i < 3; i++) {
2806 assertEquals(0, gkoPool.getNumWaitersByKey().get(keys[i]).intValue());
2807 }
2808 assertEquals(3, gkoPool.getNumIdle());
2809 for (final String key : keys) {
2810 assertEquals(1, gkoPool.getNumIdle(key));
2811 }
2812
2813
2814 gkoPool.clear();
2815 assertTrue(gkoPool.getNumWaitersByKey().isEmpty());
2816 assertEquals(0, gkoPool.getNumWaiters());
2817
2818 gkoPool.close();
2819 }
2820
2821
2822
2823
2824
2825
2826 @Test
2827 @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS)
2828 public void testWhenExhaustedBlockClosePool() throws Exception {
2829 gkoPool.setMaxTotalPerKey(1);
2830 gkoPool.setBlockWhenExhausted(true);
2831 gkoPool.setMaxWaitMillis(-1);
2832 final String obj1 = gkoPool.borrowObject("a");
2833
2834
2835 assertNotNull(obj1);
2836
2837
2838 final WaitingTestThread wtt = new WaitingTestThread(gkoPool, "a", 200);
2839 wtt.start();
2840
2841 Thread.sleep(200);
2842
2843
2844 gkoPool.close();
2845
2846
2847 Thread.sleep(200);
2848
2849
2850 assertTrue(wtt.thrown instanceof InterruptedException);
2851 }
2852
2853 }
2854