Skip to content

Commit 4ff1dcb

Browse files
committed
HHH-10104 - Fix HHH-10104 Using JPA 2.1 schema generation together with hbm2ddl runs into deadlock with MySQL
1 parent 076ee5f commit 4ff1dcb

File tree

2 files changed

+175
-60
lines changed

2 files changed

+175
-60
lines changed

hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/DriverManagerConnectionProviderImpl.java

Lines changed: 34 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,16 @@
1111
import java.sql.SQLException;
1212
import java.util.Map;
1313
import java.util.Properties;
14-
import java.util.concurrent.ConcurrentLinkedQueue;
1514
import java.util.concurrent.Executors;
1615
import java.util.concurrent.ScheduledExecutorService;
1716
import java.util.concurrent.TimeUnit;
1817

1918
import org.hibernate.HibernateException;
2019
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
2120
import org.hibernate.cfg.AvailableSettings;
22-
import org.hibernate.cfg.Environment;
2321
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
2422
import org.hibernate.internal.CoreLogging;
2523
import org.hibernate.internal.CoreMessageLogger;
26-
import org.hibernate.internal.util.ReflectHelper;
2724
import org.hibernate.internal.util.config.ConfigurationHelper;
2825
import org.hibernate.service.UnknownUnwrapTypeException;
2926
import org.hibernate.service.spi.Configurable;
@@ -56,10 +53,9 @@ public class DriverManagerConnectionProviderImpl
5653

5754
private boolean active = true;
5855

59-
private ConcurrentLinkedQueue<Connection> connections = new ConcurrentLinkedQueue<Connection>();
6056
private ConnectionCreator connectionCreator;
6157
private ScheduledExecutorService executorService;
62-
58+
private PooledConnections pool;
6359

6460

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

7874
connectionCreator = buildCreator( configurationValues );
75+
pool = buildPool( configurationValues );
7976

80-
final int minSize = ConfigurationHelper.getInt( MIN_SIZE, configurationValues, 1 );
81-
final int maxSize = ConfigurationHelper.getInt( AvailableSettings.POOL_SIZE, configurationValues, 20 );
82-
final int initialSize = ConfigurationHelper.getInt( INITIAL_SIZE, configurationValues, minSize );
8377
final long validationInterval = ConfigurationHelper.getLong( VALIDATION_INTERVAL, configurationValues, 30 );
84-
85-
log.hibernateConnectionPoolSize( maxSize, minSize );
86-
87-
log.debugf( "Initializing Connection pool with %s Connections", initialSize );
88-
for ( int i = 0; i < initialSize; i++ ) {
89-
connections.add( connectionCreator.createConnection() );
90-
}
91-
9278
executorService = Executors.newSingleThreadScheduledExecutor();
9379
executorService.scheduleWithFixedDelay(
9480
new Runnable() {
9581
private boolean primed;
9682
@Override
9783
public void run() {
98-
int size = connections.size();
99-
100-
if ( !primed && size >= minSize ) {
101-
// IMPL NOTE : the purpose of primed is to allow the pool to lazily reach its
102-
// defined min-size.
103-
log.debug( "Connection pool now considered primed; min-size will be maintained" );
104-
primed = true;
105-
}
106-
107-
if ( size < minSize && primed ) {
108-
int numberToBeAdded = minSize - size;
109-
log.debugf( "Adding %s Connections to the pool", numberToBeAdded );
110-
for (int i = 0; i < numberToBeAdded; i++) {
111-
connections.add( connectionCreator.createConnection() );
112-
}
113-
}
114-
else if ( size > maxSize ) {
115-
int numberToBeRemoved = size - maxSize;
116-
log.debugf( "Removing %s Connections from the pool", numberToBeRemoved );
117-
for ( int i = 0; i < numberToBeRemoved; i++ ) {
118-
Connection connection = connections.poll();
119-
try {
120-
connection.close();
121-
}
122-
catch (SQLException e) {
123-
log.unableToCloseConnection( e );
124-
}
125-
}
126-
}
84+
pool.validate();
12785
}
12886
},
12987
validationInterval,
@@ -132,6 +90,27 @@ else if ( size > maxSize ) {
13290
);
13391
}
13492

93+
private PooledConnections buildPool(Map configurationValues) {
94+
final boolean autoCommit = ConfigurationHelper.getBoolean(
95+
AvailableSettings.AUTOCOMMIT,
96+
configurationValues,
97+
false
98+
);
99+
final int minSize = ConfigurationHelper.getInt( MIN_SIZE, configurationValues, 1 );
100+
final int maxSize = ConfigurationHelper.getInt( AvailableSettings.POOL_SIZE, configurationValues, 20 );
101+
final int initialSize = ConfigurationHelper.getInt( INITIAL_SIZE, configurationValues, minSize );
102+
103+
PooledConnections.Builder pooledConnectionBuilder = new PooledConnections.Builder(
104+
connectionCreator,
105+
autoCommit
106+
);
107+
pooledConnectionBuilder.initialSize( initialSize );
108+
pooledConnectionBuilder.minSize( minSize );
109+
pooledConnectionBuilder.maxSize( maxSize );
110+
111+
return pooledConnectionBuilder.build();
112+
}
113+
135114
private ConnectionCreator buildCreator(Map configurationValues) {
136115
final ConnectionCreatorBuilder connectionCreatorBuilder = new ConnectionCreatorBuilder( serviceRegistry );
137116

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

209-
Connection connection;
210-
if ( (connection = connections.poll()) == null ) {
211-
connection = connectionCreator.createConnection();
188+
Connection conn = pool.poll();
189+
if ( conn == null ) {
190+
conn = connectionCreator.createConnection();
212191
}
213-
214-
return connection;
192+
return conn;
215193
}
216194

217195
@Override
@@ -220,10 +198,9 @@ public void closeConnection(Connection conn) throws SQLException {
220198
return;
221199
}
222200

223-
this.connections.offer( conn );
201+
pool.add( conn );
224202
}
225203

226-
227204
@Override
228205
public boolean supportsAggressiveRelease() {
229206
return false;
@@ -265,17 +242,14 @@ public void stop() {
265242
}
266243
executorService = null;
267244

268-
for ( Connection connection : connections ) {
269-
try {
270-
connection.close();
271-
}
272-
catch (SQLException e) {
273-
log.unableToClosePooledConnection( e );
274-
}
245+
try {
246+
pool.close();
247+
}
248+
catch (SQLException e) {
249+
log.unableToClosePooledConnection( e );
275250
}
276251
}
277252

278-
279253
//CHECKSTYLE:START_ALLOW_FINALIZER
280254
@Override
281255
protected void finalize() throws Throwable {
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.engine.jdbc.connections.internal;
8+
9+
import java.sql.Connection;
10+
import java.sql.SQLException;
11+
import java.util.concurrent.ConcurrentLinkedQueue;
12+
13+
import org.hibernate.internal.CoreLogging;
14+
import org.hibernate.internal.CoreMessageLogger;
15+
16+
/**
17+
* @author Andrea Boriero
18+
*/
19+
public class PooledConnections {
20+
21+
private ConcurrentLinkedQueue<Connection> connections = new ConcurrentLinkedQueue<Connection>();
22+
23+
private static final CoreMessageLogger log = CoreLogging.messageLogger( DriverManagerConnectionProviderImpl.class );
24+
25+
private final ConnectionCreator connectionCreator;
26+
private final boolean autoCommit;
27+
private final int minSize;
28+
private final int maxSize;
29+
30+
private boolean primed;
31+
32+
private PooledConnections(
33+
Builder builder) {
34+
log.debugf( "Initializing Connection pool with %s Connections", builder.initialSize );
35+
connectionCreator = builder.connectionCreator;
36+
autoCommit = builder.autoCommit;
37+
maxSize = builder.maxSize;
38+
minSize = builder.minSize;
39+
log.hibernateConnectionPoolSize( maxSize, minSize );
40+
addConnections( builder.initialSize );
41+
}
42+
43+
public void validate() {
44+
final int size = size();
45+
46+
if ( !primed && size >= minSize ) {
47+
// IMPL NOTE : the purpose of primed is to allow the pool to lazily reach its
48+
// defined min-size.
49+
log.debug( "Connection pool now considered primed; min-size will be maintained" );
50+
primed = true;
51+
}
52+
53+
if ( size < minSize && primed ) {
54+
int numberToBeAdded = minSize - size;
55+
log.debugf( "Adding %s Connections to the pool", numberToBeAdded );
56+
addConnections( numberToBeAdded );
57+
}
58+
else if ( size > maxSize ) {
59+
int numberToBeRemoved = size - maxSize;
60+
log.debugf( "Removing %s Connections from the pool", numberToBeRemoved );
61+
removeConnections( numberToBeRemoved );
62+
}
63+
}
64+
65+
public void add(Connection conn) throws SQLException {
66+
conn.setAutoCommit( true );
67+
conn.clearWarnings();
68+
connections.offer( conn );
69+
}
70+
71+
public Connection poll() throws SQLException {
72+
Connection conn = connections.poll();
73+
if ( conn == null ) {
74+
return null;
75+
}
76+
conn.setAutoCommit( autoCommit );
77+
return conn;
78+
}
79+
80+
public void close() throws SQLException {
81+
for ( Connection connection : connections ) {
82+
connection.close();
83+
}
84+
}
85+
86+
public int size() {
87+
return connections.size();
88+
}
89+
90+
protected void removeConnections(int numberToBeRemoved) {
91+
for ( int i = 0; i < numberToBeRemoved; i++ ) {
92+
Connection connection = connections.poll();
93+
try {
94+
if ( connection != null ) {
95+
connection.close();
96+
}
97+
}
98+
catch (SQLException e) {
99+
log.unableToCloseConnection( e );
100+
}
101+
}
102+
}
103+
104+
protected void addConnections(int numberOfConnections) {
105+
for ( int i = 0; i < numberOfConnections; i++ ) {
106+
connections.add( connectionCreator.createConnection() );
107+
}
108+
}
109+
110+
public static class Builder {
111+
private final ConnectionCreator connectionCreator;
112+
private boolean autoCommit;
113+
private int initialSize = 1;
114+
private int minSize = 1;
115+
private int maxSize = 20;
116+
117+
public Builder(ConnectionCreator connectionCreator, boolean autoCommit) {
118+
this.connectionCreator = connectionCreator;
119+
this.autoCommit = autoCommit;
120+
}
121+
122+
public Builder initialSize(int initialSize) {
123+
this.initialSize = initialSize;
124+
return this;
125+
}
126+
127+
public Builder minSize(int minSize) {
128+
this.minSize = minSize;
129+
return this;
130+
}
131+
132+
public Builder maxSize(int maxSize) {
133+
this.maxSize = maxSize;
134+
return this;
135+
}
136+
137+
public PooledConnections build() {
138+
return new PooledConnections( this );
139+
}
140+
}
141+
}

0 commit comments

Comments
 (0)