HHH-12933 - Generate_statistics grows QueryStatistics ConcurrentHashMap indefinitely
This commit is contained in:
parent
440a2ef490
commit
b3c2c2fe47
|
@ -60,11 +60,10 @@ import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
|
|||
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
||||
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
import org.hibernate.stat.Statistics;
|
||||
import org.hibernate.tuple.entity.EntityTuplizer;
|
||||
import org.hibernate.tuple.entity.EntityTuplizerFactory;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.cfg.AvailableSettings.ACQUIRE_CONNECTIONS;
|
||||
import static org.hibernate.cfg.AvailableSettings.ALLOW_JTA_TRANSACTION_ACCESS;
|
||||
import static org.hibernate.cfg.AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY;
|
||||
|
@ -113,6 +112,7 @@ import static org.hibernate.cfg.AvailableSettings.SESSION_SCOPED_INTERCEPTOR;
|
|||
import static org.hibernate.cfg.AvailableSettings.STATEMENT_BATCH_SIZE;
|
||||
import static org.hibernate.cfg.AvailableSettings.STATEMENT_FETCH_SIZE;
|
||||
import static org.hibernate.cfg.AvailableSettings.STATEMENT_INSPECTOR;
|
||||
import static org.hibernate.cfg.AvailableSettings.QUERY_STATISTICS_MAX_SIZE;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_DIRECT_REFERENCE_CACHE_ENTRIES;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_GET_GENERATED_KEYS;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_IDENTIFIER_ROLLBACK;
|
||||
|
@ -243,6 +243,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
private boolean inClauseParameterPaddingEnabled;
|
||||
|
||||
private boolean nativeExceptionHandling51Compliance;
|
||||
private int queryStatisticsMaxSize;
|
||||
|
||||
@SuppressWarnings({"WeakerAccess", "deprecation"})
|
||||
public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, BootstrapContext context) {
|
||||
|
@ -509,6 +510,13 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
configurationSettings,
|
||||
false
|
||||
);
|
||||
|
||||
this.queryStatisticsMaxSize = ConfigurationHelper.getInt(
|
||||
QUERY_STATISTICS_MAX_SIZE,
|
||||
configurationSettings,
|
||||
Statistics.DEFAULT_QUERY_STATISTICS_MAX_SIZE
|
||||
);
|
||||
|
||||
if ( context.isJpaBootstrap() && nativeExceptionHandling51Compliance ) {
|
||||
log.nativeExceptionHandling51ComplianceJpaBootstrapping();
|
||||
this.nativeExceptionHandling51Compliance = false;
|
||||
|
@ -1031,6 +1039,11 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
return nativeExceptionHandling51Compliance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getQueryStatisticsMaxSize() {
|
||||
return queryStatisticsMaxSize;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// In-flight mutation access
|
||||
|
||||
|
|
|
@ -432,4 +432,9 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
|
|||
public boolean nativeExceptionHandling51Compliance() {
|
||||
return delegate.nativeExceptionHandling51Compliance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getQueryStatisticsMaxSize() {
|
||||
return delegate.getQueryStatisticsMaxSize();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;
|
|||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
|
||||
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
||||
import org.hibernate.stat.Statistics;
|
||||
import org.hibernate.tuple.entity.EntityTuplizerFactory;
|
||||
|
||||
/**
|
||||
|
@ -290,4 +291,8 @@ public interface SessionFactoryOptions {
|
|||
default boolean nativeExceptionHandling51Compliance() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default int getQueryStatisticsMaxSize() {
|
||||
return Statistics.DEFAULT_QUERY_STATISTICS_MAX_SIZE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1951,4 +1951,14 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings {
|
|||
*/
|
||||
String IN_CLAUSE_PARAMETER_PADDING = "hibernate.query.in_clause_parameter_padding";
|
||||
|
||||
/**
|
||||
* This setting controls the number of {@link org.hibernate.stat.QueryStatistics} entries
|
||||
* that will be stored by the Hibernate {@link org.hibernate.stat.Statistics} object.
|
||||
* </p>
|
||||
* The default value is given by the {@link org.hibernate.stat.Statistics#DEFAULT_QUERY_STATISTICS_MAX_SIZE} constant value.
|
||||
*
|
||||
* @since 5.4
|
||||
*/
|
||||
String QUERY_STATISTICS_MAX_SIZE = "hibernate.statistics.query_max_size";
|
||||
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ package org.hibernate.stat;
|
|||
*/
|
||||
public interface Statistics {
|
||||
|
||||
int DEFAULT_QUERY_STATISTICS_MAX_SIZE = 5000;
|
||||
|
||||
/**
|
||||
* Are statistics enabled
|
||||
*/
|
||||
|
|
|
@ -17,9 +17,11 @@ import org.hibernate.cache.spi.Region;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.internal.util.collections.BoundedConcurrentHashMap;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.service.Service;
|
||||
import org.hibernate.stat.Statistics;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
|
||||
import static org.hibernate.internal.CoreLogging.messageLogger;
|
||||
|
@ -92,7 +94,7 @@ public class StatisticsImpl implements StatisticsImplementor, Service {
|
|||
/**
|
||||
* Keyed by query string
|
||||
*/
|
||||
private final ConcurrentMap<String, QueryStatisticsImpl> queryStatsMap = new ConcurrentHashMap();
|
||||
private final BoundedConcurrentHashMap<String, QueryStatisticsImpl> queryStatsMap;
|
||||
|
||||
/**
|
||||
* Keyed by region name
|
||||
|
@ -108,8 +110,15 @@ public class StatisticsImpl implements StatisticsImplementor, Service {
|
|||
}
|
||||
|
||||
public StatisticsImpl(SessionFactoryImplementor sessionFactory) {
|
||||
clear();
|
||||
this.sessionFactory = sessionFactory;
|
||||
this.queryStatsMap = new BoundedConcurrentHashMap(
|
||||
sessionFactory != null ?
|
||||
sessionFactory.getSessionFactoryOptions().getQueryStatisticsMaxSize() :
|
||||
Statistics.DEFAULT_QUERY_STATISTICS_MAX_SIZE,
|
||||
20,
|
||||
BoundedConcurrentHashMap.Eviction.LRU
|
||||
);
|
||||
clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.test.stats;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class ExplicitQueryStatsMaxSizeTest extends QueryStatsMaxSizeTest {
|
||||
|
||||
public static final int QUERY_STATISTICS_MAX_SIZE = 100;
|
||||
|
||||
@Override
|
||||
protected void addConfigOptions(Map options) {
|
||||
super.addConfigOptions( options );
|
||||
options.put( AvailableSettings.QUERY_STATISTICS_MAX_SIZE, QUERY_STATISTICS_MAX_SIZE );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int expectedQueryStatisticsMaxSize() {
|
||||
return QUERY_STATISTICS_MAX_SIZE;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaxSize() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
EntityManagerFactory entityManagerFactory = entityManager.getEntityManagerFactory();
|
||||
SessionFactory sessionFactory = entityManagerFactory.unwrap( SessionFactory.class );
|
||||
|
||||
assertEquals(
|
||||
expectedQueryStatisticsMaxSize(),
|
||||
sessionFactory.getSessionFactoryOptions().getQueryStatisticsMaxSize()
|
||||
);
|
||||
|
||||
StatisticsImplementor statistics = (StatisticsImplementor) sessionFactory.getStatistics();
|
||||
|
||||
for ( int i = 0; i < 10; i++ ) {
|
||||
statistics.queryExecuted( String.valueOf( i ), 100, i * 1000 );
|
||||
}
|
||||
|
||||
assertEquals( 1000, statistics.getQueryStatistics( "1" ).getExecutionTotalTime() );
|
||||
|
||||
for ( int i = 100; i < 300; i++ ) {
|
||||
statistics.queryExecuted( String.valueOf( i ), 100, i * 1000 );
|
||||
}
|
||||
|
||||
assertEquals( 0, statistics.getQueryStatistics( "1" ).getExecutionTotalTime() );
|
||||
} );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 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.test.stats;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.internal.util.collections.BoundedConcurrentHashMap;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
import org.hibernate.stat.SessionStatistics;
|
||||
import org.hibernate.stat.Statistics;
|
||||
import org.hibernate.stat.internal.StatisticsImpl;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class QueryStatsMaxSizeTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Employee.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConfigOptions(Map options) {
|
||||
options.put( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
EntityManagerFactory entityManagerFactory = entityManager.getEntityManagerFactory();
|
||||
SessionFactory sessionFactory = entityManagerFactory.unwrap( SessionFactory.class );
|
||||
|
||||
assertEquals(
|
||||
expectedQueryStatisticsMaxSize(),
|
||||
sessionFactory.getSessionFactoryOptions().getQueryStatisticsMaxSize()
|
||||
);
|
||||
} );
|
||||
}
|
||||
|
||||
protected int expectedQueryStatisticsMaxSize() {
|
||||
return Statistics.DEFAULT_QUERY_STATISTICS_MAX_SIZE;
|
||||
}
|
||||
|
||||
@Entity(name = "Employee")
|
||||
public static class Employee {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@NaturalId
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue