Skip to content

Commit

Permalink
HHH-16983 Avoid unnecessary allocations for HQL interpretation caching
Browse files Browse the repository at this point in the history
  • Loading branch information
beikov authored and Sanne committed Jul 25, 2023
1 parent 34628e7 commit 7eba1b4
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ private <R> HqlInterpretation interpretHql(String hql, Class<R> resultType) {
.resolveHqlInterpretation(
hql,
resultType,
s -> queryEngine.getHqlTranslator().translate( hql, resultType )
queryEngine.getHqlTranslator()
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
import jakarta.persistence.Tuple;

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;
Expand Down Expand Up @@ -40,7 +40,7 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
*/
private final BoundedConcurrentHashMap<Key, QueryPlan> queryPlanCache;

private final BoundedConcurrentHashMap<String, HqlInterpretation> hqlInterpretationCache;
private final BoundedConcurrentHashMap<Object, HqlInterpretation> hqlInterpretationCache;
private final BoundedConcurrentHashMap<String, ParameterInterpretation> nativeQueryParamCache;
private final Supplier<StatisticsImplementor> statisticsSupplier;

Expand Down Expand Up @@ -104,18 +104,29 @@ public HqlInterpretation resolveHqlInterpretation(
String queryString,
Class<?> expectedResultType,
Function<String, SqmStatement<?>> creator) {
return resolveHqlInterpretation( queryString, expectedResultType, new HqlTranslator() {
@Override
public <R> SqmStatement<R> translate(String hql, Class<R> expectedResultType) {
//noinspection unchecked
return (SqmStatement<R>) creator.apply( hql );
}
} );
}

@Override
public HqlInterpretation resolveHqlInterpretation(
String queryString,
Class<?> expectedResultType,
HqlTranslator translator) {
log.tracef( "QueryPlan#resolveHqlInterpretation( `%s` )", queryString );

final String cacheKey;
if ( expectedResultType != null
&& ( expectedResultType.isArray() || Tuple.class.isAssignableFrom( expectedResultType ) ) ) {
cacheKey = "multi_" + queryString;
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();
Expand All @@ -124,21 +135,28 @@ public HqlInterpretation resolveHqlInterpretation(
}
return existing;
}

final HqlInterpretation hqlInterpretation = createHqlInterpretation( queryString, creator, statisticsSupplier );
hqlInterpretationCache.put( cacheKey, hqlInterpretation );
return hqlInterpretation;
else {
final HqlInterpretation hqlInterpretation = createHqlInterpretation(
queryString,
expectedResultType,
translator,
statisticsSupplier
);
hqlInterpretationCache.put( cacheKey, hqlInterpretation );
return hqlInterpretation;
}
}

protected static HqlInterpretation createHqlInterpretation(
String queryString,
Function<String, SqmStatement<?>> creator,
Class<?> expectedResultType,
HqlTranslator translator,
Supplier<StatisticsImplementor> 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;

Expand Down Expand Up @@ -188,4 +206,32 @@ public void close() {
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;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
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;

Expand All @@ -35,8 +36,13 @@ default Key prepareForStore() {
int getNumberOfCachedHqlInterpretations();
int getNumberOfCachedQueryPlans();

@Deprecated(forRemoval = true)
HqlInterpretation resolveHqlInterpretation(String queryString, Class<?> expectedResultType, Function<String, SqmStatement<?>> creator);

default HqlInterpretation resolveHqlInterpretation(String queryString, Class<?> expectedResultType, HqlTranslator translator) {
return resolveHqlInterpretation( queryString, expectedResultType, s -> translator.translate( queryString, expectedResultType ) );
}

<R> SelectQueryPlan<R> resolveSelectQueryPlan(Key key, Supplier<SelectQueryPlan<R>> creator);

NonSelectQueryPlan getNonSelectQueryPlan(Key key);
Expand Down

0 comments on commit 7eba1b4

Please sign in to comment.