Author: steve.ebersole(a)jboss.com
Date: 2010-05-12 11:13:47 -0400 (Wed, 12 May 2010)
New Revision: 19478
Added:
core/trunk/core/src/test/java/org/hibernate/id/enhanced/
core/trunk/core/src/test/java/org/hibernate/id/enhanced/OptimizerUnitTest.java
core/trunk/core/src/test/java/org/hibernate/id/enhanced/SequenceStyleConfigUnitTest.java
Removed:
core/trunk/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java
core/trunk/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/SequenceStyleConfigUnitTest.java
Modified:
core/trunk/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java
core/trunk/core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java
core/trunk/core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java
Log:
HHH-5217 - Minimize double sequence value reads in PooledOptimizer
Modified: core/trunk/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java
===================================================================
---
core/trunk/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java 2010-05-12
15:13:03 UTC (rev 19477)
+++
core/trunk/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java 2010-05-12
15:13:47 UTC (rev 19478)
@@ -44,10 +44,40 @@
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";
private static Class[] CTOR_SIG = new Class[] { Class.class, int.class };
+ /**
+ * Marker interface for optimizer which wish to know the user-specified initial value.
+ * <p/>
+ * Used instead of constructor injection since that is already a public understanding
and
+ * because not all optimizers care.
+ */
+ public static interface InitialValueAwareOptimizer {
+ /**
+ * Reports the user specified initial value to the optimizer.
+ * <p/>
+ * <tt>-1</tt> is used to indicate that the user did not specify.
+ *
+ * @param initialValue The initial value specified by the user, or
<tt>-1</tt> to indicate that the
+ * user did not specify.
+ */
+ public void injectInitialValue(long initialValue);
+ }
+
+ /**
+ * Builds an optimizer
+ *
+ * @param type The optimizer type, either a short-hand name or the {@link Optimizer}
class name.
+ * @param returnClass The generated value java type
+ * @param incrementSize The increment size.
+ *
+ * @return The built optimizer
+ *
+ * @deprecated Use {@link #buildOptimizer(String, Class, int, long)} instead
+ */
@SuppressWarnings({ "UnnecessaryBoxing" })
public static Optimizer buildOptimizer(String type, Class returnClass, int
incrementSize) {
String optimizerClassName;
@@ -57,6 +87,9 @@
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();
}
@@ -70,14 +103,34 @@
return ( Optimizer ) ctor.newInstance( returnClass, Integer.valueOf( incrementSize )
);
}
catch( Throwable ignore ) {
- // intentionally empty
+ log.warn( "Unable to instantiate specified optimizer [{}], falling back to
noop", type );
}
// the default...
return new NoopOptimizer( returnClass, incrementSize );
}
+
/**
+ * Builds an optimizer
+ *
+ * @param type The optimizer type, either a short-hand name or the {@link Optimizer}
class name.
+ * @param returnClass The generated value java type
+ * @param incrementSize The increment size.
+ * @param explicitInitialValue The user supplied initial-value (-1 indicates the user
did not specify).
+ *
+ * @return The built optimizer
+ */
+ @SuppressWarnings({ "UnnecessaryBoxing", "deprecation" })
+ public static Optimizer buildOptimizer(String type, Class returnClass, int
incrementSize, long explicitInitialValue) {
+ final Optimizer optimizer = buildOptimizer( type, returnClass, incrementSize );
+ if ( InitialValueAwareOptimizer.class.isInstance( optimizer ) ) {
+ ( (InitialValueAwareOptimizer) optimizer ).injectInitialValue( explicitInitialValue
);
+ }
+ return optimizer;
+ }
+
+ /**
* Common support for optimizer implementations.
*/
public static abstract class OptimizerSupport implements Optimizer {
@@ -335,9 +388,10 @@
* {@link HiLoOptimizer} except that here the bucket ranges are actually
* encoded into the database structures.
*/
- public static class PooledOptimizer extends OptimizerSupport {
+ public static class PooledOptimizer extends OptimizerSupport implements
InitialValueAwareOptimizer {
private IntegralDataTypeHolder hiValue;
private IntegralDataTypeHolder value;
+ private long initialValue = -1;
public PooledOptimizer(Class returnClass, int incrementSize) {
super( returnClass, incrementSize );
@@ -362,7 +416,14 @@
// we are using a sequence...
log.info( "pooled optimizer source reported [" + value + "] as the
initial value; use of 1 or greater highly recommended" );
}
- hiValue = callback.getNextValue();
+ if ( ( initialValue == -1 && value.lt( incrementSize ) ) || value.eq(
initialValue ) ) {
+ // the call to obtain next-value just gave us the initialValue
+ hiValue = callback.getNextValue();
+ }
+ else {
+ hiValue = value;
+ value = hiValue.copy().subtract( incrementSize );
+ }
}
else if ( ! hiValue.gt( value ) ) {
hiValue = callback.getNextValue();
@@ -395,5 +456,12 @@
public IntegralDataTypeHolder getLastValue() {
return value.copy().decrement();
}
+
+ /**
+ * {@inheritDoc}
+ */
+ public void injectInitialValue(long initialValue) {
+ this.initialValue = initialValue;
+ }
}
}
Modified:
core/trunk/core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java
===================================================================
---
core/trunk/core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java 2010-05-12
15:13:03 UTC (rev 19477)
+++
core/trunk/core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java 2010-05-12
15:13:47 UTC (rev 19478)
@@ -187,8 +187,12 @@
initialValue,
incrementSize
);
-
- this.optimizer = OptimizerFactory.buildOptimizer( optimizationStrategy,
identifierType.getReturnedClass(), incrementSize );
+ this.optimizer = OptimizerFactory.buildOptimizer(
+ optimizationStrategy,
+ identifierType.getReturnedClass(),
+ incrementSize,
+ PropertiesHelper.getInt( INITIAL_PARAM, params, -1 )
+ );
this.databaseStructure.prepare( optimizer );
}
@@ -305,7 +309,9 @@
* @param forceTableUse Should a table be used even if the dialect supports sequences?
* @param sequenceName The name to use for the sequence or table.
* @param initialValue The initial value.
- * @param incrementSize the increment size to use (after any adjustments). @return
The db structure representation
+ * @param incrementSize the increment size to use (after any adjustments).
+ *
+ * @return An abstraction for the actual database structure in use (table vs.
sequence).
*/
protected DatabaseStructure buildDatabaseStructure(
Type type,
Modified: core/trunk/core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java 2010-05-12
15:13:03 UTC (rev 19477)
+++ core/trunk/core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java 2010-05-12
15:13:47 UTC (rev 19478)
@@ -303,9 +303,14 @@
this.updateQuery = buildUpdateQuery();
this.insertQuery = buildInsertQuery();
- String defOptStrategy = incrementSize <= 1 ? OptimizerFactory.NONE :
OptimizerFactory.POOL;
- String optimizationStrategy = PropertiesHelper.getString( OPT_PARAM, params,
defOptStrategy );
- optimizer = OptimizerFactory.buildOptimizer( optimizationStrategy,
identifierType.getReturnedClass(), incrementSize );
+ final String defOptStrategy = incrementSize <= 1 ? OptimizerFactory.NONE :
OptimizerFactory.POOL;
+ final String optimizationStrategy = PropertiesHelper.getString( OPT_PARAM, params,
defOptStrategy );
+ optimizer = OptimizerFactory.buildOptimizer(
+ optimizationStrategy,
+ identifierType.getReturnedClass(),
+ incrementSize,
+ PropertiesHelper.getInt( INITIAL_PARAM, params, -1 )
+ );
}
/**
@@ -430,8 +435,8 @@
String query = "select " + StringHelper.qualify( alias, valueColumnName ) +
" from " + tableName + ' ' + alias +
" where " + StringHelper.qualify( alias, segmentColumnName ) +
"=?";
- LockOptions lockOptions = new LockOptions(LockMode.UPGRADE);
- lockOptions.setAliasSpecificLockMode( alias, LockMode.UPGRADE );
+ LockOptions lockOptions = new LockOptions( LockMode.PESSIMISTIC_WRITE );
+ lockOptions.setAliasSpecificLockMode( alias, LockMode.PESSIMISTIC_WRITE );
Map updateTargetColumnsMap = Collections.singletonMap( alias, new String[] {
valueColumnName } );
return dialect.applyLocksToSql( query, lockOptions, updateTargetColumnsMap );
}
Copied: core/trunk/core/src/test/java/org/hibernate/id/enhanced/OptimizerUnitTest.java
(from rev 19411,
core/trunk/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java)
===================================================================
--- core/trunk/core/src/test/java/org/hibernate/id/enhanced/OptimizerUnitTest.java
(rev 0)
+++
core/trunk/core/src/test/java/org/hibernate/id/enhanced/OptimizerUnitTest.java 2010-05-12
15:13:47 UTC (rev 19478)
@@ -0,0 +1,235 @@
+/*
+ * 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 junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.hibernate.id.IdentifierGeneratorHelper;
+import org.hibernate.id.IntegralDataTypeHolder;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+@SuppressWarnings({ "deprecation" })
+public class OptimizerUnitTest extends TestCase {
+ public OptimizerUnitTest(String string) {
+ super( string );
+ }
+
+ public static Test suite() {
+ return new TestSuite( OptimizerUnitTest.class );
+ }
+
+ 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() );
+ }
+
+ 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() );
+ }
+
+ 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() );
+ }
+
+ 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( 1000, 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( 1000, sequence.getCurrentValue() );
+
+ Long next = (Long) optimizer.generate( sequence );
+ assertEquals( 1000, next.intValue() );
+ assertEquals( (5+1), sequence.getTimesCalled() );
+ assertEquals( (1000+3), sequence.getCurrentValue() );
+
+ next = (Long) optimizer.generate( sequence );
+ assertEquals( 1001, next.intValue() );
+ assertEquals( (5+1), sequence.getTimesCalled() );
+ assertEquals( (1000+3), sequence.getCurrentValue() );
+
+ next = (Long) optimizer.generate( sequence );
+ assertEquals( 1002, next.intValue() );
+ assertEquals( (5+1), sequence.getTimesCalled() );
+ assertEquals( (1000+3), sequence.getCurrentValue() );
+
+ // force a "clock over"
+ next = (Long) optimizer.generate( sequence );
+ assertEquals( 1003, next.intValue() );
+ assertEquals( (5+2), sequence.getTimesCalled() );
+ assertEquals( (1000+6), 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.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();
+ }
+ }
+
+// public void testNoopDumping() {
+// SourceMock sequence = new SourceMock( 1 );
+// Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.NONE,
Long.class, 1 );
+// for ( int i = 1; i <= 41; i++ ) {
+// System.out.println( i + " => " + optimizer.generate( sequence ) +
" (" + sequence.getCurrentValue() + ")" );
+// }
+// }
+//
+// public void testHiLoDumping() {
+// int increment = 10;
+// SourceMock sequence = new SourceMock( 1 );
+// Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.HILO,
Long.class, increment );
+// for ( int i = 1; i <= 41; i++ ) {
+// System.out.println( i + " => " + optimizer.generate( sequence ) +
" (" + sequence.getCurrentValue() + ")" );
+// }
+// }
+//
+// public void testPooledDumping() {
+// int increment = 10;
+// SourceMock sequence = new SourceMock( 1, increment );
+// Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.POOL,
Long.class, increment );
+// for ( int i = 1; i <= 41; i++ ) {
+// System.out.println( i + " => " + optimizer.generate( sequence ) +
" (" + sequence.getCurrentValue() + ")" );
+// }
+// }
+
+}
Copied:
core/trunk/core/src/test/java/org/hibernate/id/enhanced/SequenceStyleConfigUnitTest.java
(from rev 19411,
core/trunk/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/SequenceStyleConfigUnitTest.java)
===================================================================
---
core/trunk/core/src/test/java/org/hibernate/id/enhanced/SequenceStyleConfigUnitTest.java
(rev 0)
+++
core/trunk/core/src/test/java/org/hibernate/id/enhanced/SequenceStyleConfigUnitTest.java 2010-05-12
15:13:47 UTC (rev 19478)
@@ -0,0 +1,207 @@
+package org.hibernate.id.enhanced;
+
+import java.util.Properties;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.id.PersistentIdentifierGenerator;
+import org.hibernate.Hibernate;
+import org.hibernate.MappingException;
+import org.hibernate.cfg.ObjectNameNormalizer;
+import org.hibernate.cfg.NamingStrategy;
+
+/**
+ * Tests that SequenceStyleGenerator configures itself as expected
+ * in various scenarios
+ *
+ * @author Steve Ebersole
+ */
+@SuppressWarnings({ "deprecation" })
+public class SequenceStyleConfigUnitTest extends TestCase {
+ public SequenceStyleConfigUnitTest(String string) {
+ super( string );
+ }
+
+ public static Test suite() {
+ return new TestSuite( SequenceStyleConfigUnitTest.class );
+ }
+
+ private void assertClassAssignability(Class expected, Class actual) {
+ if ( ! expected.isAssignableFrom( actual ) ) {
+ fail( "Actual type [" + actual.getName() + "] is not assignable to
expected type [" + expected.getName() + "]" );
+ }
+ }
+
+
+ /**
+ * Test all params defaulted with a dialect supporting sequences
+ */
+ public void testDefaultedSequenceBackedConfiguration() {
+ Dialect dialect = new SequenceDialect();
+ Properties props = buildGeneratorPropertiesBase();
+ SequenceStyleGenerator generator = new SequenceStyleGenerator();
+ generator.configure( Hibernate.LONG, props, dialect );
+
+ assertClassAssignability( SequenceStructure.class,
generator.getDatabaseStructure().getClass() );
+ assertClassAssignability( OptimizerFactory.NoopOptimizer.class,
generator.getOptimizer().getClass() );
+ assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME,
generator.getDatabaseStructure().getName() );
+ }
+
+ private Properties buildGeneratorPropertiesBase() {
+ Properties props = new Properties();
+ props.put(
+ PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER,
+ new ObjectNameNormalizer() {
+ protected boolean isUseQuotedIdentifiersGlobally() {
+ return false;
+ }
+
+ protected NamingStrategy getNamingStrategy() {
+ return null;
+ }
+ }
+ );
+ return props;
+ }
+
+ /**
+ * Test all params defaulted with a dialect which does not support sequences
+ */
+ public void testDefaultedTableBackedConfiguration() {
+ Dialect dialect = new TableDialect();
+ Properties props = buildGeneratorPropertiesBase();
+ SequenceStyleGenerator generator = new SequenceStyleGenerator();
+ generator.configure( Hibernate.LONG, props, dialect );
+
+ assertClassAssignability( TableStructure.class,
generator.getDatabaseStructure().getClass() );
+ assertClassAssignability( OptimizerFactory.NoopOptimizer.class,
generator.getOptimizer().getClass() );
+ assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME,
generator.getDatabaseStructure().getName() );
+ }
+
+ /**
+ * Test default optimizer selection for sequence backed generators
+ * based on the configured increment size; both in the case of the
+ * dialect supporting pooled sequences (pooled) and not (hilo)
+ */
+ public void testDefaultOptimizerBasedOnIncrementBackedBySequence() {
+ Properties props = buildGeneratorPropertiesBase();
+ props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "10" );
+
+ // for dialects which do not support pooled sequences, we default to pooled+table
+ Dialect dialect = new SequenceDialect();
+ SequenceStyleGenerator generator = new SequenceStyleGenerator();
+ generator.configure( Hibernate.LONG, props, dialect );
+ assertClassAssignability( TableStructure.class,
generator.getDatabaseStructure().getClass() );
+ assertClassAssignability( OptimizerFactory.PooledOptimizer.class,
generator.getOptimizer().getClass() );
+ assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME,
generator.getDatabaseStructure().getName() );
+
+ // for dialects which do support pooled sequences, we default to pooled+sequence
+ dialect = new PooledSequenceDialect();
+ generator = new SequenceStyleGenerator();
+ generator.configure( Hibernate.LONG, props, dialect );
+ assertClassAssignability( SequenceStructure.class,
generator.getDatabaseStructure().getClass() );
+ assertClassAssignability( OptimizerFactory.PooledOptimizer.class,
generator.getOptimizer().getClass() );
+ assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME,
generator.getDatabaseStructure().getName() );
+ }
+
+ /**
+ * Test default optimizer selection for table backed generators
+ * based on the configured increment size. Here we always prefer
+ * pooled.
+ */
+ public void testDefaultOptimizerBasedOnIncrementBackedByTable() {
+ Properties props = buildGeneratorPropertiesBase();
+ props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "10" );
+ Dialect dialect = new TableDialect();
+ SequenceStyleGenerator generator = new SequenceStyleGenerator();
+ generator.configure( Hibernate.LONG, props, dialect );
+ assertClassAssignability( TableStructure.class,
generator.getDatabaseStructure().getClass() );
+ assertClassAssignability( OptimizerFactory.PooledOptimizer.class,
generator.getOptimizer().getClass() );
+ assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME,
generator.getDatabaseStructure().getName() );
+ }
+
+ /**
+ * Test forcing of table as backing strucuture with dialect supporting sequences
+ */
+ public void testForceTableUse() {
+ Dialect dialect = new SequenceDialect();
+ Properties props = buildGeneratorPropertiesBase();
+ props.setProperty( SequenceStyleGenerator.FORCE_TBL_PARAM, "true" );
+ SequenceStyleGenerator generator = new SequenceStyleGenerator();
+ generator.configure( Hibernate.LONG, props, dialect );
+ assertClassAssignability( TableStructure.class,
generator.getDatabaseStructure().getClass() );
+ assertClassAssignability( OptimizerFactory.NoopOptimizer.class,
generator.getOptimizer().getClass() );
+ assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME,
generator.getDatabaseStructure().getName() );
+ }
+
+ /**
+ * Test explicitly specifying both optimizer and increment
+ */
+ public void testExplicitOptimizerWithExplicitIncrementSize() {
+ // with sequence ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ final Dialect dialect = new SequenceDialect();
+
+ // optimizer=none w/ increment > 1 => should honor optimizer
+ Properties props = buildGeneratorPropertiesBase();
+ props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.NONE );
+ props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );
+ SequenceStyleGenerator generator = new SequenceStyleGenerator();
+ generator.configure( Hibernate.LONG, props, dialect );
+ assertClassAssignability( SequenceStructure.class,
generator.getDatabaseStructure().getClass() );
+ assertClassAssignability( OptimizerFactory.NoopOptimizer.class,
generator.getOptimizer().getClass() );
+ assertEquals( 1, generator.getOptimizer().getIncrementSize() );
+ assertEquals( 1, generator.getDatabaseStructure().getIncrementSize() );
+
+ // optimizer=hilo w/ increment > 1 => hilo
+ props = buildGeneratorPropertiesBase();
+ props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.HILO );
+ props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );
+ generator = new SequenceStyleGenerator();
+ generator.configure( Hibernate.LONG, props, dialect );
+ assertClassAssignability( SequenceStructure.class,
generator.getDatabaseStructure().getClass() );
+ assertClassAssignability( OptimizerFactory.HiLoOptimizer.class,
generator.getOptimizer().getClass() );
+ assertEquals( 20, generator.getOptimizer().getIncrementSize() );
+ assertEquals( 20, generator.getDatabaseStructure().getIncrementSize() );
+
+ // optimizer=pooled w/ increment > 1 => hilo
+ props = buildGeneratorPropertiesBase();
+ props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.POOL );
+ props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );
+ generator = new SequenceStyleGenerator();
+ generator.configure( Hibernate.LONG, props, dialect );
+ // because the dialect reports to not support pooled seqyences, the expectation is that
we will
+ // use a table for the backing structure...
+ assertClassAssignability( TableStructure.class,
generator.getDatabaseStructure().getClass() );
+ assertClassAssignability( OptimizerFactory.PooledOptimizer.class,
generator.getOptimizer().getClass() );
+ assertEquals( 20, generator.getOptimizer().getIncrementSize() );
+ assertEquals( 20, generator.getDatabaseStructure().getIncrementSize() );
+
+ }
+
+ private static class TableDialect extends Dialect {
+ public boolean supportsSequences() {
+ return false;
+ }
+ }
+
+ private static class SequenceDialect extends Dialect {
+ public boolean supportsSequences() {
+ return true;
+ }
+ public boolean supportsPooledSequences() {
+ return false;
+ }
+ public String getSequenceNextValString(String sequenceName) throws MappingException {
+ return "";
+ }
+ }
+
+ private static class PooledSequenceDialect extends SequenceDialect {
+ public boolean supportsPooledSequences() {
+ return true;
+ }
+ }
+}
Deleted:
core/trunk/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java
===================================================================
---
core/trunk/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java 2010-05-12
15:13:03 UTC (rev 19477)
+++
core/trunk/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java 2010-05-12
15:13:47 UTC (rev 19478)
@@ -1,156 +0,0 @@
-package org.hibernate.test.idgen.enhanced;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-import org.hibernate.id.IdentifierGeneratorHelper;
-import org.hibernate.id.IntegralDataTypeHolder;
-import org.hibernate.junit.UnitTestCase;
-import org.hibernate.id.enhanced.Optimizer;
-import org.hibernate.id.enhanced.OptimizerFactory;
-import org.hibernate.id.enhanced.AccessCallback;
-
-/**
- * {@inheritDoc}
- *
- * @author Steve Ebersole
- */
-public class OptimizerUnitTest extends UnitTestCase {
- public OptimizerUnitTest(String string) {
- super( string );
- }
-
- public static Test suite() {
- return new TestSuite( OptimizerUnitTest.class );
- }
-
- 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() );
- }
-
- 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() );
- }
-
- 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() );
- }
-
- private static class SourceMock implements AccessCallback {
- private IdentifierGeneratorHelper.BasicHolder value = new
IdentifierGeneratorHelper.BasicHolder( Long.class );
- private int increment;
- private int timesCalled = 0;
-
- public SourceMock(long initialValue) {
- this( initialValue, 1 );
- }
-
- public SourceMock(long initialValue, int increment) {
- this.increment = increment;
- this.value.initialize( initialValue - increment );
- }
-
- public IntegralDataTypeHolder getNextValue() {
- timesCalled++;
- return value.add( increment ).copy();
- }
-
- public int getTimesCalled() {
- return timesCalled;
- }
-
- public long getCurrentValue() {
- return value.getActualLongValue();
- }
- }
-
-// public void testNoopDumping() {
-// SourceMock sequence = new SourceMock( 1 );
-// Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.NONE,
Long.class, 1 );
-// for ( int i = 1; i <= 41; i++ ) {
-// System.out.println( i + " => " + optimizer.generate( sequence ) +
" (" + sequence.getCurrentValue() + ")" );
-// }
-// }
-//
-// public void testHiLoDumping() {
-// int increment = 10;
-// SourceMock sequence = new SourceMock( 1 );
-// Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.HILO,
Long.class, increment );
-// for ( int i = 1; i <= 41; i++ ) {
-// System.out.println( i + " => " + optimizer.generate( sequence ) +
" (" + sequence.getCurrentValue() + ")" );
-// }
-// }
-//
-// public void testPooledDumping() {
-// int increment = 10;
-// SourceMock sequence = new SourceMock( 1, increment );
-// Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.POOL,
Long.class, increment );
-// for ( int i = 1; i <= 41; i++ ) {
-// System.out.println( i + " => " + optimizer.generate( sequence ) +
" (" + sequence.getCurrentValue() + ")" );
-// }
-// }
-
-}
Deleted:
core/trunk/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/SequenceStyleConfigUnitTest.java
===================================================================
---
core/trunk/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/SequenceStyleConfigUnitTest.java 2010-05-12
15:13:03 UTC (rev 19477)
+++
core/trunk/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/SequenceStyleConfigUnitTest.java 2010-05-12
15:13:47 UTC (rev 19478)
@@ -1,203 +0,0 @@
-package org.hibernate.test.idgen.enhanced;
-
-import java.util.Properties;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-import org.hibernate.junit.UnitTestCase;
-import org.hibernate.dialect.Dialect;
-import org.hibernate.id.enhanced.SequenceStyleGenerator;
-import org.hibernate.id.enhanced.SequenceStructure;
-import org.hibernate.id.enhanced.OptimizerFactory;
-import org.hibernate.id.enhanced.TableStructure;
-import org.hibernate.id.PersistentIdentifierGenerator;
-import org.hibernate.Hibernate;
-import org.hibernate.MappingException;
-import org.hibernate.cfg.ObjectNameNormalizer;
-import org.hibernate.cfg.NamingStrategy;
-
-/**
- * Tests that SequenceStyleGenerator configures itself as expected
- * in various scenarios
- *
- * @author Steve Ebersole
- */
-public class SequenceStyleConfigUnitTest extends UnitTestCase {
- public SequenceStyleConfigUnitTest(String string) {
- super( string );
- }
-
- public static Test suite() {
- return new TestSuite( SequenceStyleConfigUnitTest.class );
- }
-
- /**
- * Test all params defaulted with a dialect supporting sequences
- */
- public void testDefaultedSequenceBackedConfiguration() {
- Dialect dialect = new SequenceDialect();
- Properties props = buildGeneratorPropertiesBase();
- SequenceStyleGenerator generator = new SequenceStyleGenerator();
- generator.configure( Hibernate.LONG, props, dialect );
-
- assertClassAssignability( SequenceStructure.class,
generator.getDatabaseStructure().getClass() );
- assertClassAssignability( OptimizerFactory.NoopOptimizer.class,
generator.getOptimizer().getClass() );
- assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME,
generator.getDatabaseStructure().getName() );
- }
-
- private Properties buildGeneratorPropertiesBase() {
- Properties props = new Properties();
- props.put(
- PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER,
- new ObjectNameNormalizer() {
- protected boolean isUseQuotedIdentifiersGlobally() {
- return false;
- }
-
- protected NamingStrategy getNamingStrategy() {
- return null;
- }
- }
- );
- return props;
- }
-
- /**
- * Test all params defaulted with a dialect which does not support sequences
- */
- public void testDefaultedTableBackedConfiguration() {
- Dialect dialect = new TableDialect();
- Properties props = buildGeneratorPropertiesBase();
- SequenceStyleGenerator generator = new SequenceStyleGenerator();
- generator.configure( Hibernate.LONG, props, dialect );
-
- assertClassAssignability( TableStructure.class,
generator.getDatabaseStructure().getClass() );
- assertClassAssignability( OptimizerFactory.NoopOptimizer.class,
generator.getOptimizer().getClass() );
- assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME,
generator.getDatabaseStructure().getName() );
- }
-
- /**
- * Test default optimizer selection for sequence backed generators
- * based on the configured increment size; both in the case of the
- * dialect supporting pooled sequences (pooled) and not (hilo)
- */
- public void testDefaultOptimizerBasedOnIncrementBackedBySequence() {
- Properties props = buildGeneratorPropertiesBase();
- props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "10" );
-
- // for dialects which do not support pooled sequences, we default to pooled+table
- Dialect dialect = new SequenceDialect();
- SequenceStyleGenerator generator = new SequenceStyleGenerator();
- generator.configure( Hibernate.LONG, props, dialect );
- assertClassAssignability( TableStructure.class,
generator.getDatabaseStructure().getClass() );
- assertClassAssignability( OptimizerFactory.PooledOptimizer.class,
generator.getOptimizer().getClass() );
- assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME,
generator.getDatabaseStructure().getName() );
-
- // for dialects which do support pooled sequences, we default to pooled+sequence
- dialect = new PooledSequenceDialect();
- generator = new SequenceStyleGenerator();
- generator.configure( Hibernate.LONG, props, dialect );
- assertClassAssignability( SequenceStructure.class,
generator.getDatabaseStructure().getClass() );
- assertClassAssignability( OptimizerFactory.PooledOptimizer.class,
generator.getOptimizer().getClass() );
- assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME,
generator.getDatabaseStructure().getName() );
- }
-
- /**
- * Test default optimizer selection for table backed generators
- * based on the configured increment size. Here we always prefer
- * pooled.
- */
- public void testDefaultOptimizerBasedOnIncrementBackedByTable() {
- Properties props = buildGeneratorPropertiesBase();
- props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "10" );
- Dialect dialect = new TableDialect();
- SequenceStyleGenerator generator = new SequenceStyleGenerator();
- generator.configure( Hibernate.LONG, props, dialect );
- assertClassAssignability( TableStructure.class,
generator.getDatabaseStructure().getClass() );
- assertClassAssignability( OptimizerFactory.PooledOptimizer.class,
generator.getOptimizer().getClass() );
- assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME,
generator.getDatabaseStructure().getName() );
- }
-
- /**
- * Test forcing of table as backing strucuture with dialect supporting sequences
- */
- public void testForceTableUse() {
- Dialect dialect = new SequenceDialect();
- Properties props = buildGeneratorPropertiesBase();
- props.setProperty( SequenceStyleGenerator.FORCE_TBL_PARAM, "true" );
- SequenceStyleGenerator generator = new SequenceStyleGenerator();
- generator.configure( Hibernate.LONG, props, dialect );
- assertClassAssignability( TableStructure.class,
generator.getDatabaseStructure().getClass() );
- assertClassAssignability( OptimizerFactory.NoopOptimizer.class,
generator.getOptimizer().getClass() );
- assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME,
generator.getDatabaseStructure().getName() );
- }
-
- /**
- * Test explicitly specifying both optimizer and increment
- */
- public void testExplicitOptimizerWithExplicitIncrementSize() {
- // with sequence ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- final Dialect dialect = new SequenceDialect();
-
- // optimizer=none w/ increment > 1 => should honor optimizer
- Properties props = buildGeneratorPropertiesBase();
- props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.NONE );
- props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );
- SequenceStyleGenerator generator = new SequenceStyleGenerator();
- generator.configure( Hibernate.LONG, props, dialect );
- assertClassAssignability( SequenceStructure.class,
generator.getDatabaseStructure().getClass() );
- assertClassAssignability( OptimizerFactory.NoopOptimizer.class,
generator.getOptimizer().getClass() );
- assertEquals( 1, generator.getOptimizer().getIncrementSize() );
- assertEquals( 1, generator.getDatabaseStructure().getIncrementSize() );
-
- // optimizer=hilo w/ increment > 1 => hilo
- props = buildGeneratorPropertiesBase();
- props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.HILO );
- props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );
- generator = new SequenceStyleGenerator();
- generator.configure( Hibernate.LONG, props, dialect );
- assertClassAssignability( SequenceStructure.class,
generator.getDatabaseStructure().getClass() );
- assertClassAssignability( OptimizerFactory.HiLoOptimizer.class,
generator.getOptimizer().getClass() );
- assertEquals( 20, generator.getOptimizer().getIncrementSize() );
- assertEquals( 20, generator.getDatabaseStructure().getIncrementSize() );
-
- // optimizer=pooled w/ increment > 1 => hilo
- props = buildGeneratorPropertiesBase();
- props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.POOL );
- props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );
- generator = new SequenceStyleGenerator();
- generator.configure( Hibernate.LONG, props, dialect );
- // because the dialect reports to not support pooled seqyences, the expectation is that
we will
- // use a table for the backing structure...
- assertClassAssignability( TableStructure.class,
generator.getDatabaseStructure().getClass() );
- assertClassAssignability( OptimizerFactory.PooledOptimizer.class,
generator.getOptimizer().getClass() );
- assertEquals( 20, generator.getOptimizer().getIncrementSize() );
- assertEquals( 20, generator.getDatabaseStructure().getIncrementSize() );
-
- }
-
- private static class TableDialect extends Dialect {
- public boolean supportsSequences() {
- return false;
- }
- }
-
- private static class SequenceDialect extends Dialect {
- public boolean supportsSequences() {
- return true;
- }
- public boolean supportsPooledSequences() {
- return false;
- }
- public String getSequenceNextValString(String sequenceName) throws MappingException {
- return "";
- }
- }
-
- private static class PooledSequenceDialect extends SequenceDialect {
- public boolean supportsPooledSequences() {
- return true;
- }
- }
-}