Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Firebird Open Source J2ee connector - jdbc driver
   *
   * Distributable under LGPL license.
   * You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * LGPL License for more details.
  *
  * This file was created by members of the firebird development team.
  * All individual contributions remain the Copyright (C) of those
  * individuals.  Contributors to this file are either listed here or
  * can be obtained from a CVS history command.
  *
  * All rights reserved.
  */
 
 package org.firebirdsql.pool;
 
 
Implementation of free connection queue.

Author(s):
Roman Rokytskyy
 
     
     private static final boolean LOG_DEBUG_INFO = .;
     private static final boolean SHOW_STACK_ON_BLOCK = .;
     private static final boolean SHOW_STACK_ON_ALLOCATION = .;
 
     private Logger logger;
     
     private Object key;
 
     private String queueName;
     private int blockingTimeout;
 
     private int size;
     private BlockingStack stack = new BlockingStack();
     private boolean blocked;
     
     private Object takeMutex = new Object();
     
     private IdleRemover idleRemover;
 
     private int totalConnections;
 
     private HashSet workingConnections = new HashSet();
     private HashSet workingConnectionsToClose = new HashSet();
     private HashMap connectionIdleTime = new HashMap();

    
Create instance of this queue.

Parameters:
connectionManager instance of PooledConnectionManager.
logger instance of org.firebirdsql.logging.Logger.
configuration instance of Configuration.
queueName name of this queue.
 
     private PooledConnectionQueue(PooledConnectionManager connectionManager,
         Logger loggerConnectionPoolConfiguration configuration
         String queueName
     {
         this. = connectionManager;
         this. = logger;
         this. = configuration;
         
         this. = queueName;
         this. = configuration.getBlockingTimeout();
     }
    
    
Create instance of this queue for the specified user name and password.

Parameters:
connectionManager instance of PooledConnectionManager.
logger instance of org.firebirdsql.logging.Logger.
configuration instance of ConnectionPoolConfiguration.
queueName name of this queue.
key Key used for this instance
 
     public PooledConnectionQueue(PooledConnectionManager connectionManager,
         Logger loggerConnectionPoolConfiguration configuration
         String queueNameObject key)
     {
         this(connectionManagerloggerconfigurationqueueName);
         this. = key;
    }
    
    
Get logger for this instance. By default all log messages belong to this class. Subclasses can override this behavior.

Returns:
instance of org.firebirdsql.logging.Logger.
    protected Logger getLogger() {
        return ;
    }
    
    
        return ;
    }

    
Get size of this queue. This method can be used to check how many free connections is left.

Returns:
size of this queue.
    public int size() {
        return ;
    }

    
Get total number of physical connections opened to the database.

Returns:
total number of physical connections opened to the database.
    public int totalSize() {
        return ;
    }

    
Get number of working connections.

Returns:
number for working connections.
    public int workingSize() {
        return .size();
    }

    
Start this queue.

Throws:
java.sql.SQLException if initial number of connections could not be created.
    public void start() throws SQLException {
        for (int i = 0; i < getConfiguration().getMinPoolSize(); i++) {
            try {
                addConnection();
            } catch (InterruptedException iex) {
                throw new SQLException("Could not start connection queue.");
            }
        }
        
         = new IdleRemover();
        Thread t = new Thread("Pool " +  + " idleRemover");
        t.setDaemon(true);
        t.start();
    }

    
Restart this queue.
    public synchronized void restart()
    {
    	// flag working connections for deallocation when returned to the queue.
    	
        // close all free connections
        while (size() > 0)
            try {
            	PooledObject connection = take();
                if (connection.isValid()) {
                	connection.deallocate();
                	
                	physicalConnectionDeallocated(connection);
                }
            } catch (SQLException ex) {
                if (getLogger() != null)
                getLogger().warn("Could not close connection."ex);
            }
        //Create enough connections to restore the queue to MinPoolSize.
        while (totalSize() < getConfiguration().getMinPoolSize())
        	try {
        		addConnection();
        	}
            catch (Exception e)
            {
            	if (getLogger() != null)
                    getLogger().warn("Could not add connection."e);
            }
    }
    
    
