View Javadoc

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.pool;
19  
20  import java.util.List;
21  import java.util.logging.Logger;
22  import org.apache.commons.dbcp.AbandonedConfig;
23  import org.apache.commons.dbcp.AbandonedObjectPool;
24  import org.apache.commons.math.stat.descriptive.SummaryStatistics;
25  import org.apache.commons.pool.ObjectPool;
26  import org.apache.commons.pool.KeyedObjectPool;
27  import org.apache.commons.pool.impl.GenericObjectPool;
28  import org.apache.commons.pool.impl.StackObjectPool;
29  import org.apache.commons.pool.impl.SoftReferenceObjectPool;
30  import org.apache.commons.pool.impl.GenericKeyedObjectPool;
31  import org.apache.commons.pool.impl.StackKeyedObjectPool;
32  import org.apache.commons.performance.ConfigurationException;
33  import org.apache.commons.performance.ClientThread;
34  import org.apache.commons.performance.LoadGenerator;
35  import org.apache.commons.performance.Statistics;
36   
37  /**
38   * Configurable load / performance tester for commons pool.
39   * Uses Commons Digester to parse and load configuration and spawns
40   * PoolClientThread instances to generate load and gather statistics.
41   *
42   */
43  public class PoolSoak extends LoadGenerator {
44      
45      // Pool instances
46      private GenericObjectPool genericObjectPool;
47      private GenericKeyedObjectPool genericKeyedObjectPool;
48      private StackObjectPool stackObjectPool;
49      private SoftReferenceObjectPool softReferenceObjectPool;
50      private StackKeyedObjectPool stackKeyedObjectPool;
51      
52      // Pool properties
53      private String poolType;
54      private int maxActive;       // maxActive for GOP, maxTotal for GKOP
55      private int maxActivePerKey; // maxActive for GKOP
56      private int maxIdle;
57      private int minIdle;
58      private long maxWait;
59      private byte exhaustedAction;
60      private boolean testOnBorrow;
61      private boolean testOnReturn;
62      private long timeBetweenEvictions;
63      private int testsPerEviction;
64      private long idleTimeout;
65      private boolean testWhileIdle;
66      private AbandonedConfig abandonedConfig = new AbandonedConfig();
67      private boolean lifo;
68      private double samplingRate;
69      
70      // WaiterFactory properties
71      private long activateLatency;
72      private long destroyLatency;
73      private long makeLatency;
74      private long passivateLatency;
75      private long validateLatency;
76      private long waiterLatency;
77      
78      /**
79       * Add pool configuration to parameters loaded by super.
80       * Also set config file name.
81       */
82      protected void configure() throws Exception {
83          super.configure();
84          digester.addCallMethod("configuration/factory", 
85                  "configureFactory", 6);
86          digester.addCallParam(
87                  "configuration/factory/activate-latency", 0);
88          digester.addCallParam(
89                  "configuration/factory/destroy-latency", 1);
90          digester.addCallParam(
91                  "configuration/factory/make-latency", 2);
92          digester.addCallParam(
93                  "configuration/factory/passivate-latency", 3);
94          digester.addCallParam(
95                  "configuration/factory/validate-latency", 4);
96          digester.addCallParam(
97                  "configuration/factory/waiter-latency", 5);   
98          digester.addCallMethod("configuration/pool", 
99                  "configurePool", 15);
100         digester.addCallParam(
101                 "configuration/pool/max-active", 0);
102         digester.addCallParam(
103                 "configuration/pool/max-active-per-key", 1);
104         digester.addCallParam(
105                 "configuration/pool/max-idle", 2);
106         digester.addCallParam(
107                 "configuration/pool/min-idle", 3);
108         digester.addCallParam(
109                 "configuration/pool/max-wait", 4);
110         digester.addCallParam(
111                 "configuration/pool/exhausted-action", 5);
112         digester.addCallParam(
113                 "configuration/pool/test-on-borrow", 6);
114         digester.addCallParam(
115                 "configuration/pool/test-on-return", 7);
116         digester.addCallParam(
117                 "configuration/pool/time-between-evictions", 8);
118         digester.addCallParam(
119                 "configuration/pool/tests-per-eviction", 9);
120         digester.addCallParam(
121                 "configuration/pool/idle-timeout", 10);
122         digester.addCallParam(
123                 "configuration/pool/test-while-idle", 11);
124         digester.addCallParam(
125                 "configuration/pool/lifo", 12);
126         digester.addCallParam(
127                 "configuration/pool/type", 13);
128         digester.addCallParam(
129                 "configuration/pool/sampling-rate", 14);
130         digester.addCallMethod("configuration/abandoned-config",
131                 "configureAbandonedConfig", 3);
132         digester.addCallParam(
133                 "configuration/abandoned-config/log-abandoned", 0);
134         digester.addCallParam(
135                 "configuration/abandoned-config/remove-abandoned", 1);
136         digester.addCallParam(
137                 "configuration/abandoned-config/abandoned-timeout", 2); 
138         
139         this.configFile = "config-pool.xml";
140         
141     }
142     
143     /**
144      * Create object pool and factory
145      */
146     protected void init() throws Exception {
147         // Create factory
148         WaiterFactory factory = new WaiterFactory(activateLatency, destroyLatency,
149                 makeLatency, passivateLatency, validateLatency, waiterLatency,
150                 maxActive, maxActivePerKey); 
151         
152         // Create object pool
153         if (poolType.equals("GenericObjectPool")) {
154             genericObjectPool = new GenericObjectPool(factory);
155             genericObjectPool.setMaxActive(maxActive);
156             genericObjectPool.setWhenExhaustedAction(exhaustedAction);
157             genericObjectPool.setMaxWait(maxWait);
158             genericObjectPool.setMaxIdle(maxIdle);
159             genericObjectPool.setMinIdle(minIdle);
160             genericObjectPool.setTestOnBorrow(testOnBorrow);
161             genericObjectPool.setTestOnReturn(testOnReturn);
162             genericObjectPool.setTimeBetweenEvictionRunsMillis(
163                     timeBetweenEvictions);
164             genericObjectPool.setNumTestsPerEvictionRun(testsPerEviction);
165             genericObjectPool.setMinEvictableIdleTimeMillis(idleTimeout);
166             genericObjectPool.setTestWhileIdle(testWhileIdle);
167             //genericObjectPool.setLifo(lifo);
168         } else if (poolType.equals("AbandonedObjectPool")) {
169             genericObjectPool = new AbandonedObjectPool(null,abandonedConfig);
170             genericObjectPool.setMaxActive(maxActive);
171             genericObjectPool.setWhenExhaustedAction(exhaustedAction);
172             genericObjectPool.setMaxWait(maxWait);
173             genericObjectPool.setMaxIdle(maxIdle);
174             genericObjectPool.setMinIdle(minIdle);
175             genericObjectPool.setTestOnBorrow(testOnBorrow);
176             genericObjectPool.setTestOnReturn(testOnReturn);
177             genericObjectPool.setTimeBetweenEvictionRunsMillis(
178                     timeBetweenEvictions);
179             genericObjectPool.setNumTestsPerEvictionRun(testsPerEviction);
180             genericObjectPool.setMinEvictableIdleTimeMillis(idleTimeout);
181             genericObjectPool.setTestWhileIdle(testWhileIdle);
182             //genericObjectPool.setLifo(lifo);
183             genericObjectPool.setFactory(factory);
184         } else if (poolType.equals("GenericKeyedObjectPool")) {
185             genericKeyedObjectPool = new GenericKeyedObjectPool();
186             genericKeyedObjectPool.setMaxActive(maxActivePerKey);
187             genericKeyedObjectPool.setMaxTotal(maxActive);
188             genericKeyedObjectPool.setWhenExhaustedAction(exhaustedAction);
189             genericKeyedObjectPool.setMaxWait(maxWait);
190             genericKeyedObjectPool.setMaxIdle(maxIdle);
191             genericKeyedObjectPool.setMinIdle(minIdle);
192             genericKeyedObjectPool.setTestOnBorrow(testOnBorrow);
193             genericKeyedObjectPool.setTestOnReturn(testOnReturn);
194             genericKeyedObjectPool.setTimeBetweenEvictionRunsMillis(
195                     timeBetweenEvictions);
196             genericKeyedObjectPool.setNumTestsPerEvictionRun(testsPerEviction);
197             genericKeyedObjectPool.setMinEvictableIdleTimeMillis(idleTimeout);
198             genericKeyedObjectPool.setTestWhileIdle(testWhileIdle);
199             //genericKeyedObjectPool.setLifo(lifo);
200             genericKeyedObjectPool.setFactory(factory);
201         } else if (poolType.equals("StackObjectPool")) {
202             stackObjectPool = new StackObjectPool();
203             stackObjectPool.setFactory(factory);
204         } else if (poolType.equals("SoftReferenceObjectPool")) {
205             softReferenceObjectPool = new SoftReferenceObjectPool();
206             softReferenceObjectPool.setFactory(factory);
207         } else if (poolType.equals("StackKeyedObjectPool")) {
208             stackKeyedObjectPool = new StackKeyedObjectPool();
209             stackKeyedObjectPool.setFactory(factory);
210         } else {
211             throw new ConfigurationException(
212                     "invalid pool type configuration: " + poolType);
213         }
214         
215         logger.info("Initialized pool with properties: ");
216         logger.info(" poolTypeT: " + poolType);
217         logger.info(" exhaustedAction: " + exhaustedAction);
218         logger.info(" maxActive: " + maxActive);
219         logger.info(" maxActivePerKey: " + maxActivePerKey);
220         logger.info(" maxIdle: " + maxIdle);
221         logger.info(" minIdle: " + minIdle);
222         logger.info(" testOnBorrow: " + testOnBorrow);
223         logger.info(" testWhileIdle: " + testWhileIdle);
224         logger.info(" timeBetweenEvictions: " + timeBetweenEvictions);
225         logger.info(" testsPerEviction: " + testsPerEviction);
226         logger.info(" idleTimeout: " + idleTimeout);
227         logger.info(" lifo: " + lifo);
228         logger.info(" abandonedConfig: ");
229         logger.info("  logAbandoned: " +
230                 abandonedConfig.getLogAbandoned());
231         logger.info("  removeAbandoned: " +
232                 abandonedConfig.getRemoveAbandoned());
233         logger.info("  abandonedTimeout: " + 
234                 abandonedConfig.getRemoveAbandonedTimeout()); 
235     }
236     
237     /**
238      * Close object pool
239      */
240     protected void cleanUp() throws Exception {
241         if (genericObjectPool != null) {
242             genericObjectPool.close();
243         }
244         if (genericKeyedObjectPool != null) {
245             genericKeyedObjectPool.close();
246         }
247         if (stackObjectPool != null) {
248             stackObjectPool.close();
249         }
250         if (softReferenceObjectPool != null) {
251             softReferenceObjectPool.close();
252         }
253         if (stackKeyedObjectPool != null) {
254             stackKeyedObjectPool.close();
255         }
256     }
257     
258     /**
259      * Create and return a PoolClientThread
260      */
261     protected ClientThread makeClientThread(long iterations, long minDelay,
262             long maxDelay, double sigma, String delayType, long rampPeriod,
263             long peakPeriod, long troughPeriod, String cycleType, 
264             String rampType, Logger logger, Statistics stats) {
265         if (poolType.equals("GenericObjectPool")) {
266             return new PoolClientThread(iterations, minDelay, maxDelay,
267                     sigma, delayType, rampPeriod, peakPeriod, troughPeriod,
268                     cycleType, rampType, logger, stats, genericObjectPool, 
269                     samplingRate);
270         }
271         if (poolType.equals("GenericKeyedObjectPool")) {
272             return new PoolClientThread(iterations, minDelay, maxDelay,
273                     sigma, delayType, rampPeriod, peakPeriod, troughPeriod,
274                     cycleType, rampType, logger, stats,
275                     genericKeyedObjectPool, samplingRate);
276         }
277         if (poolType.equals("StackKeyedObjectPool")) {
278             return new PoolClientThread(iterations, minDelay, maxDelay,
279                     sigma, delayType, rampPeriod, peakPeriod, troughPeriod,
280                     cycleType, rampType, logger, stats,
281                     stackKeyedObjectPool, samplingRate);
282         }
283         if (poolType.equals("StackObjectPool")) {
284             return new PoolClientThread(iterations, minDelay, maxDelay,
285                     sigma, delayType, rampPeriod, peakPeriod, troughPeriod,
286                     cycleType, rampType, logger, stats,
287                     stackObjectPool, samplingRate);
288         }
289         if (poolType.equals("SoftReferenceObjectPool")) {
290             return new PoolClientThread(iterations, minDelay, maxDelay,
291                     sigma, delayType, rampPeriod, peakPeriod, troughPeriod,
292                     cycleType, rampType, logger, stats,
293                     softReferenceObjectPool, samplingRate);
294         }
295         return null;
296     }
297     
298     // ------------------------------------------------------------------------
299     // Configuration methods specific to this LoadGenerator invoked by Digester
300     // when superclass execute calls digerster.parse.
301     // ------------------------------------------------------------------------       
302     public void configureFactory(String activateLatency, String destroyLatency,
303             String makeLatency, String passivateLatency, String validateLatency,
304             String waiterLatency) {
305        
306         this.activateLatency = Long.parseLong(activateLatency);
307         this.destroyLatency = Long.parseLong(destroyLatency);
308         this.makeLatency = Long.parseLong(makeLatency);
309         this.passivateLatency = Long.parseLong(passivateLatency);
310         this.validateLatency = Long.parseLong(validateLatency);
311         this.waiterLatency = Long.parseLong(waiterLatency);
312     }
313     
314     public void configurePool(String maxActive, String maxActivePerKey,
315             String maxIdle, String minIdle, String maxWait,
316             String exhaustedAction, String testOnBorrow,
317             String testOnReturn, String timeBetweenEvictions,
318             String testsPerEviction, String idleTimeout, 
319             String testWhileIdle, String lifo, String type, String samplingRate)
320         throws ConfigurationException { 
321         this.maxActive = Integer.parseInt(maxActive);
322         this.maxActivePerKey = Integer.parseInt(maxActivePerKey);
323         this.maxIdle = Integer.parseInt(maxIdle);
324         this.minIdle = Integer.parseInt(minIdle);
325         this.maxWait = Long.parseLong(maxWait);
326         this.testOnBorrow = Boolean.parseBoolean(testOnBorrow);
327         this.testOnReturn = Boolean.parseBoolean(testOnReturn);
328         this.timeBetweenEvictions = Long.parseLong(timeBetweenEvictions);
329         this.testsPerEviction = Integer.parseInt(testsPerEviction);
330         this.idleTimeout = Long.parseLong(idleTimeout);
331         this.testWhileIdle = Boolean.parseBoolean(testWhileIdle);
332         this.lifo = Boolean.parseBoolean(lifo);
333         this.poolType = type;
334         if (exhaustedAction.equals("block")) {
335             this.exhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_BLOCK;
336         } else if (exhaustedAction.equals("fail")) {
337             this.exhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_FAIL;
338         } else if (exhaustedAction.equals("grow")) {
339             this.exhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW;
340         } else { 
341             throw new ConfigurationException(
342             "Bad configuration setting for exhausted action: "
343                     + exhaustedAction); 
344         }  
345         this.samplingRate = Double.parseDouble(samplingRate);
346     }
347     
348     public void configureAbandonedConfig(String logAbandoned,
349             String removeAbandoned, String abandonedTimeout) {
350         abandonedConfig.setLogAbandoned(Boolean.parseBoolean(logAbandoned));
351         abandonedConfig.setRemoveAbandoned(
352                 Boolean.parseBoolean(removeAbandoned));
353         abandonedConfig.setRemoveAbandonedTimeout(
354                 Integer.parseInt(abandonedTimeout));
355     }
356     
357     // Pool getters for unit tests
358     protected GenericObjectPool getGenericObjectPool() {
359         return genericObjectPool;
360     }
361     
362     protected GenericKeyedObjectPool getGenericKeyedObjectPool() {
363         return genericKeyedObjectPool;
364     }
365     
366 }