HHH-13654 Make AbstractFlushingEventListener#entitiesByKey also lazily initialized
This commit is contained in:
parent
6034ece731
commit
f89bf35106
|
@ -95,7 +95,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
private SharedSessionContractImplementor session;
|
||||
|
||||
// Loaded entity instances, by EntityKey
|
||||
private Map<EntityKey, Object> entitiesByKey;
|
||||
private HashMap<EntityKey, Object> entitiesByKey;
|
||||
|
||||
// Loaded entity instances, by EntityUniqueKey
|
||||
private Map<EntityUniqueKey, Object> entitiesByUniqueKey;
|
||||
|
@ -155,8 +155,6 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
*/
|
||||
public StatefulPersistenceContext(SharedSessionContractImplementor session) {
|
||||
this.session = session;
|
||||
|
||||
entitiesByKey = new HashMap<>( INIT_COLL_SIZE );
|
||||
entityEntryContext = new EntityEntryContext( this );
|
||||
}
|
||||
|
||||
|
@ -239,7 +237,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
}
|
||||
|
||||
arrayHolders = null;
|
||||
entitiesByKey.clear();
|
||||
entitiesByKey = null;
|
||||
entitiesByUniqueKey = null;
|
||||
entityEntryContext.clear();
|
||||
parentsByChild = null;
|
||||
|
@ -383,34 +381,43 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
|
||||
@Override
|
||||
public void addEntity(EntityKey key, Object entity) {
|
||||
if ( entitiesByKey == null ) {
|
||||
entitiesByKey = new HashMap<>( INIT_COLL_SIZE );
|
||||
}
|
||||
entitiesByKey.put( key, entity );
|
||||
final BatchFetchQueue fetchQueue = this.batchFetchQueue;
|
||||
if ( fetchQueue != null ) {
|
||||
fetchQueue.removeBatchLoadableEntityKey(key);
|
||||
fetchQueue.removeBatchLoadableEntityKey( key );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getEntity(EntityKey key) {
|
||||
return entitiesByKey.get( key );
|
||||
return entitiesByKey == null ? null : entitiesByKey.get( key );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsEntity(EntityKey key) {
|
||||
return entitiesByKey.containsKey( key );
|
||||
return entitiesByKey == null ? false : entitiesByKey.containsKey( key );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object removeEntity(EntityKey key) {
|
||||
final Object entity = entitiesByKey.remove( key );
|
||||
if ( entitiesByUniqueKey != null ) {
|
||||
final Iterator itr = entitiesByUniqueKey.values().iterator();
|
||||
while ( itr.hasNext() ) {
|
||||
if ( itr.next() == entity ) {
|
||||
itr.remove();
|
||||
final Object entity;
|
||||
if ( entitiesByKey != null ) {
|
||||
entity = entitiesByKey.remove( key );
|
||||
if ( entitiesByUniqueKey != null ) {
|
||||
final Iterator itr = entitiesByUniqueKey.values().iterator();
|
||||
while ( itr.hasNext() ) {
|
||||
if ( itr.next() == entity ) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
entity = null;
|
||||
}
|
||||
|
||||
// Clear all parent cache
|
||||
parentsByChild = null;
|
||||
|
@ -757,6 +764,9 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
|
||||
@Override
|
||||
public void addEnhancedProxy(EntityKey key, PersistentAttributeInterceptable entity) {
|
||||
if ( entitiesByKey == null ) {
|
||||
entitiesByKey = new HashMap<>( INIT_COLL_SIZE );
|
||||
}
|
||||
entitiesByKey.put( key, entity );
|
||||
}
|
||||
|
||||
|
@ -1062,9 +1072,25 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
return nullifiableEntityKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this will be removed: it provides too wide access, making it hard to optimise the internals
|
||||
* for specific access needs. Consider using #iterateEntities instead.
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public Map getEntitiesByKey() {
|
||||
return entitiesByKey;
|
||||
return entitiesByKey == null ? Collections.emptyMap() : entitiesByKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator managedEntitiesIterator() {
|
||||
if ( entitiesByKey == null ) {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
else {
|
||||
return entitiesByKey.values().iterator();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1200,13 +1226,9 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
if ( collectionsByKey == null ) {
|
||||
return "PersistenceContext[entityKeys=" + entitiesByKey.keySet() + ",collectionKeys=[]]";
|
||||
}
|
||||
else {
|
||||
return "PersistenceContext[entityKeys=" + entitiesByKey.keySet()
|
||||
+ ",collectionKeys=" + collectionsByKey.keySet() + "]";
|
||||
}
|
||||
final String entityKeySet = entitiesByKey == null ? "[]" : entitiesByKey.keySet().toString();
|
||||
final String collectionsKeySet = collectionsByKey == null ? "[]" : collectionsByKey.keySet().toString();
|
||||
return "PersistenceContext[entityKeys=" + entityKeySet + ", collectionKeys=" + collectionsKeySet + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1503,7 +1525,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
|
||||
@Override
|
||||
public void replaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, Serializable generatedId) {
|
||||
final Object entity = entitiesByKey.remove( oldKey );
|
||||
final Object entity = entitiesByKey == null ? null : entitiesByKey.remove( oldKey );
|
||||
final EntityEntry oldEntry = entityEntryContext.removeEntityEntry( entity );
|
||||
this.parentsByChild = null;
|
||||
|
||||
|
@ -1536,13 +1558,18 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
oos.writeBoolean( defaultReadOnly );
|
||||
oos.writeBoolean( hasNonReadOnlyEntities );
|
||||
|
||||
oos.writeInt( entitiesByKey.size() );
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.trace( "Starting serialization of [" + entitiesByKey.size() + "] entitiesByKey entries" );
|
||||
if ( entitiesByKey == null ) {
|
||||
oos.writeInt( 0 );
|
||||
}
|
||||
for ( Map.Entry<EntityKey,Object> entry : entitiesByKey.entrySet() ) {
|
||||
entry.getKey().serialize( oos );
|
||||
oos.writeObject( entry.getValue() );
|
||||
else {
|
||||
oos.writeInt( entitiesByKey.size() );
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.trace( "Starting serialization of [" + entitiesByKey.size() + "] entitiesByKey entries" );
|
||||
}
|
||||
for ( Map.Entry<EntityKey,Object> entry : entitiesByKey.entrySet() ) {
|
||||
entry.getKey().serialize( oos );
|
||||
oos.writeObject( entry.getValue() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( entitiesByUniqueKey == null ) {
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.engine.spi;
|
|||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Supplier;
|
||||
|
@ -486,7 +487,10 @@ public interface PersistenceContext {
|
|||
|
||||
/**
|
||||
* Get the mapping from key value to entity instance
|
||||
* @deprecated this will be removed: it provides too wide access, making it hard to optimise the internals
|
||||
* for specific access needs. Consider using #iterateEntities instead.
|
||||
*/
|
||||
@Deprecated
|
||||
Map getEntitiesByKey();
|
||||
|
||||
/**
|
||||
|
@ -793,6 +797,12 @@ public interface PersistenceContext {
|
|||
*/
|
||||
void removeCollectionByKey(CollectionKey collectionKey);
|
||||
|
||||
/**
|
||||
* A read-only iterator on all entities managed by this persistence context
|
||||
* @return
|
||||
*/
|
||||
Iterator managedEntitiesIterator();
|
||||
|
||||
/**
|
||||
* Provides centralized access to natural-id-related functionality.
|
||||
*/
|
||||
|
|
|
@ -37,7 +37,6 @@ import org.hibernate.event.spi.FlushEntityEventListener;
|
|||
import org.hibernate.event.spi.FlushEvent;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.EntityPrinter;
|
||||
import org.hibernate.internal.util.collections.LazyIterator;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -77,7 +76,7 @@ public abstract class AbstractFlushingEventListener implements JpaBootstrapSensi
|
|||
EventSource session = event.getSession();
|
||||
|
||||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||
session.getInterceptor().preFlush( new LazyIterator( persistenceContext.getEntitiesByKey() ) );
|
||||
session.getInterceptor().preFlush( persistenceContext.managedEntitiesIterator() );
|
||||
|
||||
prepareEntityFlushes( session, persistenceContext );
|
||||
// we could move this inside if we wanted to
|
||||
|
@ -397,6 +396,7 @@ public abstract class AbstractFlushingEventListener implements JpaBootstrapSensi
|
|||
}
|
||||
|
||||
protected void postPostFlush(SessionImplementor session) {
|
||||
session.getInterceptor().postFlush( new LazyIterator( session.getPersistenceContextInternal().getEntitiesByKey() ) );
|
||||
session.getInterceptor().postFlush( session.getPersistenceContextInternal().managedEntitiesIterator() );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* 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.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
public final class LazyIterator implements Iterator {
|
||||
|
||||
private final Map map;
|
||||
private Iterator iterator;
|
||||
|
||||
private Iterator getIterator() {
|
||||
if (iterator==null) {
|
||||
iterator = map.values().iterator();
|
||||
}
|
||||
return iterator;
|
||||
}
|
||||
|
||||
public LazyIterator(Map map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return getIterator().hasNext();
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
return getIterator().next();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.test.stateless;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.function.Consumer;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
|
@ -115,10 +116,18 @@ public class StatelessSessionPersistentContextTest extends BaseCoreFunctionalTes
|
|||
"StatelessSession: PersistenceContext has not been cleared",
|
||||
persistenceContextInternal.getEntitiesByKey().isEmpty()
|
||||
);
|
||||
assertTrue(
|
||||
"StatelessSession: PersistenceContext has not been cleared",
|
||||
persistenceContextInternal.managedEntitiesIterator() == Collections.emptyIterator()
|
||||
);
|
||||
assertTrue(
|
||||
"StatelessSession: PersistenceContext has not been cleared",
|
||||
persistenceContextInternal.getCollectionsByKey().isEmpty()
|
||||
);
|
||||
assertTrue(
|
||||
"StatelessSession: PersistenceContext has not been cleared",
|
||||
persistenceContextInternal.getCollectionsByKey() == Collections.emptyMap()
|
||||
);
|
||||
}
|
||||
|
||||
@Entity(name = "TestEntity")
|
||||
|
|
Loading…
Reference in New Issue