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.LockMode;
|
||||
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.ManagedEntity;
|
||||
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.CoreMessageLogger;
|
||||
|
||||
|
@ -25,6 +28,7 @@ import java.util.Map;
|
|||
import java.util.function.Consumer;
|
||||
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.asManagedEntity;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptableOrNull;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.isManagedEntity;
|
||||
|
||||
/**
|
||||
|
@ -329,18 +333,6 @@ public class EntityEntryContext {
|
|||
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) {
|
||||
ManagedEntity node = head;
|
||||
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
|
||||
*/
|
||||
public void clear() {
|
||||
dirty = true;
|
||||
|
||||
processEachManagedEntity( EntityEntryContext::clearManagedEntity );
|
||||
clearAllReferencesFromManagedEntities();
|
||||
|
||||
if ( immutableManagedEntityXref != null ) {
|
||||
immutableManagedEntityXref.clear();
|
||||
|
|
|
@ -272,6 +272,14 @@ public final class ManagedTypeHelper {
|
|||
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
|
||||
* (using this is highly preferrable over a direct cast)
|
||||
|
|
|
@ -35,7 +35,6 @@ import org.hibernate.PersistentObjectException;
|
|||
import org.hibernate.TransientObjectException;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
||||
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.engine.spi.AssociationKey;
|
||||
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.EntityKey;
|
||||
import org.hibernate.engine.spi.EntityUniqueKey;
|
||||
import org.hibernate.engine.spi.ManagedEntity;
|
||||
import org.hibernate.engine.spi.NaturalIdResolutions;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
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.asManagedEntity;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy;
|
||||
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();
|
||||
if ( collectionEntries != null ) {
|
||||
IdentityMap.onEachKey( collectionEntries, k -> k.unsetSession( session ) );
|
||||
|
@ -267,18 +262,6 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
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
|
||||
public boolean isDefaultReadOnly() {
|
||||
return defaultReadOnly;
|
||||
|
|
Loading…
Reference in New Issue