HHH-16911 Save some memory in CallbackRegistryImpl

This commit is contained in:
Sanne Grinovero 2023-07-18 19:18:22 +01:00 committed by Sanne Grinovero
parent 724e376b7c
commit 9d118a5482
4 changed files with 79 additions and 18 deletions

View File

@ -0,0 +1,21 @@
/*
* 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;
final class EmptyReadOnlyMap<K,V> implements ReadOnlyMap<K,V> {
@Override
public V get(K key) {
return null;
}
@Override
public void dispose() {
//no-op
}
}

View File

@ -20,7 +20,7 @@ import java.util.Map;
* @author Sanne Grinovero
* @since 6.2
*/
public final class MapBackedClassValue<V> {
public final class MapBackedClassValue<V> implements ReadOnlyMap<Class,V> {
private volatile Map<Class<?>, V> map;
@ -45,7 +45,8 @@ public final class MapBackedClassValue<V> {
this.map = Map.copyOf( map );
}
public V get(Class<?> key) {
@Override
public V get(Class key) {
return classValue.get( key );
}
@ -53,6 +54,7 @@ public final class MapBackedClassValue<V> {
* Use this to wipe the backing map, important
* to avoid classloader leaks.
*/
@Override
public void dispose() {
Map<Class<?>, V> existing = this.map;
this.map = null;

View File

@ -0,0 +1,28 @@
/*
* 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;
public interface ReadOnlyMap<K, V> {
//To help saving memory
public static final ReadOnlyMap EMPTY = new EmptyReadOnlyMap();
/**
* The main operation.
* @param key
* @return the corresponding object, or null if there is no association with any entry.
*/
V get(K key);
/**
* Some implementations might hold on to references,
* which could be just heavy or potentially harmful,
* such as ClassLoader leaks: allow for proper cleanup.
*/
void dispose();
}

View File

@ -13,6 +13,7 @@ import jakarta.persistence.PersistenceException;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.MapBackedClassValue;
import org.hibernate.internal.util.collections.ReadOnlyMap;
import org.hibernate.jpa.event.spi.Callback;
import org.hibernate.jpa.event.spi.CallbackRegistry;
import org.hibernate.jpa.event.spi.CallbackType;
@ -26,13 +27,13 @@ import org.hibernate.jpa.event.spi.CallbackType;
*/
final class CallbackRegistryImpl implements CallbackRegistry {
private final MapBackedClassValue<Callback[]> preCreates;
private final MapBackedClassValue<Callback[]> postCreates;
private final MapBackedClassValue<Callback[]> preRemoves;
private final MapBackedClassValue<Callback[]> postRemoves;
private final MapBackedClassValue<Callback[]> preUpdates;
private final MapBackedClassValue<Callback[]> postUpdates;
private final MapBackedClassValue<Callback[]> postLoads;
private final ReadOnlyMap<Class,Callback[]> preCreates;
private final ReadOnlyMap<Class,Callback[]> postCreates;
private final ReadOnlyMap<Class,Callback[]> preRemoves;
private final ReadOnlyMap<Class,Callback[]> postRemoves;
private final ReadOnlyMap<Class,Callback[]> preUpdates;
private final ReadOnlyMap<Class,Callback[]> postUpdates;
private final ReadOnlyMap<Class,Callback[]> postLoads;
public CallbackRegistryImpl(
Map<Class<?>, Callback[]> preCreates,
@ -42,18 +43,27 @@ final class CallbackRegistryImpl implements CallbackRegistry {
Map<Class<?>, Callback[]> preUpdates,
Map<Class<?>, Callback[]> postUpdates,
Map<Class<?>, Callback[]> postLoads) {
this.preCreates = new MapBackedClassValue<>( preCreates );
this.postCreates = new MapBackedClassValue<>( postCreates );
this.preRemoves = new MapBackedClassValue<>( preRemoves );
this.postRemoves = new MapBackedClassValue<>( postRemoves );
this.preUpdates = new MapBackedClassValue<>( preUpdates );
this.postUpdates = new MapBackedClassValue<>( postUpdates );
this.postLoads = new MapBackedClassValue<>( postLoads );
this.preCreates = createBackingMap( preCreates );
this.postCreates = createBackingMap( postCreates );
this.preRemoves = createBackingMap( preRemoves );
this.postRemoves = createBackingMap( postRemoves );
this.preUpdates = createBackingMap( preUpdates );
this.postUpdates = createBackingMap( postUpdates );
this.postLoads = createBackingMap( postLoads );
}
private static ReadOnlyMap<Class, Callback[]> createBackingMap(final Map<Class<?>, Callback[]> src) {
if ( src == null || src.isEmpty() ) {
return ReadOnlyMap.EMPTY;
}
else {
return new MapBackedClassValue<>( src );
}
}
@Override
public boolean hasRegisteredCallbacks(Class<?> entityClass, CallbackType callbackType) {
final MapBackedClassValue<Callback[]> map = determineAppropriateCallbackMap( callbackType );
final ReadOnlyMap<Class,Callback[]> map = determineAppropriateCallbackMap( callbackType );
return notEmpty( map.get( entityClass ) );
}
@ -119,7 +129,7 @@ final class CallbackRegistryImpl implements CallbackRegistry {
}
}
private MapBackedClassValue<Callback[]> determineAppropriateCallbackMap(CallbackType callbackType) {
private ReadOnlyMap<Class,Callback[]> determineAppropriateCallbackMap(CallbackType callbackType) {
if ( callbackType == CallbackType.PRE_PERSIST ) {
return preCreates;
}