1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.dbcp2;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20
21 import java.sql.Connection;
22 import java.sql.PreparedStatement;
23 import java.sql.ResultSet;
24 import java.time.Duration;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.List;
29
30 import org.junit.jupiter.api.BeforeEach;
31 import org.junit.jupiter.api.Test;
32
33
34
35
36 public class TestParallelCreationWithNoIdle {
37
38 final class TestThread extends Thread {
39 final java.util.Random _random = new java.util.Random();
40 final int iter;
41 final int delay;
42 final int delayAfter;
43
44 public TestThread(final int iter, final int delay, final int delayAfter) {
45 this.iter = iter;
46 this.delay = delay;
47 this.delayAfter = delayAfter;
48 }
49
50 @Override
51 public void run() {
52
53 for (int i = 0; i < iter; i++) {
54 sleepMax(delay);
55 try (Connection conn = ds.getConnection();
56 PreparedStatement stmt = conn.prepareStatement("select 'literal', SYSDATE from dual")) {
57
58 final ResultSet rset = stmt.executeQuery();
59 rset.next();
60 sleepMax(delayAfter);
61 rset.close();
62 } catch (final Exception e) {
63 e.printStackTrace();
64 throw new RuntimeException(e);
65 }
66 }
67
68 }
69
70 private void sleepMax(final int timeMax) {
71 if (timeMax == 0) {
72 return;
73 }
74 try {
75 Thread.sleep(_random.nextInt(timeMax));
76 } catch (final Exception e) {
77
78 }
79 }
80 }
81 private static final String CATALOG = "test catalog";
82
83 protected BasicDataSource ds;
84
85 @BeforeEach
86 public void setUp() throws Exception {
87 ds = new BasicDataSource();
88 ds.setDriverClassName("org.apache.commons.dbcp2.TesterConnectionDelayDriver");
89 ds.setUrl("jdbc:apache:commons:testerConnectionDelayDriver:50");
90 ds.setMaxTotal(10);
91
92
93
94 ds.setMaxIdle(0);
95
96
97
98
99 ds.setMaxWait(Duration.ofMinutes(1));
100
101 ds.setDefaultAutoCommit(Boolean.TRUE);
102 ds.setDefaultReadOnly(Boolean.FALSE);
103 ds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
104 ds.setDefaultCatalog(CATALOG);
105 ds.setUsername("userName");
106 ds.setPassword("password");
107 ds.setValidationQuery("SELECT DUMMY FROM DUAL");
108 ds.setConnectionInitSqls(Arrays.asList("SELECT 1", "SELECT 2"));
109 ds.setDriverClassLoader(new TesterClassLoader());
110 ds.setJmxName("org.apache.commons.dbcp2:name=test");
111 }
112
113
114
115
116
117
118 @Test
119 public void testMassiveConcurrentInitBorrow() throws Exception {
120 final int numThreads = 200;
121 ds.setDriverClassName("org.apache.commons.dbcp2.TesterConnectionDelayDriver");
122 ds.setUrl("jdbc:apache:commons:testerConnectionDelayDriver:20");
123 ds.setInitialSize(8);
124 final List<Throwable> errors = Collections.synchronizedList(new ArrayList<>());
125
126 final Thread[] threads = new Thread[numThreads];
127 for (int i = 0; i < numThreads; i++) {
128 threads[i] = new TestThread(2, 0, 50);
129 threads[i].setUncaughtExceptionHandler((t, e) -> errors.add(e));
130 }
131
132 for (int i = 0; i < numThreads; i++) {
133 threads[i].start();
134
135 if (i%4 == 0) {
136 Thread.sleep(20);
137 }
138 }
139
140 for (int i = 0; i < numThreads; i++) {
141 threads[i].join();
142 }
143
144 assertEquals(0, errors.size());
145 ds.close();
146 }
147
148 }