[hibernate-commits] Hibernate SVN: r18167 - core/branches/Branch_3_3/core/src/main/java/org/hibernate/engine.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Dec 8 13:55:27 EST 2009


Author: steve.ebersole at jboss.com
Date: 2009-12-08 13:55:27 -0500 (Tue, 08 Dec 2009)
New Revision: 18167

Modified:
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/engine/Cascade.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/engine/PersistenceContext.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java
Log:
HHH-3860 - Cascading performance problems when session contains many entities


Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/engine/Cascade.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/engine/Cascade.java	2009-12-08 16:32:59 UTC (rev 18166)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/engine/Cascade.java	2009-12-08 18:55:27 UTC (rev 18167)
@@ -152,6 +152,7 @@
 
 				if ( style.doCascade( action ) ) {
 					cascadeProperty(
+						    parent,
 					        persister.getPropertyValue( parent, i, entityMode ),
 					        types[i],
 					        style,
@@ -180,6 +181,7 @@
 	 * 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 @@
 				AssociationType associationType = (AssociationType) type;
 				if ( cascadeAssociationNow( associationType ) ) {
 					cascadeAssociation(
+							parent,
 							child,
 							type,
 							style,
@@ -200,7 +203,7 @@
 				}
 			}
 			else if ( type.isComponentType() ) {
-				cascadeComponent( child, (AbstractComponentType) type, anything );
+				cascadeComponent( parent, child, (AbstractComponentType) type, anything );
 			}
 		}
 	}
@@ -211,6 +214,7 @@
 	}
 
 	private void cascadeComponent(
+			final Object parent,
 			final Object child,
 			final AbstractComponentType componentType,
 			final Object anything) {
@@ -220,6 +224,7 @@
 			CascadeStyle componentPropertyStyle = componentType.getCascadeStyle(i);
 			if ( componentPropertyStyle.doCascade(action) ) {
 				cascadeProperty(
+						parent,
 						children[i],
 						types[i],
 						componentPropertyStyle,
@@ -231,16 +236,17 @@
 	}
 
 	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 @@
 	 * 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 @@
 		//cascade to current collection elements
 		if ( elemType.isEntityType() || elemType.isAnyType() || elemType.isComponentType() ) {
 			cascadeCollectionElements(
+				parent,
 				child,
 				type,
 				style,
@@ -280,6 +288,7 @@
 	 * 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 @@
 				? ( (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 @@
 	 * Cascade to the collection elements
 	 */
 	private void cascadeCollectionElements(
+			final Object parent,
 			final Object child,
 			final CollectionType collectionType,
 			final CascadeStyle style,
@@ -318,6 +334,7 @@
 			Iterator iter = action.getCascadableChildrenIterator(eventSource, collectionType, child);
 			while ( iter.hasNext() ) {
 				cascadeProperty(
+						parent,
 						iter.next(), 
 						elemType,
 						style, 

Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/engine/PersistenceContext.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/engine/PersistenceContext.java	2009-12-08 16:32:59 UTC (rev 18166)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/engine/PersistenceContext.java	2009-12-08 18:55:27 UTC (rev 18167)
@@ -482,4 +482,17 @@
 	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);
 }

Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java	2009-12-08 16:32:59 UTC (rev 18166)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java	2009-12-08 18:55:27 UTC (rev 18167)
@@ -119,6 +119,10 @@
 	// 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 @@
 		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 @@
 		entitiesByKey.clear();
 		entitiesByUniqueKey.clear();
 		entityEntries.clear();
+		parentsByChild.clear();
 		entitySnapshotsByKey.clear();
 		collectionsByKey.clear();
 		collectionEntries.clear();
@@ -360,6 +366,8 @@
 		while ( iter.hasNext() ) {
 			if ( iter.next()==entity ) iter.remove();
 		}
+		// Clear all parent cache
+		parentsByChild.clear();
 		entitySnapshotsByKey.remove(key);
 		nullifiableEntityKeys.remove(key);
 		getBatchFetchQueue().removeBatchLoadableEntityKey(key);
@@ -1100,8 +1108,18 @@
 		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();
@@ -1203,7 +1221,26 @@
 				.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();
@@ -1273,6 +1310,7 @@
 	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 );
@@ -1483,4 +1521,18 @@
 
 		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);
+	}
 }



More information about the hibernate-commits mailing list