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; return enabledCascadingFetchProfile;
} }
public boolean hasEnabledCascadingFetchProfile() {
return enabledCascadingFetchProfile != null;
}
/** /**
* Set the effective {@linkplain #getEnabledCascadingFetchProfile() cascading fetch-profile} * Set the effective {@linkplain #getEnabledCascadingFetchProfile() cascading fetch-profile}
*/ */

View File

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

View File

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