From 90eb697020722608c2ea420f408e361fa5ae48eb Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Mon, 24 Jul 2023 12:55:40 +0200 Subject: [PATCH] HHH-16983 Avoid unnecessary allocations for HQL interpretation caching --- .../AbstractSharedSessionContract.java | 2 +- .../QueryInterpretationCacheStandardImpl.java | 104 ++++++++++-------- .../query/spi/QueryInterpretationCache.java | 6 + 3 files changed, 67 insertions(+), 45 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index cee8b745bb..178b4cce37 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -744,7 +744,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont .resolveHqlInterpretation( hql, resultType, - s -> queryEngine.getHqlTranslator().translate( hql, resultType ) + queryEngine.getHqlTranslator() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryInterpretationCacheStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryInterpretationCacheStandardImpl.java index b56310f7de..c88918d99e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryInterpretationCacheStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryInterpretationCacheStandardImpl.java @@ -12,6 +12,7 @@ import java.util.function.Supplier; import org.hibernate.internal.util.collections.BoundedConcurrentHashMap; import org.hibernate.query.QueryLogging; +import org.hibernate.query.hql.HqlTranslator; import org.hibernate.query.spi.HqlInterpretation; import org.hibernate.query.spi.NonSelectQueryPlan; import org.hibernate.query.spi.ParameterMetadataImplementor; @@ -40,7 +41,7 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation */ private final BoundedConcurrentHashMap queryPlanCache; - private final BoundedConcurrentHashMap hqlInterpretationCache; + private final BoundedConcurrentHashMap hqlInterpretationCache; private final BoundedConcurrentHashMap nativeQueryParamCache; private final Supplier statisticsSupplier; @@ -99,53 +100,35 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation log.tracef( "QueryPlan#cacheNonSelectQueryPlan(%s)", key ); } - private static String typedKey(String queryString, Class expectedResultType) { - return expectedResultType.getName() + ":" + queryString; - } - - private void putInCache(String queryString, Class expectedResultType, HqlInterpretation hqlInterpretation) { - final SqmStatement statement = hqlInterpretation.getSqmStatement(); - if ( statement instanceof SqmSelectStatement && expectedResultType != null ) { - hqlInterpretationCache.put( typedKey( queryString, expectedResultType ), hqlInterpretation); - } - else { - hqlInterpretationCache.put( queryString, hqlInterpretation ); - } - } - - private HqlInterpretation getFromCache(String queryString, Class expectedResultType) { - if ( expectedResultType != null ) { - final HqlInterpretation typedHqlInterpretation = - hqlInterpretationCache.get( typedKey( queryString, expectedResultType ) ); - if ( typedHqlInterpretation != null ) { - return typedHqlInterpretation; + @Override + public HqlInterpretation resolveHqlInterpretation( + String queryString, + Class expectedResultType, + Function> creator) { + return resolveHqlInterpretation( queryString, expectedResultType, new HqlTranslator() { + @Override + public SqmStatement translate(String hql, Class expectedResultType) { + //noinspection unchecked + return (SqmStatement) creator.apply( hql ); } - } - - final HqlInterpretation hqlInterpretation = hqlInterpretationCache.get( queryString ); - if ( hqlInterpretation != null ) { - final SqmStatement statement = hqlInterpretation.getSqmStatement(); - if ( statement instanceof SqmSelectStatement && expectedResultType != null ) { - final Class resultType = ((SqmSelectStatement) statement).getSelection().getJavaType(); - return expectedResultType.equals( resultType ) ? hqlInterpretation : null; - } - else { - return hqlInterpretation; - } - } - else { - return null; - } + } ); } @Override public HqlInterpretation resolveHqlInterpretation( String queryString, Class expectedResultType, - Function> creator) { + HqlTranslator translator) { log.tracef( "QueryPlan#resolveHqlInterpretation( `%s` )", queryString ); - final HqlInterpretation existing = getFromCache( queryString, expectedResultType ); + final Object cacheKey; + if ( expectedResultType != null ) { + cacheKey = new HqlInterpretationCacheKey( queryString, expectedResultType ); + } + else { + cacheKey = queryString; + } + final HqlInterpretation existing = hqlInterpretationCache.get( cacheKey ); if ( existing != null ) { final StatisticsImplementor statistics = statisticsSupplier.get(); if ( statistics.isStatisticsEnabled() ) { @@ -154,22 +137,27 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation return existing; } else { - final HqlInterpretation hqlInterpretation = - createHqlInterpretation( queryString, creator, statisticsSupplier ); - putInCache( queryString, expectedResultType, hqlInterpretation ); + final HqlInterpretation hqlInterpretation = createHqlInterpretation( + queryString, + expectedResultType, + translator, + statisticsSupplier + ); + hqlInterpretationCache.put( cacheKey, hqlInterpretation ); return hqlInterpretation; } } protected static HqlInterpretation createHqlInterpretation( String queryString, - Function> creator, + Class expectedResultType, + HqlTranslator translator, Supplier statisticsSupplier) { final StatisticsImplementor statistics = statisticsSupplier.get(); final boolean stats = statistics.isStatisticsEnabled(); final long startTime = stats ? System.nanoTime() : 0L; - final SqmStatement sqmStatement = creator.apply( queryString ); + final SqmStatement sqmStatement = translator.translate( queryString, expectedResultType ); final ParameterMetadataImplementor parameterMetadata; final DomainParameterXref domainParameterXref; @@ -219,4 +207,32 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation queryPlanCache.clear(); } + private static final class HqlInterpretationCacheKey { + private final String queryString; + private final Class expectedResultType; + + public HqlInterpretationCacheKey(String queryString, Class expectedResultType) { + this.queryString = queryString; + this.expectedResultType = expectedResultType; + } + + @Override + public boolean equals(Object o) { + if ( o.getClass() != HqlInterpretationCacheKey.class ) { + return false; + } + + final HqlInterpretationCacheKey that = (HqlInterpretationCacheKey) o; + return queryString.equals( that.queryString ) + && expectedResultType.equals( that.expectedResultType ); + } + + @Override + public int hashCode() { + int result = queryString.hashCode(); + result = 31 * result + expectedResultType.hashCode(); + return result; + } + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryInterpretationCache.java b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryInterpretationCache.java index c101e577ec..2d08e5d098 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryInterpretationCache.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryInterpretationCache.java @@ -10,6 +10,7 @@ import java.util.function.Function; import java.util.function.Supplier; import org.hibernate.Incubating; +import org.hibernate.query.hql.HqlTranslator; import org.hibernate.query.sql.spi.ParameterInterpretation; import org.hibernate.query.sqm.tree.SqmStatement; @@ -36,8 +37,13 @@ public interface QueryInterpretationCache { int getNumberOfCachedHqlInterpretations(); int getNumberOfCachedQueryPlans(); + @Deprecated(forRemoval = true) HqlInterpretation resolveHqlInterpretation(String queryString, Class expectedResultType, Function> creator); + default HqlInterpretation resolveHqlInterpretation(String queryString, Class expectedResultType, HqlTranslator translator) { + return resolveHqlInterpretation( queryString, expectedResultType, s -> translator.translate( queryString, expectedResultType ) ); + } + SelectQueryPlan resolveSelectQueryPlan(Key key, Supplier> creator); NonSelectQueryPlan getNonSelectQueryPlan(Key key);