HHH-10381 - Introduce a ThreadLocal-based pooled-lo optimizer to avoid locking

This commit is contained in:
Steve Ebersole 2015-12-16 13:49:31 -06:00
parent 0c358d80f6
commit 20ebd8f5ca
6 changed files with 58 additions and 32 deletions

View File

@ -784,9 +784,19 @@ public interface AvailableSettings {
/**
* When using pooled {@link org.hibernate.id.enhanced.Optimizer optimizers}, prefer interpreting the
* database value as the lower (lo) boundary. The default is to interpret it as the high boundary.
*
* @deprecated Use {@link #PREFERRED_POOLED_OPTIMIZER} instead
*/
@Deprecated
String PREFER_POOLED_VALUES_LO = "hibernate.id.optimizer.pooled.prefer_lo";
/**
* When a generator specified an increment-size and an optimizer was not explicitly specified, which of
* the "pooled" optimizers should be preferred? Can specify an optimizer short name or an Optimizer
* impl FQN.
*/
String PREFERRED_POOLED_OPTIMIZER = "hibernate.id.optimizer.pooled.preferred";
/**
* The maximum number of strong references maintained by {@link org.hibernate.engine.query.spi.QueryPlanCache}. Default is 128.
* @deprecated in favor of {@link #QUERY_PLAN_CACHE_PARAMETER_METADATA_MAX_SIZE}

View File

@ -7,9 +7,14 @@
package org.hibernate.id.enhanced;
import java.lang.reflect.Constructor;
import java.util.Properties;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.jboss.logging.Logger;
/**
@ -144,6 +149,26 @@ public class OptimizerFactory {
@SuppressWarnings( {"UnusedDeclaration"})
public static final String POOL_LO = "pooled-lo";
/**
* Determine the optimizer to use when there was not one explicitly specified.
*/
public static String determineImplicitOptimizerName(int incrementSize, Properties configSettings) {
if ( incrementSize <= 1 ) {
return StandardOptimizerDescriptor.NONE.getExternalName();
}
// see if the user defined a preferred pooled optimizer...
final String preferredPooledOptimizerStrategy = configSettings.getProperty( AvailableSettings.PREFERRED_POOLED_OPTIMIZER );
if ( StringHelper.isNotEmpty( preferredPooledOptimizerStrategy ) ) {
return preferredPooledOptimizerStrategy;
}
// otherwise fallback to the fallback strategy (considering the deprecated PREFER_POOLED_VALUES_LO setting)
return ConfigurationHelper.getBoolean( AvailableSettings.PREFER_POOLED_VALUES_LO, configSettings, false )
? StandardOptimizerDescriptor.POOLED_LO.getExternalName()
: StandardOptimizerDescriptor.POOLED.getExternalName();
}
private OptimizerFactory() {
}
}

View File

