clean up the code in SingleIdEntityLoaderStandardImpl

and remove an AtomicInteger that existed only for the benefit of LoadingSmokeTests
This commit is contained in:
Gavin 2023-05-25 16:55:35 +02:00 committed by Gavin King
parent ecbcc2d940
commit afc97ac6c9
3 changed files with 74 additions and 81 deletions

View File

@ -111,6 +111,10 @@ public class LoadQueryInfluencers implements Serializable {
return enabledCascadingFetchProfile;
}
public boolean hasEnabledCascadingFetchProfile() {
return enabledCascadingFetchProfile != null;
}
/**
* Set the effective {@linkplain #getEnabledCascadingFetchProfile() cascading fetch-profile}
*/

View File

@ -6,10 +6,7 @@
*/
package org.hibernate.loader.ast.internal;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.hibernate.Internal;
import org.hibernate.LockMode;
@ -19,9 +16,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.ast.spi.CascadingFetchProfile;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.exec.spi.JdbcParametersList;
/**
@ -30,22 +25,17 @@ import org.hibernate.sql.exec.spi.JdbcParametersList;
* @author Steve Ebersole
*/
public class SingleIdEntityLoaderStandardImpl<T> extends SingleIdEntityLoaderSupport<T> {
private EnumMap<LockMode, SingleIdLoadPlan> selectByLockMode = new EnumMap<>( LockMode.class );
private EnumMap<CascadingFetchProfile, SingleIdLoadPlan> selectByInternalCascadeProfile;
private AtomicInteger nonReusablePlansGenerated = new AtomicInteger();
public AtomicInteger getNonReusablePlansGenerated() {
return nonReusablePlansGenerated;
}
private final EnumMap<LockMode, SingleIdLoadPlan<T>> selectByLockMode = new EnumMap<>( LockMode.class );
private EnumMap<CascadingFetchProfile, SingleIdLoadPlan<T>> selectByInternalCascadeProfile;
public SingleIdEntityLoaderStandardImpl(
EntityMappingType entityDescriptor,
SessionFactoryImplementor sessionFactory) {
// todo (6.0) : consider creating a base AST and "cloning" it
super( entityDescriptor, sessionFactory );
// see `org.hibernate.persister.entity.AbstractEntityPersister#createLoaders`
// we should pre-load a few - maybe LockMode.NONE and LockMode.READ
// see org.hibernate.persister.entity.AbstractEntityPersister#createLoaders
// we should preload a few - maybe LockMode.NONE and LockMode.READ
final LockOptions lockOptions = LockOptions.NONE;
final LoadQueryInfluencers queryInfluencers = new LoadQueryInfluencers( sessionFactory );
final SingleIdLoadPlan<T> plan = createLoadPlan(
@ -53,7 +43,7 @@ public class SingleIdEntityLoaderStandardImpl<T> extends SingleIdEntityLoaderSup
queryInfluencers,
sessionFactory
);
if ( determineIfReusable( lockOptions, queryInfluencers ) ) {
if ( isLoadPlanReusable( lockOptions, queryInfluencers ) ) {
selectByLockMode.put( lockOptions.getLockMode(), plan );
}
}
@ -65,7 +55,6 @@ public class SingleIdEntityLoaderStandardImpl<T> extends SingleIdEntityLoaderSup
session.getLoadQueryInfluencers(),
session.getFactory()
);
return loadPlan.load( key, readOnly, true, session );
}
@ -81,7 +70,6 @@ public class SingleIdEntityLoaderStandardImpl<T> extends SingleIdEntityLoaderSup
session.getLoadQueryInfluencers(),
session.getFactory()
);
return loadPlan.load( key, entityInstance, readOnly, false, session );
}
@ -90,81 +78,89 @@ public class SingleIdEntityLoaderStandardImpl<T> extends SingleIdEntityLoaderSup
LockOptions lockOptions,
LoadQueryInfluencers loadQueryInfluencers,
SessionFactoryImplementor sessionFactory) {
if ( getLoadable().isAffectedByEnabledFilters( loadQueryInfluencers ) ) {
// special case of not-cacheable based on enabled filters effecting this load.
//
// This case is special because the filters need to be applied in order to
// properly restrict the SQL/JDBC results. For this reason it has higher
// precedence than even "internal" fetch profiles.
nonReusablePlansGenerated.incrementAndGet();
// properly restrict the SQL/JDBC results. For this reason it has higher
// precedence than even "internal" fetch profiles.
return createLoadPlan( lockOptions, loadQueryInfluencers, sessionFactory );
}
else if ( loadQueryInfluencers.hasEnabledCascadingFetchProfile()
&& LockMode.WRITE.greaterThan( lockOptions.getLockMode() ) ) {
return getInternalCascadeLoadPlan(
lockOptions,
loadQueryInfluencers,
sessionFactory
);
}
else {
// otherwise see if the loader for the requested load can be cached,
// which also means we should look in the cache for an existing one
return getRegularLoadPlan(
lockOptions,
loadQueryInfluencers,
sessionFactory
);
}
}
final CascadingFetchProfile enabledCascadingFetchProfile = loadQueryInfluencers.getEnabledCascadingFetchProfile();
if ( enabledCascadingFetchProfile != null ) {
if ( LockMode.WRITE.greaterThan( lockOptions.getLockMode() ) ) {
if ( selectByInternalCascadeProfile == null ) {
selectByInternalCascadeProfile = new EnumMap<>( CascadingFetchProfile.class );
}
else {
final SingleIdLoadPlan existing = selectByInternalCascadeProfile.get( enabledCascadingFetchProfile );
if ( existing != null ) {
//noinspection unchecked
return existing;
}
}
private SingleIdLoadPlan<T> getRegularLoadPlan(
LockOptions lockOptions,
LoadQueryInfluencers loadQueryInfluencers,
SessionFactoryImplementor sessionFactory) {
if ( isLoadPlanReusable( lockOptions, loadQueryInfluencers ) ) {
final SingleIdLoadPlan<T> existing = selectByLockMode.get( lockOptions.getLockMode() );
if ( existing != null ) {
return existing;
}
else {
final SingleIdLoadPlan<T> plan = createLoadPlan(
lockOptions,
loadQueryInfluencers,
sessionFactory
);
selectByInternalCascadeProfile.put( enabledCascadingFetchProfile, plan );
selectByLockMode.put( lockOptions.getLockMode(), plan );
return plan;
}
}
// otherwise see if the loader for the requested load can be cached - which
// also means we should look in the cache for an existing one
final boolean reusable = determineIfReusable( lockOptions, loadQueryInfluencers );
if ( reusable ) {
final SingleIdLoadPlan existing = selectByLockMode.get( lockOptions.getLockMode() );
if ( existing != null ) {
//noinspection unchecked
return existing;
}
final SingleIdLoadPlan<T> plan = createLoadPlan(
lockOptions,
loadQueryInfluencers,
sessionFactory
);
selectByLockMode.put( lockOptions.getLockMode(), plan );
return plan;
else {
return createLoadPlan(lockOptions, loadQueryInfluencers, sessionFactory);
}
nonReusablePlansGenerated.incrementAndGet();
return createLoadPlan( lockOptions, loadQueryInfluencers, sessionFactory );
}
private boolean determineIfReusable(LockOptions lockOptions, LoadQueryInfluencers loadQueryInfluencers) {
if ( getLoadable().isAffectedByEntityGraph( loadQueryInfluencers ) ) {
return false;
private SingleIdLoadPlan<T> getInternalCascadeLoadPlan(
LockOptions lockOptions,
LoadQueryInfluencers loadQueryInfluencers,
SessionFactoryImplementor sessionFactory) {
final CascadingFetchProfile fetchProfile =
loadQueryInfluencers.getEnabledCascadingFetchProfile();
if ( selectByInternalCascadeProfile == null ) {
selectByInternalCascadeProfile = new EnumMap<>( CascadingFetchProfile.class );
}
else {
final SingleIdLoadPlan<T> existing =
selectByInternalCascadeProfile.get( fetchProfile );
if ( existing != null ) {
return existing;
}
}
if ( getLoadable().isAffectedByEnabledFetchProfiles( loadQueryInfluencers ) ) {
return false;
}
final SingleIdLoadPlan<T> plan = createLoadPlan(
lockOptions,
loadQueryInfluencers,
sessionFactory
);
selectByInternalCascadeProfile.put( fetchProfile, plan );
return plan;
}
//noinspection RedundantIfStatement
if ( lockOptions.getTimeOut() != LockOptions.WAIT_FOREVER ) {
return false;
}
return true;
private boolean isLoadPlanReusable(LockOptions lockOptions, LoadQueryInfluencers loadQueryInfluencers) {
return lockOptions.getTimeOut() == LockOptions.WAIT_FOREVER
&& !getLoadable().isAffectedByEntityGraph( loadQueryInfluencers )
&& !getLoadable().isAffectedByEnabledFetchProfiles( loadQueryInfluencers );
}
private SingleIdLoadPlan<T> createLoadPlan(
@ -173,7 +169,6 @@ public class SingleIdEntityLoaderStandardImpl<T> extends SingleIdEntityLoaderSup
SessionFactoryImplementor sessionFactory) {
final JdbcParametersList.Builder jdbcParametersBuilder = JdbcParametersList.newBuilder();
final SelectStatement sqlAst = LoaderSelectBuilder.createSelect(
getLoadable(),
// null here means to select everything
@ -186,13 +181,11 @@ public class SingleIdEntityLoaderStandardImpl<T> extends SingleIdEntityLoaderSup
jdbcParametersBuilder::add,
sessionFactory
);
final JdbcParametersList jdbcParameters = jdbcParametersBuilder.build();
return new SingleIdLoadPlan<>(
(Loadable) getLoadable(),
getLoadable(),
getLoadable().getIdentifierMapping(),
sqlAst,
jdbcParameters,
jdbcParametersBuilder.build(),
lockOptions,
sessionFactory
);

View File

@ -62,10 +62,6 @@ public class LoadingSmokeTests {
final SingleIdEntityLoader singleIdEntityLoader = entityDescriptor.getSingleIdLoader();
assertThat( singleIdEntityLoader, instanceOf( SingleIdEntityLoaderStandardImpl.class ) );
assertThat(
( (SingleIdEntityLoaderStandardImpl) singleIdEntityLoader ).getNonReusablePlansGenerated().get(),
is( 0 )
);
}
);
}