All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.mongodb.util.SimplePool Maven / Gradle / Ivy

There is a newer version: 5.1.4
Show newest version
// SimplePool.java

/**
 *      Copyright (C) 2008 10gen Inc.
 *  
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

package com.mongodb.util;

import java.util.*;
import java.util.concurrent.*;

import java.lang.management.*;
import javax.management.*;

public abstract class SimplePool implements DynamicMBean {

    static final boolean TRACK_LEAKS = Boolean.getBoolean( "MONGO-TRACKLEAKS" );
    static final long _sleepTime = 2;
    
    /** 
     * See full constructor docs
     */
    public SimplePool( String name , int maxToKeep , int maxTotal ){
        this( name , maxToKeep , maxTotal , false , false );
    } 
    
    /** Initializes a new pool of objects.
     * @param name name for the pool
     * @param maxToKeep max to hold to at any given time. if < 0 then no limit
     * @param maxTotal max to have allocated at any point.  if there are no more, get() will block
     * @param trackLeaks if leaks should be tracked
     */
    public SimplePool( String name , int maxToKeep , int maxTotal , boolean trackLeaks , boolean debug ){
        _name = name;
        _maxToKeep = maxToKeep;
        _maxTotal = maxTotal;
        _trackLeaks = trackLeaks || TRACK_LEAKS;
        _debug = debug;
        
    }

    /** Creates a new object of this pool's type.
     * @return the new object.
     */
    protected abstract T createNew();

    /** 
     * callback to determine if an object is ok to be added back to the pool or used
     * will be called when something is put back into the queue and when it comes out
     * @return true iff the object is ok to be added back to pool
     */
    public boolean ok( T t ){
        return true;
    }

    /**
     * override this if you need to do any cleanup
     */
    public void cleanup( T t ){}

    /**
     * @return >= 0 the one to use, -1 don't use any
     */
    protected int pick( int iThink , boolean couldCreate ){
        return iThink;
    }

    /** 
     * call done when you are done with an object form the pool
     * if there is room and the object is ok will get added
     * @param t Object to add
     */
    public void done( T t ){
        done( t , ok( t ) );
    }

    void done( T t , boolean ok ){
        if ( _trackLeaks ){
            synchronized ( _where ){
                _where.remove( _hash( t ) );
            }
        }
        
        if ( ! ok ){
            synchronized ( _avail ){
                _all.remove( t );
            }
            return;
        }

        synchronized ( _avail ){
            if ( _maxToKeep < 0 || _avail.size() < _maxToKeep ){
                for ( int i=0; i<_avail.size(); i++ )
                    if ( _avail.get( i ) == t )
                        throw new RuntimeException( "trying to put something back in the pool that's already there" );
                
                // if all doesn't contain it, it probably means this was cleared, so we don't want it
                if ( _all.contains( t ) ){
                    _avail.add( t );
                    _waiting.release();
                }
            }
            else {
                cleanup( t );
            }
        }
    }

    public void remove( T t ){
        done( t , false );
    }

    /** Gets an object from the pool - will block if none are available
     * @return An object from the pool
     */
    public T get(){
	return get(-1);
    }
    
    /** Gets an object from the pool - will block if none are available
     * @param waitTime 
     *        negative - forever
     *        0        - return immediately no matter what
     *        positive ms to wait
     * @return An object from the pool
     */
    public T get( long waitTime ){
        final T t = _get( waitTime );
        if ( t != null ){
            if ( _trackLeaks ){
                Throwable stack = new Throwable();
                stack.fillInStackTrace();
                synchronized ( _where ){
                    _where.put( _hash( t ) , stack );
                }
            }
        }
        return t;
    }

    private int _hash( T t ){
        return System.identityHashCode( t );
    }
    
    private T _get( long waitTime ){
	long totalSlept = 0;
        while ( true ){
            synchronized ( _avail ){
                
                boolean couldCreate = _maxTotal <= 0 || _all.size() < _maxTotal;

                while ( _avail.size() > 0 ){
                    int toTake = _avail.size() - 1;
                    toTake = pick( toTake, couldCreate );
                    if ( toTake >= 0 ){
                        T t = _avail.remove( toTake );
                        if ( ok( t ) ){
                            _debug( "got an old one" );
                            return t;
                        }
                        _debug( "old one was not ok" );
                        _all.remove( t );
                        continue;
                    }
                    else if ( ! couldCreate ) {
                        throw new IllegalStateException( "can't pick nothing if can't create" );
                    }
                    break;
                }
                
                if ( couldCreate ){
                    _everCreated++;
                    T t = createNew();
                    _all.add( t );
                    return t;
                }
		
                if ( _trackLeaks && _trackPrintCount++ % 200 == 0 ){
                    _wherePrint();
                    _trackPrintCount = 1;
                }
            }
	    
	    if ( waitTime == 0 )
		return null;

	    if ( waitTime > 0 && totalSlept >= waitTime )
		return null;
	    
            long start = System.currentTimeMillis();
            try {
                _waiting.tryAcquire( _sleepTime , TimeUnit.MILLISECONDS );
            }
            catch ( InterruptedException ie ){
            }

	    totalSlept += ( System.currentTimeMillis() - start );

        }
    }

    private void _wherePrint(){
        StringBuilder buf = new StringBuilder( toString() ).append( " waiting \n" );
        synchronized ( _where ){
            for ( Throwable t : _where.values() ){
                buf.append( "--\n" );
                final StackTraceElement[] st = t.getStackTrace();
                for ( int i=0; i getAll(){
        return _all.getAll().iterator();
    }

    public int available(){
        if ( _maxTotal <= 0 )
            throw new IllegalStateException( "this pool has an infinite number of things available" );
        return _maxTotal - inUse();
    }

    public int everCreated(){
        return _everCreated;
    }

    private void _debug( String msg ){
        if( _debug )
            System.out.println( "SimplePool [" + _name + "] : " + msg );
    }

    public int maxToKeep(){
        return _maxToKeep;
    }

    public Object getAttribute(String attribute){
        if ( attribute.equals( "name" ) )
            return _name;
        if ( attribute.equals( "size" ) )
            return _maxToKeep;
        if ( attribute.equals( "available" ) )
            return available();
        if ( attribute.equals( "inUse" ) )
            return inUse();
        if ( attribute.equals( "everCreated" ) )
            return _everCreated;
        
        System.err.println( "com.mongo.util.SimplePool unknown attribute: " + attribute );
        throw new RuntimeException( "unknown attribute: " + attribute );
    }
    
    public AttributeList getAttributes(String[] attributes){
        AttributeList l = new AttributeList();
        for ( int i=0; i _avail = new ArrayList();
    protected final List _availSafe = Collections.unmodifiableList( _avail );
    private final WeakBag _all = new WeakBag();
    private final Map _where = new HashMap();

    private final Semaphore _waiting = new Semaphore(0);

    private int _everCreated = 0;
    private int _trackPrintCount = 0;
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy