HHH-8946 Optimize JdbcCoordinatorImpl for CPU performance
- unnecessary HashMap lookups - size HashMap allocations appropriately - a leak of tracked statements - complex logging logic Conflicts: hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java
This commit is contained in:
parent
d402c06170
commit
265963c33b
|
@ -30,6 +30,7 @@ import java.sql.Connection;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -57,7 +58,6 @@ import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.jdbc.WorkExecutor;
|
import org.hibernate.jdbc.WorkExecutor;
|
||||||
import org.hibernate.jdbc.WorkExecutorVisitable;
|
import org.hibernate.jdbc.WorkExecutorVisitable;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.jboss.logging.Logger.Level;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard Hibernate implementation of {@link JdbcCoordinator}
|
* Standard Hibernate implementation of {@link JdbcCoordinator}
|
||||||
|
@ -66,6 +66,7 @@ import org.jboss.logging.Logger.Level;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
* @author Brett Meyer
|
* @author Brett Meyer
|
||||||
|
* @author Sanne Grinovero
|
||||||
*/
|
*/
|
||||||
public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
||||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
|
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
|
||||||
|
@ -79,6 +80,14 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
||||||
|
|
||||||
private transient long transactionTimeOutInstant = -1;
|
private transient long transactionTimeOutInstant = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a marker value to insert instead of null values for when a Statement gets registered in xref
|
||||||
|
* but has no associations registered. This is useful to be able to efficiently check against duplicate
|
||||||
|
* registraction but you'll have to check against instance equality rather than null before attempting
|
||||||
|
* to add elements to this set.
|
||||||
|
*/
|
||||||
|
private static final Set<ResultSet> EMPTY_RESULTSET = Collections.emptySet();
|
||||||
|
|
||||||
private final HashMap<Statement,Set<ResultSet>> xref = new HashMap<Statement,Set<ResultSet>>();
|
private final HashMap<Statement,Set<ResultSet>> xref = new HashMap<Statement,Set<ResultSet>>();
|
||||||
private final Set<ResultSet> unassociatedResultSets = new HashSet<ResultSet>();
|
private final Set<ResultSet> unassociatedResultSets = new HashSet<ResultSet>();
|
||||||
private final SqlExceptionHelper exceptionHelper;
|
private final SqlExceptionHelper exceptionHelper;
|
||||||
|
@ -317,10 +326,14 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
||||||
@Override
|
@Override
|
||||||
public void register(Statement statement) {
|
public void register(Statement statement) {
|
||||||
LOG.tracev( "Registering statement [{0}]", statement );
|
LOG.tracev( "Registering statement [{0}]", statement );
|
||||||
if ( xref.containsKey( statement ) ) {
|
final Set<ResultSet> previousValue = xref.put( statement, EMPTY_RESULTSET );
|
||||||
|
if ( previousValue != null ) {
|
||||||
|
//we could check as a pre-condition but this is a very hot spot in terms of computation,
|
||||||
|
//so we optimize for the common scenario. At this point however we need to put the previous
|
||||||
|
//value back to undo the put:
|
||||||
|
xref.put( statement, previousValue );
|
||||||
throw new HibernateException( "statement already registered with JDBCContainer" );
|
throw new HibernateException( "statement already registered with JDBCContainer" );
|
||||||
}
|
}
|
||||||
xref.put( statement, null );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -371,7 +384,6 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void register(ResultSet resultSet, Statement statement) {
|
public void register(ResultSet resultSet, Statement statement) {
|
||||||
LOG.tracev( "Registering result set [{0}]", resultSet );
|
|
||||||
if ( statement == null ) {
|
if ( statement == null ) {
|
||||||
try {
|
try {
|
||||||
statement = resultSet.getStatement();
|
statement = resultSet.getStatement();
|
||||||
|
@ -381,18 +393,20 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( statement != null ) {
|
if ( statement != null ) {
|
||||||
|
LOG.tracev( "Registering result set [{0}]", resultSet );
|
||||||
|
final Set<ResultSet> resultSets = xref.get( statement );
|
||||||
|
if ( resultSets == null ) {
|
||||||
// Keep this at DEBUG level, rather than warn. Numerous connection pool implementations can return a
|
// Keep this at DEBUG level, rather than warn. Numerous connection pool implementations can return a
|
||||||
// proxy/wrapper around the JDBC Statement, causing excessive logging here. See HHH-8210.
|
// proxy/wrapper around the JDBC Statement, causing excessive logging here. See HHH-8210.
|
||||||
if ( LOG.isEnabled( Level.DEBUG ) && !xref.containsKey( statement ) ) {
|
|
||||||
LOG.unregisteredStatement();
|
LOG.unregisteredStatement();
|
||||||
}
|
}
|
||||||
Set<ResultSet> resultSets = xref.get( statement );
|
if ( resultSets == null || resultSets == EMPTY_RESULTSET ) {
|
||||||
if ( resultSets == null ) {
|
xref.put( statement, new HashSet<ResultSet>() );
|
||||||
resultSets = new HashSet<ResultSet>();
|
|
||||||
xref.put( statement, resultSets );
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
resultSets.add( resultSet );
|
resultSets.add( resultSet );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
unassociatedResultSets.add( resultSet );
|
unassociatedResultSets.add( resultSet );
|
||||||
}
|
}
|
||||||
|
@ -410,13 +424,13 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( statement != null ) {
|
if ( statement != null ) {
|
||||||
|
final Set<ResultSet> resultSets = xref.get( statement );
|
||||||
|
if ( resultSets == null ) {
|
||||||
// Keep this at DEBUG level, rather than warn. Numerous connection pool implementations can return a
|
// Keep this at DEBUG level, rather than warn. Numerous connection pool implementations can return a
|
||||||
// proxy/wrapper around the JDBC Statement, causing excessive logging here. See HHH-8210.
|
// proxy/wrapper around the JDBC Statement, causing excessive logging here. See HHH-8210.
|
||||||
if ( LOG.isEnabled( Level.DEBUG ) && !xref.containsKey( statement ) ) {
|
|
||||||
LOG.unregisteredStatement();
|
LOG.unregisteredStatement();
|
||||||
}
|
}
|
||||||
Set<ResultSet> resultSets = xref.get( statement );
|
else {
|
||||||
if ( resultSets != null ) {
|
|
||||||
resultSets.remove( resultSet );
|
resultSets.remove( resultSet );
|
||||||
if ( resultSets.isEmpty() ) {
|
if ( resultSets.isEmpty() ) {
|
||||||
xref.remove( statement );
|
xref.remove( statement );
|
||||||
|
@ -455,9 +469,7 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
||||||
|
|
||||||
private void cleanup() {
|
private void cleanup() {
|
||||||
for ( Map.Entry<Statement,Set<ResultSet>> entry : xref.entrySet() ) {
|
for ( Map.Entry<Statement,Set<ResultSet>> entry : xref.entrySet() ) {
|
||||||
if ( entry.getValue() != null ) {
|
|
||||||
closeAll( entry.getValue() );
|
closeAll( entry.getValue() );
|
||||||
}
|
|
||||||
close( entry.getKey() );
|
close( entry.getKey() );
|
||||||
}
|
}
|
||||||
xref.clear();
|
xref.clear();
|
||||||
|
|
Loading…
Reference in New Issue