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