HHH-15878 Micro optimisations of StatefulPersistenceContext#clear
This commit is contained in:
parent
c6ecdb78f4
commit
49c096f146
|
@ -9,9 +9,12 @@ package org.hibernate.engine.internal;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||||
|
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||||
import org.hibernate.engine.spi.EntityEntry;
|
import org.hibernate.engine.spi.EntityEntry;
|
||||||
import org.hibernate.engine.spi.ManagedEntity;
|
import org.hibernate.engine.spi.ManagedEntity;
|
||||||
import org.hibernate.engine.spi.PersistenceContext;
|
import org.hibernate.engine.spi.PersistenceContext;
|
||||||
|
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||||
|
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||||
import org.hibernate.internal.CoreLogging;
|
import org.hibernate.internal.CoreLogging;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
|
|
||||||
|
@ -25,6 +28,7 @@ import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static org.hibernate.engine.internal.ManagedTypeHelper.asManagedEntity;
|
import static org.hibernate.engine.internal.ManagedTypeHelper.asManagedEntity;
|
||||||
|
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptableOrNull;
|
||||||
import static org.hibernate.engine.internal.ManagedTypeHelper.isManagedEntity;
|
import static org.hibernate.engine.internal.ManagedTypeHelper.isManagedEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -329,18 +333,6 @@ public class EntityEntryContext {
|
||||||
return reentrantSafeEntries;
|
return reentrantSafeEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Not reentrant like #reentrantSafeEntityEntries but most likely
|
|
||||||
* the more efficient choice, when reentrant safety isn't required.
|
|
||||||
*/
|
|
||||||
public void processEachEntity(final Consumer<Object> entityProcessor) {
|
|
||||||
ManagedEntity managedEntity = head;
|
|
||||||
while ( managedEntity != null ) {
|
|
||||||
entityProcessor.accept( managedEntity.$$_hibernate_getEntityInstance() );
|
|
||||||
managedEntity = managedEntity.$$_hibernate_getNextManagedEntity();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processEachManagedEntity(final Consumer<ManagedEntity> action) {
|
private void processEachManagedEntity(final Consumer<ManagedEntity> action) {
|
||||||
ManagedEntity node = head;
|
ManagedEntity node = head;
|
||||||
while ( node != null ) {
|
while ( node != null ) {
|
||||||
|
@ -350,13 +342,37 @@ public class EntityEntryContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Could have used #processEachManagedEntity but avoided because of measurable overhead.
|
||||||
|
// Careful, this needs to be very efficient as we potentially iterate quite a bit!
|
||||||
|
// Also: we perform two operations at once, so to not iterate on the list twice;
|
||||||
|
// being a linked list, multiple iterations are not cache friendly at all.
|
||||||
|
private void clearAllReferencesFromManagedEntities() {
|
||||||
|
ManagedEntity nextManagedEntity = head;
|
||||||
|
while ( nextManagedEntity != null ) {
|
||||||
|
final ManagedEntity current = nextManagedEntity;
|
||||||
|
nextManagedEntity = current.$$_hibernate_getNextManagedEntity();
|
||||||
|
Object toProcess = current.$$_hibernate_getEntityInstance();
|
||||||
|
unsetSession( asPersistentAttributeInterceptableOrNull( toProcess ) );
|
||||||
|
clearManagedEntity( current );//careful this also unlinks from the "next" entry in the list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void unsetSession(PersistentAttributeInterceptable persistentAttributeInterceptable) {
|
||||||
|
if ( persistentAttributeInterceptable != null ) {
|
||||||
|
final PersistentAttributeInterceptor interceptor = persistentAttributeInterceptable.$$_hibernate_getInterceptor();
|
||||||
|
if ( interceptor instanceof LazyAttributeLoadingInterceptor ) {
|
||||||
|
( (LazyAttributeLoadingInterceptor) interceptor ).unsetSession();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear this context of all managed entities
|
* Clear this context of all managed entities
|
||||||
*/
|
*/
|
||||||
public void clear() {
|
public void clear() {
|
||||||
dirty = true;
|
dirty = true;
|
||||||
|
|
||||||
processEachManagedEntity( EntityEntryContext::clearManagedEntity );
|
clearAllReferencesFromManagedEntities();
|
||||||
|
|
||||||
if ( immutableManagedEntityXref != null ) {
|
if ( immutableManagedEntityXref != null ) {
|
||||||
immutableManagedEntityXref.clear();
|
immutableManagedEntityXref.clear();
|
||||||
|
|
|
@ -272,6 +272,14 @@ public final class ManagedTypeHelper {
|
||||||
throw new ClassCastException( "Object of type '" + entity.getClass() + "' can't be cast to PersistentAttributeInterceptable" );
|
throw new ClassCastException( "Object of type '" + entity.getClass() + "' can't be cast to PersistentAttributeInterceptable" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PersistentAttributeInterceptable asPersistentAttributeInterceptableOrNull(final Object entity) {
|
||||||
|
if ( entity instanceof PrimeAmongSecondarySupertypes ) {
|
||||||
|
PrimeAmongSecondarySupertypes t = (PrimeAmongSecondarySupertypes) entity;
|
||||||
|
return t.asPersistentAttributeInterceptable();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cast the object to HibernateProxy
|
* Cast the object to HibernateProxy
|
||||||
* (using this is highly preferrable over a direct cast)
|
* (using this is highly preferrable over a direct cast)
|
||||||
|
|
|
@ -35,7 +35,6 @@ import org.hibernate.PersistentObjectException;
|
||||||
import org.hibernate.TransientObjectException;
|
import org.hibernate.TransientObjectException;
|
||||||
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
||||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
|
||||||
import org.hibernate.collection.spi.PersistentCollection;
|
import org.hibernate.collection.spi.PersistentCollection;
|
||||||
import org.hibernate.engine.spi.AssociationKey;
|
import org.hibernate.engine.spi.AssociationKey;
|
||||||
import org.hibernate.engine.spi.BatchFetchQueue;
|
import org.hibernate.engine.spi.BatchFetchQueue;
|
||||||
|
@ -44,7 +43,6 @@ import org.hibernate.engine.spi.CollectionKey;
|
||||||
import org.hibernate.engine.spi.EntityEntry;
|
import org.hibernate.engine.spi.EntityEntry;
|
||||||
import org.hibernate.engine.spi.EntityKey;
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.engine.spi.EntityUniqueKey;
|
import org.hibernate.engine.spi.EntityUniqueKey;
|
||||||
import org.hibernate.engine.spi.ManagedEntity;
|
|
||||||
import org.hibernate.engine.spi.NaturalIdResolutions;
|
import org.hibernate.engine.spi.NaturalIdResolutions;
|
||||||
import org.hibernate.engine.spi.PersistenceContext;
|
import org.hibernate.engine.spi.PersistenceContext;
|
||||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||||
|
@ -71,7 +69,6 @@ import org.jboss.logging.Logger;
|
||||||
import static org.hibernate.engine.internal.ManagedTypeHelper.asHibernateProxy;
|
import static org.hibernate.engine.internal.ManagedTypeHelper.asHibernateProxy;
|
||||||
import static org.hibernate.engine.internal.ManagedTypeHelper.asManagedEntity;
|
import static org.hibernate.engine.internal.ManagedTypeHelper.asManagedEntity;
|
||||||
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
|
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
|
||||||
import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy;
|
|
||||||
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
|
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -236,8 +233,6 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entityEntryContext.processEachEntity( StatefulPersistenceContext::processEntityOnClear );
|
|
||||||
|
|
||||||
final SharedSessionContractImplementor session = getSession();
|
final SharedSessionContractImplementor session = getSession();
|
||||||
if ( collectionEntries != null ) {
|
if ( collectionEntries != null ) {
|
||||||
IdentityMap.onEachKey( collectionEntries, k -> k.unsetSession( session ) );
|
IdentityMap.onEachKey( collectionEntries, k -> k.unsetSession( session ) );
|
||||||
|
@ -267,18 +262,6 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
||||||
naturalIdResolutions = null;
|
naturalIdResolutions = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void processEntityOnClear(final Object entity) {
|
|
||||||
//type-cache-pollution agent: it's crucial to use the ManagedTypeHelper rather than attempting a direct cast
|
|
||||||
ManagedTypeHelper.processIfPersistentAttributeInterceptable( entity, StatefulPersistenceContext::unsetSession, null );
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void unsetSession(PersistentAttributeInterceptable persistentAttributeInterceptable, Object ignoredParam) {
|
|
||||||
final PersistentAttributeInterceptor interceptor = persistentAttributeInterceptable.$$_hibernate_getInterceptor();
|
|
||||||
if ( interceptor instanceof LazyAttributeLoadingInterceptor ) {
|
|
||||||
( (LazyAttributeLoadingInterceptor) interceptor ).unsetSession();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDefaultReadOnly() {
|
public boolean isDefaultReadOnly() {
|
||||||
return defaultReadOnly;
|
return defaultReadOnly;
|
||||||
|
|
Loading…
Reference in New Issue