1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.pool2.impl;
18
19 import java.time.Duration;
20 import java.time.Instant;
21 import java.util.ArrayList;
22 import java.util.NoSuchElementException;
23 import java.util.Set;
24 import java.util.concurrent.ConcurrentHashMap;
25 import java.util.concurrent.atomic.AtomicLong;
26 import java.util.stream.Collectors;
27
28 import org.apache.commons.pool2.DestroyMode;
29 import org.apache.commons.pool2.ObjectPool;
30 import org.apache.commons.pool2.PoolUtils;
31 import org.apache.commons.pool2.PooledObject;
32 import org.apache.commons.pool2.PooledObjectFactory;
33 import org.apache.commons.pool2.PooledObjectState;
34 import org.apache.commons.pool2.SwallowedExceptionListener;
35 import org.apache.commons.pool2.TrackedUse;
36 import org.apache.commons.pool2.UsageTracking;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
83 implements ObjectPool<T>, GenericObjectPoolMXBean, UsageTracking<T> {
84
85
86 private static final String ONAME_BASE =
87 "org.apache.commons.pool2:type=GenericObjectPool,name=";
88
89 private static void wait(final Object obj, final Duration duration) throws InterruptedException {
90 obj.wait(duration.toMillis(), duration.getNano() % 1_000_000);
91 }
92
93 private volatile String factoryType;
94
95 private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
96
97 private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
98
99 private final PooledObjectFactory<T> factory;
100
101
102
103
104
105
106
107
108 private final ConcurrentHashMap<IdentityWrapper<T>, PooledObject<T>> allObjects = new ConcurrentHashMap<>();
109
110
111
112
113
114
115
116
117 private final AtomicLong createCount = new AtomicLong();
118
119 private long makeObjectCount;
120
121 private final Object makeObjectCountLock = new Object();
122
123 private final LinkedBlockingDeque<PooledObject<T>> idleObjects;
124
125
126
127
128
129
130
131
132 public GenericObjectPool(final PooledObjectFactory<T> factory) {
133 this(factory, new GenericObjectPoolConfig<>());
134 }
135
136
137
138
139
140
141
142
143
144
145
146
147 public GenericObjectPool(final PooledObjectFactory<T> factory,
148 final GenericObjectPoolConfig<T> config) {
149
150 super(config, ONAME_BASE, config.getJmxNamePrefix());
151
152 if (factory == null) {
153 jmxUnregister();
154 throw new IllegalArgumentException("Factory may not be null");
155 }
156 this.factory = factory;
157
158 idleObjects = new LinkedBlockingDeque<>(config.getFairness());
159
160 setConfig(config);
161 }
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176 public GenericObjectPool(final PooledObjectFactory<T> factory,
177 final GenericObjectPoolConfig<T> config, final AbandonedConfig abandonedConfig) {
178 this(factory, config);
179 setAbandonedConfig(abandonedConfig);
180 }
181
182
183
184
185
186
187
188
189
190
191 private void addIdleObject(final PooledObject<T> p) throws Exception {
192 if (!PooledObject.isNull(p)) {
193 factory.passivateObject(p);
194 if (getLifo()) {
195 idleObjects.addFirst(p);
196 } else {
197 idleObjects.addLast(p);
198 }
199 }
200 }
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216 @Override
217 public void addObject() throws Exception {
218 assertOpen();
219 if (factory == null) {
220 throw new IllegalStateException("Cannot add objects without a factory.");
221 }
222 addIdleObject(create());
223 }
224
225
226
227
228
229
230
231 @Override
232 public T borrowObject() throws Exception {
233 return borrowObject(getMaxWaitDuration());
234 }
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284 public T borrowObject(final Duration borrowMaxWaitDuration) throws Exception {
285 assertOpen();
286
287 final AbandonedConfig ac = this.abandonedConfig;
288 if (ac != null && ac.getRemoveAbandonedOnBorrow() && getNumIdle() < 2 &&
289 getNumActive() > getMaxTotal() - 3) {
290 removeAbandoned(ac);
291 }
292
293 PooledObject<T> p = null;
294
295
296
297 final boolean blockWhenExhausted = getBlockWhenExhausted();
298
299 boolean create;
300 final Instant waitTime = Instant.now();
301
302 while (p == null) {
303 create = false;
304 p = idleObjects.pollFirst();
305 if (p == null) {
306 p = create();
307 if (!PooledObject.isNull(p)) {
308 create = true;
309 }
310 }
311 if (blockWhenExhausted) {
312 if (PooledObject.isNull(p)) {
313 p = borrowMaxWaitDuration.isNegative() ? idleObjects.takeFirst() : idleObjects.pollFirst(borrowMaxWaitDuration);
314 }
315 if (PooledObject.isNull(p)) {
316 throw new NoSuchElementException(appendStats(
317 "Timeout waiting for idle object, borrowMaxWaitDuration=" + borrowMaxWaitDuration));
318 }
319 } else if (PooledObject.isNull(p)) {
320 throw new NoSuchElementException(appendStats("Pool exhausted"));
321 }
322 if (!p.allocate()) {
323 p = null;
324 }
325
326 if (!PooledObject.isNull(p)) {
327 try {
328 factory.activateObject(p);
329 } catch (final Exception e) {
330 try {
331 destroy(p, DestroyMode.NORMAL);
332 } catch (final Exception ignored) {
333
334 }
335 p = null;
336 if (create) {
337 final NoSuchElementException nsee = new NoSuchElementException(
338 appendStats("Unable to activate object"));
339 nsee.initCause(e);
340 throw nsee;
341 }
342 }
343 if (!PooledObject.isNull(p) && getTestOnBorrow()) {
344 boolean validate = false;
345 Throwable validationThrowable = null;
346 try {
347 validate = factory.validateObject(p);
348 } catch (final Throwable t) {
349 PoolUtils.checkRethrow(t);
350 validationThrowable = t;
351 }
352 if (!validate) {
353 try {
354 destroy(p, DestroyMode.NORMAL);
355 destroyedByBorrowValidationCount.incrementAndGet();
356 } catch (final Exception ignored) {
357
358 }
359 p = null;
360 if (create) {
361 final NoSuchElementException nsee = new NoSuchElementException(
362 appendStats("Unable to validate object"));
363 nsee.initCause(validationThrowable);
364 throw nsee;
365 }
366 }
367 }
368 }
369 }
370
371 updateStatsBorrow(p, Duration.between(waitTime, Instant.now()));
372
373 return p.getObject();
374 }
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426 public T borrowObject(final long borrowMaxWaitMillis) throws Exception {
427 return borrowObject(Duration.ofMillis(borrowMaxWaitMillis));
428 }
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448 @Override
449 public void clear() {
450 PooledObject<T> p = idleObjects.poll();
451
452 while (p != null) {
453 try {
454 destroy(p, DestroyMode.NORMAL);
455 } catch (final Exception e) {
456 swallowException(e);
457 }
458 p = idleObjects.poll();
459 }
460 }
461
462
463
464
465
466
467
468
469
470
471 @Override
472 public void close() {
473 if (isClosed()) {
474 return;
475 }
476
477 synchronized (closeLock) {
478 if (isClosed()) {
479 return;
480 }
481
482
483
484 stopEvictor();
485
486 closed = true;
487
488 clear();
489
490 jmxUnregister();
491
492
493 idleObjects.interuptTakeWaiters();
494 }
495 }
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510 private PooledObject<T> create() throws Exception {
511 int localMaxTotal = getMaxTotal();
512
513 if (localMaxTotal < 0) {
514 localMaxTotal = Integer.MAX_VALUE;
515 }
516
517 final Instant localStartInstant = Instant.now();
518 final Duration maxWaitDurationRaw = getMaxWaitDuration();
519 final Duration localMaxWaitDuration = maxWaitDurationRaw.isNegative() ? Duration.ZERO : maxWaitDurationRaw;
520
521
522
523
524
525
526 Boolean create = null;
527 while (create == null) {
528 synchronized (makeObjectCountLock) {
529 final long newCreateCount = createCount.incrementAndGet();
530 if (newCreateCount > localMaxTotal) {
531
532
533 createCount.decrementAndGet();
534 if (makeObjectCount == 0) {
535
536
537
538 create = Boolean.FALSE;
539 } else {
540
541
542
543
544 wait(makeObjectCountLock, localMaxWaitDuration);
545 }
546 } else {
547
548 makeObjectCount++;
549 create = Boolean.TRUE;
550 }
551 }
552
553
554 if (create == null && localMaxWaitDuration.compareTo(Duration.ZERO) > 0 &&
555 Duration.between(localStartInstant, Instant.now()).compareTo(localMaxWaitDuration) >= 0) {
556 create = Boolean.FALSE;
557 }
558 }
559
560 if (!create.booleanValue()) {
561 return null;
562 }
563
564 final PooledObject<T> p;
565 try {
566 p = factory.makeObject();
567 if (PooledObject.isNull(p)) {
568 createCount.decrementAndGet();
569 throw new NullPointerException(String.format("%s.makeObject() = null", factory.getClass().getSimpleName()));
570 }
571 if (getTestOnCreate() && !factory.validateObject(p)) {
572 createCount.decrementAndGet();
573 return null;
574 }
575 } catch (final Throwable e) {
576 createCount.decrementAndGet();
577 throw e;
578 } finally {
579 synchronized (makeObjectCountLock) {
580 makeObjectCount--;
581 makeObjectCountLock.notifyAll();
582 }
583 }
584
585 final AbandonedConfig ac = this.abandonedConfig;
586 if (ac != null && ac.getLogAbandoned()) {
587 p.setLogAbandoned(true);
588 p.setRequireFullStackTrace(ac.getRequireFullStackTrace());
589 }
590
591 createdCount.incrementAndGet();
592 allObjects.put(new IdentityWrapper<>(p.getObject()), p);
593 return p;
594 }
595
596
597
598
599
600
601
602
603
604
605 private void destroy(final PooledObject<T> toDestroy, final DestroyMode destroyMode) throws Exception {
606 toDestroy.invalidate();
607 idleObjects.remove(toDestroy);
608 allObjects.remove(new IdentityWrapper<>(toDestroy.getObject()));
609 try {
610 factory.destroyObject(toDestroy, destroyMode);
611 } finally {
612 destroyedCount.incrementAndGet();
613 createCount.decrementAndGet();
614 }
615 }
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634 private void ensureIdle(final int idleCount, final boolean always) throws Exception {
635 if (idleCount < 1 || isClosed() || !always && !idleObjects.hasTakeWaiters()) {
636 return;
637 }
638
639 while (idleObjects.size() < idleCount) {
640 final PooledObject<T> p = create();
641 if (PooledObject.isNull(p)) {
642
643
644 break;
645 }
646 if (getLifo()) {
647 idleObjects.addFirst(p);
648 } else {
649 idleObjects.addLast(p);
650 }
651 }
652 if (isClosed()) {
653
654
655
656 clear();
657 }
658 }
659
660 @Override
661 void ensureMinIdle() throws Exception {
662 ensureIdle(getMinIdle(), true);
663 }
664
665
666
667
668
669
670
671
672 @Override
673 public void evict() throws Exception {
674 assertOpen();
675
676 if (!idleObjects.isEmpty()) {
677
678 PooledObject<T> underTest = null;
679 final EvictionPolicy<T> evictionPolicy = getEvictionPolicy();
680
681 synchronized (evictionLock) {
682 final EvictionConfig evictionConfig = new EvictionConfig(
683 getMinEvictableIdleDuration(),
684 getSoftMinEvictableIdleDuration(),
685 getMinIdle());
686
687 final boolean testWhileIdle = getTestWhileIdle();
688
689 for (int i = 0, m = getNumTests(); i < m; i++) {
690 if (evictionIterator == null || !evictionIterator.hasNext()) {
691 evictionIterator = new EvictionIterator(idleObjects);
692 }
693 if (!evictionIterator.hasNext()) {
694
695 return;
696 }
697
698 try {
699 underTest = evictionIterator.next();
700 } catch (final NoSuchElementException nsee) {
701
702
703 i--;
704 evictionIterator = null;
705 continue;
706 }
707
708 if (!underTest.startEvictionTest()) {
709
710
711 i--;
712 continue;
713 }
714
715
716
717
718 boolean evict;
719 try {
720 evict = evictionPolicy.evict(evictionConfig, underTest,
721 idleObjects.size());
722 } catch (final Throwable t) {
723
724
725 PoolUtils.checkRethrow(t);
726 swallowException(new Exception(t));
727
728 evict = false;
729 }
730
731 if (evict) {
732 destroy(underTest, DestroyMode.NORMAL);
733 destroyedByEvictorCount.incrementAndGet();
734 } else {
735 if (testWhileIdle) {
736 boolean active = false;
737 try {
738 factory.activateObject(underTest);
739 active = true;
740 } catch (final Exception e) {
741 destroy(underTest, DestroyMode.NORMAL);
742 destroyedByEvictorCount.incrementAndGet();
743 }
744 if (active) {
745 boolean validate = false;
746 Throwable validationThrowable = null;
747 try {
748 validate = factory.validateObject(underTest);
749 } catch (final Throwable t) {
750 PoolUtils.checkRethrow(t);
751 validationThrowable = t;
752 }
753 if (!validate) {
754 destroy(underTest, DestroyMode.NORMAL);
755 destroyedByEvictorCount.incrementAndGet();
756 if (validationThrowable != null) {
757 if (validationThrowable instanceof RuntimeException) {
758 throw (RuntimeException) validationThrowable;
759 }
760 throw (Error) validationThrowable;
761 }
762 } else {
763 try {
764 factory.passivateObject(underTest);
765 } catch (final Exception e) {
766 destroy(underTest, DestroyMode.NORMAL);
767 destroyedByEvictorCount.incrementAndGet();
768 }
769 }
770 }
771 }
772 underTest.endEvictionTest(idleObjects);
773
774
775 }
776 }
777 }
778 }
779 final AbandonedConfig ac = this.abandonedConfig;
780 if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
781 removeAbandoned(ac);
782 }
783 }
784
785
786
787
788
789
790
791 public PooledObjectFactory<T> getFactory() {
792 return factory;
793 }
794
795
796
797
798
799
800
801 @Override
802 public String getFactoryType() {
803
804 if (factoryType == null) {
805 final StringBuilder result = new StringBuilder();
806 result.append(factory.getClass().getName());
807 result.append('<');
808 final Class<?> pooledObjectType =
809 PoolImplUtils.getFactoryType(factory.getClass());
810 result.append(pooledObjectType.getName());
811 result.append('>');
812 factoryType = result.toString();
813 }
814 return factoryType;
815 }
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831 @Override
832 public int getMaxIdle() {
833 return maxIdle;
834 }
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853 @Override
854 public int getMinIdle() {
855 final int maxIdleSave = getMaxIdle();
856 return Math.min(this.minIdle, maxIdleSave);
857 }
858
859 @Override
860 public int getNumActive() {
861 return allObjects.size() - idleObjects.size();
862 }
863
864 @Override
865 public int getNumIdle() {
866 return idleObjects.size();
867 }
868
869
870
871
872
873
874
875 private int getNumTests() {
876 final int numTestsPerEvictionRun = getNumTestsPerEvictionRun();
877 if (numTestsPerEvictionRun >= 0) {
878 return Math.min(numTestsPerEvictionRun, idleObjects.size());
879 }
880 return (int) Math.ceil(idleObjects.size() /
881 Math.abs((double) numTestsPerEvictionRun));
882 }
883
884
885
886
887
888
889
890
891
892 @Override
893 public int getNumWaiters() {
894 if (getBlockWhenExhausted()) {
895 return idleObjects.getTakeQueueLength();
896 }
897 return 0;
898 }
899
900 PooledObject<T> getPooledObject(final T obj) {
901 return allObjects.get(new IdentityWrapper<>(obj));
902 }
903
904 @Override
905 String getStatsString() {
906
907 return super.getStatsString() +
908 String.format(", createdCount=%,d, makeObjectCount=%,d, maxIdle=%,d, minIdle=%,d",
909 createdCount.get(), makeObjectCount, maxIdle, minIdle);
910 }
911
912
913
914
915
916
917
918
919
920
921
922 @Override
923 public void invalidateObject(final T obj) throws Exception {
924 invalidateObject(obj, DestroyMode.NORMAL);
925 }
926
927
928
929
930
931
932
933
934
935
936
937
938 @Override
939 public void invalidateObject(final T obj, final DestroyMode destroyMode) throws Exception {
940 final PooledObject<T> p = getPooledObject(obj);
941 if (p == null) {
942 if (isAbandonedConfig()) {
943 return;
944 }
945 throw new IllegalStateException("Invalidated object not currently part of this pool");
946 }
947 synchronized (p) {
948 if (p.getState() != PooledObjectState.INVALID) {
949 destroy(p, destroyMode);
950 }
951 }
952 ensureIdle(1, false);
953 }
954
955
956
957
958
959
960
961
962
963
964
965
966
967 @Override
968 public Set<DefaultPooledObjectInfo> listAllObjects() {
969 return allObjects.values().stream().map(DefaultPooledObjectInfo::new).collect(Collectors.toSet());
970 }
971
972
973
974
975
976
977
978 public void preparePool() throws Exception {
979 if (getMinIdle() < 1) {
980 return;
981 }
982 ensureMinIdle();
983 }
984
985
986
987
988
989
990
991 @SuppressWarnings("resource")
992 private void removeAbandoned(final AbandonedConfig abandonedConfig) {
993
994 final ArrayList<PooledObject<T>> remove = createRemoveList(abandonedConfig, allObjects);
995
996 remove.forEach(pooledObject -> {
997 if (abandonedConfig.getLogAbandoned()) {
998 pooledObject.printStackTrace(abandonedConfig.getLogWriter());
999 }
1000 try {
1001 invalidateObject(pooledObject.getObject(), DestroyMode.ABANDONED);
1002 } catch (final Exception e) {
1003 swallowException(e);
1004 }
1005 });
1006 }
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025 @Override
1026 public void returnObject(final T obj) {
1027 final PooledObject<T> p = getPooledObject(obj);
1028
1029 if (p == null) {
1030 if (!isAbandonedConfig()) {
1031 throw new IllegalStateException(
1032 "Returned object not currently part of this pool");
1033 }
1034 return;
1035 }
1036
1037 markReturningState(p);
1038
1039 final Duration activeTime = p.getActiveDuration();
1040
1041 if (getTestOnReturn() && !factory.validateObject(p)) {
1042 try {
1043 destroy(p, DestroyMode.NORMAL);
1044 } catch (final Exception e) {
1045 swallowException(e);
1046 }
1047 try {
1048 ensureIdle(1, false);
1049 } catch (final Exception e) {
1050 swallowException(e);
1051 }
1052 updateStatsReturn(activeTime);
1053 return;
1054 }
1055
1056 try {
1057 factory.passivateObject(p);
1058 } catch (final Exception e1) {
1059 swallowException(e1);
1060 try {
1061 destroy(p, DestroyMode.NORMAL);
1062 } catch (final Exception e) {
1063 swallowException(e);
1064 }
1065 try {
1066 ensureIdle(1, false);
1067 } catch (final Exception e) {
1068 swallowException(e);
1069 }
1070 updateStatsReturn(activeTime);
1071 return;
1072 }
1073
1074 if (!p.deallocate()) {
1075 throw new IllegalStateException(
1076 "Object has already been returned to this pool or is invalid");
1077 }
1078
1079 final int maxIdleSave = getMaxIdle();
1080 if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {
1081 try {
1082 destroy(p, DestroyMode.NORMAL);
1083 } catch (final Exception e) {
1084 swallowException(e);
1085 }
1086 try {
1087 ensureIdle(1, false);
1088 } catch (final Exception e) {
1089 swallowException(e);
1090 }
1091 } else {
1092 if (getLifo()) {
1093 idleObjects.addFirst(p);
1094 } else {
1095 idleObjects.addLast(p);
1096 }
1097 if (isClosed()) {
1098
1099
1100
1101 clear();
1102 }
1103 }
1104 updateStatsReturn(activeTime);
1105 }
1106
1107
1108
1109
1110
1111
1112
1113
1114 public void setConfig(final GenericObjectPoolConfig<T> conf) {
1115 super.setConfig(conf);
1116 setMaxIdle(conf.getMaxIdle());
1117 setMinIdle(conf.getMinIdle());
1118 setMaxTotal(conf.getMaxTotal());
1119 }
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137 public void setMaxIdle(final int maxIdle) {
1138 this.maxIdle = maxIdle;
1139 }
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159 public void setMinIdle(final int minIdle) {
1160 this.minIdle = minIdle;
1161 }
1162
1163 @Override
1164 protected void toStringAppendFields(final StringBuilder builder) {
1165 super.toStringAppendFields(builder);
1166 builder.append(", factoryType=");
1167 builder.append(factoryType);
1168 builder.append(", maxIdle=");
1169 builder.append(maxIdle);
1170 builder.append(", minIdle=");
1171 builder.append(minIdle);
1172 builder.append(", factory=");
1173 builder.append(factory);
1174 builder.append(", allObjects=");
1175 builder.append(allObjects);
1176 builder.append(", createCount=");
1177 builder.append(createCount);
1178 builder.append(", idleObjects=");
1179 builder.append(idleObjects);
1180 builder.append(", abandonedConfig=");
1181 builder.append(abandonedConfig);
1182 }
1183
1184 @Override
1185 public void use(final T pooledObject) {
1186 final AbandonedConfig abandonedCfg = this.abandonedConfig;
1187 if (abandonedCfg != null && abandonedCfg.getUseUsageTracking()) {
1188 final PooledObject<T> po = getPooledObject(pooledObject);
1189 if (po != null) {
1190 po.use();
1191 }
1192 }
1193 }
1194
1195 }