From 1905b03c952978dee497458cccb9c3d86333405c Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Fri, 5 Aug 2022 16:10:16 +0200 Subject: [PATCH] HHH-15479 Improve ListresultConsumer duplication check method performance --- .../sql/results/spi/ListResultsConsumer.java | 111 ++++++++++++------ 1 file changed, 73 insertions(+), 38 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/ListResultsConsumer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/ListResultsConsumer.java index e90f4ff2d6..16ef70f0b3 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/ListResultsConsumer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/ListResultsConsumer.java @@ -9,10 +9,12 @@ package org.hibernate.sql.results.spi; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.Set; import org.hibernate.HibernateException; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.internal.util.collections.IdentitySet; import org.hibernate.query.ResultListTransformer; import org.hibernate.query.spi.QueryOptions; import org.hibernate.sql.results.internal.RowProcessingStateStandardImpl; @@ -105,6 +107,49 @@ public class ListResultsConsumer implements ResultsConsumer, R> { } } + private static class Results { + private final List results = new ArrayList<>(); + private final JavaType resultJavaType; + + public Results(JavaType resultJavaType) { + this.resultJavaType = resultJavaType; + } + + public boolean contains(R result) { + for ( int i = 0; i < results.size(); i++ ) { + if ( resultJavaType.areEqual( results.get( i ), result ) ) { + return true; + } + } + return false; + } + + public void add(R result) { + results.add( result ); + } + + public List getResults() { + return results; + } + } + + private static class EntityResult extends Results { + private final Set added = new IdentitySet<>(); + + public EntityResult(JavaType resultJavaType) { + super( resultJavaType ); + } + + public boolean contains(R result) { + return added.contains( result ); + } + + public void add(R result) { + super.add( result ); + added.add( result ); + } + } + @Override public List consume( JdbcValues jdbcValues, @@ -116,13 +161,10 @@ public class ListResultsConsumer implements ResultsConsumer, R> { final PersistenceContext persistenceContext = session.getPersistenceContext(); final TypeConfiguration typeConfiguration = session.getTypeConfiguration(); final QueryOptions queryOptions = rowProcessingState.getQueryOptions(); - RuntimeException ex = null; try { persistenceContext.getLoadContexts().register( jdbcValuesSourceProcessingState ); - final List results = new ArrayList<>(); - final JavaType domainResultJavaType = resolveDomainResultJavaType( rowReader.getDomainResultResultJavaType(), rowReader.getResultJavaTypes(), @@ -131,17 +173,25 @@ public class ListResultsConsumer implements ResultsConsumer, R> { final ResultHandler resultHandlerToUse; - if ( uniqueSemantic == UniqueSemantic.ALLOW - && domainResultJavaType instanceof EntityJavaType ) { + boolean isEnityResultType = domainResultJavaType instanceof EntityJavaType; + if ( uniqueSemantic == UniqueSemantic.ALLOW && isEnityResultType ) { resultHandlerToUse = ListResultsConsumer::deDuplicationHandling; } else { resultHandlerToUse = this.resultHandler; } + final Results results; + if ( isEnityResultType ) { + results = new EntityResult<>( domainResultJavaType ); + } + else { + results = new Results<>( domainResultJavaType ); + } + while ( rowProcessingState.next() ) { final R row = rowReader.readRow( rowProcessingState, processingOptions ); - resultHandlerToUse.handle( row, domainResultJavaType, results, rowProcessingState ); + resultHandlerToUse.handle( row, results, rowProcessingState ); rowProcessingState.finishRowProcessing(); } @@ -155,10 +205,10 @@ public class ListResultsConsumer implements ResultsConsumer, R> { //noinspection unchecked final ResultListTransformer resultListTransformer = (ResultListTransformer) queryOptions.getResultListTransformer(); if ( resultListTransformer != null ) { - return resultListTransformer.transformList( results ); + return resultListTransformer.transformList( results.getResults() ); } - return results; + return results.getResults(); } catch (RuntimeException e) { ex = e; @@ -193,17 +243,15 @@ public class ListResultsConsumer implements ResultsConsumer, R> { */ @FunctionalInterface private interface ResultHandler { - void handle(R result, JavaType transformedJavaType, List results, RowProcessingStateStandardImpl rowProcessingState); + void handle(R result, Results results, RowProcessingStateStandardImpl rowProcessingState); } public static void deDuplicationHandling( R result, - JavaType transformedJavaType, - List results, + Results results, RowProcessingStateStandardImpl rowProcessingState) { withDuplicationCheck( result, - transformedJavaType, results, rowProcessingState, false @@ -212,43 +260,31 @@ public class ListResultsConsumer implements ResultsConsumer, R> { private static void withDuplicationCheck( R result, - JavaType transformedJavaType, - List results, + Results results, RowProcessingStateStandardImpl rowProcessingState, boolean throwException) { - boolean addResult = true; - - for ( int i = 0; i < results.size(); i++ ) { - final R existingResult = results.get( i ); - if ( transformedJavaType.areEqual( result, existingResult ) ) { - if ( throwException && ! rowProcessingState.hasCollectionInitializers ) { - throw new HibernateException( - String.format( - Locale.ROOT, - "Duplicate row was found and `%s` was specified", - UniqueSemantic.ASSERT - ) - ); - } - - addResult = false; - break; + if ( results.contains( result ) ) { + if ( throwException && !rowProcessingState.hasCollectionInitializers ) { + throw new HibernateException( + String.format( + Locale.ROOT, + "Duplicate row was found and `%s` was specified", + UniqueSemantic.ASSERT + ) + ); } } - - if ( addResult ) { + else { results.add( result ); } } public static void duplicationErrorHandling( R result, - JavaType transformedJavaType, - List results, + Results results, RowProcessingStateStandardImpl rowProcessingState) { withDuplicationCheck( result, - transformedJavaType, results, rowProcessingState, true @@ -257,8 +293,7 @@ public class ListResultsConsumer implements ResultsConsumer, R> { public static void applyAll( R result, - JavaType transformedJavaType, - List results, + Results results, RowProcessingStateStandardImpl rowProcessingState) { results.add( result ); }