dirkv       2004/09/19 10:24:18

  Modified:    pool/src/java/org/apache/commons/pool/impl
                        GenericKeyedObjectPool.java
                        GenericKeyedObjectPoolFactory.java
  Log:
  Bugzilla Bug 31298:   setMinIdle feature implemented for GenericKeyedObjectPool
  - original patch from Bowler Simon
  
  Revision  Changes    Path
  1.29      +178 -3    
jakarta-commons/pool/src/java/org/apache/commons/pool/impl/GenericKeyedObjectPool.java
  
  Index: GenericKeyedObjectPool.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons/pool/src/java/org/apache/commons/pool/impl/GenericKeyedObjectPool.java,v
  retrieving revision 1.28
  retrieving revision 1.29
  diff -u -r1.28 -r1.29
  --- GenericKeyedObjectPool.java       4 Jul 2004 17:41:15 -0000       1.28
  +++ GenericKeyedObjectPool.java       19 Sep 2004 17:24:18 -0000      1.29
  @@ -18,6 +18,7 @@
   
   import java.util.HashMap;
   import java.util.Iterator;
  +import java.util.ListIterator;
   import java.util.Map;
   import java.util.NoSuchElementException;
   import java.util.Set;
  @@ -255,6 +256,13 @@
        */
       public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 
30L;
   
  +    /**
  +     * The default minimum level of idle objects in the pool.
  +     * @see #setMinIdle
  +     * @see #getMinIdle
  +     */
  +    public static final int DEFAULT_MIN_IDLE = 0;
  +    
       //--- constructors -----------------------------------------------
   
       /**
  @@ -374,6 +382,26 @@
        * @param testWhileIdle whether or not to validate objects in the idle object 
eviction thread, if any (see [EMAIL PROTECTED] #setTestWhileIdle})
        */
       public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int 
maxActive, byte whenExhaustedAction, long maxWait, int maxIdle, int maxTotal, boolean 
testOnBorrow, boolean testOnReturn, long timeBetweenEvictionRunsMillis, int 
numTestsPerEvictionRun, long minEvictableIdleTimeMillis, boolean testWhileIdle) {
  +        this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, 
GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, GenericKeyedObjectPool.DEFAULT_MIN_IDLE, 
testOnBorrow, testOnReturn, timeBetweenEvictionRunsMillis, numTestsPerEvictionRun, 
minEvictableIdleTimeMillis, testWhileIdle);
  +    }
  +    
  +    /**
  +     * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
  +     * @param factory the (possibly <tt>null</tt>)PoolableObjectFactory to use to 
create, validate and destroy objects
  +     * @param maxActive the maximum number of objects that can be borrowed from me 
at one time (per key) (see [EMAIL PROTECTED] #setMaxActive})
  +     * @param whenExhaustedAction the action to take when the pool is exhausted 
(see [EMAIL PROTECTED] #setWhenExhaustedAction})
  +     * @param maxWait the maximum amount of time to wait for an idle object when 
the pool is exhausted an and <i>whenExhaustedAction</i> is [EMAIL PROTECTED] 
#WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see [EMAIL PROTECTED] #setMaxWait})
  +     * @param maxIdle the maximum number of idle objects in my pool (see [EMAIL 
PROTECTED] #setMaxIdle})
  +     * @param maxTotal the maximum number of objects that can exists at one time 
(see [EMAIL PROTECTED] #setMaxTotal})
  +     * @param minIdle the minimum number of idle objects to have in the pool at any 
one time (see [EMAIL PROTECTED] #setMinIdle})
  +     * @param testOnBorrow whether or not to validate objects before they are 
returned by the [EMAIL PROTECTED] #borrowObject} method (see [EMAIL PROTECTED] 
#setTestOnBorrow})
  +     * @param testOnReturn whether or not to validate objects after they are 
returned to the [EMAIL PROTECTED] #returnObject} method (see [EMAIL PROTECTED] 
#setTestOnReturn})
  +     * @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to 
sleep between examining idle objects for eviction (see [EMAIL PROTECTED] 
#setTimeBetweenEvictionRunsMillis})
  +     * @param numTestsPerEvictionRun the number of idle objects to examine per run 
within the idle object eviction thread (if any) (see [EMAIL PROTECTED] 
#setNumTestsPerEvictionRun})
  +     * @param minEvictableIdleTimeMillis the minimum number of milliseconds an 
object can sit idle in the pool before it is eligable for evcition (see [EMAIL 
PROTECTED] #setMinEvictableIdleTimeMillis})
  +     * @param testWhileIdle whether or not to validate objects in the idle object 
eviction thread, if any (see [EMAIL PROTECTED] #setTestWhileIdle})
  +     */
  +    public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int 