@ -6,29 +6,30 @@
*/
package org.hibernate.id.enhanced;
import org.hibernate.HibernateException;
import org.hibernate.id.IntegralDataTypeHolder;
import org.hibernate.internal.CoreMessageLogger;
import org.jboss.logging.Logger;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.hibernate.HibernateException;
import org.hibernate.id.IntegralDataTypeHolder;
import org.hibernate.internal.CoreMessageLogger;
import org.jboss.logging.Logger;
/**
* Variation of {@link PooledOptimizer} which interprets the incoming database value as the lo value, rather than
* the hi value, as well as using thread local to cache the generation state.
*
* @author Steve Ebersole
* @author Stuart Douglas
* @author Scott Marlow
* @author Steve Ebersole
*
* @see PooledOptimizer
*/
public class PooledThreadLocalLoOptimizer extends AbstractOptimizer {
public class PooledLoThreadLocalOptimizer extends AbstractOptimizer {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
PooledThreadLocalLoOptimizer.class.getName()
PooledLoThreadLocalOptimizer.class.getName()
);
private static class GenerationState {
@ -51,7 +52,7 @@ public class PooledThreadLocalLoOptimizer extends AbstractOptimizer {
* @param returnClass The Java type of the values to be generated
* @param incrementSize The increment size.
*/
public PooledThreadLocalLoOptimizer(Class returnClass, int incrementSize) {
public PooledLoThreadLocalOptimizer(Class returnClass, int incrementSize) {
super( returnClass, incrementSize );
if ( incrementSize < 1 ) {
throw new HibernateException( "increment size cannot be less than 1" );

View File

@ -15,7 +15,6 @@ import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.model.relational.QualifiedName;
import org.hibernate.boot.model.relational.QualifiedNameParser;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.spi.SessionImplementor;
@ -347,15 +346,11 @@ public class SequenceStyleGenerator
* @return The optimizer strategy (name)
*/
protected String determineOptimizationStrategy(Properties params, int incrementSize) {
// if the increment size is greater than one, we prefer pooled optimization; but we first
// need to see if the user prefers POOL or POOL_LO...
final String defaultPooledOptimizerStrategy = ConfigurationHelper.getBoolean( Environment.PREFER_POOLED_VALUES_LO, params, false )
? StandardOptimizerDescriptor.POOLED_LO.getExternalName()
: StandardOptimizerDescriptor.POOLED.getExternalName();
final String defaultOptimizerStrategy = incrementSize <= 1
? StandardOptimizerDescriptor.NONE.getExternalName()
: defaultPooledOptimizerStrategy;
return ConfigurationHelper.getString( OPT_PARAM, params, defaultOptimizerStrategy );
return ConfigurationHelper.getString(
OPT_PARAM,
params,
OptimizerFactory.determineImplicitOptimizerName( incrementSize, params )
);
}
/**

View File

@ -43,7 +43,7 @@ public enum StandardOptimizerDescriptor {
* Describes the optimizer for use with tables/sequences that store the chunk information. Here, specifically the
* lo value is stored in the database and ThreadLocal used to cache the generation state.
*/
POOLED_LOTL( "pooled-lotl", PooledThreadLocalLoOptimizer.class, true );
POOLED_LOTL( "pooled-lotl", PooledLoThreadLocalOptimizer.class, true );
private static final Logger log = Logger.getLogger( StandardOptimizerDescriptor.class );
@ -51,11 +51,11 @@ public enum StandardOptimizerDescriptor {
private final Class<? extends Optimizer> optimizerClass;
private final boolean isPooled;
private StandardOptimizerDescriptor(String externalName, Class<? extends Optimizer> optimizerClass) {
StandardOptimizerDescriptor(String externalName, Class<? extends Optimizer> optimizerClass) {
this( externalName, optimizerClass, false );
}
private StandardOptimizerDescriptor(String externalName, Class<? extends Optimizer> optimizerClass, boolean pooled) {
StandardOptimizerDescriptor(String externalName, Class<? extends Optimizer> optimizerClass, boolean pooled) {
this.externalName = externalName;
this.optimizerClass = optimizerClass;
this.isPooled = pooled;

View File

@ -25,7 +25,6 @@ import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.model.relational.Namespace;
import org.hibernate.boot.model.relational.QualifiedName;
import org.hibernate.boot.model.relational.QualifiedNameParser;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.internal.FormatStyle;
@ -360,15 +359,11 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
initialValue = determineInitialValue( params );
incrementSize = determineIncrementSize( params );
// if the increment size is greater than one, we prefer pooled optimization; but we
// need to see if the user prefers POOL or POOL_LO...
final String defaultPooledOptimizerStrategy = ConfigurationHelper.getBoolean( Environment.PREFER_POOLED_VALUES_LO, params, false )
? StandardOptimizerDescriptor.POOLED_LO.getExternalName()
: StandardOptimizerDescriptor.POOLED.getExternalName();
final String defaultOptimizerStrategy = incrementSize <= 1
? StandardOptimizerDescriptor.NONE.getExternalName()
: defaultPooledOptimizerStrategy;
final String optimizationStrategy = ConfigurationHelper.getString( OPT_PARAM, params, defaultOptimizerStrategy );
final String optimizationStrategy = ConfigurationHelper.getString(
OPT_PARAM,
params,
OptimizerFactory.determineImplicitOptimizerName( incrementSize, params )
);
optimizer = OptimizerFactory.buildOptimizer(
optimizationStrategy,
identifierType.getReturnedClass(),