From 427204910c6b53b13f47b161ca2c4e9fe4f46eda Mon Sep 17 00:00:00 2001 From: Fabio Massimo Ercoli Date: Thu, 25 Nov 2021 15:11:36 +0100 Subject: [PATCH] Cache only immutable part of HqlInterpretation So that it can be reused safely from different threads --- .../QueryInterpretationCacheStandardImpl.java | 73 +++++++++++++------ .../sqm/internal/DomainParameterXref.java | 2 +- 2 files changed, 50 insertions(+), 25 deletions(-) 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 f7f6aed45d..eab7e07fdc 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 @@ -52,7 +52,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; @@ -111,41 +111,38 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation final StatisticsImplementor statistics = statisticsSupplier.get(); final boolean stats = statistics.isStatisticsEnabled(); final long startTime = ( stats ) ? System.nanoTime() : 0L; - final HqlInterpretation cached = hqlInterpretationCache.get( queryString ); - if ( cached != null ) { + + ImmutableHqlInterpretation immutableHqlInterpretation = hqlInterpretationCache.get( queryString ); + if ( immutableHqlInterpretation == null ) { + log.debugf( "Creating and caching HqlInterpretation - %s", queryString ); + immutableHqlInterpretation = create( queryString, creator ); + hqlInterpretationCache.put( queryString, immutableHqlInterpretation ); + + if ( stats ) { + final long endTime = System.nanoTime(); + final long microseconds = TimeUnit.MICROSECONDS.convert( endTime - startTime, TimeUnit.NANOSECONDS ); + statistics.queryCompiled( queryString, microseconds ); + } + } + else { if ( stats ) { statistics.queryPlanCacheHit( queryString ); } - return cached; } - log.debugf( "Creating and caching HqlInterpretation - %s", queryString ); + DomainParameterXref domainParameterXref; - final SqmStatement sqmStatement = creator.apply( queryString ); - final DomainParameterXref domainParameterXref; - final ParameterMetadataImplementor parameterMetadata; - - if ( sqmStatement.getSqmParameters().isEmpty() ) { + if ( immutableHqlInterpretation.sqmStatement.getSqmParameters().isEmpty() ) { domainParameterXref = DomainParameterXref.empty(); - parameterMetadata = ParameterMetadataImpl.EMPTY; } else { - domainParameterXref = DomainParameterXref.from( sqmStatement ); - parameterMetadata = new ParameterMetadataImpl( domainParameterXref.getQueryParameters() ); + domainParameterXref = DomainParameterXref.from( immutableHqlInterpretation.sqmStatement ); } - final HqlInterpretation interpretation = new SimpleHqlInterpretationImpl( - sqmStatement, - parameterMetadata, + return new SimpleHqlInterpretationImpl( + immutableHqlInterpretation.sqmStatement, + immutableHqlInterpretation.parameterMetadata, domainParameterXref); - hqlInterpretationCache.put( queryString, interpretation ); - - if ( stats ) { - final long endTime = System.nanoTime(); - final long microseconds = TimeUnit.MICROSECONDS.convert( endTime - startTime, TimeUnit.NANOSECONDS ); - statistics.queryCompiled( queryString, microseconds ); - } - return interpretation; } @Override @@ -175,4 +172,32 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation nativeQueryParamCache.clear(); queryPlanCache.clear(); } + + private ImmutableHqlInterpretation create(String queryString, Function> creator) { + final SqmStatement sqmStatement = creator.apply( queryString ); + final ParameterMetadataImplementor parameterMetadata; + + if ( sqmStatement.getSqmParameters().isEmpty() ) { + parameterMetadata = ParameterMetadataImpl.EMPTY; + } + else { + // TODO Avoid to recreate the DomainParameterXref twice + parameterMetadata = new ParameterMetadataImpl( DomainParameterXref.from( sqmStatement ).getQueryParameters() ); + } + + return new ImmutableHqlInterpretation( sqmStatement, parameterMetadata); + } + + private static class ImmutableHqlInterpretation { + + private final SqmStatement sqmStatement; + private final ParameterMetadataImplementor parameterMetadata; + + public ImmutableHqlInterpretation( + SqmStatement sqmStatement, + ParameterMetadataImplementor parameterMetadata) { + this.sqmStatement = sqmStatement; + this.parameterMetadata = parameterMetadata; + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/DomainParameterXref.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/DomainParameterXref.java index 10488a2eab..fd18e52069 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/DomainParameterXref.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/DomainParameterXref.java @@ -11,7 +11,6 @@ import java.util.Collections; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.TreeMap; import org.hibernate.HibernateException; @@ -258,4 +257,5 @@ public class DomainParameterXref { expansions.clear(); } + }