maxActive, byte whenExhaustedAction, long maxWait, int maxIdle, int maxTotal, int 
minIdle, boolean testOnBorrow, boolean testOnReturn, long 
timeBetweenEvictionRunsMillis, int numTestsPerEvictionRun, long 
minEvictableIdleTimeMillis, boolean testWhileIdle) {
           _factory = factory;
           _maxActive = maxActive;
           switch(whenExhaustedAction) {
  @@ -388,6 +416,7 @@
           _maxWait = maxWait;
           _maxIdle = maxIdle;
           _maxTotal = maxTotal;
  +        _minIdle = minIdle;
           _testOnBorrow = testOnBorrow;
           _testOnReturn = testOnReturn;
           _timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
  @@ -540,6 +569,24 @@
       }
   
       /**
  +     * Sets the minimum number of idle objects in pool to maintain (per key)
  +     * @param poolSize - The minimum size of the pool
  +     * @see #getMinIdle
  +     */
  +    public synchronized void setMinIdle(int poolSize) {
  +        _minIdle = poolSize;
  +    }
  +    
  +    /**
  +     * Returns the minimum number of idle objects in pool to maintain (per key)
  +     * @return the minimum number of idle objects in pool to maintain (per key)
  +     * @see #setMinIdle
  +     */
  +    public synchronized int getMinIdle() {
  +        return _minIdle;
  +    }
  +    
  +    /**
        * When <tt>true</tt>, objects will be
        * [EMAIL PROTECTED] 
org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
        * before being returned by the [EMAIL PROTECTED] #borrowObject}
  @@ -702,6 +749,7 @@
           setMaxIdle(conf.maxIdle);
           setMaxActive(conf.maxActive);
           setMaxTotal(conf.maxTotal);
  +        setMinIdle(conf.minIdle);
           setMaxWait(conf.maxWait);
           setWhenExhaustedAction(conf.whenExhaustedAction);
           setTestOnBorrow(conf.testOnBorrow);
  @@ -969,6 +1017,37 @@
           }
       }
   
  +    /**
  +     * Registers a key for pool control. 
  +     * 
  +     * If <i>populateImmediately</i> is <code>true</code>, the pool will 
immediately commence
  +     * a sustain cycle. If <i>populateImmediately</i> is <code>false</code>, the 
pool will be
  +     * populated when the next schedules sustain task is run.
  +     * 
  +     * @param key - The key to register for pool control.
  +     * @param populateImmediately - If this is <code>true</code>, the pool
  +     * will start a sustain cycle immediately.
  +     */
  +    public void preparePool(Object key, boolean populateImmediately) {
  +        synchronized(this) {
  +            CursorableLinkedList pool = (CursorableLinkedList)(_poolMap.get(key));
  +            if (null == pool) {
  +                pool = new CursorableLinkedList();
  +                _poolMap.put(key,pool);
  +                _poolList.add(key);
  +            }
  +        }
  +        if (populateImmediately) {
  +            try {
  +                // Create the pooled objects
  +                ensureMinIdle(key);
  +            }
  +            catch (Exception e) {
  +                //Do nothing
  +            }
  +        }
  +    }
  +    
       public synchronized void close() throws Exception {
           clear();
           _poolList = null;
  @@ -1063,8 +1142,12 @@
                               _totalIdle--;
                               _factory.destroyObject(key,pair.value);
   
  -                            // if that was the last object for that key, drop that 
pool
  -                            if( 
((CursorableLinkedList)(_poolMap.get(key))).isEmpty() ) {
  +                            // Do not remove the key from the _poolList or 
_poolmap, even if the list
  +                            // stored in the _poolMap for this key is empty when 
the 
  +                            // [EMAIL PROTECTED] #getMinIdle <i>minIdle</i>} is > 0.
  +                            // 
  +                            // Otherwise if it was the last object for that key, 
drop that pool
  +                            if ((_minIdle == 0) && 
(((CursorableLinkedList)(_poolMap.get(key))).isEmpty())) {
                                   _poolMap.remove(key);
                                   _poolList.remove(key);
                               }
  @@ -1083,6 +1166,51 @@
           }
       }
   
  +    /**
  +     * Iterates through all the known keys and creates any necessary objects to 
maintain
  +     * the minimum level of pooled objects.
  +     * @see #getMinIdle
  +     * @see #setMinIdle
  +     * @throws Exception If there was an error whilst creating the pooled objects.
  +     */
  +    private synchronized void ensureMinIdle() throws Exception {
  +        ListIterator iterator = _poolList.cursor();
  +   
  +        //Check if should sustain the pool
  +        if (_minIdle > 0) {
  +            // Loop through all elements in _poolList
  +            // Find out the total number of max active and max idle for that class
  +            // If the number is less than the minIdle, do creation loop to boost 
numbers
  +            // Increment idle count + 1
  +            while (iterator.hasNext()) {
  +                //Get the next key to process
  +                Object key = iterator.next();
  +                ensureMinIdle(key);
  +            }
  +        }
  +    }
  +
  +    /**
  +     * Re-creates any needed objects to maintain the minimum levels of
  +     * pooled objects for the specified key.
  +     * 
  +     * This method uses [EMAIL PROTECTED] #calculateDefecit} to calculate the number
  +     * of objects to be created. [EMAIL PROTECTED] #calculateDefecit} can be 
overridden to
  +     * provide a different method of calculating the number of objects to be
  +     * created.
  +     * @param key The key to process
  +     * @throws Exception If there was an error whilst creating the pooled objects
  +     */
  +    private synchronized void ensureMinIdle(Object key) throws Exception {
  +        // Calculate current pool objects
  +        int numberToCreate = calculateDefecit(key);
  +        
  +        //Create required pool objects, if none to create, this loop will not be 
run.
  +        for (int i = 0; i < numberToCreate; i++) {
  +            addObject(key);
  +        }
  +    }
  +    
       //--- non-public methods ----------------------------------------
   
       /**
  @@ -1152,6 +1280,38 @@
           }
           return active;
       }
  +    /**
  +     * This returns the number of objects to create during the pool
  +     * sustain cycle. This will ensure that the minimum number of idle 
  +     * connections is maintained without going past the maxPool value.
  +     * <p>
  +     * This method has been left public so derived classes can override 
  +     * the way the defecit is calculated. ie... Increase/decrease the pool 
  +     * size at certain times of day to accomodate for usage patterns.
  +     *  
  +     * @param key - The key of the pool to calculate the number of
  +     *              objects to be re-created
  +     * @return The number of objects to be created
  +     */
  +    private synchronized int calculateDefecit(Object key) {
  +        int objectDefecit = 0;
  +        
  +        //Calculate no of objects needed to be created, in order to have
  +        //the number of pooled objects < maxActive();
  +        objectDefecit = getMinIdle() - getNumIdle(key);
  +        if (getMaxActive() > 0) {
  +            int growLimit = Math.max(0, getMaxActive() - getNumActive(key) - 
getNumIdle(key));
  +            objectDefecit = Math.min(objectDefecit, growLimit);
  +        }
  +        
  +        // Take the maxTotal limit into account 
  +        if (getMaxTotal() > 0) {
  +            int growLimit = Math.max(0, getMaxTotal() - getNumActive() - 
getNumIdle());
  +            objectDefecit = Math.min(objectDefecit, growLimit);
  +        }
  +
  +        return objectDefecit;
  +    }
   
       //--- inner classes ----------------------------------------------
   
  @@ -1214,11 +1374,18 @@
                   } catch(Exception e) {
                       ; // ignored
                   }
  +                //Evict from the pool
                   try {
                       evict();
                   } catch(Exception e) {
                       ; // ignored
                   }
  +                //Re-create the connections.
  +                try {
  +                    ensureMinIdle();
  +                } catch (Exception e) { 
  +                    ; // ignored
  +                }
               }
               synchronized(GenericKeyedObjectPool.this) {
                   if(null != _evictionCursor) {
  @@ -1243,6 +1410,7 @@
           public int maxIdle = GenericKeyedObjectPool.DEFAULT_MAX_IDLE;
           public int maxActive = GenericKeyedObjectPool.DEFAULT_MAX_ACTIVE;
           public int maxTotal = GenericKeyedObjectPool.DEFAULT_MAX_TOTAL;
  +        public int minIdle = GenericKeyedObjectPool.DEFAULT_MIN_IDLE;
           public long maxWait = GenericKeyedObjectPool.DEFAULT_MAX_WAIT;
           public byte whenExhaustedAction = 
GenericKeyedObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION;
           public boolean testOnBorrow = GenericKeyedObjectPool.DEFAULT_TEST_ON_BORROW;
  @@ -1261,6 +1429,13 @@
        * @see #getMaxIdle
        */
       private int _maxIdle = DEFAULT_MAX_IDLE;
  +
  +    /**
  +     * The minimum no of idle objects to keep in the pool (per key)
  +     * @see #setMinIdle
  +     * @see #getMinIdle
  +     */
  +    private int _minIdle = DEFAULT_MIN_IDLE;
   
       /**
        * The cap on the number of active instances from the pool (per key).
  
  
  
  1.8       +8 -2      
jakarta-commons/pool/src/java/org/apache/commons/pool/impl/GenericKeyedObjectPoolFactory.java
  
  Index: GenericKeyedObjectPoolFactory.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons/pool/src/java/org/apache/commons/pool/impl/GenericKeyedObjectPoolFactory.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- GenericKeyedObjectPoolFactory.java        28 Feb 2004 12:16:21 -0000      1.7
  +++ GenericKeyedObjectPoolFactory.java        19 Sep 2004 17:24:18 -0000      1.8
  @@ -68,9 +68,14 @@
       }
   
       public GenericKeyedObjectPoolFactory(KeyedPoolableObjectFactory factory, int 
maxActive, byte whenExhaustedAction, long maxWait, int maxIdle, int maxTotal, boolean 
testOnBorrow, boolean testOnReturn, long timeBetweenEvictionRunsMillis, int 
numTestsPerEvictionRun, long minEvictableIdleTimeMillis, boolean testWhileIdle) {
  +        this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, 
GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, GenericKeyedObjectPool.DEFAULT_MIN_IDLE , 
testOnBorrow, testOnReturn, timeBetweenEvictionRunsMillis, numTestsPerEvictionRun, 
minEvictableIdleTimeMillis, testWhileIdle);
  +    }
  +
  +    public GenericKeyedObjectPoolFactory(KeyedPoolableObjectFactory factory, int 
maxActive, byte whenExhaustedAction, long maxWait, int maxIdle, int maxTotal, int 
minIdle, boolean testOnBorrow, boolean testOnReturn, long 
timeBetweenEvictionRunsMillis, int numTestsPerEvictionRun, long 
minEvictableIdleTimeMillis, boolean testWhileIdle) {
           _maxIdle = maxIdle;
           _maxActive = maxActive;
           _maxTotal = maxTotal;
  +        _minIdle = minIdle;
           _maxWait = maxWait;
           _whenExhaustedAction = whenExhaustedAction;
           _testOnBorrow = testOnBorrow;
  @@ -83,7 +88,7 @@
       }
   
       public KeyedObjectPool createPool() {
  -        return new 
GenericKeyedObjectPool(_factory,_maxActive,_whenExhaustedAction,_maxWait,_maxIdle,_maxTotal,_testOnBorrow,_testOnReturn,_timeBetweenEvictionRunsMillis,_numTestsPerEvictionRun,_minEvictableIdleTimeMillis,_testWhileIdle);
  +        return new 
GenericKeyedObjectPool(_factory,_maxActive,_whenExhaustedAction,_maxWait,_maxIdle,_maxTotal,_minIdle,_testOnBorrow,_testOnReturn,_timeBetweenEvictionRunsMillis,_numTestsPerEvictionRun,_minEvictableIdleTimeMillis,_testWhileIdle);
       }
   
       //--- protected attributes ---------------------------------------
  @@ -91,6 +96,7 @@
       protected int _maxIdle = GenericKeyedObjectPool.DEFAULT_MAX_IDLE;
       protected int _maxActive = GenericKeyedObjectPool.DEFAULT_MAX_ACTIVE;
       protected int _maxTotal = GenericKeyedObjectPool.DEFAULT_MAX_TOTAL;
  +    protected int _minIdle = GenericKeyedObjectPool.DEFAULT_MIN_IDLE;
       protected long _maxWait = GenericKeyedObjectPool.DEFAULT_MAX_WAIT;
       protected byte _whenExhaustedAction = 
GenericKeyedObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION;
       protected boolean _testOnBorrow = GenericKeyedObjectPool.DEFAULT_TEST_ON_BORROW;
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to