Coverage Report - org.apache.commons.performance.dbcp.DBCPSoak
 
Classes in this File Line Coverage Branch Coverage Complexity
DBCPSoak
0%
0/169
0%
0/30
2.769
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  * 
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  * 
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 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  
  * Configurable load / performance tester for commons dbcp.
 50  
  * Uses Commons Digester to parse and load configuration and spawns
 51  
  * DBCPClientThread instances to generate load and gather statistics.
 52  
  *
 53  
  */
 54  0
 public class DBCPSoak extends LoadGenerator {
 55  
     // Connection properties
 56  
     private String driverClass;
 57  
     private String connectUrl;
 58  
     private String connectUser;
 59  
     private String connectPassword;
 60  
     private String queryType;
 61  
     
 62  
     // Connection pool properties
 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  0
     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  
     // DataSource type
 85  
     private String dataSourceType;
 86  
     
 87  
     // Instance variables
 88  
     private GenericObjectPool connectionPool;
 89  
     private DataSource dataSource;
 90  
     
 91  
     /**
 92  
      * Create connection pool and, if necessary, test table.
 93  
      */
 94  
     protected void init() throws Exception {
 95  
         
 96  0
         if (dataSourceType.equals("BasicDataSource")) {
 97  0
             BasicDataSource bds = new BasicDataSource();
 98  0
             bds.setDefaultAutoCommit(autocommit);
 99  0
             bds.setPassword(connectPassword);
 100  0
             bds.setUrl(connectUrl);
 101  0
             bds.setUsername(connectUser);
 102  0
             bds.setDriverClassName(driverClass);
 103  0
             bds.setMinEvictableIdleTimeMillis(idleTimeout);
 104  0
             bds.setMaxActive(maxActive);
 105  0
             bds.setMaxIdle(maxIdle);
 106  0
             bds.setMaxWait(maxWait);
 107  0
             bds.setMinIdle(minIdle);
 108  0
             bds.setPoolPreparedStatements(poolPreparedStatements);
 109  0
             bds.setDefaultReadOnly(readOnly);
 110  0
             bds.setTestOnBorrow(testOnBorrow);
 111  0
             bds.setTestOnReturn(testOnReturn);
 112  0
             bds.setTestWhileIdle(testWhileIdle);
 113  0
             bds.setNumTestsPerEvictionRun(testsPerEviction);
 114  0
             bds.setTimeBetweenEvictionRunsMillis(timeBetweenEvictions);
 115  0
             bds.setValidationQuery(validationQuery);
 116  0
             if (poolType.equals("AbandonedObjectPool")) {
 117  0
                     bds.setRemoveAbandoned(true);
 118  
             }
 119  0
             dataSource = bds; 
 120  0
             checkDatabase();
 121  0
             return;
 122  
         }
 123  
 
 124  0
         Class.forName(driverClass);
 125  
         
 126  
         // Create object pool
 127  0
         if (poolType.equals("GenericObjectPool")) {
 128  0
             connectionPool = new GenericObjectPool(
 129  
                     null, maxActive, exhaustedAction,
 130  
                     maxWait, maxIdle, minIdle, testOnBorrow, testOnReturn,
 131  
                     timeBetweenEvictions, testsPerEviction, idleTimeout,
 132  
                     testWhileIdle);
 133  0
         } else if (poolType.equals("AbandonedObjectPool")) {
 134  0
             connectionPool = new AbandonedObjectPool(null,abandonedConfig);
 135  
         } else {
 136  0
             throw new ConfigurationException(
 137  
                     "invalid pool type configuration: " + poolType);
 138  
         }
 139  
         
 140  
         // Create raw connection factory
 141  0
         ConnectionFactory connectionFactory = null;
 142  0
         if (driverType.equals("DriverManager")) {
 143  0
             connectionFactory = new DriverManagerConnectionFactory(
 144  
                     connectUrl,connectUser,
 145  
                     connectPassword);
 146  0
         } else if (driverType.equals("Driver")) {
 147  0
             Properties props = new Properties();
 148  0
             props.put("user", connectUser);
 149  0
             props.put("password", connectPassword);
 150  0
             connectionFactory = new DriverConnectionFactory(
 151  
                     (Driver) Class.forName(driverClass).newInstance(),
 152  
                     connectUrl, props);
 153  0
         } else {
 154  0
             throw new ConfigurationException(
 155  
             "Bad config setting for driver type"); 
 156  
         } 
 157  
    
 158  
         // Create object factory
 159  0
         PoolableObjectFactory poolableConnectionFactory = null;
 160  0
         KeyedObjectPoolFactory statementPoolFactory = null;
 161  0
         if (poolPreparedStatements) { // Use same defaults as BasicDataSource
 162  0
             statementPoolFactory = new GenericKeyedObjectPoolFactory(null,
 163  
                         -1, // unlimited maxActive (per key)
 164  
                         GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL,
 165  
                         0, // maxWait
 166  
                         1, // maxIdle (per key)
 167  
                         maxOpenStatements); //TODO: make all configurable
 168  
         }
 169  0
         if (factoryType.equals("PoolableConnectionFactory")) {
 170  0
             poolableConnectionFactory = 
 171  
                 new PoolableConnectionFactory(
 172  
                         connectionFactory,connectionPool, statementPoolFactory,
 173  
                         validationQuery, readOnly, autocommit);
 174  0
         } else if (factoryType.equals("CPDSConnectionFactory")) {
 175  0
             throw new ConfigurationException(
 176  
             "CPDSConnectionFactory not implemented yet");
 177  
         } else {
 178  0
             throw new ConfigurationException(
 179  
                     "Invalid factory type: " + factoryType);
 180  
         }
 181  
         
 182  
         // Create DataSource
 183  0
         dataSource = new PoolingDataSource(connectionPool); 
 184  0
         checkDatabase();   
 185  0
     }
 186  
     
 187  
     protected void checkDatabase() throws Exception {
 188  
         // Try to connect and query test_table. If "test_table" appears in 
 189  
         // exception message, assume table needs to be created. 
 190  0
         Connection conn = dataSource.getConnection();
 191  
         try {
 192  0
             Statement stmnt = conn.createStatement();
 193  0
             stmnt.execute("select * from test_table where indexed=1;");
 194  0
             stmnt.close();
 195  0
         } catch (Exception ex) {
 196  0
             if (ex.getMessage().indexOf("test_table") > 0) {
 197  0
                 logger.info("Creating test_table");
 198  0
                 makeTable();
 199  0
                 logger.info("test_table created successfully");
 200  
             } else {
 201  0
                 throw ex;
 202  
             }
 203  
         } finally {
 204  0
             conn.close();
 205  0
         }
 206  0
     }
 207  
     
 208  
     /**
 209  
      * Close connection pool
 210  
      */
 211  
     protected void cleanUp() throws Exception {
 212  0
         if (dataSourceType.equals("BasicDataSource")) {
 213  0
             ((BasicDataSource) dataSource).close();
 214  
         } else {
 215  0
             connectionPool.close();
 216  
         }
 217  0
     }
 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  0
         return new DBCPClientThread(iterations, minDelay, maxDelay,
 226  
             sigma, delayType, queryType, rampPeriod, peakPeriod, 
 227  
             troughPeriod, cycleType, rampType, logger, dataSource,
 228  
             stats);
 229  
     }
 230  
     
 231  
     // ------------------------------------------------------------------------
 232  
     // Configuration methods specific to this LoadGenerator invoked by Digester
 233  
     // when superclass execute calls digester.parse.
 234  
     // ------------------------------------------------------------------------
 235  
     public void configureDataBase(String driver, String url,
 236  
             String username, String password, String queryType) {
 237  0
         this.driverClass = driver;
 238  0
         this.connectUrl = url;
 239  0
         this.connectUser = username;
 240  0
         this.connectPassword = password;
 241  0
         this.queryType = queryType;
 242  0
     }
 243  
     
 244  
     public void configureDataSource(String type) {
 245  0
         this.dataSourceType = type;
 246  0
     }
 247  
     
 248  
     public void configureConnectionFactory(String type,
 249  
             String autoCommit, String readOnly, String validationQuery) {
 250  0
         this.driverType = type;
 251  0
         this.autocommit = Boolean.parseBoolean(autoCommit);
 252  0
         this.readOnly = Boolean.parseBoolean(readOnly);
 253  0
         this.validationQuery = validationQuery;
 254  0
     }
 255  
     
 256  
     public void configurePoolableConnectionFactory(String type, 
 257  
             String poolPreparedStatements, String maxOpenStatements) {
 258  0
         this.factoryType = type;
 259  0
         this.poolPreparedStatements = 
 260  
             Boolean.parseBoolean(poolPreparedStatements);
 261  0
         this.maxOpenStatements = Integer.parseInt(maxOpenStatements);
 262  0
     }
 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  0
         this.maxActive = Integer.parseInt(maxActive);
 270  0
         this.maxIdle = Integer.parseInt(maxIdle);
 271  0
         this.minIdle = Integer.parseInt(minIdle);
 272  0
         this.maxWait = Long.parseLong(maxWait);
 273  0
         this.testOnBorrow = Boolean.parseBoolean(testOnBorrow);
 274  0
         this.testOnReturn = Boolean.parseBoolean(testOnReturn);
 275  0
         this.timeBetweenEvictions = Long.parseLong(timeBetweenEvictions);
 276  0
         this.testsPerEviction = Integer.parseInt(testsPerEviction);
 277  0
         this.idleTimeout = Long.parseLong(idleTimeout);
 278  0
         this.testWhileIdle = Boolean.parseBoolean(testWhileIdle);
 279  0
         this.poolType = type;
 280  0
         if (exhaustedAction.equals("block")) {
 281  0
             this.exhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_BLOCK;
 282  0
         } else if (exhaustedAction.equals("fail")) {
 283  0
             this.exhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_FAIL;
 284  0
         } else if (exhaustedAction.equals("grow")) {
 285  0
             this.exhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW;
 286  
         } else { 
 287  0
             throw new ConfigurationException(
 288  
             "Bad configuration setting for exhausted action: "
 289  
                     + exhaustedAction); 
 290  
         }  
 291  0
     }
 292  
     
 293  
     public void configureAbandonedConfig(String logAbandoned,
 294  
             String removeAbandoned, String abandonedTimeout) {
 295  0
         abandonedConfig.setLogAbandoned(Boolean.parseBoolean(logAbandoned));
 296  0
         abandonedConfig.setRemoveAbandoned(
 297  
                 Boolean.parseBoolean(removeAbandoned));
 298  0
         abandonedConfig.setRemoveAbandonedTimeout(
 299  
                 Integer.parseInt(abandonedTimeout));
 300  0
     }
 301  
      
 302  
     /**
 303  
      * Creates and populates the test table (test_table) used in the 
 304  
      * load tests. The created table will have 10,000 rows and 3 columns,
 305  
      * populated with random data: <ul>
 306  
      * <li> indexed (indexed integer column) </li>
 307  
      * <li> not_indexed (non-indexed integer column) </li>
 308  
      * <li> text (non-indexed varchar column) </li>
 309  
      * </ul>
 310  
      *
 311  
      * @throws Exception
 312  
      */
 313  
     protected void makeTable() throws Exception {
 314  0
         Class.forName(driverClass); 
 315  0
         Connection db = DriverManager.getConnection(connectUrl,connectUser,
 316  
                 connectPassword);
 317  
         try {
 318  0
             Statement sql = db.createStatement();
 319  0
             String sqlText = 
 320  
                 "create table test_table (indexed int, text varchar(20)," + 
 321  
                 " not_indexed int)";
 322  0
             sql.executeUpdate(sqlText);
 323  0
             sqlText = "CREATE INDEX test1_id_index ON test_table (indexed);";
 324  0
             sql.executeUpdate(sqlText);
 325  0
             RandomData randomData = new RandomDataImpl();
 326  0
             for (int i = 0; i < 10000; i++) {
 327  0
                 int indexed = randomData.nextInt(0, 100);
 328  0
                 int not_indexed = randomData.nextInt(0, 1000);
 329  0
                 String text = randomData.nextHexString(20);
 330  0
                 sqlText = 
 331  
                     "INSERT INTO test_table (indexed, text, not_indexed)" + 
 332  
                     "VALUES (" + indexed + "," + "'"+ text + "'," + 
 333  
                     not_indexed + ");";
 334  0
                 sql.executeUpdate(sqlText);
 335  
             }
 336  0
             sql.close();
 337  
         } finally {
 338  0
             db.close();
 339  0
         }
 340  0
     }
 341  
     
 342  
     /**
 343  
      * Add dbcp configuration to parameters loaded by super.
 344  
      * Also set config file name.
 345  
      */
 346  
     protected void configure() throws Exception {
 347  
         
 348  0
         super.configure();
 349  
         
 350  0
         digester.addCallMethod("configuration/database",
 351  
                 "configureDataBase", 5);
 352  0
         digester.addCallParam("configuration/database/driver", 0);
 353  0
         digester.addCallParam("configuration/database/url", 1);
 354  0
         digester.addCallParam("configuration/database/username", 2);
 355  0
         digester.addCallParam("configuration/database/password", 3);
 356  0
         digester.addCallParam("configuration/database/query-type", 4);
 357  
         
 358  0
         digester.addCallMethod("configuration", "configureDataSource", 1);
 359  0
         digester.addCallParam("configuration/datasource-type", 0);
 360  
         
 361  0
         digester.addCallMethod("configuration/connection-factory", 
 362  
                 "configureConnectionFactory", 4);
 363  0
         digester.addCallParam(
 364  
                 "configuration/connection-factory/type", 0);
 365  0
         digester.addCallParam(
 366  
                 "configuration/connection-factory/auto-commit", 1);
 367  0
         digester.addCallParam(
 368  
                 "configuration/connection-factory/read-only", 2);
 369  0
         digester.addCallParam(
 370  
                 "configuration/connection-factory/validation-query", 3);
 371  
         
 372  0
         digester.addCallMethod("configuration/poolable-connection-factory", 
 373  
                 "configurePoolableConnectionFactory", 3);
 374  0
         digester.addCallParam(
 375  
                 "configuration/poolable-connection-factory/type", 0);
 376  0
         digester.addCallParam(
 377  
                 "configuration/poolable-connection-factory/pool-prepared-statements", 1);
 378  0
         digester.addCallParam(
 379  
                 "configuration/poolable-connection-factory/max-open-statements", 2);
 380  
         
 381  0
         digester.addCallMethod("configuration/pool", 
 382  
                 "configurePool", 12);
 383  0
         digester.addCallParam(
 384  
                 "configuration/pool/max-active", 0);
 385  0
         digester.addCallParam(
 386  
                 "configuration/pool/max-idle", 1);
 387  0
         digester.addCallParam(
 388  
                 "configuration/pool/min-idle", 2);
 389  0
         digester.addCallParam(
 390  
                 "configuration/pool/max-wait", 3);
 391  0
         digester.addCallParam(
 392  
                 "configuration/pool/exhausted-action", 4);
 393  0
         digester.addCallParam(
 394  
                 "configuration/pool/test-on-borrow", 5);
 395  0
         digester.addCallParam(
 396  
                 "configuration/pool/test-on-return", 6);
 397  0
         digester.addCallParam(
 398  
                 "configuration/pool/time-between-evictions", 7);
 399  0
         digester.addCallParam(
 400  
                 "configuration/pool/tests-per-eviction", 8);
 401  0
         digester.addCallParam(
 402  
                 "configuration/pool/idle-timeout", 9);
 403  0
         digester.addCallParam(
 404  
                 "configuration/pool/test-while-idle", 10);
 405  0
         digester.addCallParam(
 406  
                 "configuration/pool/type", 11);
 407  
         
 408  0
         digester.addCallMethod("configuration/abandoned-config",
 409  
                 "configureAbandonedConfig", 3);
 410  0
         digester.addCallParam(
 411  
                 "configuration/abandoned-config/log-abandoned", 0);
 412  0
         digester.addCallParam(
 413  
                 "configuration/abandoned-config/remove-abandoned", 1);
 414  0
         digester.addCallParam(
 415  
                 "configuration/abandoned-config/abandoned-timeout", 2);
 416  
         
 417  0
         this.configFile = "config-dbcp.xml";
 418  0
     }
 419  
 
 420  
     public GenericObjectPool getConnectionPool() {
 421  0
         return connectionPool;
 422  
     }
 423  
 }