Skip to content

Commit

Permalink
HHH-10104 - Fix HHH-10104 Using JPA 2.1 schema generation together wi…
Browse files Browse the repository at this point in the history
…th hbm2ddl runs into deadlock with MySQL
  • Loading branch information
dreab8 committed Oct 15, 2015
1 parent 0e93d00 commit 65c7cfa
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 60 deletions.
Expand Up @@ -11,19 +11,16 @@
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;


import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.UnknownUnwrapTypeException; import org.hibernate.service.UnknownUnwrapTypeException;
import org.hibernate.service.spi.Configurable; import org.hibernate.service.spi.Configurable;
Expand Down Expand Up @@ -56,10 +53,9 @@ public class DriverManagerConnectionProviderImpl


private boolean active = true; private boolean active = true;


private ConcurrentLinkedQueue<Connection> connections = new ConcurrentLinkedQueue<Connection>();
private ConnectionCreator connectionCreator; private ConnectionCreator connectionCreator;
private ScheduledExecutorService executorService; private ScheduledExecutorService executorService;

private PooledConnections pool;




// create the pool ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // create the pool ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -76,54 +72,16 @@ public void configure(Map configurationValues) {
log.usingHibernateBuiltInConnectionPool(); log.usingHibernateBuiltInConnectionPool();


connectionCreator = buildCreator( configurationValues ); connectionCreator = buildCreator( configurationValues );
pool = buildPool( configurationValues );


final int minSize = ConfigurationHelper.getInt( MIN_SIZE, configurationValues, 1 );
final int maxSize = ConfigurationHelper.getInt( AvailableSettings.POOL_SIZE, configurationValues, 20 );
final int initialSize = ConfigurationHelper.getInt( INITIAL_SIZE, configurationValues, minSize );
final long validationInterval = ConfigurationHelper.getLong( VALIDATION_INTERVAL, configurationValues, 30 ); final long validationInterval = ConfigurationHelper.getLong( VALIDATION_INTERVAL, configurationValues, 30 );

log.hibernateConnectionPoolSize( maxSize, minSize );

log.debugf( "Initializing Connection pool with %s Connections", initialSize );
for ( int i = 0; i < initialSize; i++ ) {
connections.add( connectionCreator.createConnection() );
}

executorService = Executors.newSingleThreadScheduledExecutor(); executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleWithFixedDelay( executorService.scheduleWithFixedDelay(
new Runnable() { new Runnable() {
private boolean primed; private boolean primed;
@Override @Override
public void run() { public void run() {
int size = connections.size(); pool.validate();

if ( !primed && size >= minSize ) {
// IMPL NOTE : the purpose of primed is to allow the pool to lazily reach its
// defined min-size.
log.debug( "Connection pool now considered primed; min-size will be maintained" );
primed = true;
}

if ( size < minSize && primed ) {
int numberToBeAdded = minSize - size;
log.debugf( "Adding %s Connections to the pool", numberToBeAdded );
for (int i = 0; i < numberToBeAdded; i++) {
connections.add( connectionCreator.createConnection() );
}
}
else if ( size > maxSize ) {
int numberToBeRemoved = size - maxSize;
log.debugf( "Removing %s Connections from the pool", numberToBeRemoved );
for ( int i = 0; i < numberToBeRemoved; i++ ) {
Connection connection = connections.poll();
try {
connection.close();
}
catch (SQLException e) {
log.unableToCloseConnection( e );
}
}
}
} }
}, },
validationInterval, validationInterval,
Expand All @@ -132,6 +90,27 @@ else if ( size > maxSize ) {
); );
} }


private PooledConnections buildPool(Map configurationValues) {
final boolean autoCommit = ConfigurationHelper.getBoolean(
AvailableSettings.AUTOCOMMIT,
configurationValues,
false
);
final int minSize = ConfigurationHelper.getInt( MIN_SIZE, configurationValues, 1 );
final int maxSize = ConfigurationHelper.getInt( AvailableSettings.POOL_SIZE, configurationValues, 20 );
final int initialSize = ConfigurationHelper.getInt( INITIAL_SIZE, configurationValues, minSize );

PooledConnections.Builder pooledConnectionBuilder = new PooledConnections.Builder(
connectionCreator,
autoCommit
);
pooledConnectionBuilder.initialSize( initialSize );
pooledConnectionBuilder.minSize( minSize );
pooledConnectionBuilder.maxSize( maxSize );

return pooledConnectionBuilder.build();
}

