[hibernate-commits] Hibernate SVN: r19906 - in core/branches/Branch_3_3_2_GA_CP: testsuite/src/test/perf/org/hibernate/test/perf and 1 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Wed Jul 7 09:08:31 EDT 2010


Author: stliu
Date: 2010-07-07 09:08:31 -0400 (Wed, 07 Jul 2010)
New Revision: 19906

Added:
   core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/CascadingTest.hbm.xml
   core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/CascadingTest.java
   core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/object/
   core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/object/A.java
   core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/object/B.java
   core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/object/C.java
Modified:
   core/branches/Branch_3_3_2_GA_CP/core/src/main/java/org/hibernate/engine/Cascade.java
   core/branches/Branch_3_3_2_GA_CP/core/src/main/java/org/hibernate/engine/PersistenceContext.java
   core/branches/Branch_3_3_2_GA_CP/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java
Log:
JBPAPP-4562 HHH-3860 Cascading performance problems when session contains many entities

Modified: core/branches/Branch_3_3_2_GA_CP/core/src/main/java/org/hibernate/engine/Cascade.java
===================================================================
--- core/branches/Branch_3_3_2_GA_CP/core/src/main/java/org/hibernate/engine/Cascade.java	2010-07-06 19:35:13 UTC (rev 19905)
+++ core/branches/Branch_3_3_2_GA_CP/core/src/main/java/org/hibernate/engine/Cascade.java	2010-07-07 13:08:31 UTC (rev 19906)
@@ -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,9 @@
 				? ( (EntityType) type ).getAssociatedEntityName()
 				: null;
 		if ( style.reallyDoCascade(action) ) { //not really necessary, but good for consistency...
+			eventSource.getPersistenceContext().addChildParent(child, parent);
 			action.cascade(eventSource, child, entityName, anything, isCascadeDeleteEnabled);
+			eventSource.getPersistenceContext().removeChildParent(child);
 		}
 	}
 
@@ -297,6 +308,7 @@
 	 * Cascade to the collection elements
 	 */
 	private void cascadeCollectionElements(
+			final Object parent,
 			final Object child,
 			final CollectionType collectionType,
 			final CascadeStyle style,
@@ -318,6 +330,7 @@
 			Iterator iter = action.getCascadableChildrenIterator(eventSource, collectionType, child);
 			while ( iter.hasNext() ) {
 				cascadeProperty(
+						parent,
 						iter.next(), 
 						elemType,
 						style, 

Modified: core/branches/Branch_3_3_2_GA_CP/core/src/main/java/org/hibernate/engine/PersistenceContext.java
===================================================================
--- core/branches/Branch_3_3_2_GA_CP/core/src/main/java/org/hibernate/engine/PersistenceContext.java	2010-07-06 19:35:13 UTC (rev 19905)
+++ core/branches/Branch_3_3_2_GA_CP/core/src/main/java/org/hibernate/engine/PersistenceContext.java	2010-07-07 13:08:31 UTC (rev 19906)
@@ -486,4 +486,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 child
+	 */
+	public void removeChildParent(Object child);
 }

Modified: core/branches/Branch_3_3_2_GA_CP/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java
===================================================================
--- core/branches/Branch_3_3_2_GA_CP/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java	2010-07-06 19:35:13 UTC (rev 19905)
+++ core/branches/Branch_3_3_2_GA_CP/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java	2010-07-07 13:08:31 UTC (rev 19906)
@@ -118,7 +118,9 @@
 	// A container for collections we load up when the owning entity is not
 	// 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 +149,7 @@
 		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();
@@ -210,6 +212,7 @@
 		entitiesByKey.clear();
 		entitiesByUniqueKey.clear();
 		entityEntries.clear();
+		parentsByChild.clear();
 		entitySnapshotsByKey.clear();
 		collectionsByKey.clear();
 		collectionEntries.clear();
@@ -356,6 +359,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);
@@ -1093,9 +1098,18 @@
 		final String collectionRole = entityName + '.' + propertyName;
 		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();
@@ -1197,7 +1211,27 @@
 				.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();
@@ -1267,6 +1301,8 @@
 	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 );
@@ -1477,4 +1513,19 @@
 
 		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);
+	}
 }