Shutdown this queue.
    public void shutdown() {
        try {
            // close all working connections.
            Iterator iter = .iterator();
            while (iter.hasNext()) {
                PooledObject item = (PooledObject)iter.next();
    
                if (item.isValid())
                    item.deallocate();
            }
    
            // close all free connections
            while (size() > 0)
                try {
                    PooledObject item = (PooledObject)take();
                    if (item.isValid())
                        item.deallocate();
                    
                } catch (SQLException ex) {
                    if (getLogger() != null)
                    getLogger().warn("Could not close connection."ex);
                }
    
             = 0;
            .clear();
            .clear();
        } finally {
            if ( != null)
                .stop();
            
             = null;
        }
    }
    
    
Check if take() method can keep blocking.

Parameters:
startTime time when the method was entered.
Returns:
true if method can keep blocking.
    private boolean keepBlocking(long startTime) {
        return System.currentTimeMillis() - startTime < ;
    }
    
    
Destroy connection and restore the balance of connections in the pool.

Parameters:
connection connection to destroy
    public void destroyConnection(PooledObject connection) {
        connection.deallocate();
        
        --;
    }
    
    
Notify queue that a physical connection was deallocated.

Parameters:
connection connection that was deallocated.
    public synchronized void physicalConnectionDeallocated(PooledObject connection) {
        --;
        .remove(connection);
        .remove(connection);
    }

    
Put connection to this queue.

