HHH-15976 Introduce InitializersList helper and optimise Row processing

This commit is contained in:
Sanne Grinovero 2023-01-04 13:07:40 +01:00 committed by Sanne Grinovero
parent e1ecf734c2
commit 04becd0aa4
6 changed files with 188 additions and 82 deletions

View File

@ -0,0 +1,153 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.results.graph.Initializer;
import org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchInitializer;
import org.hibernate.sql.results.graph.entity.internal.EntitySelectFetchInitializer;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
/**
* Internal helper to keep track of the various
* Initializer instances being used during RowReader processing:
* different types of initializers need to be invoked in different orders,
* so rather than finding them during each row we keep separated lists
* of initializers defined upfront and then reused for the scope of the whole
* resultset.
*/
public final class InitializersList {
private final List<Initializer> initializers;
private final List<Initializer> collectionInitializers;
private final List<Initializer> nonCollectionInitializers;
private final List<Initializer> resolveInstanceFirstInitializers;
private final List<Initializer> resolveInstanceLaterInitializers;
private final boolean hasCollectionInitializers;
private final Map<NavigablePath, Initializer> initializerMap;
private InitializersList(
List<Initializer> initializers,
List<Initializer> collectionInitializers,
List<Initializer> nonCollectionInitializers,
List<Initializer> resolveInstanceFirstInitializers,
List<Initializer> resolveInstanceLaterInitializers,
Map<NavigablePath, Initializer> initializerMap) {
this.initializers = initializers;
this.collectionInitializers = collectionInitializers;
this.nonCollectionInitializers = nonCollectionInitializers;
this.resolveInstanceFirstInitializers = resolveInstanceFirstInitializers;
this.resolveInstanceLaterInitializers = resolveInstanceLaterInitializers;
this.hasCollectionInitializers = ! collectionInitializers.isEmpty();
this.initializerMap = initializerMap;
}
@Deprecated //for simpler migration to the new SPI
public List<Initializer> asList() {
return initializers;
}
public Initializer resolveInitializer(final NavigablePath path) {
return initializerMap.get( path );
}
public void finishUpRow(final RowProcessingState rowProcessingState) {
for ( Initializer init : initializers ) {
init.finishUpRow( rowProcessingState );
}
}
public void initializeInstance(final RowProcessingState rowProcessingState) {
for ( Initializer init : initializers ) {
init.initializeInstance( rowProcessingState );
}
}
public void endLoading(final ExecutionContext executionContext) {
for ( Initializer initializer : initializers ) {
initializer.endLoading( executionContext );
}
}
public void resolveKeys(final RowProcessingState rowProcessingState) {
for ( Initializer init : nonCollectionInitializers ) {
init.resolveKey( rowProcessingState );
}
for ( Initializer init : collectionInitializers ) {
init.resolveKey( rowProcessingState );
}
}
public void resolveInstances(final RowProcessingState rowProcessingState) {
for ( Initializer init : resolveInstanceFirstInitializers ) {
init.resolveInstance( rowProcessingState );
}
for ( Initializer init : resolveInstanceLaterInitializers ) {
init.resolveInstance( rowProcessingState );
}
}
public boolean hasCollectionInitializers() {
return this.hasCollectionInitializers;
}
static class Builder {
private List<Initializer> initializers = new ArrayList<>();
private List<Initializer> collectionInitializers;
private List<Initializer> nonCollectionInitializers;
private List<Initializer> resolveInstanceFirstInitializers;
private List<Initializer> resolveInstanceLaterInitializers;
public Builder() {}
public void addInitializer(Initializer initializer) {
initializers.add( initializer );
if ( initializer.isCollectionInitializer() ) {
if ( collectionInitializers == null ) {
collectionInitializers = new ArrayList<>();
}
collectionInitializers.add( initializer );
}
else {
if ( nonCollectionInitializers == null ) {
nonCollectionInitializers = new ArrayList<>();
}
nonCollectionInitializers.add( initializer );
}
if ( !( initializer instanceof EntityDelayedFetchInitializer ) && ! (initializer instanceof EntitySelectFetchInitializer ) ) {
if ( resolveInstanceFirstInitializers == null ) {
resolveInstanceFirstInitializers = new ArrayList<>();
}
resolveInstanceFirstInitializers.add( initializer );
}
else {
if ( resolveInstanceLaterInitializers == null ) {
resolveInstanceLaterInitializers = new ArrayList<>();
}
resolveInstanceLaterInitializers.add( initializer );
}
}
InitializersList build(Map<NavigablePath, Initializer> initializerMap) {
return new InitializersList(
initializers,
collectionInitializers == null ? Collections.EMPTY_LIST : collectionInitializers,
nonCollectionInitializers == null ? Collections.EMPTY_LIST : nonCollectionInitializers,
resolveInstanceFirstInitializers == null ? Collections.EMPTY_LIST : resolveInstanceFirstInitializers,
resolveInstanceLaterInitializers == null ? Collections.EMPTY_LIST : resolveInstanceLaterInitializers,
initializerMap
);
}
}
}