Added: core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/CascadingTest.hbm.xml
===================================================================
--- core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/CascadingTest.hbm.xml	                        (rev 0)
+++ core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/CascadingTest.hbm.xml	2010-07-07 13:08:31 UTC (rev 19906)
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping package="org.hibernate.test.perf.object">
+  <class name="A" table="A">
+    <id name="id" type="long" access="field">
+      <generator class="hilo">
+        <param name="max_lo">10000</param>
+      </generator>
+    </id>
+    <property name="a" type="integer" access="field"/>
+    <map name="map" access="field" cascade="all">
+      <key column="a" not-null="true"/>
+      <map-key column="keycol" type="integer"/>
+      <one-to-many class="B"/>
+    </map>
+  </class>
+  <class name="B" table="B">
+    <id name="id" type="long" access="field">
+      <generator class="hilo">
+        <param name="max_lo">10000</param>
+      </generator>
+    </id>
+    <property name="b" type="integer" access="field"/>
+    <list name="list" access="field" cascade="all">
+      <key column="keycol" not-null="true"/>
+      <list-index column="pos"/>
+      <one-to-many class="C"/>
+    </list>
+  </class>
+  <class name="C" table="C">
+    <id name="id" type="long" access="field">
+      <generator class="hilo">
+        <param name="max_lo">10000</param>
+      </generator>
+    </id>
+    <property name="c" type="integer" access="field"/>
+  </class>
+</hibernate-mapping>
\ No newline at end of file

Added: core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/CascadingTest.java
===================================================================
--- core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/CascadingTest.java	                        (rev 0)
+++ core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/CascadingTest.java	2010-07-07 13:08:31 UTC (rev 19906)
@@ -0,0 +1,65 @@
+package org.hibernate.test.perf;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.test.perf.object.A;
+import org.hibernate.test.perf.object.B;
+import org.hibernate.test.perf.object.C;
+
+public class CascadingTest   extends FunctionalTestCase  {
+
+    public CascadingTest(String string) {
+		super(string);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "perf/CascadingTest.hbm.xml" };
+	}
+
+	/**
+     * Make 5510 objects on database
+     */
+    public void testSaveSession() {
+        Session session = openSession();
+        Transaction tx = session.beginTransaction();
+        long timeTotal = System.currentTimeMillis();
+        for (int x = 0; x < 10; x++) {
+            makeObjects(session);
+        }
+        session.flush();
+        tx.commit();
+        session.close();
+        System.out.println("Total took " + ((System.currentTimeMillis() - timeTotal)) + " ms");
+    }
+    
+
+    /**
+     * Make 551 new objects
+     * 
+     * @param session
+     */
+    private void makeObjects(Session session) {
+        A a = new A();
+        a.setA(-1);
+        a.setMap(new HashMap());
+        for (int i = 0; i < 50; i++) {
+            B b = new B();
+            b.setB(i);
+            b.setList(new ArrayList());
+            a.getMap().put(new Integer(i), b);
+            for (int j = 0; j < 10; j++) {
+                C c = new C();
+                c.setC(j * 1000000);
+                b.getList().add(c);
+            }
+        }
+        long time = System.currentTimeMillis();
+        session.save(a);
+        System.out.println("Save took " + ((System.currentTimeMillis() - time)) + " ms");
+        time = System.currentTimeMillis();
+    }
+}

Added: core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/object/A.java
===================================================================
--- core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/object/A.java	                        (rev 0)
+++ core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/object/A.java	2010-07-07 13:08:31 UTC (rev 19906)
@@ -0,0 +1,32 @@
+package org.hibernate.test.perf.object;
+
+import java.util.Map;
+
+public class A {
+	protected long id;
+
+	protected int a;
+
+	protected Map map;
+
+	public int getA() {
+		return a;
+	}
+
+	public void setA(int a) {
+		this.a = a;
+	}
+
+	public Map getMap() {
+		return map;
+	}
+
+	public void setMap(Map map) {
+		this.map = map;
+	}
+
+	public long getId() {
+		return id;
+	}
+
+}

Added: core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/object/B.java
===================================================================
--- core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/object/B.java	                        (rev 0)
+++ core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/object/B.java	2010-07-07 13:08:31 UTC (rev 19906)
@@ -0,0 +1,32 @@
+package org.hibernate.test.perf.object;
+
+import java.util.List;
+
+public class B {
+	protected long id;
+
+	protected int b;
+
+	protected List list;
+
+	public int getB() {
+		return b;
+	}
+
+	public void setB(int b) {
+		this.b = b;
+	}
+
+	public List getList() {
+		return list;
+	}
+
+	public void setList(List list) {
+		this.list = list;
+	}
+
+	public long getId() {
+		return id;
+	}
+
+}

Added: core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/object/C.java
===================================================================
--- core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/object/C.java	                        (rev 0)
+++ core/branches/Branch_3_3_2_GA_CP/testsuite/src/test/perf/org/hibernate/test/perf/object/C.java	2010-07-07 13:08:31 UTC (rev 19906)
@@ -0,0 +1,19 @@
+package org.hibernate.test.perf.object;
+
+public class C {
+	protected long id;
+
+	protected int c;
+
+	public int getC() {
+		return c;
+	}
+
+	public void setC(int c) {
+		this.c = c;
+	}
+
+	public long getId() {
+		return id;
+	}
+}



More information about the hibernate-commits mailing list