Parameters:
connection free pooled connection.
Throws:
java.sql.SQLException if connection cannot be added to this queue.
    public void put(PooledObject connectionthrows SQLException {
        try {
            if ( && getLogger() != null)
                getLogger().warn("Pool " +  + " will be unblocked");
            if (getConfiguration().isPooling()) {
            	
            	if (.remove(connection)) {
            		connection.deallocate();
            		
            		physicalConnectionDeallocated(connection);
            		
            		addConnection();
            	}
            	else {
            		.push(connection);
                    connection.setInPool(true);
                
            		// save timestamp when connection was returned to queue
            		.put(
            				connectionnew Long(System.currentTimeMillis()));
    
            		++;
            	}
            } else {
                .remove(connection);
            }
             = false;
            .remove(connection);
            // deallocate connection if pooling is not enabled.
            if (!getConfiguration().isPooling())
                destroyConnection(connection);
            if ( && getLogger() != null)
                getLogger().debug("Thread "
                        + Thread.currentThread().getName()
                        + " released connection.");
        } catch (InterruptedException iex) {
            if (getLogger() != null)
                getLogger().warn("Thread "
                    + Thread.currentThread().getName()
                    + " was interrupted.",
                    iex);
            connection.deallocate();
        }
    }

    
Take pooled connection from this queue. This method will block until free and valid connection is available.

Returns:
free instance of FBPooledConnection.
Throws:
java.sql.SQLException if no free connection was available and waiting thread was interruped while waiting for a new free connection.
    public PooledObject take() throws SQLException {
        
        long startTime = System.currentTimeMillis();
        if ( && getLogger() != null)
            getLogger().debug(
                "Thread "
                    + Thread.currentThread().getName()
                    + " wants to take connection.");
        PooledObject result = null;
        
        // TODO Pending exceptions are only thrown on timeout, is that correct?
        SQLExceptionChainBuilder pendingExceptions = new SQLExceptionChainBuilder();
        try {
            synchronized() {
                if (.isEmpty()) {
    
                    while (result == null) {
                        
                        if (!keepBlocking(startTime)) {
                            String message = "Could not obtain connection during " + 
                                "blocking timeout (" +  + " ms)";
                            
                            FBSQLException ex = new FBSQLException(message.);
                            if (pendingExceptions.hasException()) {
                                ex.setNextException(pendingExceptions.getException());
                            }
                                
                            throw ex;
                        };
    
                        boolean connectionAdded = false;
    
                        try {
                            connectionAdded = addConnection();
                        } catch (SQLException sqlex) {
                            if (getLogger() != null)
                                getLogger().warn(
                                    "Could not create connection."
                                    + sqlex.getMessage());
    
                            // could not add connection... bad luck
                            // let's wait more
                            
                            if (!pendingExceptions.hasException()) {
                                pendingExceptions.append(sqlex);
                            } else if (pendingExceptions.getException().getErrorCode() != sqlex.getErrorCode()) {
                                pendingExceptions.append(sqlex);
                            }
                        }
    
                        if (!connectionAdded) {
                            String message =
                                "Pool "
                                    + 
                                    + " is empty and will block here."
                                    + " Thread "
                                    + Thread.currentThread().getName();
    
                            if () {
                                if (getLogger() != null)
                                    getLogger().warn(messagenew Exception());
                            } else {
                                if (getLogger() != null)
                                    getLogger().warn(message);
                            }
    
                             = true;
                        }
                        
                        result = (PooledObject.pop(
                            getConfiguration().getRetryInterval());
                            
                        if (result == null && getLogger() != null)
                            getLogger().warn("No connection in pool. Thread " +
                                Thread.currentThread().getName());
                        else
                        if (result != null && !connectionAdded && getLogger() != null)
                            getLogger().info("Obtained connection. Thread " + 
                                Thread.currentThread().getName());
                    }
    
                } else {
                    result = (PooledObject).pop();
                }
            }
        } catch (InterruptedException iex) {
            throw new SQLException(
                "No free connection was available and "
                    + "waiting thread was interrupted.");
        }
        --;
        .add(result);
        if ( && getLogger() != null) {
            if ()
                getLogger().debug(
                    "Thread "+ Thread.currentThread().getName() +
                     " got connection."new Exception());
            else
                getLogger().debug(
                    "Thread "+ Thread.currentThread().getName() +
                     " got connection.");
        }
        result.setInPool(false);
        
        return result;
    }

    
Open new connection to database.

Returns:
true if new physical connection was created, otherwise false.
Throws:
java.sql.SQLException if new connection cannot be opened.
java.lang.InterruptedException if thread was interrupted.
    private boolean addConnection(BlockingStack queue)
        throws SQLExceptionInterruptedException {
        synchronized (this) {
            if ( && getLogger() != null)
                getLogger().debug(
                    "Trying to create connection, total connections "
                        + 
                        + ", max allowed "
                        + getConfiguration().getMaxPoolSize());
            
            boolean maximumCapacityReached = 
                getConfiguration().getMaxPoolSize() <=   && 
                getConfiguration().getMaxPoolSize() != 0 &&
                getConfiguration().isPooling();
            if (maximumCapacityReached) {
                if ( && getLogger() != null)
                    getLogger().debug("Was not able to add more connections.");
                return false;
            }
            Object pooledConnection = .allocateConnection();
            if ( && getLogger() != null)
                getLogger().debug(
                    "Thread "
                        + Thread.currentThread().getName()
                        + " created connection.");
            queue.push(pooledConnection);
            ++;
            ++;
            return true;
        }
    }

    
Release first connection in the queue if it was idle longer than idle timeout interval.

Returns:
true if method removed idle connection, otherwise false
Throws:
java.sql.SQLException if exception happened when releasing the connection.
    private boolean releaseNextIdleConnection() throws SQLException {
                  
        synchronized() {
            
            if (totalSize() <= getConfiguration().getMinPoolSize())
                return false;
            
            PooledObject candidate = (PooledObject).peek();
            
            if (candidate == null)
                return false;
            
            Long lastUsageTime = (Long).get(candidate);
            if (lastUsageTime == null)
                return false;
            
            long idleTime = System.currentTimeMillis() - lastUsageTime.longValue();
            
            if (idleTime < getConfiguration().getMaxIdleTime()) 
                return false;
            
            try {    
                take().deallocate();
            } finally {
                .remove(candidate);
                .remove(candidate);
                --;
            }
            
            return true;
        }
    }

    
Implementation of java.lang.Runnable interface responsible for removing idle connections.
    private class IdleRemover implements Runnable {
        
        private boolean running;
        
        public IdleRemover() {
             = true;
        }
        
        public void stop() {
             = false;
        }
        
        public void run() {
            while () {
                
                try {
                    while(releaseNextIdleConnection()) {
                        // do nothing, we already released connection
                        // next one, please :)
                    }
                } catch(SQLException ex) {
                    // do nothing, we hardly can handle this situation
                }
                
                try {
                    int idleTimeout = getConfiguration().getMaxIdleTime();
                    int maxConnections =  getConfiguration().getMaxPoolSize();
                    
                    if (maxConnections < 1)
                        maxConnections = 1;
                    
                    Thread.sleep(idleTimeout / maxConnections);
                } catch(InterruptedException ex) {
                    // do nothing
                }
            }
        }
        
    }
New to GrepCode? Check out our FAQ X