View File

@ -73,7 +73,7 @@ public class ResultsHelper {
final SessionFactoryImplementor sessionFactory = executionContext.getSession().getFactory();
final Map<NavigablePath, Initializer> initializerMap = new LinkedHashMap<>();
final List<Initializer> initializers = new ArrayList<>();
final InitializersList.Builder initializersBuilder = new InitializersList.Builder();
final List<DomainResultAssembler<?>> assemblers = jdbcValuesMapping.resolveAssemblers(
new AssemblerCreationState() {
@ -112,7 +112,7 @@ public class ResultsHelper {
);
initializerMap.put( navigablePath, initializer );
initializers.add( initializer );
initializersBuilder.addInitializer( initializer );
return initializer;
}
@ -126,7 +126,9 @@ public class ResultsHelper {
logInitializers( initializerMap );
return new StandardRowReader<>( assemblers, initializers, rowTransformer, transformedResultJavaType );
final InitializersList initializersList = initializersBuilder.build( initializerMap );
return new StandardRowReader<>( assemblers, initializersList, rowTransformer, transformedResultJavaType );
}
private static void logInitializers(Map<NavigablePath, Initializer> initializerMap) {

View File

@ -6,8 +6,6 @@
*/
package org.hibernate.sql.results.internal;
import java.util.List;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.spi.NavigablePath;
import org.hibernate.query.spi.QueryOptions;
@ -28,16 +26,14 @@ import org.hibernate.sql.results.spi.RowReader;
* Standard RowProcessingState implementation
*/
public class RowProcessingStateStandardImpl extends BaseExecutionContext implements RowProcessingState {
private static final Initializer[] NO_INITIALIZERS = new Initializer[0];
private final JdbcValuesSourceProcessingStateStandardImpl resultSetProcessingState;
private final Initializer[] initializers;
private final InitializersList initializers;
private final RowReader<?> rowReader;
private final JdbcValues jdbcValues;
private final ExecutionContext executionContext;
public final boolean hasCollectionInitializers;
public RowProcessingStateStandardImpl(
JdbcValuesSourceProcessingStateStandardImpl resultSetProcessingState,
@ -49,30 +45,7 @@ public class RowProcessingStateStandardImpl extends BaseExecutionContext impleme
this.executionContext = executionContext;
this.rowReader = rowReader;
this.jdbcValues = jdbcValues;
final List<Initializer> initializers = rowReader.getInitializers();
if ( initializers == null || initializers.isEmpty() ) {
this.initializers = NO_INITIALIZERS;
hasCollectionInitializers = false;
}
else {
//noinspection ToArrayCallWithZeroLengthArrayArgument
this.initializers = initializers.toArray( new Initializer[initializers.size()] );
hasCollectionInitializers = hasCollectionInitializers(this.initializers);
}
}
private static boolean hasCollectionInitializers(Initializer[] initializers) {
for ( int i = 0; i < initializers.length; i++ ) {
if ( initializers[i].isCollectionInitializer() ) {
return true;
}
}
return false;
}
public boolean hasCollectionInitializers(){
return this.hasCollectionInitializers;
this.initializers = rowReader.getInitializersList();
}
@Override
@ -177,12 +150,10 @@ public class RowProcessingStateStandardImpl extends BaseExecutionContext impleme
@Override
public Initializer resolveInitializer(NavigablePath path) {
for ( Initializer initializer : initializers ) {
if ( initializer.getNavigablePath().equals( path ) ) {
return initializer;
}
}
return this.initializers.resolveInitializer( path );
}
return null;
public boolean hasCollectionInitializers() {
return this.initializers.hasCollectionInitializers();
}
}

View File

@ -15,8 +15,6 @@ import org.hibernate.query.named.RowReaderMemento;
import org.hibernate.sql.results.LoadingLogger;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.Initializer;
import org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchInitializer;
import org.hibernate.sql.results.graph.entity.internal.EntitySelectFetchInitializer;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
@ -30,7 +28,7 @@ import org.hibernate.type.descriptor.java.JavaType;
@SuppressWarnings("rawtypes")
public class StandardRowReader<T> implements RowReader<T> {
private final List<DomainResultAssembler<?>> resultAssemblers;
private final List<Initializer> initializers;
private final InitializersList initializers;
private final RowTransformer<T> rowTransformer;
private final Class<T> domainResultJavaType;
@ -38,7 +36,7 @@ public class StandardRowReader<T> implements RowReader<T> {
public StandardRowReader(
List<DomainResultAssembler<?>> resultAssemblers,
List<Initializer> initializers,
InitializersList initializers,
RowTransformer<T> rowTransformer,
Class<T> domainResultJavaType) {
this.resultAssemblers = resultAssemblers;
@ -72,7 +70,13 @@ public class StandardRowReader<T> implements RowReader<T> {
}
@Override
@Deprecated
public List<Initializer> getInitializers() {
return initializers.asList();
}
@Override
public InitializersList getInitializersList() {
return initializers;
}
@ -97,54 +101,20 @@ public class StandardRowReader<T> implements RowReader<T> {
private void afterRow(RowProcessingState rowProcessingState) {
LoadingLogger.LOGGER.trace( "StandardRowReader#afterRow" );
initializers.forEach( initializer -> initializer.finishUpRow( rowProcessingState ) );
initializers.finishUpRow( rowProcessingState );
}
@SuppressWarnings("ForLoopReplaceableByForEach")
private void coordinateInitializers(RowProcessingState rowProcessingState) {
final int numberOfInitializers = initializers.size();
for ( int i = 0; i < numberOfInitializers; i++ ) {
final Initializer initializer = initializers.get( i );
if ( ! initializer.isCollectionInitializer() ) {
initializer.resolveKey( rowProcessingState );
}
}
for ( int i = 0; i < numberOfInitializers; i++ ) {
final Initializer initializer = initializers.get( i );
if ( initializer.isCollectionInitializer() ) {
initializer.resolveKey( rowProcessingState );
}
}
for ( int i = 0; i < numberOfInitializers; i++ ) {
Initializer initializer = initializers.get( i );
if ( !( initializer instanceof EntityDelayedFetchInitializer ) && ! (initializer instanceof EntitySelectFetchInitializer ) ) {
initializer.resolveInstance( rowProcessingState );
}
}
for ( int i = 0; i < numberOfInitializers; i++ ) {
Initializer initializer = initializers.get( i );
if ( initializer instanceof EntityDelayedFetchInitializer || initializer instanceof EntitySelectFetchInitializer ) {
initializer.resolveInstance( rowProcessingState );
}
}
for ( int i = 0; i < numberOfInitializers; i++ ) {
initializers.get( i ).initializeInstance( rowProcessingState );
}
initializers.resolveKeys( rowProcessingState );
initializers.resolveInstances( rowProcessingState );
initializers.initializeInstance( rowProcessingState );
}
@Override
@SuppressWarnings("ForLoopReplaceableByForEach")
public void finishUp(JdbcValuesSourceProcessingState processingState) {
for ( int i = 0; i < initializers.size(); i++ ) {
initializers.get( i ).endLoading( processingState.getExecutionContext() );
}
initializers.endLoading( processingState.getExecutionContext() );
}
@Override

View File

@ -172,7 +172,7 @@ public class ListResultsConsumer<R> implements ResultsConsumer<List<R>, R> {
}
if ( this.uniqueSemantic == UniqueSemantic.FILTER
|| this.uniqueSemantic == UniqueSemantic.ASSERT && rowProcessingState.hasCollectionInitializers
|| this.uniqueSemantic == UniqueSemantic.ASSERT && rowProcessingState.hasCollectionInitializers()
|| this.uniqueSemantic == UniqueSemantic.ALLOW && isEnityResultType ) {
while ( rowProcessingState.next() ) {
results.addUnique( rowReader.readRow( rowProcessingState, processingOptions ) );

View File

@ -10,6 +10,7 @@ import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.sql.results.graph.Initializer;
import org.hibernate.sql.results.internal.InitializersList;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
@ -50,7 +51,9 @@ public interface RowReader<R> {
* The initializers associated with this reader.
*
* @see org.hibernate.sql.results.graph.DomainResult
* @deprecated use {@link #getInitializersList()}
*/
@Deprecated
List<Initializer> getInitializers();
/**
@ -70,4 +73,11 @@ public interface RowReader<R> {
@Deprecated
RowReaderMemento toMemento(SessionFactoryImplementor factory);
/**
* The initializers associated with this reader.
*
* @see org.hibernate.sql.results.graph.DomainResult
*/
InitializersList getInitializersList();
}