HHH-16815 Improvements in SqmInterpretationsKey
This commit is contained in:
parent
4095e16212
commit
dfa26e0b5c
|
@ -512,7 +512,7 @@ public class LockOptions implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a copy.
|
* Make a copy. The new copy will be mutable even if the original wasn't.
|
||||||
*
|
*
|
||||||
* @return The copy
|
* @return The copy
|
||||||
*/
|
*/
|
||||||
|
@ -522,6 +522,22 @@ public class LockOptions implements Serializable {
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a copy, unless this is an immutable instance.
|
||||||
|
*
|
||||||
|
* @return The copy, or this if it was immutable.
|
||||||
|
*/
|
||||||
|
public LockOptions makeDefensiveCopy() {
|
||||||
|
if ( immutable ) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final LockOptions copy = new LockOptions();
|
||||||
|
copy( this, copy );
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy the given lock options into this instance,
|
* Copy the given lock options into this instance,
|
||||||
* merging the alias-specific lock modes.
|
* merging the alias-specific lock modes.
|
||||||
|
|
|
@ -7,8 +7,10 @@
|
||||||
package org.hibernate.query.sqm.internal;
|
package org.hibernate.query.sqm.internal;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import jakarta.persistence.criteria.Order;
|
import jakarta.persistence.criteria.Order;
|
||||||
|
@ -26,7 +28,7 @@ import static org.hibernate.query.spi.AbstractSelectionQuery.CRITERIA_HQL_STRING
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class SqmInterpretationsKey implements QueryInterpretationCache.Key {
|
public final class SqmInterpretationsKey implements QueryInterpretationCache.Key {
|
||||||
public interface CacheabilityInfluencers {
|
public interface CacheabilityInfluencers {
|
||||||
boolean isQueryPlanCacheable();
|
boolean isQueryPlanCacheable();
|
||||||
String getQueryString();
|
String getQueryString();
|
||||||
|
@ -43,16 +45,18 @@ public class SqmInterpretationsKey implements QueryInterpretationCache.Key {
|
||||||
|
|
||||||
public static SqmInterpretationsKey createInterpretationsKey(InterpretationsKeySource keySource) {
|
public static SqmInterpretationsKey createInterpretationsKey(InterpretationsKeySource keySource) {
|
||||||
if ( isCacheable ( keySource ) ) {
|
if ( isCacheable ( keySource ) ) {
|
||||||
return new SqmInterpretationsKey(
|
final Object query = CRITERIA_HQL_STRING.equals( keySource.getQueryString() )
|
||||||
CRITERIA_HQL_STRING.equals( keySource.getQueryString() )
|
|
||||||
? keySource.getSqmStatement()
|
? keySource.getSqmStatement()
|
||||||
: keySource.getQueryString(),
|
: keySource.getQueryString();
|
||||||
|
return new SqmInterpretationsKey(
|
||||||
|
query,
|
||||||
|
query.hashCode(),
|
||||||
keySource.getResultType(),
|
keySource.getResultType(),
|
||||||
keySource.getOrder(),
|
keySource.getOrder(),
|
||||||
keySource.getQueryOptions().getLockOptions(),
|
keySource.getQueryOptions().getLockOptions(),
|
||||||
keySource.getQueryOptions().getTupleTransformer(),
|
keySource.getQueryOptions().getTupleTransformer(),
|
||||||
keySource.getQueryOptions().getResultListTransformer(),
|
keySource.getQueryOptions().getResultListTransformer(),
|
||||||
new HashSet<>( keySource.getLoadQueryInfluencers().getEnabledFetchProfileNames() )
|
memoryEfficientDefensiveSetCopy( keySource.getLoadQueryInfluencers().getEnabledFetchProfileNames() )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -60,6 +64,25 @@ public class SqmInterpretationsKey implements QueryInterpretationCache.Key {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Collection<String> memoryEfficientDefensiveSetCopy(final Set<String> set) {
|
||||||
|
if ( set == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch ( set.size() ) {
|
||||||
|
case 0:
|
||||||
|
return null;
|
||||||
|
case 1:
|
||||||
|
return Set.of( set.iterator().next() );
|
||||||
|
case 2:
|
||||||
|
final Iterator<String> iterator = set.iterator();
|
||||||
|
return Set.of( iterator.next(), iterator.next() );
|
||||||
|
default:
|
||||||
|
return Set.copyOf( set );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isCacheable(InterpretationsKeySource keySource) {
|
private static boolean isCacheable(InterpretationsKeySource keySource) {
|
||||||
assert keySource.getQueryOptions().getAppliedGraph() != null;
|
assert keySource.getQueryOptions().getAppliedGraph() != null;
|
||||||
|
|
||||||
|
@ -95,9 +118,11 @@ public class SqmInterpretationsKey implements QueryInterpretationCache.Key {
|
||||||
private final TupleTransformer<?> tupleTransformer;
|
private final TupleTransformer<?> tupleTransformer;
|
||||||
private final ResultListTransformer<?> resultListTransformer;
|
private final ResultListTransformer<?> resultListTransformer;
|
||||||
private final Collection<String> enabledFetchProfiles;
|
private final Collection<String> enabledFetchProfiles;
|
||||||
|
private final int hashcode;
|
||||||
|
|
||||||
private SqmInterpretationsKey(
|
private SqmInterpretationsKey(
|
||||||
Object query,
|
Object query,
|
||||||
|
int hash,
|
||||||
Class<?> resultType,
|
Class<?> resultType,
|
||||||
List<Order> order,
|
List<Order> order,
|
||||||
LockOptions lockOptions,
|
LockOptions lockOptions,
|
||||||
|
@ -105,6 +130,7 @@ public class SqmInterpretationsKey implements QueryInterpretationCache.Key {
|
||||||
ResultListTransformer<?> resultListTransformer,
|
ResultListTransformer<?> resultListTransformer,
|
||||||
Collection<String> enabledFetchProfiles) {
|
Collection<String> enabledFetchProfiles) {
|
||||||
this.query = query;
|
this.query = query;
|
||||||
|
this.hashcode = hash;
|
||||||
this.resultType = resultType;
|
this.resultType = resultType;
|
||||||
this.order = order;
|
this.order = order;
|
||||||
this.lockOptions = lockOptions;
|
this.lockOptions = lockOptions;
|
||||||
|
@ -117,10 +143,11 @@ public class SqmInterpretationsKey implements QueryInterpretationCache.Key {
|
||||||
public QueryInterpretationCache.Key prepareForStore() {
|
public QueryInterpretationCache.Key prepareForStore() {
|
||||||
return new SqmInterpretationsKey(
|
return new SqmInterpretationsKey(
|
||||||
query,
|
query,
|
||||||
|
hashcode,
|
||||||
resultType,
|
resultType,
|
||||||
// Since lock options are mutable, we need a copy for the cache key
|
|
||||||
order,
|
order,
|
||||||
lockOptions.makeCopy(),
|
// Since lock options might be mutable, we need a copy for the cache key
|
||||||
|
lockOptions.makeDefensiveCopy(),
|
||||||
tupleTransformer,
|
tupleTransformer,
|
||||||
resultListTransformer,
|
resultListTransformer,
|
||||||
enabledFetchProfiles
|
enabledFetchProfiles
|
||||||
|
@ -137,26 +164,23 @@ public class SqmInterpretationsKey implements QueryInterpretationCache.Key {
|
||||||
if ( this == o ) {
|
if ( this == o ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ( o == null || getClass() != o.getClass() ) {
|
if ( o == null || SqmInterpretationsKey.class != o.getClass() ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final SqmInterpretationsKey that = (SqmInterpretationsKey) o;
|
final SqmInterpretationsKey that = (SqmInterpretationsKey) o;
|
||||||
return query.equals( that.query )
|
return this.hashcode == o.hashCode() //check this first as some other checks are expensive
|
||||||
&& areEqual( resultType, that.resultType )
|
&& query.equals( that.query )
|
||||||
&& areEqual( order, that.order )
|
&& Objects.equals( resultType, that.resultType )
|
||||||
&& areEqual( lockOptions, that.lockOptions )
|
&& Objects.equals( order, that.order )
|
||||||
&& areEqual( tupleTransformer, that.tupleTransformer )
|
&& Objects.equals( lockOptions, that.lockOptions )
|
||||||
&& areEqual( resultListTransformer, that.resultListTransformer )
|
&& Objects.equals( tupleTransformer, that.tupleTransformer )
|
||||||
&& areEqual( enabledFetchProfiles, that.enabledFetchProfiles );
|
&& Objects.equals( resultListTransformer, that.resultListTransformer )
|
||||||
}
|
&& Objects.equals( enabledFetchProfiles, that.enabledFetchProfiles );
|
||||||
|
|
||||||
private <T> boolean areEqual(T o1, T o2) {
|
|
||||||
return o1 == null ? o2 == null : o1.equals(o2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return query.hashCode();
|
return hashcode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue