HHH-6855 - SequenceStyleGenerator should force use of TableStructure when the optimizer is PooledLo
This commit is contained in:
parent
5071a82458
commit
b2f24c6987
|
@ -1,78 +1,78 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.id.enhanced;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.id.IntegralDataTypeHolder;
|
||||
|
||||
/**
|
||||
* Performs optimization on an optimizable identifier generator. Typically
|
||||
* this optimization takes the form of trying to ensure we do not have to
|
||||
* hit the database on each and every request to get an identifier value.
|
||||
* <p/>
|
||||
* Optimizers work on constructor injection. They should provide
|
||||
* a constructor with the following arguments <ol>
|
||||
* <li>java.lang.Class - The return type for the generated values</li>
|
||||
* <li>int - The increment size</li>
|
||||
* </ol>
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface Optimizer {
|
||||
/**
|
||||
* Generate an identifier value accounting for this specific optimization.
|
||||
*
|
||||
* @param callback Callback to access the underlying value source.
|
||||
* @return The generated identifier value.
|
||||
*/
|
||||
public Serializable generate(AccessCallback callback);
|
||||
|
||||
/**
|
||||
* A common means to access the last value obtained from the underlying
|
||||
* source. This is intended for testing purposes, since accessing the
|
||||
* underlying database source directly is much more difficult.
|
||||
*
|
||||
* @return The last value we obtained from the underlying source;
|
||||
* null indicates we have not yet consulted with the source.
|
||||
*/
|
||||
public IntegralDataTypeHolder getLastSourceValue();
|
||||
|
||||
/**
|
||||
* Retrieves the defined increment size.
|
||||
*
|
||||
* @return The increment size.
|
||||
*/
|
||||
public int getIncrementSize();
|
||||
|
||||
/**
|
||||
* Are increments to be applied to the values stored in the underlying
|
||||
* value source?
|
||||
*
|
||||
* @return True if the values in the source are to be incremented
|
||||
* according to the defined increment size; false otherwise, in which
|
||||
* case the increment is totally an in memory construct.
|
||||
*/
|
||||
public boolean applyIncrementSizeToSourceValues();
|
||||
}
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.id.enhanced;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.id.IntegralDataTypeHolder;
|
||||
|
||||
/**
|
||||
* Performs optimization on an optimizable identifier generator. Typically
|
||||
* this optimization takes the form of trying to ensure we do not have to
|
||||
* hit the database on each and every request to get an identifier value.
|
||||
* <p/>
|
||||
* Optimizers work on constructor injection. They should provide
|
||||
* a constructor with the following arguments <ol>
|
||||
* <li>java.lang.Class - The return type for the generated values</li>
|
||||
* <li>int - The increment size</li>
|
||||
* </ol>
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface Optimizer {
|
||||
/**
|
||||
* Generate an identifier value accounting for this specific optimization.
|
||||
*
|
||||
* @param callback Callback to access the underlying value source.
|
||||
* @return The generated identifier value.
|
||||
*/
|
||||
public Serializable generate(AccessCallback callback);
|
||||
|
||||
/**
|
||||
* A common means to access the last value obtained from the underlying
|
||||
* source. This is intended for testing purposes, since accessing the
|
||||
* underlying database source directly is much more difficult.
|
||||
*
|
||||
* @return The last value we obtained from the underlying source;
|
||||
* null indicates we have not yet consulted with the source.
|
||||
*/
|
||||
public IntegralDataTypeHolder getLastSourceValue();
|
||||
|
||||
/**
|
||||
* Retrieves the defined increment size.
|
||||
*
|
||||
* @return The increment size.
|
||||
*/
|
||||
public int getIncrementSize();
|
||||
|
||||
/**
|
||||
* Are increments to be applied to the values stored in the underlying
|
||||
* value source?
|
||||
*
|
||||
* @return True if the values in the source are to be incremented
|
||||
* according to the defined increment size; false otherwise, in which
|
||||
* case the increment is totally an in memory construct.
|
||||
*/
|
||||
public boolean applyIncrementSizeToSourceValues();
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.id.IntegralDataTypeHolder;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
||||
/**
|
||||
* Factory for {@link Optimizer} instances.
|
||||
|
@ -39,16 +40,70 @@ import org.hibernate.internal.util.ReflectHelper;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class OptimizerFactory {
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
|
||||
CoreMessageLogger.class,
|
||||
OptimizerFactory.class.getName()
|
||||
);
|
||||
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, OptimizerFactory.class.getName());
|
||||
public static enum StandardOptimizerDescriptor {
|
||||
NONE( "none", NoopOptimizer.class ),
|
||||
HILO( "hilo", HiLoOptimizer.class ),
|
||||
LEGACY_HILO( "legacy-hilo", LegacyHiLoAlgorithmOptimizer.class ),
|
||||
POOLED( "pooled", PooledOptimizer.class, true ),
|
||||
POOLED_LO( "pooled-lo", PooledLoOptimizer.class, true );
|
||||
|
||||
public static final String NONE = "none";
|
||||
public static final String HILO = "hilo";
|
||||
public static final String LEGACY_HILO = "legacy-hilo";
|
||||
public static final String POOL = "pooled";
|
||||
public static final String POOL_LO = "pooled-lo";
|
||||
private final String externalName;
|
||||
private final Class<? extends Optimizer> optimizerClass;
|
||||
private final boolean isPooled;
|
||||
|
||||
private static Class[] CTOR_SIG = new Class[] { Class.class, int.class };
|
||||
StandardOptimizerDescriptor(String externalName, Class<? extends Optimizer> optimizerClass) {
|
||||
this( externalName, optimizerClass, false );
|
||||
}
|
||||
|
||||
StandardOptimizerDescriptor(String externalName, Class<? extends Optimizer> optimizerClass, boolean pooled) {
|
||||
this.externalName = externalName;
|
||||
this.optimizerClass = optimizerClass;
|
||||
this.isPooled = pooled;
|
||||
}
|
||||
|
||||
public String getExternalName() {
|
||||
return externalName;
|
||||
}
|
||||
|
||||
public Class<? extends Optimizer> getOptimizerClass() {
|
||||
return optimizerClass;
|
||||
}
|
||||
|
||||
public boolean isPooled() {
|
||||
return isPooled;
|
||||
}
|
||||
|
||||
public static StandardOptimizerDescriptor fromExternalName(String externalName) {
|
||||
if ( StringHelper.isEmpty( externalName ) ) {
|
||||
LOG.debug( "No optimizer specified, using NONE as default" );
|
||||
return NONE;
|
||||
}
|
||||
else if ( NONE.externalName.equals( externalName ) ) {
|
||||
return NONE;
|
||||
}
|
||||
else if ( HILO.externalName.equals( externalName ) ) {
|
||||
return HILO;
|
||||
}
|
||||
else if ( LEGACY_HILO.externalName.equals( externalName ) ) {
|
||||
return LEGACY_HILO;
|
||||
}
|
||||
else if ( POOLED.externalName.equals( externalName ) ) {
|
||||
return POOLED;
|
||||
}
|
||||
else if ( POOLED_LO.externalName.equals( externalName ) ) {
|
||||
return POOLED_LO;
|
||||
}
|
||||
else {
|
||||
LOG.debugf( "Unknown optimizer key [%s]; returning null assuming Optimizer impl class name" );
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marker interface for optimizer which wish to know the user-specified initial value.
|
||||
|
@ -68,6 +123,13 @@ public class OptimizerFactory {
|
|||
public void injectInitialValue(long initialValue);
|
||||
}
|
||||
|
||||
public static boolean isPooledOptimizer(String type) {
|
||||
final StandardOptimizerDescriptor standardDescriptor = StandardOptimizerDescriptor.fromExternalName( type );
|
||||
return standardDescriptor != null && standardDescriptor.isPooled();
|
||||
}
|
||||
|
||||
private static Class[] CTOR_SIG = new Class[] { Class.class, int.class };
|
||||
|
||||
/**
|
||||
* Builds an optimizer
|
||||
*
|
||||
|
@ -80,41 +142,38 @@ public class OptimizerFactory {
|
|||
* @deprecated Use {@link #buildOptimizer(String, Class, int, long)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings({ "UnnecessaryBoxing" })
|
||||
@SuppressWarnings( {"UnnecessaryBoxing", "unchecked"})
|
||||
public static Optimizer buildOptimizer(String type, Class returnClass, int incrementSize) {
|
||||
String optimizerClassName;
|
||||
if ( NONE.equals( type ) ) {
|
||||
optimizerClassName = NoopOptimizer.class.getName();
|
||||
}
|
||||
else if ( HILO.equals( type ) ) {
|
||||
optimizerClassName = HiLoOptimizer.class.getName();
|
||||
}
|
||||
else if ( LEGACY_HILO.equals( type ) ) {
|
||||
optimizerClassName = LegacyHiLoAlgorithmOptimizer.class.getName();
|
||||
}
|
||||
else if ( POOL.equals( type ) ) {
|
||||
optimizerClassName = PooledOptimizer.class.getName();
|
||||
}
|
||||
else if ( POOL_LO.equals( type ) ) {
|
||||
optimizerClassName = PooledLoOptimizer.class.getName();
|
||||
final Class<? extends Optimizer> optimizerClass;
|
||||
|
||||
final StandardOptimizerDescriptor standardDescriptor = StandardOptimizerDescriptor.fromExternalName( type );
|
||||
if ( standardDescriptor != null ) {
|
||||
optimizerClass = standardDescriptor.getOptimizerClass();
|
||||
}
|
||||
else {
|
||||
optimizerClassName = type;
|
||||
try {
|
||||
optimizerClass = ReflectHelper.classForName( type );
|
||||
}
|
||||
catch( Throwable ignore ) {
|
||||
LOG.unableToLocateCustomOptimizerClass( type );
|
||||
return buildFallbackOptimizer( returnClass, incrementSize );
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Class optimizerClass = ReflectHelper.classForName( optimizerClassName );
|
||||
Constructor ctor = optimizerClass.getConstructor( CTOR_SIG );
|
||||
return ( Optimizer ) ctor.newInstance( returnClass, Integer.valueOf( incrementSize ) );
|
||||
}
|
||||
catch( Throwable ignore ) {
|
||||
LOG.unableToInstantiateOptimizer(type);
|
||||
LOG.unableToInstantiateOptimizer( type );
|
||||
}
|
||||
|
||||
// the default...
|
||||
return new NoopOptimizer( returnClass, incrementSize );
|
||||
return buildFallbackOptimizer( returnClass, incrementSize );
|
||||
}
|
||||
|
||||
private static Optimizer buildFallbackOptimizer(Class returnClass, int incrementSize) {
|
||||
return new NoopOptimizer( returnClass, incrementSize );
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an optimizer
|
||||
|
@ -162,13 +221,12 @@ public class OptimizerFactory {
|
|||
*
|
||||
* @return Value for property 'returnClass'.
|
||||
*/
|
||||
@SuppressWarnings( {"UnusedDeclaration"})
|
||||
public final Class getReturnClass() {
|
||||
return returnClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final int getIncrementSize() {
|
||||
return incrementSize;
|
||||
}
|
||||
|
@ -185,9 +243,7 @@ public class OptimizerFactory {
|
|||
super( returnClass, incrementSize );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Serializable generate(AccessCallback callback) {
|
||||
// IMPL NOTE : it is incredibly important that the method-local variable be used here to
|
||||
// avoid concurrency issues.
|
||||
|
@ -199,16 +255,12 @@ public class OptimizerFactory {
|
|||
return value.makeValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public IntegralDataTypeHolder getLastSourceValue() {
|
||||
return lastSourceValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean applyIncrementSizeToSourceValues() {
|
||||
return false;
|
||||
}
|
||||
|
@ -261,9 +313,7 @@ public class OptimizerFactory {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public synchronized Serializable generate(AccessCallback callback) {
|
||||
if ( lastSourceValue == null ) {
|
||||
// first call, so initialize ourselves. we need to read the database
|
||||
|
@ -284,17 +334,12 @@ public class OptimizerFactory {
|
|||
return value.makeValueThenIncrement();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public IntegralDataTypeHolder getLastSourceValue() {
|
||||
return lastSourceValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean applyIncrementSizeToSourceValues() {
|
||||
return false;
|
||||
}
|
||||
|
@ -342,9 +387,7 @@ public class OptimizerFactory {
|
|||
lo = maxLo+1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public synchronized Serializable generate(AccessCallback callback) {
|
||||
if ( lo > maxLo ) {
|
||||
lastSourceValue = callback.getNextValue();
|
||||
|
@ -355,16 +398,12 @@ public class OptimizerFactory {
|
|||
return value.makeValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public IntegralDataTypeHolder getLastSourceValue() {
|
||||
return lastSourceValue.copy();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean applyIncrementSizeToSourceValues() {
|
||||
return false;
|
||||
}
|
||||
|
@ -376,6 +415,7 @@ public class OptimizerFactory {
|
|||
*
|
||||
* @return Value for property 'lastValue'.
|
||||
*/
|
||||
@SuppressWarnings( {"UnusedDeclaration"})
|
||||
public IntegralDataTypeHolder getLastValue() {
|
||||
return value;
|
||||
}
|
||||
|
@ -407,9 +447,7 @@ public class OptimizerFactory {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public synchronized Serializable generate(AccessCallback callback) {
|
||||
if ( hiValue == null ) {
|
||||
value = callback.getNextValue();
|
||||
|
@ -432,16 +470,12 @@ public class OptimizerFactory {
|
|||
return value.makeValueThenIncrement();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public IntegralDataTypeHolder getLastSourceValue() {
|
||||
return hiValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean applyIncrementSizeToSourceValues() {
|
||||
return true;
|
||||
}
|
||||
|
@ -457,9 +491,7 @@ public class OptimizerFactory {
|
|||
return value.copy().decrement();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void injectInitialValue(long initialValue) {
|
||||
this.initialValue = initialValue;
|
||||
}
|
||||
|
@ -479,6 +511,7 @@ public class OptimizerFactory {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable generate(AccessCallback callback) {
|
||||
if ( lastSourceValue == null || ! value.lt( lastSourceValue.copy().add( incrementSize ) ) ) {
|
||||
lastSourceValue = callback.getNextValue();
|
||||
|
@ -491,12 +524,49 @@ public class OptimizerFactory {
|
|||
return value.makeValueThenIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntegralDataTypeHolder getLastSourceValue() {
|
||||
return lastSourceValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyIncrementSizeToSourceValues() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link StandardOptimizerDescriptor#getExternalName()} via {@link StandardOptimizerDescriptor#NONE}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings( {"UnusedDeclaration"})
|
||||
public static final String NONE = StandardOptimizerDescriptor.NONE.getExternalName();
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link StandardOptimizerDescriptor#getExternalName()} via {@link StandardOptimizerDescriptor#HILO}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings( {"UnusedDeclaration"})
|
||||
public static final String HILO = StandardOptimizerDescriptor.HILO.getExternalName();
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link StandardOptimizerDescriptor#getExternalName()} via {@link StandardOptimizerDescriptor#LEGACY_HILO}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings( {"UnusedDeclaration"})
|
||||
public static final String LEGACY_HILO = "legacy-hilo";
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link StandardOptimizerDescriptor#getExternalName()} via {@link StandardOptimizerDescriptor#POOLED}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings( {"UnusedDeclaration"})
|
||||
public static final String POOL = "pooled";
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link StandardOptimizerDescriptor#getExternalName()} via {@link StandardOptimizerDescriptor#POOLED_LO}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings( {"UnusedDeclaration"})
|
||||
public static final String POOL_LO = "pooled-lo";
|
||||
}
|
||||
|
|
|
@ -174,7 +174,7 @@ public class SequenceStyleGenerator
|
|||
incrementSize = determineAdjustedIncrementSize( optimizationStrategy, incrementSize );
|
||||
|
||||
if ( dialect.supportsSequences() && !forceTableUse ) {
|
||||
if ( OptimizerFactory.POOL.equals( optimizationStrategy ) && !dialect.supportsPooledSequences() ) {
|
||||
if ( !dialect.supportsPooledSequences() && OptimizerFactory.isPooledOptimizer( optimizationStrategy ) ) {
|
||||
forceTableUse = true;
|
||||
LOG.forcingTableUse();
|
||||
}
|
||||
|
@ -282,12 +282,14 @@ 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
|
||||
// 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...
|
||||
String defaultPooledOptimizerStrategy = ConfigurationHelper.getBoolean( Environment.PREFER_POOLED_VALUES_LO, params, false )
|
||||
? OptimizerFactory.POOL_LO
|
||||
: OptimizerFactory.POOL;
|
||||
String defaultOptimizerStrategy = incrementSize <= 1 ? OptimizerFactory.NONE : defaultPooledOptimizerStrategy;
|
||||
? OptimizerFactory.StandardOptimizerDescriptor.POOLED_LO.getExternalName()
|
||||
: OptimizerFactory.StandardOptimizerDescriptor.POOLED.getExternalName();
|
||||
String defaultOptimizerStrategy = incrementSize <= 1
|
||||
? OptimizerFactory.StandardOptimizerDescriptor.NONE.getExternalName()
|
||||
: defaultPooledOptimizerStrategy;
|
||||
return ConfigurationHelper.getString( OPT_PARAM, params, defaultOptimizerStrategy );
|
||||
}
|
||||
|
||||
|
@ -300,8 +302,13 @@ public class SequenceStyleGenerator
|
|||
* @return The adjusted increment size.
|
||||
*/
|
||||
protected int determineAdjustedIncrementSize(String optimizationStrategy, int incrementSize) {
|
||||
if ( OptimizerFactory.NONE.equals( optimizationStrategy ) && incrementSize > 1 ) {
|
||||
LOG.honoringOptimizerSetting(OptimizerFactory.NONE, INCREMENT_PARAM, incrementSize);
|
||||
if ( incrementSize > 1
|
||||
&& OptimizerFactory.StandardOptimizerDescriptor.NONE.getExternalName().equals( optimizationStrategy ) ) {
|
||||
LOG.honoringOptimizerSetting(
|
||||
OptimizerFactory.StandardOptimizerDescriptor.NONE.getExternalName(),
|
||||
INCREMENT_PARAM,
|
||||
incrementSize
|
||||
);
|
||||
incrementSize = 1;
|
||||
}
|
||||
return incrementSize;
|
||||
|
|
|
@ -305,9 +305,11 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
|
|||
// 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...
|
||||
String defaultPooledOptimizerStrategy = ConfigurationHelper.getBoolean( Environment.PREFER_POOLED_VALUES_LO, params, false )
|
||||
? OptimizerFactory.POOL_LO
|
||||
: OptimizerFactory.POOL;
|
||||
final String defaultOptimizerStrategy = incrementSize <= 1 ? OptimizerFactory.NONE : defaultPooledOptimizerStrategy;
|
||||
? OptimizerFactory.StandardOptimizerDescriptor.POOLED_LO.getExternalName()
|
||||
: OptimizerFactory.StandardOptimizerDescriptor.POOLED.getExternalName();
|
||||
final String defaultOptimizerStrategy = incrementSize <= 1
|
||||
? OptimizerFactory.StandardOptimizerDescriptor.NONE.getExternalName()
|
||||
: defaultPooledOptimizerStrategy;
|
||||
final String optimizationStrategy = ConfigurationHelper.getString( OPT_PARAM, params, defaultOptimizerStrategy );
|
||||
optimizer = OptimizerFactory.buildOptimizer(
|
||||
optimizationStrategy,
|
||||
|
@ -569,7 +571,7 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
|
|||
|
||||
@Override
|
||||
public String[] sqlDropStrings(Dialect dialect) throws HibernateException {
|
||||
StringBuffer sqlDropString = new StringBuffer().append( "drop table " );
|
||||
StringBuilder sqlDropString = new StringBuilder().append( "drop table " );
|
||||
if ( dialect.supportsIfExistsBeforeTableName() ) {
|
||||
sqlDropString.append( "if exists " );
|
||||
}
|
||||
|
|
|
@ -1095,6 +1095,10 @@ public interface CoreMessageLogger extends BasicLogger {
|
|||
void unableToInstantiateConfiguredSchemaNameResolver(String resolverClassName,
|
||||
String message);
|
||||
|
||||
@LogMessage(level = WARN)
|
||||
@Message(value = "Unable to interpret specified optimizer [%s], falling back to noop", id = 321)
|
||||
void unableToLocateCustomOptimizerClass(String type);
|
||||
|
||||
@LogMessage(level = WARN)
|
||||
@Message(value = "Unable to instantiate specified optimizer [%s], falling back to noop", id = 322)
|
||||
void unableToInstantiateOptimizer(String type);
|
||||
|
|
|
@ -1,312 +1,334 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.id.enhanced;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.id.IdentifierGeneratorHelper;
|
||||
import org.hibernate.id.IntegralDataTypeHolder;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings({ "deprecation" })
|
||||
public class OptimizerUnitTest extends BaseUnitTestCase {
|
||||
@Test
|
||||
public void testBasicNoOptimizerUsage() {
|
||||
// test historic sequence behavior, where the initial values start at 1...
|
||||
SourceMock sequence = new SourceMock( 1 );
|
||||
Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.NONE, Long.class, 1 );
|
||||
for ( int i = 1; i < 11; i++ ) {
|
||||
final Long next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( i, next.intValue() );
|
||||
}
|
||||
assertEquals( 10, sequence.getTimesCalled() );
|
||||
assertEquals( 10, sequence.getCurrentValue() );
|
||||
|
||||
// test historic table behavior, where the initial values started at 0 (we now force 1 to be the first used id value)
|
||||
sequence = new SourceMock( 0 );
|
||||
optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.NONE, Long.class, 1 );
|
||||
for ( int i = 1; i < 11; i++ ) {
|
||||
final Long next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( i, next.intValue() );
|
||||
}
|
||||
assertEquals( 11, sequence.getTimesCalled() ); // an extra time to get to 1 initially
|
||||
assertEquals( 10, sequence.getCurrentValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicHiLoOptimizerUsage() {
|
||||
int increment = 10;
|
||||
Long next;
|
||||
|
||||
// test historic sequence behavior, where the initial values start at 1...
|
||||
SourceMock sequence = new SourceMock( 1 );
|
||||
Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.HILO, Long.class, increment );
|
||||
for ( int i = 1; i <= increment; i++ ) {
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( i, next.intValue() );
|
||||
}
|
||||
assertEquals( 1, sequence.getTimesCalled() ); // once to initialze state
|
||||
assertEquals( 1, sequence.getCurrentValue() );
|
||||
// force a "clock over"
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 11, next.intValue() );
|
||||
assertEquals( 2, sequence.getTimesCalled() );
|
||||
assertEquals( 2, sequence.getCurrentValue() );
|
||||
|
||||
// test historic table behavior, where the initial values started at 0 (we now force 1 to be the first used id value)
|
||||
sequence = new SourceMock( 0 );
|
||||
optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.HILO, Long.class, increment );
|
||||
for ( int i = 1; i <= increment; i++ ) {
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( i, next.intValue() );
|
||||
}
|
||||
assertEquals( 2, sequence.getTimesCalled() ); // here have have an extra call to get to 1 initially
|
||||
assertEquals( 1, sequence.getCurrentValue() );
|
||||
// force a "clock over"
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 11, next.intValue() );
|
||||
assertEquals( 3, sequence.getTimesCalled() );
|
||||
assertEquals( 2, sequence.getCurrentValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicPooledOptimizerUsage() {
|
||||
Long next;
|
||||
// test historic sequence behavior, where the initial values start at 1...
|
||||
SourceMock sequence = new SourceMock( 1, 10 );
|
||||
Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.POOL, Long.class, 10 );
|
||||
for ( int i = 1; i < 11; i++ ) {
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( i, next.intValue() );
|
||||
}
|
||||
assertEquals( 2, sequence.getTimesCalled() ); // twice to initialize state
|
||||
assertEquals( 11, sequence.getCurrentValue() );
|
||||
// force a "clock over"
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 11, next.intValue() );
|
||||
assertEquals( 3, sequence.getTimesCalled() );
|
||||
assertEquals( 21, sequence.getCurrentValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubsequentPooledOptimizerUsage() {
|
||||
// test the pooled optimizer in situation where the sequence is already beyond its initial value on init.
|
||||
// cheat by telling the sequence to start with 1000
|
||||
final SourceMock sequence = new SourceMock( 1001, 3, 5 );
|
||||
// but tell the optimizer the start-with is 1
|
||||
final Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.POOL, Long.class, 3, 1 );
|
||||
|
||||
assertEquals( 5, sequence.getTimesCalled() );
|
||||
assertEquals( 1001, sequence.getCurrentValue() );
|
||||
|
||||
Long next = (Long) optimizer.generate( sequence );
|
||||
assertEquals( 1001, next.intValue() );
|
||||
assertEquals( (5+1), sequence.getTimesCalled() );
|
||||
assertEquals( (1001+3), sequence.getCurrentValue() );
|
||||
|
||||
next = (Long) optimizer.generate( sequence );
|
||||
assertEquals( (1001+1), next.intValue() );
|
||||
assertEquals( (5+1), sequence.getTimesCalled() );
|
||||
assertEquals( (1001+3), sequence.getCurrentValue() );
|
||||
|
||||
next = (Long) optimizer.generate( sequence );
|
||||
assertEquals( (1001+2), next.intValue() );
|
||||
assertEquals( (5+1), sequence.getTimesCalled() );
|
||||
assertEquals( (1001+3), sequence.getCurrentValue() );
|
||||
|
||||
// force a "clock over"
|
||||
next = (Long) optimizer.generate( sequence );
|
||||
assertEquals( (1001+3), next.intValue() );
|
||||
assertEquals( (5+2), sequence.getTimesCalled() );
|
||||
assertEquals( (1001+6), sequence.getCurrentValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicPooledLoOptimizerUsage() {
|
||||
final SourceMock sequence = new SourceMock( 1, 3 );
|
||||
final Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.POOL_LO, Long.class, 3 );
|
||||
|
||||
assertEquals( 0, sequence.getTimesCalled() );
|
||||
assertEquals( -1, sequence.getCurrentValue() );
|
||||
|
||||
Long next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 1, next.intValue() );
|
||||
assertEquals( 1, sequence.getTimesCalled() );
|
||||
assertEquals( 1, sequence.getCurrentValue() );
|
||||
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 2, next.intValue() );
|
||||
assertEquals( 1, sequence.getTimesCalled() );
|
||||
assertEquals( 1, sequence.getCurrentValue() );
|
||||
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 3, next.intValue() );
|
||||
assertEquals( 1, sequence.getTimesCalled() );
|
||||
assertEquals( 1, sequence.getCurrentValue() );
|
||||
|
||||
// // force a "clock over"
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 4, next.intValue() );
|
||||
assertEquals( 2, sequence.getTimesCalled() );
|
||||
assertEquals( (1+3), sequence.getCurrentValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubsequentPooledLoOptimizerUsage() {
|
||||
// test the pooled optimizer in situation where the sequence is already beyond its initial value on init.
|
||||
// cheat by telling the sequence to start with 1000
|
||||
final SourceMock sequence = new SourceMock( 1001, 3, 5 );
|
||||
// but tell the optimizer the start-with is 1
|
||||
final Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.POOL, Long.class, 3, 1 );
|
||||
|
||||
assertEquals( 5, sequence.getTimesCalled() );
|
||||
assertEquals( 1001, sequence.getCurrentValue() );
|
||||
|
||||
Long next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( (1001), next.intValue() );
|
||||
assertEquals( (5+1), sequence.getTimesCalled() );
|
||||
assertEquals( (1001+3), sequence.getCurrentValue() );
|
||||
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( (1001+1), next.intValue() );
|
||||
assertEquals( (5+1), sequence.getTimesCalled() );
|
||||
assertEquals( (1001+3), sequence.getCurrentValue() );
|
||||
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( (1001+2), next.intValue() );
|
||||
assertEquals( (5+1), sequence.getTimesCalled() );
|
||||
assertEquals( (1001+3), sequence.getCurrentValue() );
|
||||
|
||||
// // force a "clock over"
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( (1001+3), next.intValue() );
|
||||
assertEquals( (5+2), sequence.getTimesCalled() );
|
||||
assertEquals( (1001+6), sequence.getCurrentValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecoveredPooledOptimizerUsage() {
|
||||
final SourceMock sequence = new SourceMock( 1, 3 );
|
||||
final Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.POOL, Long.class, 3, 1 );
|
||||
|
||||
assertEquals( 0, sequence.getTimesCalled() );
|
||||
assertEquals( -1, sequence.getCurrentValue() );
|
||||
|
||||
Long next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 1, next.intValue() );
|
||||
assertEquals( 2, sequence.getTimesCalled() );
|
||||
assertEquals( 4, sequence.getCurrentValue() );
|
||||
|
||||
// app ends, and starts back up (we should "lose" only 2 and 3 as id values)
|
||||
final Optimizer optimizer2 = OptimizerFactory.buildOptimizer( OptimizerFactory.POOL, Long.class, 3, 1 );
|
||||
next = ( Long ) optimizer2.generate( sequence );
|
||||
assertEquals( 4, next.intValue() );
|
||||
assertEquals( 3, sequence.getTimesCalled() );
|
||||
assertEquals( 7, sequence.getCurrentValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecoveredPooledLoOptimizerUsage() {
|
||||
final SourceMock sequence = new SourceMock( 1, 3 );
|
||||
final Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.POOL_LO, Long.class, 3, 1 );
|
||||
|
||||
assertEquals( 0, sequence.getTimesCalled() );
|
||||
assertEquals( -1, sequence.getCurrentValue() );
|
||||
|
||||
Long next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 1, next.intValue() );
|
||||
assertEquals( 1, sequence.getTimesCalled() );
|
||||
assertEquals( 1, sequence.getCurrentValue() );
|
||||
|
||||
// app ends, and starts back up (we should "lose" only 2 and 3 as id values)
|
||||
final Optimizer optimizer2 = OptimizerFactory.buildOptimizer( OptimizerFactory.POOL_LO, Long.class, 3, 1 );
|
||||
next = ( Long ) optimizer2.generate( sequence );
|
||||
assertEquals( 4, next.intValue() );
|
||||
assertEquals( 2, sequence.getTimesCalled() );
|
||||
assertEquals( 4, sequence.getCurrentValue() );
|
||||
}
|
||||
|
||||
private static class SourceMock implements AccessCallback {
|
||||
private IdentifierGeneratorHelper.BasicHolder value = new IdentifierGeneratorHelper.BasicHolder( Long.class );
|
||||
private long initialValue;
|
||||
private int increment;
|
||||
private int timesCalled = 0;
|
||||
|
||||
public SourceMock(long initialValue) {
|
||||
this( initialValue, 1 );
|
||||
}
|
||||
|
||||
public SourceMock(long initialValue, int increment) {
|
||||
this( initialValue, increment, 0 );
|
||||
}
|
||||
|
||||
public SourceMock(long initialValue, int increment, int timesCalled) {
|
||||
this.increment = increment;
|
||||
this.timesCalled = timesCalled;
|
||||
if ( timesCalled != 0 ) {
|
||||
this.value.initialize( initialValue );
|
||||
this.initialValue = 1;
|
||||
}
|
||||
else {
|
||||
this.value.initialize( -1 );
|
||||
this.initialValue = initialValue;
|
||||
}
|
||||
}
|
||||
|
||||
public IntegralDataTypeHolder getNextValue() {
|
||||
try {
|
||||
if ( timesCalled == 0 ) {
|
||||
initValue();
|
||||
return value.copy();
|
||||
}
|
||||
else {
|
||||
return value.add( increment ).copy();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
timesCalled++;
|
||||
}
|
||||
}
|
||||
|
||||
private void initValue() {
|
||||
this.value.initialize( initialValue );
|
||||
}
|
||||
|
||||
public int getTimesCalled() {
|
||||
return timesCalled;
|
||||
}
|
||||
|
||||
public long getCurrentValue() {
|
||||
return value == null ? -1 : value.getActualLongValue();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.id.enhanced;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.id.IdentifierGeneratorHelper;
|
||||
import org.hibernate.id.IntegralDataTypeHolder;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class OptimizerUnitTest extends BaseUnitTestCase {
|
||||
@Test
|
||||
public void testBasicNoOptimizerUsage() {
|
||||
// test historic sequence behavior, where the initial values start at 1...
|
||||
SourceMock sequence = new SourceMock( 1 );
|
||||
Optimizer optimizer = buildNoneOptimizer( -1, 1 );
|
||||
for ( int i = 1; i < 11; i++ ) {
|
||||
final Long next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( i, next.intValue() );
|
||||
}
|
||||
assertEquals( 10, sequence.getTimesCalled() );
|
||||
assertEquals( 10, sequence.getCurrentValue() );
|
||||
|
||||
// test historic table behavior, where the initial values started at 0 (we now force 1 to be the first used id value)
|
||||
sequence = new SourceMock( 0 );
|
||||
optimizer = buildNoneOptimizer( -1, 1 );
|
||||
for ( int i = 1; i < 11; i++ ) {
|
||||
final Long next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( i, next.intValue() );
|
||||
}
|
||||
assertEquals( 11, sequence.getTimesCalled() ); // an extra time to get to 1 initially
|
||||
assertEquals( 10, sequence.getCurrentValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicHiLoOptimizerUsage() {
|
||||
int increment = 10;
|
||||
Long next;
|
||||
|
||||
// test historic sequence behavior, where the initial values start at 1...
|
||||
SourceMock sequence = new SourceMock( 1 );
|
||||
Optimizer optimizer = buildHiloOptimizer( -1, increment );
|
||||
for ( int i = 1; i <= increment; i++ ) {
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( i, next.intValue() );
|
||||
}
|
||||
assertEquals( 1, sequence.getTimesCalled() ); // once to initialze state
|
||||
assertEquals( 1, sequence.getCurrentValue() );
|
||||
// force a "clock over"
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 11, next.intValue() );
|
||||
assertEquals( 2, sequence.getTimesCalled() );
|
||||
assertEquals( 2, sequence.getCurrentValue() );
|
||||
|
||||
// test historic table behavior, where the initial values started at 0 (we now force 1 to be the first used id value)
|
||||
sequence = new SourceMock( 0 );
|
||||
optimizer = buildHiloOptimizer( -1, increment );
|
||||
for ( int i = 1; i <= increment; i++ ) {
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( i, next.intValue() );
|
||||
}
|
||||
assertEquals( 2, sequence.getTimesCalled() ); // here have have an extra call to get to 1 initially
|
||||
assertEquals( 1, sequence.getCurrentValue() );
|
||||
// force a "clock over"
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 11, next.intValue() );
|
||||
assertEquals( 3, sequence.getTimesCalled() );
|
||||
assertEquals( 2, sequence.getCurrentValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicPooledOptimizerUsage() {
|
||||
Long next;
|
||||
// test historic sequence behavior, where the initial values start at 1...
|
||||
SourceMock sequence = new SourceMock( 1, 10 );
|
||||
Optimizer optimizer = buildPooledOptimizer( -1, 10 );
|
||||
for ( int i = 1; i < 11; i++ ) {
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( i, next.intValue() );
|
||||
}
|
||||
assertEquals( 2, sequence.getTimesCalled() ); // twice to initialize state
|
||||
assertEquals( 11, sequence.getCurrentValue() );
|
||||
// force a "clock over"
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 11, next.intValue() );
|
||||
assertEquals( 3, sequence.getTimesCalled() );
|
||||
assertEquals( 21, sequence.getCurrentValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubsequentPooledOptimizerUsage() {
|
||||
// test the pooled optimizer in situation where the sequence is already beyond its initial value on init.
|
||||
// cheat by telling the sequence to start with 1000
|
||||
final SourceMock sequence = new SourceMock( 1001, 3, 5 );
|
||||
// but tell the optimizer the start-with is 1
|
||||
final Optimizer optimizer = buildPooledOptimizer( 1, 3 );
|
||||
|
||||
assertEquals( 5, sequence.getTimesCalled() );
|
||||
assertEquals( 1001, sequence.getCurrentValue() );
|
||||
|
||||
Long next = (Long) optimizer.generate( sequence );
|
||||
assertEquals( 1001, next.intValue() );
|
||||
assertEquals( (5+1), sequence.getTimesCalled() );
|
||||
assertEquals( (1001+3), sequence.getCurrentValue() );
|
||||
|
||||
next = (Long) optimizer.generate( sequence );
|
||||
assertEquals( (1001+1), next.intValue() );
|
||||
assertEquals( (5+1), sequence.getTimesCalled() );
|
||||
assertEquals( (1001+3), sequence.getCurrentValue() );
|
||||
|
||||
next = (Long) optimizer.generate( sequence );
|
||||
assertEquals( (1001+2), next.intValue() );
|
||||
assertEquals( (5+1), sequence.getTimesCalled() );
|
||||
assertEquals( (1001+3), sequence.getCurrentValue() );
|
||||
|
||||
// force a "clock over"
|
||||
next = (Long) optimizer.generate( sequence );
|
||||
assertEquals( (1001+3), next.intValue() );
|
||||
assertEquals( (5+2), sequence.getTimesCalled() );
|
||||
assertEquals( (1001+6), sequence.getCurrentValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicPooledLoOptimizerUsage() {
|
||||
final SourceMock sequence = new SourceMock( 1, 3 );
|
||||
final Optimizer optimizer = buildPooledLoOptimizer( 1, 3 );
|
||||
|
||||
assertEquals( 0, sequence.getTimesCalled() );
|
||||
assertEquals( -1, sequence.getCurrentValue() );
|
||||
|
||||
Long next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 1, next.intValue() );
|
||||
assertEquals( 1, sequence.getTimesCalled() );
|
||||
assertEquals( 1, sequence.getCurrentValue() );
|
||||
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 2, next.intValue() );
|
||||
assertEquals( 1, sequence.getTimesCalled() );
|
||||
assertEquals( 1, sequence.getCurrentValue() );
|
||||
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 3, next.intValue() );
|
||||
assertEquals( 1, sequence.getTimesCalled() );
|
||||
assertEquals( 1, sequence.getCurrentValue() );
|
||||
|
||||
// // force a "clock over"
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 4, next.intValue() );
|
||||
assertEquals( 2, sequence.getTimesCalled() );
|
||||
assertEquals( (1+3), sequence.getCurrentValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubsequentPooledLoOptimizerUsage() {
|
||||
// test the pooled optimizer in situation where the sequence is already beyond its initial value on init.
|
||||
// cheat by telling the sequence to start with 1000
|
||||
final SourceMock sequence = new SourceMock( 1001, 3, 5 );
|
||||
// but tell the optimizer the start-with is 1
|
||||
final Optimizer optimizer = buildPooledOptimizer( 1, 3 );
|
||||
|
||||
assertEquals( 5, sequence.getTimesCalled() );
|
||||
assertEquals( 1001, sequence.getCurrentValue() );
|
||||
|
||||
Long next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( (1001), next.intValue() );
|
||||
assertEquals( (5+1), sequence.getTimesCalled() );
|
||||
assertEquals( (1001+3), sequence.getCurrentValue() );
|
||||
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( (1001+1), next.intValue() );
|
||||
assertEquals( (5+1), sequence.getTimesCalled() );
|
||||
assertEquals( (1001+3), sequence.getCurrentValue() );
|
||||
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( (1001+2), next.intValue() );
|
||||
assertEquals( (5+1), sequence.getTimesCalled() );
|
||||
assertEquals( (1001+3), sequence.getCurrentValue() );
|
||||
|
||||
// // force a "clock over"
|
||||
next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( (1001+3), next.intValue() );
|
||||
assertEquals( (5+2), sequence.getTimesCalled() );
|
||||
assertEquals( (1001+6), sequence.getCurrentValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecoveredPooledOptimizerUsage() {
|
||||
final SourceMock sequence = new SourceMock( 1, 3 );
|
||||
final Optimizer optimizer = buildPooledOptimizer( 1, 3 );
|
||||
|
||||
assertEquals( 0, sequence.getTimesCalled() );
|
||||
assertEquals( -1, sequence.getCurrentValue() );
|
||||
|
||||
Long next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 1, next.intValue() );
|
||||
assertEquals( 2, sequence.getTimesCalled() );
|
||||
assertEquals( 4, sequence.getCurrentValue() );
|
||||
|
||||
// app ends, and starts back up (we should "lose" only 2 and 3 as id values)
|
||||
final Optimizer optimizer2 = buildPooledOptimizer( 1, 3 );
|
||||
next = ( Long ) optimizer2.generate( sequence );
|
||||
assertEquals( 4, next.intValue() );
|
||||
assertEquals( 3, sequence.getTimesCalled() );
|
||||
assertEquals( 7, sequence.getCurrentValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecoveredPooledLoOptimizerUsage() {
|
||||
final SourceMock sequence = new SourceMock( 1, 3 );
|
||||
final Optimizer optimizer = buildPooledLoOptimizer( 1, 3 );
|
||||
|
||||
assertEquals( 0, sequence.getTimesCalled() );
|
||||
assertEquals( -1, sequence.getCurrentValue() );
|
||||
|
||||
Long next = ( Long ) optimizer.generate( sequence );
|
||||
assertEquals( 1, next.intValue() );
|
||||
assertEquals( 1, sequence.getTimesCalled() );
|
||||
assertEquals( 1, sequence.getCurrentValue() );
|
||||
|
||||
// app ends, and starts back up (we should "lose" only 2 and 3 as id values)
|
||||
final Optimizer optimizer2 = buildPooledLoOptimizer( 1, 3 );
|
||||
next = ( Long ) optimizer2.generate( sequence );
|
||||
assertEquals( 4, next.intValue() );
|
||||
assertEquals( 2, sequence.getTimesCalled() );
|
||||
assertEquals( 4, sequence.getCurrentValue() );
|
||||
}
|
||||
|
||||
private static Optimizer buildNoneOptimizer(long initial, int increment) {
|
||||
return buildOptimizer( OptimizerFactory.StandardOptimizerDescriptor.NONE, initial, increment );
|
||||
}
|
||||
|
||||
private static Optimizer buildHiloOptimizer(long initial, int increment) {
|
||||
return buildOptimizer( OptimizerFactory.StandardOptimizerDescriptor.HILO, initial, increment );
|
||||
}
|
||||
|
||||
private static Optimizer buildPooledOptimizer(long initial, int increment) {
|
||||
return buildOptimizer( OptimizerFactory.StandardOptimizerDescriptor.POOLED, initial, increment );
|
||||
}
|
||||
|
||||
private static Optimizer buildPooledLoOptimizer(long initial, int increment) {
|
||||
return buildOptimizer( OptimizerFactory.StandardOptimizerDescriptor.POOLED_LO, initial, increment );
|
||||
}
|
||||
|
||||
private static Optimizer buildOptimizer(
|
||||
OptimizerFactory.StandardOptimizerDescriptor descriptor,
|
||||
long initial,
|
||||
int increment) {
|
||||
return OptimizerFactory.buildOptimizer( descriptor.getExternalName(), Long.class, increment, initial );
|
||||
}
|
||||
|
||||
private static class SourceMock implements AccessCallback {
|
||||
private IdentifierGeneratorHelper.BasicHolder value = new IdentifierGeneratorHelper.BasicHolder( Long.class );
|
||||
private long initialValue;
|
||||
private int increment;
|
||||
private int timesCalled = 0;
|
||||
|
||||
public SourceMock(long initialValue) {
|
||||
this( initialValue, 1 );
|
||||
}
|
||||
|
||||
public SourceMock(long initialValue, int increment) {
|
||||
this( initialValue, increment, 0 );
|
||||
}
|
||||
|
||||
public SourceMock(long initialValue, int increment, int timesCalled) {
|
||||
this.increment = increment;
|
||||
this.timesCalled = timesCalled;
|
||||
if ( timesCalled != 0 ) {
|
||||
this.value.initialize( initialValue );
|
||||
this.initialValue = 1;
|
||||
}
|
||||
else {
|
||||
this.value.initialize( -1 );
|
||||
this.initialValue = initialValue;
|
||||
}
|
||||
}
|
||||
|
||||
public IntegralDataTypeHolder getNextValue() {
|
||||
try {
|
||||
if ( timesCalled == 0 ) {
|
||||
initValue();
|
||||
return value.copy();
|
||||
}
|
||||
else {
|
||||
return value.add( increment ).copy();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
timesCalled++;
|
||||
}
|
||||
}
|
||||
|
||||
private void initValue() {
|
||||
this.value.initialize( initialValue );
|
||||
}
|
||||
|
||||
public int getTimesCalled() {
|
||||
return timesCalled;
|
||||
}
|
||||
|
||||
public long getCurrentValue() {
|
||||
return value == null ? -1 : value.getActualLongValue();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,7 +44,6 @@ import static org.junit.Assert.fail;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings({ "deprecation" })
|
||||
public class SequenceStyleConfigUnitTest extends BaseUnitTestCase {
|
||||
private void assertClassAssignability(Class expected, Class actual) {
|
||||
if ( ! expected.isAssignableFrom( actual ) ) {
|
||||
|
@ -169,7 +168,7 @@ public class SequenceStyleConfigUnitTest extends BaseUnitTestCase {
|
|||
|
||||
// optimizer=none w/ increment > 1 => should honor optimizer
|
||||
Properties props = buildGeneratorPropertiesBase();
|
||||
props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.NONE );
|
||||
props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.StandardOptimizerDescriptor.NONE.getExternalName() );
|
||||
props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );
|
||||
SequenceStyleGenerator generator = new SequenceStyleGenerator();
|
||||
generator.configure( StandardBasicTypes.LONG, props, dialect );
|
||||
|
@ -180,7 +179,7 @@ public class SequenceStyleConfigUnitTest extends BaseUnitTestCase {
|
|||
|
||||
// optimizer=hilo w/ increment > 1 => hilo
|
||||
props = buildGeneratorPropertiesBase();
|
||||
props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.HILO );
|
||||
props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.StandardOptimizerDescriptor.HILO.getExternalName() );
|
||||
props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );
|
||||
generator = new SequenceStyleGenerator();
|
||||
generator.configure( StandardBasicTypes.LONG, props, dialect );
|
||||
|
@ -191,7 +190,7 @@ public class SequenceStyleConfigUnitTest extends BaseUnitTestCase {
|
|||
|
||||
// optimizer=pooled w/ increment > 1 => hilo
|
||||
props = buildGeneratorPropertiesBase();
|
||||
props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.POOL );
|
||||
props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.StandardOptimizerDescriptor.POOLED.getExternalName() );
|
||||
props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );
|
||||
generator = new SequenceStyleGenerator();
|
||||
generator.configure( StandardBasicTypes.LONG, props, dialect );
|
||||
|
|
Loading…
Reference in New Issue