HHH-16214 Use a more efficient Map implementation in SqmFunctionRegistry
This commit is contained in:
parent
b600f36d7e
commit
56cd6a2ca0
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.internal.util.collections;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
|
||||
/**
|
||||
* Wraps a ConcurrentHashMap having all keys as Strings
|
||||
* and ensures all keys are lowercased.
|
||||
* It does assume keys and arguments are never null, preferring to throw a NPE
|
||||
* over adding unnecessary checks.
|
||||
* The public exposed methods are similar to the ones on Map, but
|
||||
* not all Map methods are exposed - only a selection we actually need; this
|
||||
* implies it doesn't implement Map; nothing stops us to make it implement Map
|
||||
* but at time of writing it seems unnecessary for our purposes.
|
||||
* @param <V> the type for the stored values.
|
||||
*/
|
||||
@Internal
|
||||
public final class CaseInsensitiveDictionary<V> {
|
||||
|
||||
private final Map<String, V> map = new ConcurrentHashMap<>();
|
||||
|
||||
public V get(final String key) {
|
||||
return map.get( trueKey( key ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Contrary to traditional Map, we make the return unmodifiable.
|
||||
* @return the map's keySet
|
||||
*/
|
||||
public Set<String> unmodifiableKeySet() {
|
||||
return Collections.unmodifiableSet( map.keySet() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Contrary to traditional Map, we make the return unmodifiable.
|
||||
* @return the map's entrySet
|
||||
*/
|
||||
public Set<Map.Entry<String, V>> unmodifiableEntrySet() {
|
||||
return Collections.unmodifiableSet( map.entrySet() );
|
||||
}
|
||||
|
||||
public V put(final String key, V value) {
|
||||
return map.put( trueKey( key ), value );
|
||||
}
|
||||
|
||||
public V remove(final String key) {
|
||||
return map.remove( trueKey( key ) );
|
||||
}
|
||||
|
||||
public boolean containsKey(final String key) {
|
||||
return map.containsKey( trueKey( key ) );
|
||||
}
|
||||
|
||||
private static String trueKey(final String key) {
|
||||
return key.toLowerCase( Locale.ROOT );
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
public void forEach(final BiConsumer<? super String, ? super V> action) {
|
||||
map.forEach( action );
|
||||
}
|
||||
|
||||
}
|
|
@ -6,11 +6,12 @@
|
|||
*/
|
||||
package org.hibernate.query.sqm.function;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.hibernate.internal.util.collections.CaseInsensitiveDictionary;
|
||||
import org.hibernate.query.sqm.produce.function.FunctionParameterType;
|
||||
import org.hibernate.query.sqm.produce.function.NamedFunctionDescriptorBuilder;
|
||||
import org.hibernate.query.sqm.produce.function.PatternFunctionDescriptorBuilder;
|
||||
|
@ -35,27 +36,31 @@ import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTyp
|
|||
public class SqmFunctionRegistry {
|
||||
private static final Logger log = Logger.getLogger( SqmFunctionRegistry.class );
|
||||
|
||||
private final Map<String, SqmFunctionDescriptor> functionMap = new TreeMap<>( CASE_INSENSITIVE_ORDER );
|
||||
private final Map<String,String> alternateKeyMap = new TreeMap<>( CASE_INSENSITIVE_ORDER );
|
||||
private final CaseInsensitiveDictionary<SqmFunctionDescriptor> functionMap = new CaseInsensitiveDictionary<>();
|
||||
private final CaseInsensitiveDictionary<String> alternateKeyMap = new CaseInsensitiveDictionary<>();
|
||||
|
||||
public SqmFunctionRegistry() {
|
||||
log.trace( "SqmFunctionRegistry created" );
|
||||
}
|
||||
|
||||
public Map<String, SqmFunctionDescriptor> getFunctions() {
|
||||
return functionMap;
|
||||
public Set<String> getValidFunctionKeys() {
|
||||
return functionMap.unmodifiableKeySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for diagnostics - not efficient: do not use in production code.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Stream<Map.Entry<String, SqmFunctionDescriptor>> getFunctionsByName() {
|
||||
return Stream.concat(
|
||||
functionMap.entrySet().stream(),
|
||||
alternateKeyMap.entrySet().stream().map(
|
||||
entry -> new AbstractMap.SimpleEntry<>(
|
||||
entry.getKey(),
|
||||
functionMap.get( entry.getValue() )
|
||||
)
|
||||
)
|
||||
);
|
||||
final Map<String, SqmFunctionDescriptor> sortedFunctionMap = new TreeMap<>( CASE_INSENSITIVE_ORDER );
|
||||
for ( Map.Entry<String, SqmFunctionDescriptor> e : functionMap.unmodifiableEntrySet() ) {
|
||||
sortedFunctionMap.put( e.getKey(), e.getValue() );
|
||||
}
|
||||
for ( Map.Entry<String, String> e : alternateKeyMap.unmodifiableEntrySet() ) {
|
||||
sortedFunctionMap.put( e.getKey(), functionMap.get( e.getValue() ) );
|
||||
}
|
||||
return sortedFunctionMap.entrySet().stream();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -35,8 +35,7 @@ public abstract class SpatialSessionFactoryAware extends SpatialTestDataProvider
|
|||
this.supportedFunctions = scope.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getSqmFunctionRegistry()
|
||||
.getFunctions()
|
||||
.keySet();
|
||||
.getValidFunctionKeys();
|
||||
if ( DialectContext.getDialect() instanceof H2Dialect ) {
|
||||
initH2GISExtensionsForInMemDb();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue