1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.performance.dbcp;
19
20
21 import java.sql.Connection;
22 import java.sql.Driver;
23 import java.sql.DriverManager;
24 import java.sql.Statement;
25 import java.util.Properties;
26 import java.util.logging.Logger;
27 import org.apache.commons.dbcp.AbandonedConfig;
28 import org.apache.commons.dbcp.AbandonedObjectPool;
29 import org.apache.commons.dbcp.ConnectionFactory;
30 import org.apache.commons.dbcp.DriverConnectionFactory;
31 import org.apache.commons.dbcp.DriverManagerConnectionFactory;
32 import org.apache.commons.dbcp.PoolableConnectionFactory;
33 import org.apache.commons.dbcp.PoolingDataSource;
34 import org.apache.commons.pool.KeyedObjectPoolFactory;
35 import org.apache.commons.pool.PoolableObjectFactory;
36 import org.apache.commons.pool.impl.GenericKeyedObjectPool;
37 import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
38 import org.apache.commons.pool.impl.GenericObjectPool;
39 import org.apache.commons.math.random.RandomData;
40 import org.apache.commons.math.random.RandomDataImpl;
41 import org.apache.commons.performance.ConfigurationException;
42 import org.apache.commons.performance.ClientThread;
43 import org.apache.commons.performance.LoadGenerator;
44 import org.apache.commons.performance.Statistics;
45
46
47
48
49
50
51
52 public class DBCPSoak extends LoadGenerator {
53
54 private String driverClass;
55 private String connectUrl;
56 private String connectUser;
57 private String connectPassword;
58 private String queryType;
59
60
61 private String poolType;
62 private String driverType;
63 private String factoryType;
64 private boolean autocommit;
65 private boolean readOnly;
66 private byte exhaustedAction;
67 private boolean testOnBorrow;
68 private boolean testOnReturn;
69 private long timeBetweenEvictions;
70 private int testsPerEviction;
71 private long idleTimeout;
72 private boolean testWhileIdle;
73 private String validationQuery;
74 private AbandonedConfig abandonedConfig = new AbandonedConfig();
75 private boolean poolPreparedStatements;
76 private int maxOpenStatements;
77 private int maxActive;
78 private int maxIdle;
79 private int minIdle;
80 private long maxWait;
81
82
83 private GenericObjectPool connectionPool;
84 private PoolingDataSource dataSource;
85
86
87
88
89 protected void init() throws Exception {
90 Class.forName(driverClass);
91
92
93 if (poolType.equals("GenericObjectPool")) {
94 connectionPool = new GenericObjectPool(
95 null, maxActive, exhaustedAction,
96 maxWait, maxIdle, minIdle, testOnBorrow, testOnReturn,
97 timeBetweenEvictions, testsPerEviction, idleTimeout,
98 testWhileIdle);
99 } else if (poolType.equals("AbandonedObjectPool")) {
100 connectionPool = new AbandonedObjectPool(null,abandonedConfig);
101 } else {
102 throw new ConfigurationException(
103 "invalid pool type configuration: " + poolType);
104 }
105
106
107 ConnectionFactory connectionFactory = null;
108 if (driverType.equals("DriverManager")) {
109 connectionFactory = new DriverManagerConnectionFactory(
110 connectUrl,connectUser,
111 connectPassword);
112 } else if (driverType.equals("Driver")) {
113 Properties props = new Properties();
114 props.put("user", connectUser);
115 props.put("password", connectPassword);
116 connectionFactory = new DriverConnectionFactory(
117 (Driver) Class.forName(driverClass).newInstance(),
118 connectUrl, props);
119 } else {
120 throw new ConfigurationException(
121 "Bad config setting for driver type");
122 }
123
124
125 PoolableObjectFactory poolableConnectionFactory = null;
126 KeyedObjectPoolFactory statementPoolFactory = null;
127 if (poolPreparedStatements) {
128 statementPoolFactory = new GenericKeyedObjectPoolFactory(null,
129 -1,
130 GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL,
131 0,
132 1,
133 maxOpenStatements);
134 }
135 if (factoryType.equals("PoolableConnectionFactory")) {
136 poolableConnectionFactory =
137 new PoolableConnectionFactory(
138 connectionFactory,connectionPool, statementPoolFactory,
139 validationQuery, readOnly, autocommit);
140 } else if (factoryType.equals("CPDSConnectionFactory")) {
141 throw new ConfigurationException(
142 "CPDSConnectionFactory not implemented yet");
143 } else {
144 throw new ConfigurationException(
145 "Invalid factory type: " + factoryType);
146 }
147
148
149 dataSource = new PoolingDataSource(connectionPool);
150
151
152
153 Connection conn = dataSource.getConnection();
154 try {
155 Statement stmnt = conn.createStatement();
156 stmnt.execute("select * from test_table where indexed=1;");
157 stmnt.close();
158 } catch (Exception ex) {
159 if (ex.getMessage().indexOf("test_table") > 0) {
160 logger.info("Creating test_table");
161 makeTable();
162 logger.info("test_table created successfully");
163 } else {
164 throw ex;
165 }
166 } finally {
167 conn.close();
168 }
169 }
170
171
172
173
174 protected void cleanUp() throws Exception {
175 connectionPool.close();
176 }
177
178 protected ClientThread makeClientThread(
179 long iterations, long minDelay, long maxDelay, double sigma,
180 String delayType, long rampPeriod, long peakPeriod,
181 long troughPeriod, String cycleType, String rampType,
182 Logger logger, Statistics stats) {
183
184 return new DBCPClientThread(iterations, minDelay, maxDelay,
185 sigma, delayType, queryType, rampPeriod, peakPeriod,
186 troughPeriod, cycleType, rampType, logger, dataSource,
187 stats);
188 }
189
190
191
192
193
194 public void configureDataBase(String driver, String url,
195 String username, String password, String queryType) {
196 this.driverClass = driver;
197 this.connectUrl = url;
198 this.connectUser = username;
199 this.connectPassword = password;
200 this.queryType = queryType;
201 }
202
203 public void configureConnectionFactory(String type,
204 String autoCommit, String readOnly, String validationQuery) {
205 this.driverType = type;
206 this.autocommit = Boolean.parseBoolean(autoCommit);
207 this.readOnly = Boolean.parseBoolean(readOnly);
208 this.validationQuery = validationQuery;
209 }
210
211 public void configurePoolableConnectionFactory(String type,
212 String poolPreparedStatements, String maxOpenStatements) {
213 this.factoryType = type;
214 this.poolPreparedStatements =
215 Boolean.parseBoolean(poolPreparedStatements);
216 this.maxOpenStatements = Integer.parseInt(maxOpenStatements);
217 }
218
219 public void configurePool(String maxActive, String maxIdle, String minIdle,
220 String maxWait, String exhaustedAction, String testOnBorrow,
221 String testOnReturn, String timeBetweenEvictions,
222 String testsPerEviction, String idleTimeout,
223 String testWhileIdle, String type) throws ConfigurationException {
224 this.maxActive = Integer.parseInt(maxActive);
225 this.maxIdle = Integer.parseInt(maxIdle);
226 this.minIdle = Integer.parseInt(minIdle);
227 this.maxWait = Long.parseLong(maxWait);
228 this.testOnBorrow = Boolean.parseBoolean(testOnBorrow);
229 this.testOnReturn = Boolean.parseBoolean(testOnReturn);
230 this.timeBetweenEvictions = Long.parseLong(timeBetweenEvictions);
231 this.testsPerEviction = Integer.parseInt(testsPerEviction);
232 this.idleTimeout = Long.parseLong(idleTimeout);
233 this.testWhileIdle = Boolean.parseBoolean(testWhileIdle);
234 this.poolType = type;
235 if (exhaustedAction.equals("block")) {
236 this.exhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_BLOCK;
237 } else if (exhaustedAction.equals("fail")) {
238 this.exhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_FAIL;
239 } else if (exhaustedAction.equals("grow")) {
240 this.exhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW;
241 } else {
242 throw new ConfigurationException(
243 "Bad configuration setting for exhausted action: "
244 + exhaustedAction);
245 }
246 }
247
248 public void configureAbandonedConfig(String logAbandoned,
249 String removeAbandoned, String abandonedTimeout) {
250 abandonedConfig.setLogAbandoned(Boolean.parseBoolean(logAbandoned));
251 abandonedConfig.setRemoveAbandoned(
252 Boolean.parseBoolean(removeAbandoned));
253 abandonedConfig.setRemoveAbandonedTimeout(
254 Integer.parseInt(abandonedTimeout));
255 }
256
257
258
259
260
261
262
263
264
265
266
267
268 protected void makeTable() throws Exception {
269 Class.forName(driverClass);
270 Connection db = DriverManager.getConnection(connectUrl,connectUser,
271 connectPassword);
272 try {
273 Statement sql = db.createStatement();
274 String sqlText =
275 "create table test_table (indexed int, text varchar(20)," +
276 " not_indexed int)";
277 sql.executeUpdate(sqlText);
278 sqlText = "CREATE INDEX test1_id_index ON test_table (indexed);";
279 sql.executeUpdate(sqlText);
280 RandomData randomData = new RandomDataImpl();
281 for (int i = 0; i < 10000; i++) {
282 int indexed = randomData.nextInt(0, 100);
283 int not_indexed = randomData.nextInt(0, 1000);
284 String text = randomData.nextHexString(20);
285 sqlText =
286 "INSERT INTO test_table (indexed, text, not_indexed)" +
287 "VALUES (" + indexed + "," + "'"+ text + "'," +
288 not_indexed + ");";
289 sql.executeUpdate(sqlText);
290 }
291 sql.close();
292 } finally {
293 db.close();
294 }
295 }
296
297
298
299
300
301 protected void configure() throws Exception {
302
303 super.configure();
304
305 digester.addCallMethod("configuration/database",
306 "configureDataBase", 5);
307 digester.addCallParam("configuration/database/driver", 0);
308 digester.addCallParam("configuration/database/url", 1);
309 digester.addCallParam("configuration/database/username", 2);
310 digester.addCallParam("configuration/database/password", 3);
311 digester.addCallParam("configuration/database/query-type", 4);
312
313 digester.addCallMethod("configuration/connection-factory",
314 "configureConnectionFactory", 4);
315 digester.addCallParam(
316 "configuration/connection-factory/type", 0);
317 digester.addCallParam(
318 "configuration/connection-factory/auto-commit", 1);
319 digester.addCallParam(
320 "configuration/connection-factory/read-only", 2);
321 digester.addCallParam(
322 "configuration/connection-factory/validation-query", 3);
323
324 digester.addCallMethod("configuration/poolable-connection-factory",
325 "configurePoolableConnectionFactory", 3);
326 digester.addCallParam(
327 "configuration/poolable-connection-factory/type", 0);
328 digester.addCallParam(
329 "configuration/poolable-connection-factory/pool-prepared-statements", 1);
330 digester.addCallParam(
331 "configuration/poolable-connection-factory/max-open-statements", 2);
332
333 digester.addCallMethod("configuration/pool",
334 "configurePool", 12);
335 digester.addCallParam(
336 "configuration/pool/max-active", 0);
337 digester.addCallParam(
338 "configuration/pool/max-idle", 1);
339 digester.addCallParam(
340 "configuration/pool/min-idle", 2);
341 digester.addCallParam(
342 "configuration/pool/max-wait", 3);
343 digester.addCallParam(
344 "configuration/pool/exhausted-action", 4);
345 digester.addCallParam(
346 "configuration/pool/test-on-borrow", 5);
347 digester.addCallParam(
348 "configuration/pool/test-on-return", 6);
349 digester.addCallParam(
350 "configuration/pool/time-between-evictions", 7);
351 digester.addCallParam(
352 "configuration/pool/tests-per-eviction", 8);
353 digester.addCallParam(
354 "configuration/pool/idle-timeout", 9);
355 digester.addCallParam(
356 "configuration/pool/test-while-idle", 10);
357 digester.addCallParam(
358 "configuration/pool/type", 11);
359
360 digester.addCallMethod("configuration/abandoned-config",
361 "configureAbandonedConfig", 3);
362 digester.addCallParam(
363 "configuration/abandoned-config/log-abandoned", 0);
364 digester.addCallParam(
365 "configuration/abandoned-config/remove-abandoned", 1);
366 digester.addCallParam(
367 "configuration/abandoned-config/abandoned-timeout", 2);
368
369 this.configFile = "config-dbcp.xml";
370 }
371
372 public GenericObjectPool getConnectionPool() {
373 return connectionPool;
374 }
375 }