HHH-3860 - Cascading performance problems when session contains many entities
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18168 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
48c2ec7e91
commit
1005f19b1a
|
@ -152,6 +152,7 @@ public final class Cascade {
|
|||
|
||||
if ( style.doCascade( action ) ) {
|
||||
cascadeProperty(
|
||||
parent,
|
||||
persister.getPropertyValue( parent, i, entityMode ),
|
||||
types[i],
|
||||
style,
|
||||
|
@ -180,6 +181,7 @@ public final class Cascade {
|
|||
* Cascade an action to the child or children
|
||||
*/
|
||||
private void cascadeProperty(
|
||||
final Object parent,
|
||||
final Object child,
|
||||
final Type type,
|
||||
final CascadeStyle style,
|
||||
|
@ -191,6 +193,7 @@ public final class Cascade {
|
|||
AssociationType associationType = (AssociationType) type;
|
||||
if ( cascadeAssociationNow( associationType ) ) {
|
||||
cascadeAssociation(
|
||||
parent,
|
||||
child,
|
||||
type,
|
||||
style,
|
||||
|
@ -200,7 +203,7 @@ public final class Cascade {
|
|||
}
|
||||
}
|
||||
else if ( type.isComponentType() ) {
|
||||
cascadeComponent( child, (AbstractComponentType) type, anything );
|
||||
cascadeComponent( parent, child, (AbstractComponentType) type, anything );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -211,6 +214,7 @@ public final class Cascade {
|
|||
}
|
||||
|
||||
private void cascadeComponent(
|
||||
final Object parent,
|
||||
final Object child,
|
||||
final AbstractComponentType componentType,
|
||||
final Object anything) {
|
||||
|
@ -220,6 +224,7 @@ public final class Cascade {
|
|||
CascadeStyle componentPropertyStyle = componentType.getCascadeStyle(i);
|
||||
if ( componentPropertyStyle.doCascade(action) ) {
|
||||
cascadeProperty(
|
||||
parent,
|
||||
children[i],
|
||||
types[i],
|
||||
componentPropertyStyle,
|
||||
|
@ -231,16 +236,17 @@ public final class Cascade {
|
|||
}
|
||||
|
||||
private void cascadeAssociation(
|
||||
final Object parent,
|
||||
final Object child,
|
||||
final Type type,
|
||||
final CascadeStyle style,
|
||||
final Object anything,
|
||||
final boolean isCascadeDeleteEnabled) {
|
||||
if ( type.isEntityType() || type.isAnyType() ) {
|
||||
cascadeToOne( child, type, style, anything, isCascadeDeleteEnabled );
|
||||
cascadeToOne( parent, child, type, style, anything, isCascadeDeleteEnabled );
|
||||
}
|
||||
else if ( type.isCollectionType() ) {
|
||||
cascadeCollection( child, style, anything, (CollectionType) type );
|
||||
cascadeCollection( parent, child, style, anything, (CollectionType) type );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -248,6 +254,7 @@ public final class Cascade {
|
|||
* Cascade an action to a collection
|
||||
*/
|
||||
private void cascadeCollection(
|
||||
final Object parent,
|
||||
final Object child,
|
||||
final CascadeStyle style,
|
||||
final Object anything,
|
||||
|
@ -264,6 +271,7 @@ public final class Cascade {
|
|||
//cascade to current collection elements
|
||||
if ( elemType.isEntityType() || elemType.isAnyType() || elemType.isComponentType() ) {
|
||||
cascadeCollectionElements(
|
||||
parent,
|
||||
child,
|
||||
type,
|
||||
style,
|
||||
|
@ -280,6 +288,7 @@ public final class Cascade {
|
|||
* Cascade an action to a to-one association or any type
|
||||
*/
|
||||
private void cascadeToOne(
|
||||
final Object parent,
|
||||
final Object child,
|
||||
final Type type,
|
||||
final CascadeStyle style,
|
||||
|
@ -289,7 +298,13 @@ public final class Cascade {
|
|||
? ( (EntityType) type ).getAssociatedEntityName()
|
||||
: null;
|
||||
if ( style.reallyDoCascade(action) ) { //not really necessary, but good for consistency...
|
||||
action.cascade(eventSource, child, entityName, anything, isCascadeDeleteEnabled);
|
||||
eventSource.getPersistenceContext().addChildParent(child, parent);
|
||||
try {
|
||||
action.cascade(eventSource, child, entityName, anything, isCascadeDeleteEnabled);
|
||||
}
|
||||
finally {
|
||||
eventSource.getPersistenceContext().removeChildParent(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,6 +312,7 @@ public final class Cascade {
|
|||
* Cascade to the collection elements
|
||||
*/
|
||||
private void cascadeCollectionElements(
|
||||
final Object parent,
|
||||
final Object child,
|
||||
final CollectionType collectionType,
|
||||
final CascadeStyle style,
|
||||
|
@ -318,6 +334,7 @@ public final class Cascade {
|
|||
Iterator iter = action.getCascadableChildrenIterator(eventSource, collectionType, child);
|
||||
while ( iter.hasNext() ) {
|
||||
cascadeProperty(
|
||||
parent,
|
||||
iter.next(),
|
||||
elemType,
|
||||
style,
|
||||
|
|
|
@ -482,4 +482,17 @@ public interface PersistenceContext {
|
|||
public void setReadOnly(Object entity, boolean readOnly);
|
||||
|
||||
void replaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, Serializable generatedId);
|
||||
|
||||
/**
|
||||
* Put child/parent relation to cache for cascading op
|
||||
* @param parent
|
||||
* @param child
|
||||
*/
|
||||
public void addChildParent(Object parent, Object child);
|
||||
|
||||
/**
|
||||
* Remove child/parent relation from cache
|
||||
* @param parent
|
||||
*/
|
||||
public void removeChildParent(Object child);
|
||||
}
|
||||
|
|
|
@ -119,6 +119,10 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
// yet loaded ... for now, this is purely transient!
|
||||
private Map unownedCollections;
|
||||
|
||||
// Parent entities cache by their child for cascading
|
||||
// May be empty or not contains all relation
|
||||
private Map parentsByChild;
|
||||
|
||||
private int cascading = 0;
|
||||
private int loadCounter = 0;
|
||||
private boolean flushing = false;
|
||||
|
@ -147,7 +151,8 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
collectionEntries = IdentityMap.instantiateSequenced( INIT_COLL_SIZE );
|
||||
collectionsByKey = new HashMap( INIT_COLL_SIZE );
|
||||
arrayHolders = IdentityMap.instantiate( INIT_COLL_SIZE );
|
||||
|
||||
parentsByChild = IdentityMap.instantiateSequenced( INIT_COLL_SIZE );
|
||||
|
||||
nullifiableEntityKeys = new HashSet();
|
||||
|
||||
initTransientState();
|
||||
|
@ -214,6 +219,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
entitiesByKey.clear();
|
||||
entitiesByUniqueKey.clear();
|
||||
entityEntries.clear();
|
||||
parentsByChild.clear();
|
||||
entitySnapshotsByKey.clear();
|
||||
collectionsByKey.clear();
|
||||
collectionEntries.clear();
|
||||
|
@ -360,6 +366,8 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
while ( iter.hasNext() ) {
|
||||
if ( iter.next()==entity ) iter.remove();
|
||||
}
|
||||
// Clear all parent cache
|
||||
parentsByChild.clear();
|
||||
entitySnapshotsByKey.remove(key);
|
||||
nullifiableEntityKeys.remove(key);
|
||||
getBatchFetchQueue().removeBatchLoadableEntityKey(key);
|
||||
|
@ -1104,8 +1112,18 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
final EntityPersister persister = session.getFactory().getEntityPersister( entityName );
|
||||
final CollectionPersister collectionPersister = session.getFactory().getCollectionPersister( collectionRole );
|
||||
|
||||
// try cache lookup first
|
||||
Object parent = parentsByChild.get(childEntity);
|
||||
if (parent != null) {
|
||||
if (isFoundInParent(propertyName, childEntity, persister, collectionPersister, parent)) {
|
||||
return getEntry(parent).getId();
|
||||
}
|
||||
else {
|
||||
parentsByChild.remove(childEntity); // remove wrong entry
|
||||
}
|
||||
}
|
||||
// iterate all the entities currently associated with the persistence context.
|
||||
Iterator entities = entityEntries.entrySet().iterator();
|
||||
Iterator entities = IdentityMap.entries(entityEntries).iterator();
|
||||
while ( entities.hasNext() ) {
|
||||
final Map.Entry me = ( Map.Entry ) entities.next();
|
||||
final EntityEntry entityEntry = ( EntityEntry ) me.getValue();
|
||||
|
@ -1207,7 +1225,26 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
.getEntityPersister(entity);
|
||||
CollectionPersister cp = session.getFactory()
|
||||
.getCollectionPersister(entity + '.' + property);
|
||||
Iterator entities = entityEntries.entrySet().iterator();
|
||||
|
||||
// try cache lookup first
|
||||
Object parent = parentsByChild.get(childEntity);
|
||||
if (parent != null) {
|
||||
Object index = getIndexInParent(property, childEntity, persister, cp, parent);
|
||||
|
||||
if (index==null && mergeMap!=null) {
|
||||
Object unmergedInstance = mergeMap.get(parent);
|
||||
Object unmergedChild = mergeMap.get(childEntity);
|
||||
if ( unmergedInstance!=null && unmergedChild!=null ) {
|
||||
index = getIndexInParent(property, unmergedChild, persister, cp, unmergedInstance);
|
||||
}
|
||||
}
|
||||
if (index!=null) {
|
||||
return index;
|
||||
}
|
||||
parentsByChild.remove(childEntity); // remove wrong entry
|
||||
}
|
||||
|
||||
Iterator entities = IdentityMap.entries(entityEntries).iterator();
|
||||
while ( entities.hasNext() ) {
|
||||
Map.Entry me = (Map.Entry) entities.next();
|
||||
EntityEntry ee = (EntityEntry) me.getValue();
|
||||
|
@ -1277,6 +1314,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
public void replaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, Serializable generatedId) {
|
||||
Object entity = entitiesByKey.remove( oldKey );
|
||||
EntityEntry oldEntry = ( EntityEntry ) entityEntries.remove( entity );
|
||||
parentsByChild.clear();
|
||||
|
||||
EntityKey newKey = new EntityKey( generatedId, oldEntry.getPersister(), getSession().getEntityMode() );
|
||||
addEntity( newKey, entity );
|
||||
|
@ -1487,4 +1525,18 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.hibernate.engine.PersistenceContext#addChildParent(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public void addChildParent(Object child, Object parent) {
|
||||
parentsByChild.put(child, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.hibernate.engine.PersistenceContext#removeChildParent(java.lang.Object)
|
||||
*/
|
||||
public void removeChildParent(Object child) {
|
||||
parentsByChild.remove(child);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue