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 import java.util.Random;
30
31 import org.junit.jupiter.api.BeforeEach;
32 import org.junit.jupiter.api.Test;
33
34
35
36
37 public class TestParallelCreationWithNoIdle {
38
39 final class TestThread extends Thread {
40 final Random random = new Random();
41 final int iter;
42 final int delay;
43 final int delayAfter;
44
45 public TestThread(final int iter, final int delay, final int delayAfter) {
46 this.iter = iter;
47 this.delay = delay;
48 this.delayAfter = delayAfter;
49 }
50
51 @Override
52 public void run() {
53
54 for (int i = 0; i < iter; i++) {
55 sleepMax(delay);
56 try (Connection conn = ds.getConnection(); 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
82 private static final String CATALOG = "test catalog";
83
84 protected BasicDataSource ds;
85
86 @BeforeEach
87 public void setUp() throws Exception {
88 ds = new BasicDataSource();
89 ds.setDriverClassName("org.apache.commons.dbcp2.TesterConnectionDelayDriver");
90 ds.setUrl("jdbc:apache:commons:testerConnectionDelayDriver:50");
91 ds.setMaxTotal(10);
92
93
94
95 ds.setMaxIdle(0);
96
97
98
99
100 ds.setMaxWait(Duration.ofMinutes(1));
101
102 ds.setDefaultAutoCommit(Boolean.TRUE);
103 ds.setDefaultReadOnly(Boolean.FALSE);
104 ds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
105 ds.setDefaultCatalog(CATALOG);
106 ds.setUsername("userName");
107 ds.setPassword("password");
108 ds.setValidationQuery("SELECT DUMMY FROM DUAL");
109 ds.setConnectionInitSqls(Arrays.asList("SELECT 1", "SELECT 2"));
110 ds.setDriverClassLoader(new TesterClassLoader());
111 ds.setJmxName("org.apache.commons.dbcp2:name=test");
112 }
113
114
115
116
117
118
119 @Test
120 void testMassiveConcurrentInitBorrow() throws Exception {
121 final int numThreads = 200;
122 ds.setDriverClassName("org.apache.commons.dbcp2.TesterConnectionDelayDriver");
123 ds.setUrl("jdbc:apache:commons:testerConnectionDelayDriver:20");
124 ds.setInitialSize(8);
125 final List<Throwable> errors = Collections.synchronizedList(new ArrayList<>());
126
127 final Thread[] threads = new Thread[numThreads];
128 for (int i = 0; i < numThreads; i++) {
129 threads[i] = new TestThread(2, 0, 50);
130 threads[i].setUncaughtExceptionHandler((t, e) -> errors.add(e));
131 }
132
133 for (int i = 0; i < numThreads; i++) {
134 threads[i].start();
135
136 if (i % 4 == 0) {
137 Thread.sleep(20);
138 }
139 }
140
141 for (int i = 0; i < numThreads; i++) {
142 threads[i].join();
143 }
144
145 assertEquals(0, errors.size());
146 ds.close();
147 }
148
149 }