private ConnectionCreator buildCreator(Map configurationValues) { private ConnectionCreator buildCreator(Map configurationValues) {
final ConnectionCreatorBuilder connectionCreatorBuilder = new ConnectionCreatorBuilder( serviceRegistry ); final ConnectionCreatorBuilder connectionCreatorBuilder = new ConnectionCreatorBuilder( serviceRegistry );


Expand Down Expand Up @@ -206,12 +185,11 @@ public Connection getConnection() throws SQLException {
throw new HibernateException( "Connection pool is no longer active" ); throw new HibernateException( "Connection pool is no longer active" );
} }


Connection connection; Connection conn = pool.poll();
if ( (connection = connections.poll()) == null ) { if ( conn == null ) {
connection = connectionCreator.createConnection(); conn = connectionCreator.createConnection();
} }

return conn;
return connection;
} }


@Override @Override
Expand All @@ -220,10 +198,9 @@ public void closeConnection(Connection conn) throws SQLException {
return; return;
} }


this.connections.offer( conn ); pool.add( conn );
} }



@Override @Override
public boolean supportsAggressiveRelease() { public boolean supportsAggressiveRelease() {
return false; return false;
Expand Down Expand Up @@ -265,17 +242,14 @@ public void stop() {
} }
executorService = null; executorService = null;


for ( Connection connection : connections ) { try {
try { pool.close();
connection.close(); }
} catch (SQLException e) {
catch (SQLException e) { log.unableToClosePooledConnection( e );
log.unableToClosePooledConnection( e );
}
} }
} }



//CHECKSTYLE:START_ALLOW_FINALIZER //CHECKSTYLE:START_ALLOW_FINALIZER
@Override @Override
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
Expand Down
@@ -0,0 +1,141 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.engine.jdbc.connections.internal;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;

/**
* @author Andrea Boriero
*/
public class PooledConnections {

private ConcurrentLinkedQueue<Connection> connections = new ConcurrentLinkedQueue<Connection>();

private static final CoreMessageLogger log = CoreLogging.messageLogger( DriverManagerConnectionProviderImpl.class );

private final ConnectionCreator connectionCreator;
private final boolean autoCommit;
private final int minSize;
private final int maxSize;

private boolean primed;

private PooledConnections(
Builder builder) {
log.debugf( "Initializing Connection pool with %s Connections", builder.initialSize );
connectionCreator = builder.connectionCreator;
autoCommit = builder.autoCommit;
maxSize = builder.maxSize;
minSize = builder.minSize;
log.hibernateConnectionPoolSize( maxSize, minSize );
addConnections( builder.initialSize );
}

public void validate() {
final int size = size();

if ( !primed && size >= minSize ) {
// IMPL NOTE : the purpose of primed is to allow the pool to lazily reach its
// defined min-size.
log.debug( "Connection pool now considered primed; min-size will be maintained" );
primed = true;
}

if ( size < minSize && primed ) {
int numberToBeAdded = minSize - size;
log.debugf( "Adding %s Connections to the pool", numberToBeAdded );
addConnections( numberToBeAdded );
}
else if ( size > maxSize ) {
int numberToBeRemoved = size - maxSize;
log.debugf( "Removing %s Connections from the pool", numberToBeRemoved );
removeConnections( numberToBeRemoved );
}
}

public void add(Connection conn) throws SQLException {
conn.setAutoCommit( true );
conn.clearWarnings();
connections.offer( conn );
}

public Connection poll() throws SQLException {
Connection conn = connections.poll();
if ( conn == null ) {
return null;
}
conn.setAutoCommit( autoCommit );
return conn;
}

public void close() throws SQLException {
for ( Connection connection : connections ) {
connection.close();
}
}

public int size() {
return connections.size();
}

protected void removeConnections(int numberToBeRemoved) {
for ( int i = 0; i < numberToBeRemoved; i++ ) {
Connection connection = connections.poll();
try {
if ( connection != null ) {
connection.close();
}
}
catch (SQLException e) {
log.unableToCloseConnection( e );
}
}
}

protected void addConnections(int numberOfConnections) {
for ( int i = 0; i < numberOfConnections; i++ ) {
connections.add( connectionCreator.createConnection() );
}
}

public static class Builder {
private final ConnectionCreator connectionCreator;
private boolean autoCommit;
private int initialSize = 1;
private int minSize = 1;
private int maxSize = 20;

public Builder(ConnectionCreator connectionCreator, boolean autoCommit) {
this.connectionCreator = connectionCreator;
this.autoCommit = autoCommit;
}

public Builder initialSize(int initialSize) {
this.initialSize = initialSize;
return this;
}

public Builder minSize(int minSize) {
this.minSize = minSize;
return this;
}

public Builder maxSize(int maxSize) {
this.maxSize = maxSize;
return this;
}

public PooledConnections build() {
return new PooledConnections( this );
}
}
}

0 comments on commit 65c7cfa

Please sign in to comment.