001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     * 
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.commons.performance.pool;
019    
020    import java.util.ArrayList;
021    import java.util.List;
022    import java.util.logging.Logger;
023    
024    import org.apache.commons.pool.ObjectPool;
025    import org.apache.commons.pool.KeyedObjectPool;
026    import org.apache.commons.math.random.RandomData;
027    import org.apache.commons.math.random.RandomDataImpl;
028    import org.apache.commons.math.stat.descriptive.SummaryStatistics;
029    import org.apache.commons.performance.ClientThread;
030    import org.apache.commons.performance.Statistics;
031    
032    /**
033     * Client thread that borrows and returns objects from a pool in a loop.
034     * See {@link ClientThread ClientThread javadoc} for a description
035     * of how times between requests are computed.
036     *
037     */
038    public class PoolClientThread extends ClientThread {
039        
040        private ObjectPool pool;
041        private KeyedObjectPool keyedPool;
042        private boolean keyed;
043        private List<Integer> keys;
044        private RandomData randomData = new RandomDataImpl();
045        private SummaryStatistics numActiveStats = new SummaryStatistics();
046        private SummaryStatistics numIdleStats = new SummaryStatistics();
047        private double samplingRate = 0;
048         
049        /**
050         * Create a pool client thread for an ObjectPool.
051         * 
052         * @param iterations number of iterations
053         * @param minDelay minimum mean time between client requests
054         * @param maxDelay maximum mean time between client requests
055         * @param delayType distribution of time between client requests
056         * @param rampPeriod ramp period of cycle for cyclic load
057         * @param peakPeriod peak period of cycle for cyclic load
058         * @param troughPeriod trough period of cycle for cyclic load
059         * @param cycleType type of cycle for mean delay
060         * @param rampType type of ramp (linear or random jumps)
061         * @param logger common logger shared by all clients
062         * @param stats Statistics container
063         * @param pool ObjectPool
064         */
065        public PoolClientThread(long iterations, long minDelay, long maxDelay,
066                double sigma, String delayType, long rampPeriod, long peakPeriod,
067                long troughPeriod, String cycleType, String rampType, Logger logger, 
068                Statistics stats, ObjectPool pool, double samplingRate) {
069            
070            super(iterations, minDelay, maxDelay, sigma, delayType, rampPeriod,
071                    peakPeriod, troughPeriod, cycleType,rampType, logger, 
072                    stats); 
073            this.pool = pool;
074            this.keyed = false;
075            this.samplingRate = samplingRate;
076        }
077        
078        /**
079         * Create a pool client thread for a KeyedObjectPool.
080         * 
081         * @param iterations number of iterations
082         * @param minDelay minimum mean time between client requests
083         * @param maxDelay maximum mean time between client requests
084         * @param delayType distribution of time between client requests
085         * @param rampPeriod ramp period of cycle for cyclic load
086         * @param peakPeriod peak period of cycle for cyclic load
087         * @param troughPeriod trough period of cycle for cyclic load
088         * @param cycleType type of cycle for mean delay
089         * @param rampType type of ramp (linear or random jumps)
090         * @param logger common logger shared by all clients
091         * @param stats Statistics container 
092         * @param keyedPool KeyedObjectPool
093         */
094        public PoolClientThread(long iterations, long minDelay, long maxDelay,
095                double sigma, String delayType, long rampPeriod, long peakPeriod,
096                long troughPeriod, String cycleType, String rampType, Logger logger, 
097                Statistics stats, KeyedObjectPool keyedPool, double samplingRate) {
098            
099            super(iterations, minDelay, maxDelay, sigma, delayType, rampPeriod,
100                    peakPeriod, troughPeriod, cycleType,rampType, logger, 
101                    stats); 
102            
103            this.keyedPool = keyedPool;
104            this.keyed = true;
105            this.samplingRate = samplingRate;
106            keys = new ArrayList<Integer>();
107            for (int i = 0; i < 20; i++) { //TODO: make number of keys configurable
108                keys.add(new Integer(i));
109            }
110            randomData = new RandomDataImpl();
111        }
112        
113        /** Borrow and return */
114        public void execute() throws Exception {
115           if (keyed) {
116               Integer key = keys.get(randomData.nextInt(0, 19));
117               Waiter waiter = (Waiter) keyedPool.borrowObject(key);
118               waiter.doWait();
119               keyedPool.returnObject(key, waiter);
120           } else {
121               Waiter waiter = (Waiter) pool.borrowObject(); 
122               waiter.doWait();
123               pool.returnObject(waiter);
124           }
125        }
126        
127        protected void cleanUp() throws Exception {
128            // Capture pool metrics 
129            if (randomData.nextUniform(0, 1) < samplingRate) {
130                if (keyed) {
131                    numIdleStats.addValue(keyedPool.getNumIdle());
132                    numActiveStats.addValue(keyedPool.getNumActive());
133                } else {
134                    numIdleStats.addValue(pool.getNumIdle());
135                    numActiveStats.addValue(pool.getNumActive());
136                }
137            }
138        }
139        
140        protected void finish() throws Exception {
141            // Add pool metrics to stats
142            stats.addStatistics(
143                    numIdleStats, Thread.currentThread().getName(), "numIdle");
144            stats.addStatistics(
145                    numActiveStats, Thread.currentThread().getName(), "numActive");
146        }
147    }