From 8837a989ad08b969283aac5e796ee2d5edc7b4d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 17 Mar 2023 16:10:09 +0100 Subject: [PATCH 1/2] Move timezone default storage tests to a more precise package --- .../{ => timezone}/AbstractTimezoneDefaultStorageTest.java | 2 +- .../orm/mapping/{ => timezone}/EntityWithTimezones.java | 2 +- .../mapping/{ => timezone}/TimezoneDefaultStorageAutoTest.java | 2 +- .../{ => timezone}/TimezoneDefaultStorageColumnTest.java | 2 +- .../{ => timezone}/TimezoneDefaultStorageDefaultTest.java | 2 +- .../{ => timezone}/TimezoneDefaultStorageNativeTest.java | 2 +- .../{ => timezone}/TimezoneDefaultStorageNormalizeTest.java | 2 +- .../{ => timezone}/TimezoneDefaultStorageNormalizeUtcTest.java | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) rename extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/{ => timezone}/AbstractTimezoneDefaultStorageTest.java (97%) rename extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/{ => timezone}/EntityWithTimezones.java (91%) rename extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/{ => timezone}/TimezoneDefaultStorageAutoTest.java (97%) rename extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/{ => timezone}/TimezoneDefaultStorageColumnTest.java (97%) rename extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/{ => timezone}/TimezoneDefaultStorageDefaultTest.java (96%) rename extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/{ => timezone}/TimezoneDefaultStorageNativeTest.java (97%) rename extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/{ => timezone}/TimezoneDefaultStorageNormalizeTest.java (97%) rename extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/{ => timezone}/TimezoneDefaultStorageNormalizeUtcTest.java (97%) diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/AbstractTimezoneDefaultStorageTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/AbstractTimezoneDefaultStorageTest.java similarity index 97% rename from extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/AbstractTimezoneDefaultStorageTest.java rename to extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/AbstractTimezoneDefaultStorageTest.java index f3f09421f0d4c..06f624e21d0f1 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/AbstractTimezoneDefaultStorageTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/AbstractTimezoneDefaultStorageTest.java @@ -1,4 +1,4 @@ -package io.quarkus.hibernate.orm.mapping; +package io.quarkus.hibernate.orm.mapping.timezone; import java.time.LocalDateTime; import java.time.Month; diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/EntityWithTimezones.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/EntityWithTimezones.java similarity index 91% rename from extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/EntityWithTimezones.java rename to extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/EntityWithTimezones.java index 189993f569629..a7c9a49b16543 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/EntityWithTimezones.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/EntityWithTimezones.java @@ -1,4 +1,4 @@ -package io.quarkus.hibernate.orm.mapping; +package io.quarkus.hibernate.orm.mapping.timezone; import java.time.OffsetDateTime; import java.time.ZonedDateTime; diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageAutoTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageAutoTest.java similarity index 97% rename from extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageAutoTest.java rename to extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageAutoTest.java index d5f808b72548e..5f5c7bab0e391 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageAutoTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageAutoTest.java @@ -1,4 +1,4 @@ -package io.quarkus.hibernate.orm.mapping; +package io.quarkus.hibernate.orm.mapping.timezone; import static org.assertj.core.api.Assertions.assertThat; diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageColumnTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageColumnTest.java similarity index 97% rename from extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageColumnTest.java rename to extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageColumnTest.java index cd92cc8f94035..7418c9660a807 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageColumnTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageColumnTest.java @@ -1,4 +1,4 @@ -package io.quarkus.hibernate.orm.mapping; +package io.quarkus.hibernate.orm.mapping.timezone; import static org.assertj.core.api.Assertions.assertThat; diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageDefaultTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageDefaultTest.java similarity index 96% rename from extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageDefaultTest.java rename to extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageDefaultTest.java index cd66ccc2c1301..05cbc25ffb7d9 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageDefaultTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageDefaultTest.java @@ -1,4 +1,4 @@ -package io.quarkus.hibernate.orm.mapping; +package io.quarkus.hibernate.orm.mapping.timezone; import static org.assertj.core.api.Assertions.assertThat; diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageNativeTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageNativeTest.java similarity index 97% rename from extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageNativeTest.java rename to extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageNativeTest.java index 85641b8063d45..fba380268c441 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageNativeTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageNativeTest.java @@ -1,4 +1,4 @@ -package io.quarkus.hibernate.orm.mapping; +package io.quarkus.hibernate.orm.mapping.timezone; import static org.assertj.core.api.Assertions.assertThat; diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageNormalizeTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageNormalizeTest.java similarity index 97% rename from extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageNormalizeTest.java rename to extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageNormalizeTest.java index b1a6f0c060feb..a1ff6748b3c02 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageNormalizeTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageNormalizeTest.java @@ -1,4 +1,4 @@ -package io.quarkus.hibernate.orm.mapping; +package io.quarkus.hibernate.orm.mapping.timezone; import static org.assertj.core.api.Assertions.assertThat; diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageNormalizeUtcTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageNormalizeUtcTest.java similarity index 97% rename from extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageNormalizeUtcTest.java rename to extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageNormalizeUtcTest.java index f7c3f36624f47..83d111bd89ec2 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/TimezoneDefaultStorageNormalizeUtcTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/timezone/TimezoneDefaultStorageNormalizeUtcTest.java @@ -1,4 +1,4 @@ -package io.quarkus.hibernate.orm.mapping; +package io.quarkus.hibernate.orm.mapping.timezone; import static org.assertj.core.api.Assertions.assertThat; From ee1583d1e8d58a79f8108191c01999be95b9a2a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 17 Mar 2023 16:09:00 +0100 Subject: [PATCH 2/2] Allow configuring the default ID optimizer and default to pooled-lo --- .../HibernateOrmConfigPersistenceUnit.java | 79 ++++++++++++++++++- .../orm/deployment/HibernateOrmProcessor.java | 3 + .../io/quarkus/hibernate/orm/SchemaUtil.java | 8 ++ .../AbstractIdOptimizerDefaultTest.java | 69 ++++++++++++++++ .../optimizer/EntityWithDefaultGenerator.java | 17 ++++ .../optimizer/EntityWithGenericGenerator.java | 21 +++++ ...hGenericGeneratorAndPooledLoOptimizer.java | 23 ++++++ ...ithGenericGeneratorAndPooledOptimizer.java | 23 ++++++ .../EntityWithSequenceGenerator.java | 19 +++++ .../optimizer/EntityWithTableGenerator.java | 19 +++++ .../IdOptimizerDefaultDefaultTest.java | 25 ++++++ .../optimizer/IdOptimizerDefaultNoneTest.java | 33 ++++++++ .../IdOptimizerDefaultPooledLoTest.java | 26 ++++++ .../IdOptimizerDefaultPooledTest.java | 26 ++++++ .../compatibility/CompatibilityTest.java | 5 +- .../compatibility/CompatibilityTest.java | 5 +- 16 files changed, 398 insertions(+), 3 deletions(-) create mode 100644 extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/AbstractIdOptimizerDefaultTest.java create mode 100644 extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithDefaultGenerator.java create mode 100644 extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithGenericGenerator.java create mode 100644 extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithGenericGeneratorAndPooledLoOptimizer.java create mode 100644 extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithGenericGeneratorAndPooledOptimizer.java create mode 100644 extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithSequenceGenerator.java create mode 100644 extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithTableGenerator.java create mode 100644 extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/IdOptimizerDefaultDefaultTest.java create mode 100644 extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/IdOptimizerDefaultNoneTest.java create mode 100644 extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/IdOptimizerDefaultPooledLoTest.java create mode 100644 extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/IdOptimizerDefaultPooledTest.java diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmConfigPersistenceUnit.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmConfigPersistenceUnit.java index 8ca4ac692d8ad..3959bb5f7072f 100644 --- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmConfigPersistenceUnit.java +++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmConfigPersistenceUnit.java @@ -11,6 +11,7 @@ import java.util.Set; import org.hibernate.annotations.TimeZoneStorageType; +import org.hibernate.id.enhanced.StandardOptimizerDescriptor; import io.quarkus.runtime.annotations.ConfigDocMapKey; import io.quarkus.runtime.annotations.ConfigDocSection; @@ -381,8 +382,84 @@ public static class HibernateOrmConfigPersistenceUnitMapping { @ConfigItem(name = "timezone.default-storage", defaultValueDocumentation = "default") public Optional timeZoneDefaultStorage; + /** + * The optimizer to apply to identifier generators + * whose optimizer is not configured explicitly. + * + * Only relevant for table- and sequence-based identifier generators. + * Other generators, such as UUID-based generators, will ignore this setting. + * + * The optimizer is responsible for pooling new identifier values, + * in order to reduce the frequency of database calls to retrieve those values + * and thereby improve performance. + * + * @asciidoclet + */ + @ConfigItem(name = "id.optimizer.default", defaultValueDocumentation = "pooled-lo") + // Note this needs to be a build-time property due to + // org.hibernate.boot.internal.InFlightMetadataCollectorImpl.handleIdentifierValueBinding + // which may call (indirectly) org.hibernate.id.enhanced.SequenceStructure.buildSequence + // whose output depends on org.hibernate.id.enhanced.SequenceStructure.applyIncrementSizeToSourceValues + // which is determined by the optimizer. + public Optional idOptimizerDefault; + public boolean isAnyPropertySet() { - return timeZoneDefaultStorage.isPresent(); + return timeZoneDefaultStorage.isPresent() + || idOptimizerDefault.isPresent(); + } + + } + + public enum IdOptimizerType { + /** + * Assumes the value retrieved from the table/sequence is the lower end of the pool. + * + * Upon retrieving value `N`, the new pool of identifiers will go from `N` to `N + - 1`, inclusive. + * `pooled`:: + * Assumes the value retrieved from the table/sequence is the higher end of the pool. + * + + * Upon retrieving value `N`, the new pool of identifiers will go from `N - ` to `N + + * - 1`, inclusive. + * + + * The first value, `1`, is handled differently to avoid negative identifiers. + * + + * Use this to get the legacy behavior of Quarkus 2 / Hibernate ORM 5 or older. + * `none`:: + * No optimizer, resulting in a database call each and every time an identifier value is needed from the generator. + * + + * Not recommended in production environments: + * may result in degraded performance and/or frequent gaps in identifier values. + * + * @asciidoclet + */ + POOLED_LO(StandardOptimizerDescriptor.POOLED_LO), + /** + * Assumes the value retrieved from the table/sequence is the higher end of the pool. + * + * Upon retrieving value `N`, the new pool of identifiers will go from `N - ` to `N + + * - 1`, inclusive. + * + * The first value, `1`, is handled differently to avoid negative identifiers. + * + * Use this to get the legacy behavior of Quarkus 2 / Hibernate ORM 5 or older. + * + * @asciidoclet + */ + POOLED(StandardOptimizerDescriptor.POOLED), + /** + * No optimizer, resulting in a database call each and every time an identifier value is needed from the generator. + * + * Not recommended in production environments: + * may result in degraded performance and/or frequent gaps in identifier values. + * + * @asciidoclet + */ + NONE(StandardOptimizerDescriptor.NONE); + + public final String configName; + + IdOptimizerType(StandardOptimizerDescriptor delegate) { + configName = delegate.getExternalName(); } } diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java index 99cfa6bb50474..bf2f09ef4c3a5 100644 --- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java +++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java @@ -1022,6 +1022,9 @@ private static void producePersistenceUnitDescriptorFromConfig( descriptor.getProperties().setProperty(AvailableSettings.TIMEZONE_DEFAULT_STORAGE, persistenceUnitConfig.mapping.timeZoneDefaultStorage.get().name()); } + descriptor.getProperties().setProperty(AvailableSettings.PREFERRED_POOLED_OPTIMIZER, + persistenceUnitConfig.mapping.idOptimizerDefault + .orElse(HibernateOrmConfigPersistenceUnit.IdOptimizerType.POOLED_LO).configName); //charset descriptor.getProperties().setProperty(AvailableSettings.HBM2DDL_CHARSET_NAME, diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/SchemaUtil.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/SchemaUtil.java index d1223244e886a..e2f936ecdf31c 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/SchemaUtil.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/SchemaUtil.java @@ -7,6 +7,7 @@ import jakarta.persistence.EntityManagerFactory; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.generator.Generator; import org.hibernate.metamodel.MappingMetamodel; import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.metamodel.mapping.SelectableMapping; @@ -50,4 +51,11 @@ public void accept(int selectionIndex, SelectableMapping selectableMapping) { entityDescriptor.forEachSelectable(columnFinder); return columnFinder.found.getJdbcMapping().getJdbcType().getFriendlyName(); } + + public static Generator getGenerator(EntityManagerFactory entityManagerFactory, Class entityType) { + MappingMetamodel domainModel = entityManagerFactory + .unwrap(SessionFactoryImplementor.class).getRuntimeMetamodels().getMappingMetamodel(); + EntityPersister entityDescriptor = domainModel.findEntityDescriptor(entityType); + return entityDescriptor.getGenerator(); + } } diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/AbstractIdOptimizerDefaultTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/AbstractIdOptimizerDefaultTest.java new file mode 100644 index 0000000000000..a41e595fe1268 --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/AbstractIdOptimizerDefaultTest.java @@ -0,0 +1,69 @@ +package io.quarkus.hibernate.orm.mapping.id.optimizer; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import jakarta.inject.Inject; + +import org.assertj.core.api.AbstractObjectAssert; +import org.assertj.core.api.InstanceOfAssertFactories; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.id.OptimizableGenerator; +import org.hibernate.id.enhanced.Optimizer; +import org.hibernate.id.enhanced.PooledLoOptimizer; +import org.hibernate.id.enhanced.PooledOptimizer; +import org.junit.jupiter.api.Test; + +import io.quarkus.hibernate.orm.SchemaUtil; +import io.quarkus.narayana.jta.QuarkusTransaction; + +public abstract class AbstractIdOptimizerDefaultTest { + + @Inject + SessionFactory sessionFactory; + + @Inject + Session session; + + abstract Class defaultOptimizerType(); + + @Test + public void defaults() { + assertThat(List.of( + EntityWithDefaultGenerator.class, + EntityWithGenericGenerator.class, + EntityWithSequenceGenerator.class, + EntityWithTableGenerator.class)) + .allSatisfy(c -> assertOptimizer(c).isInstanceOf(defaultOptimizerType())); + } + + @Test + public void explicitOverrides() { + assertOptimizer(EntityWithGenericGeneratorAndPooledOptimizer.class) + .isInstanceOf(PooledOptimizer.class); + assertOptimizer(EntityWithGenericGeneratorAndPooledLoOptimizer.class) + .isInstanceOf(PooledLoOptimizer.class); + } + + @Test + public void ids() { + for (long i = 1; i <= 51; i++) { + assertThat(QuarkusTransaction.requiringNew().call(() -> { + var entity = new EntityWithSequenceGenerator(); + session.persist(entity); + return entity.id; + })) + .isEqualTo(i); + } + } + + AbstractObjectAssert assertOptimizer(Class entityType) { + return assertThat(SchemaUtil.getGenerator(sessionFactory, entityType)) + .as("ID generator for entity type " + entityType.getSimpleName()) + .asInstanceOf(InstanceOfAssertFactories.type(OptimizableGenerator.class)) + .extracting(OptimizableGenerator::getOptimizer) + .as("ID optimizer for entity type " + entityType.getSimpleName()); + } +} diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithDefaultGenerator.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithDefaultGenerator.java new file mode 100644 index 0000000000000..edbb3ad6c5efa --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithDefaultGenerator.java @@ -0,0 +1,17 @@ +package io.quarkus.hibernate.orm.mapping.id.optimizer; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; + +@Entity +public class EntityWithDefaultGenerator { + + @Id + @GeneratedValue + Long id; + + public EntityWithDefaultGenerator() { + } + +} diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithGenericGenerator.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithGenericGenerator.java new file mode 100644 index 0000000000000..28e905a0c1a58 --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithGenericGenerator.java @@ -0,0 +1,21 @@ +package io.quarkus.hibernate.orm.mapping.id.optimizer; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; + +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.id.enhanced.SequenceStyleGenerator; + +@Entity +public class EntityWithGenericGenerator { + + @Id + @GeneratedValue(generator = "gen_gen") + @GenericGenerator(name = "gen_gen", type = SequenceStyleGenerator.class) + Long id; + + public EntityWithGenericGenerator() { + } + +} diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithGenericGeneratorAndPooledLoOptimizer.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithGenericGeneratorAndPooledLoOptimizer.java new file mode 100644 index 0000000000000..4104926d0d767 --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithGenericGeneratorAndPooledLoOptimizer.java @@ -0,0 +1,23 @@ +package io.quarkus.hibernate.orm.mapping.id.optimizer; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; + +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.Parameter; +import org.hibernate.id.OptimizableGenerator; +import org.hibernate.id.enhanced.SequenceStyleGenerator; + +@Entity +public class EntityWithGenericGeneratorAndPooledLoOptimizer { + + @Id + @GeneratedValue(generator = "gen_gen_pooled_lo") + @GenericGenerator(name = "gen_gen_pooled_lo", type = SequenceStyleGenerator.class, parameters = @Parameter(name = OptimizableGenerator.OPT_PARAM, value = "pooled-lo")) + Long id; + + public EntityWithGenericGeneratorAndPooledLoOptimizer() { + } + +} diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithGenericGeneratorAndPooledOptimizer.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithGenericGeneratorAndPooledOptimizer.java new file mode 100644 index 0000000000000..ab08b1d857c0e --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithGenericGeneratorAndPooledOptimizer.java @@ -0,0 +1,23 @@ +package io.quarkus.hibernate.orm.mapping.id.optimizer; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; + +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.Parameter; +import org.hibernate.id.OptimizableGenerator; +import org.hibernate.id.enhanced.SequenceStyleGenerator; + +@Entity +public class EntityWithGenericGeneratorAndPooledOptimizer { + + @Id + @GeneratedValue(generator = "gen_gen_pooled_lo") + @GenericGenerator(name = "gen_gen_pooled_lo", type = SequenceStyleGenerator.class, parameters = @Parameter(name = OptimizableGenerator.OPT_PARAM, value = "pooled")) + Long id; + + public EntityWithGenericGeneratorAndPooledOptimizer() { + } + +} diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithSequenceGenerator.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithSequenceGenerator.java new file mode 100644 index 0000000000000..02ba281ec0323 --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithSequenceGenerator.java @@ -0,0 +1,19 @@ +package io.quarkus.hibernate.orm.mapping.id.optimizer; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.SequenceGenerator; + +@Entity +public class EntityWithSequenceGenerator { + + @Id + @GeneratedValue(generator = "seq_gen") + @SequenceGenerator(name = "seq_gen") + Long id; + + public EntityWithSequenceGenerator() { + } + +} diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithTableGenerator.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithTableGenerator.java new file mode 100644 index 0000000000000..09d4c9d86b1dc --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/EntityWithTableGenerator.java @@ -0,0 +1,19 @@ +package io.quarkus.hibernate.orm.mapping.id.optimizer; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.TableGenerator; + +@Entity +public class EntityWithTableGenerator { + + @Id + @GeneratedValue(generator = "tab_gen") + @TableGenerator(name = "tab_gen") + Long id; + + public EntityWithTableGenerator() { + } + +} diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/IdOptimizerDefaultDefaultTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/IdOptimizerDefaultDefaultTest.java new file mode 100644 index 0000000000000..2588cbe2e8933 --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/IdOptimizerDefaultDefaultTest.java @@ -0,0 +1,25 @@ +package io.quarkus.hibernate.orm.mapping.id.optimizer; + +import org.hibernate.id.enhanced.PooledLoOptimizer; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.hibernate.orm.SchemaUtil; +import io.quarkus.test.QuarkusUnitTest; + +public class IdOptimizerDefaultDefaultTest extends AbstractIdOptimizerDefaultTest { + + @RegisterExtension + static QuarkusUnitTest TEST = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(EntityWithDefaultGenerator.class, EntityWithGenericGenerator.class, + EntityWithSequenceGenerator.class, EntityWithTableGenerator.class, + EntityWithGenericGeneratorAndPooledOptimizer.class, + EntityWithGenericGeneratorAndPooledLoOptimizer.class) + .addClasses(SchemaUtil.class)) + .withConfigurationResource("application.properties"); + + @Override + Class defaultOptimizerType() { + return PooledLoOptimizer.class; + } +} diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/IdOptimizerDefaultNoneTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/IdOptimizerDefaultNoneTest.java new file mode 100644 index 0000000000000..01c1f2359bce7 --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/IdOptimizerDefaultNoneTest.java @@ -0,0 +1,33 @@ +package io.quarkus.hibernate.orm.mapping.id.optimizer; + +import org.hibernate.id.enhanced.NoopOptimizer; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.hibernate.orm.SchemaUtil; +import io.quarkus.test.QuarkusUnitTest; + +public class IdOptimizerDefaultNoneTest extends AbstractIdOptimizerDefaultTest { + + @RegisterExtension + static QuarkusUnitTest TEST = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(EntityWithDefaultGenerator.class, EntityWithGenericGenerator.class, + EntityWithSequenceGenerator.class, EntityWithTableGenerator.class, + EntityWithGenericGeneratorAndPooledOptimizer.class, + EntityWithGenericGeneratorAndPooledLoOptimizer.class) + .addClasses(SchemaUtil.class)) + .withConfigurationResource("application.properties") + .overrideConfigKey("quarkus.hibernate-orm.mapping.id.optimizer.default", "none"); + + @Override + @Disabled("The 'none' optimizer will produce a different stream of IDs (1 then 51 then 101 then ...)") + public void ids() { + super.ids(); + } + + @Override + Class defaultOptimizerType() { + return NoopOptimizer.class; + } +} diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/IdOptimizerDefaultPooledLoTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/IdOptimizerDefaultPooledLoTest.java new file mode 100644 index 0000000000000..ac8b6ff722a29 --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/IdOptimizerDefaultPooledLoTest.java @@ -0,0 +1,26 @@ +package io.quarkus.hibernate.orm.mapping.id.optimizer; + +import org.hibernate.id.enhanced.PooledLoOptimizer; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.hibernate.orm.SchemaUtil; +import io.quarkus.test.QuarkusUnitTest; + +public class IdOptimizerDefaultPooledLoTest extends AbstractIdOptimizerDefaultTest { + + @RegisterExtension + static QuarkusUnitTest TEST = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(EntityWithDefaultGenerator.class, EntityWithGenericGenerator.class, + EntityWithSequenceGenerator.class, EntityWithTableGenerator.class, + EntityWithGenericGeneratorAndPooledOptimizer.class, + EntityWithGenericGeneratorAndPooledLoOptimizer.class) + .addClasses(SchemaUtil.class)) + .withConfigurationResource("application.properties") + .overrideConfigKey("quarkus.hibernate-orm.mapping.id.optimizer.default", "pooled-lo"); + + @Override + Class defaultOptimizerType() { + return PooledLoOptimizer.class; + } +} diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/IdOptimizerDefaultPooledTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/IdOptimizerDefaultPooledTest.java new file mode 100644 index 0000000000000..219c4905300c4 --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/mapping/id/optimizer/IdOptimizerDefaultPooledTest.java @@ -0,0 +1,26 @@ +package io.quarkus.hibernate.orm.mapping.id.optimizer; + +import org.hibernate.id.enhanced.PooledOptimizer; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.hibernate.orm.SchemaUtil; +import io.quarkus.test.QuarkusUnitTest; + +public class IdOptimizerDefaultPooledTest extends AbstractIdOptimizerDefaultTest { + + @RegisterExtension + static QuarkusUnitTest TEST = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(EntityWithDefaultGenerator.class, EntityWithGenericGenerator.class, + EntityWithSequenceGenerator.class, EntityWithTableGenerator.class, + EntityWithGenericGeneratorAndPooledOptimizer.class, + EntityWithGenericGeneratorAndPooledLoOptimizer.class) + .addClasses(SchemaUtil.class)) + .withConfigurationResource("application.properties") + .overrideConfigKey("quarkus.hibernate-orm.mapping.id.optimizer.default", "pooled"); + + @Override + Class defaultOptimizerType() { + return PooledOptimizer.class; + } +} diff --git a/integration-tests/hibernate-orm-compatibility-5.6/mariadb/src/test/java/io/quarkus/it/hibernate/compatibility/CompatibilityTest.java b/integration-tests/hibernate-orm-compatibility-5.6/mariadb/src/test/java/io/quarkus/it/hibernate/compatibility/CompatibilityTest.java index 6bf66a479147b..1eeb9d17b22eb 100644 --- a/integration-tests/hibernate-orm-compatibility-5.6/mariadb/src/test/java/io/quarkus/it/hibernate/compatibility/CompatibilityTest.java +++ b/integration-tests/hibernate-orm-compatibility-5.6/mariadb/src/test/java/io/quarkus/it/hibernate/compatibility/CompatibilityTest.java @@ -65,7 +65,10 @@ public void sequence_sequenceGenerator_defaultAllocation() { .extract().as(MyEntityWithSequenceGeneratorAndDefaultAllocationSize.class); // Sequence generators defined through @SequenceGenerator have always defaulted to an allocation size of 50. // Since we've created 2 entities in Hibernate 5, we should be starting the second pool here, starting at 52. - assertThat(createdEntity.id).isEqualTo(52L); + // BUT! Quarkus 3 changes the default ID optimizer to pooled-lo, + // which means we'll interpret the value returned by the sequence (101) as the *start* of the pool + // instead of the *end* of the pool. That's an expected change and should be harmless. + assertThat(createdEntity.id).isEqualTo(101L); } // Just check that persisting with the old schema and new application does not throw any exception diff --git a/integration-tests/hibernate-orm-compatibility-5.6/postgresql/src/test/java/io/quarkus/it/hibernate/compatibility/CompatibilityTest.java b/integration-tests/hibernate-orm-compatibility-5.6/postgresql/src/test/java/io/quarkus/it/hibernate/compatibility/CompatibilityTest.java index 19fa1ec2e5a20..db221702032b8 100644 --- a/integration-tests/hibernate-orm-compatibility-5.6/postgresql/src/test/java/io/quarkus/it/hibernate/compatibility/CompatibilityTest.java +++ b/integration-tests/hibernate-orm-compatibility-5.6/postgresql/src/test/java/io/quarkus/it/hibernate/compatibility/CompatibilityTest.java @@ -65,7 +65,10 @@ public void sequence_sequenceGenerator_defaultAllocation() { .extract().as(MyEntityWithSequenceGeneratorAndDefaultAllocationSize.class); // Sequence generators defined through @SequenceGenerator have always defaulted to an allocation size of 50. // Since we've created 2 entities in Hibernate 5, we should be starting the second pool here, starting at 52. - assertThat(createdEntity.id).isEqualTo(52L); + // BUT! Quarkus 3 changes the default ID optimizer to pooled-lo, + // which means we'll interpret the value returned by the sequence (101) as the *start* of the pool + // instead of the *end* of the pool. That's an expected change and should be harmless. + assertThat(createdEntity.id).isEqualTo(101L); } // Just check that persisting with the old schema and new application does not throw any exception