[hibernate-commits] Hibernate SVN: r11652 - in trunk/Hibernate3/code/core/src/main/java/org/hibernate: engine/loading and 1 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Thu Jun 7 14:26:42 EDT 2007


Author: steve.ebersole at jboss.com
Date: 2007-06-07 14:26:42 -0400 (Thu, 07 Jun 2007)
New Revision: 11652

Modified:
   trunk/Hibernate3/code/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java
   trunk/Hibernate3/code/core/src/main/java/org/hibernate/engine/loading/CollectionLoadContext.java
   trunk/Hibernate3/code/core/src/main/java/org/hibernate/engine/loading/EntityLoadContext.java
   trunk/Hibernate3/code/core/src/main/java/org/hibernate/engine/loading/LoadContexts.java
   trunk/Hibernate3/code/core/src/main/java/org/hibernate/impl/AbstractScrollableResults.java
   trunk/Hibernate3/code/core/src/main/java/org/hibernate/impl/IteratorImpl.java
Log:
HHH-2631 : LoadContext cleanup

Modified: trunk/Hibernate3/code/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java
===================================================================
--- trunk/Hibernate3/code/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java	2007-06-07 18:22:50 UTC (rev 11651)
+++ trunk/Hibernate3/code/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java	2007-06-07 18:26:42 UTC (rev 11652)
@@ -203,6 +203,9 @@
 			batchFetchQueue.clear();
 		}
 		hasNonReadOnlyEntities = false;
+		if ( loadContexts != null ) {
+			loadContexts.cleanup();
+		}
 	}
 	
 	public boolean hasNonReadOnlyEntities() {

Modified: trunk/Hibernate3/code/core/src/main/java/org/hibernate/engine/loading/CollectionLoadContext.java
===================================================================
--- trunk/Hibernate3/code/core/src/main/java/org/hibernate/engine/loading/CollectionLoadContext.java	2007-06-07 18:22:50 UTC (rev 11651)
+++ trunk/Hibernate3/code/core/src/main/java/org/hibernate/engine/loading/CollectionLoadContext.java	2007-06-07 18:26:42 UTC (rev 11652)
@@ -2,7 +2,6 @@
 
 import java.sql.ResultSet;
 import java.io.Serializable;
-import java.util.Map;
 import java.util.List;
 import java.util.Iterator;
 import java.util.ArrayList;
@@ -126,7 +125,7 @@
 			collection.beforeInitialize( persister, -1 );
 			collection.beginRead();
 			localLoadingCollectionKeys.add( collectionKey );
-			loadContexts.registerLoadingCollectionEntry( collectionKey, new LoadingCollectionEntry( resultSet, persister, key, collection ) );
+			loadContexts.registerLoadingCollectionXRef( collectionKey, new LoadingCollectionEntry( resultSet, persister, key, collection ) );
 			return collection;
 		}
 		else {
@@ -152,8 +151,7 @@
 	 */
 	public void endLoadingCollections(CollectionPersister persister) {
 		SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
-		if ( loadContexts.getLoadingCollectionEntryMap() == null
-				|| loadContexts.getLoadingCollectionEntryMap().isEmpty()
+		if ( !loadContexts.hasLoadingCollectionEntries()
 				|| localLoadingCollectionKeys.isEmpty() ) {
 			return;
 		}
@@ -165,12 +163,14 @@
 		// in a temp collection.  the temp collection is then used to "drive"
 		// the #endRead processing.
 		List matches = null;
-		Iterator iter = loadContexts.getLoadingCollectionEntryMap().entrySet().iterator();
+		Iterator iter = localLoadingCollectionKeys.iterator();
 		while ( iter.hasNext() ) {
-			final Map.Entry mapEntry = ( Map.Entry ) iter.next();
-			final CollectionKey collectionKey = ( CollectionKey ) mapEntry.getKey();
-			final LoadingCollectionEntry lce = ( LoadingCollectionEntry ) mapEntry.getValue();
-			if ( localLoadingCollectionKeys.contains( collectionKey ) && lce.getResultSet() == resultSet && lce.getPersister() == persister) {
+			final CollectionKey collectionKey = (CollectionKey) iter.next();
+			final LoadingCollectionEntry lce = loadContexts.locateLoadingCollectionEntry( collectionKey );
+			if ( lce == null) {
+				log.warn( "In CollectionLoadContext#endLoadingCollections, localLoadingCollectionKeys contained [" + collectionKey + "], but no LoadingCollectionEntry was found in loadContexts" );
+			}
+			else if ( lce.getResultSet() == resultSet && lce.getPersister() == persister ) {
 				if ( matches == null ) {
 					matches = new ArrayList();
 				}
@@ -184,11 +184,23 @@
 				if ( log.isTraceEnabled() ) {
 					log.trace( "removing collection load entry [" + lce + "]" );
 				}
+
+				// todo : i'd much rather have this done from #endLoadingCollection(CollectionPersister,LoadingCollectionEntry)...
+				loadContexts.unregisterLoadingCollectionXRef( collectionKey );
 				iter.remove();
 			}
 		}
 
 		endLoadingCollections( persister, matches );
+		if ( localLoadingCollectionKeys.isEmpty() ) {
+			// todo : hack!!!
+			// NOTE : here we cleanup the load context when we have no more local
+			// LCE entries.  This "works" for the time being because really
+			// only the collection load contexts are implemented.  Long term,
+			// this cleanup should become part of the "close result set"
+			// processing from the (sandbox/jdbc) jdbc-container code.
+			loadContexts.cleanup( resultSet );
+		}
 	}
 
 	private void endLoadingCollections(CollectionPersister persister, List matchedCollectionEntries) {
@@ -309,9 +321,9 @@
 
 	void cleanup() {
 		if ( !localLoadingCollectionKeys.isEmpty() ) {
-			log.warn( "On CollectionLoadContext#clear, loadingCollections contained [" + localLoadingCollectionKeys.size() + "] entries" );
+			log.warn( "On CollectionLoadContext#cleanup, localLoadingCollectionKeys contained [" + localLoadingCollectionKeys.size() + "] entries" );
 		}
-		loadContexts.cleanupCollectionEntries( localLoadingCollectionKeys );
+		loadContexts.cleanupCollectionXRefs( localLoadingCollectionKeys );
 		localLoadingCollectionKeys.clear();
 	}
 

Modified: trunk/Hibernate3/code/core/src/main/java/org/hibernate/engine/loading/EntityLoadContext.java
===================================================================
--- trunk/Hibernate3/code/core/src/main/java/org/hibernate/engine/loading/EntityLoadContext.java	2007-06-07 18:22:50 UTC (rev 11651)
+++ trunk/Hibernate3/code/core/src/main/java/org/hibernate/engine/loading/EntityLoadContext.java	2007-06-07 18:26:42 UTC (rev 11652)
@@ -30,4 +30,10 @@
 		}
 		hydratingEntities.clear();
 	}
+
+
+	public String toString() {
+		return super.toString() + "<rs=" + resultSet + ">";
+	}
+
 }

Modified: trunk/Hibernate3/code/core/src/main/java/org/hibernate/engine/loading/LoadContexts.java
===================================================================
--- trunk/Hibernate3/code/core/src/main/java/org/hibernate/engine/loading/LoadContexts.java	2007-06-07 18:22:50 UTC (rev 11651)
+++ trunk/Hibernate3/code/core/src/main/java/org/hibernate/engine/loading/LoadContexts.java	2007-06-07 18:26:42 UTC (rev 11652)
@@ -63,7 +63,80 @@
 		return persistenceContext;
 	}
 
+	private SessionImplementor getSession() {
+		return getPersistenceContext().getSession();
+	}
+
+	private EntityMode getEntityMode() {
+		return getSession().getEntityMode();
+	}
+
+
+	// cleanup code ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ 	/**
+	 * Release internal state associated with the given result set.
+	 * <p/>
+	 * This should be called when we are done with processing said result set,
+	 * ideally as the result set is being closed.
+	 *
+	 * @param resultSet The result set for which it is ok to release
+	 * associated resources.
+	 */
+	public void cleanup(ResultSet resultSet) {
+		if ( collectionLoadContexts != null ) {
+			CollectionLoadContext collectionLoadContext = ( CollectionLoadContext ) collectionLoadContexts.remove( resultSet );
+			collectionLoadContext.cleanup();
+		}
+		if ( entityLoadContexts != null ) {
+			EntityLoadContext entityLoadContext = ( EntityLoadContext ) entityLoadContexts.remove( resultSet );
+			entityLoadContext.cleanup();
+		}
+	}
+
 	/**
+	 * Release internal state associated with *all* result sets.
+	 * <p/>
+	 * This is intended as a "failsafe" process to make sure we get everything
+	 * cleaned up and released.
+	 */
+	public void cleanup() {
+		if ( collectionLoadContexts != null ) {
+			Iterator itr = collectionLoadContexts.values().iterator();
+			while ( itr.hasNext() ) {
+				CollectionLoadContext collectionLoadContext = ( CollectionLoadContext ) itr.next();
+				log.warn( "fail-safe cleanup (collections) : " + collectionLoadContext );
+				collectionLoadContext.cleanup();
+			}
+			collectionLoadContexts.clear();
+		}
+		if ( entityLoadContexts != null ) {
+			Iterator itr = entityLoadContexts.values().iterator();
+			while ( itr.hasNext() ) {
+				EntityLoadContext entityLoadContext = ( EntityLoadContext ) itr.next();
+				log.warn( "fail-safe cleanup (entities) : " + entityLoadContext );
+				entityLoadContext.cleanup();
+			}
+			entityLoadContexts.clear();
+		}
+	}
+
+
+	// Collection load contexts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Do we currently have any internal entries corresponding to loading
+	 * collections?
+	 *
+	 * @return True if we currently hold state pertaining to loading collections;
+	 * false otherwise.
+	 */
+	public boolean hasLoadingCollectionEntries() {
+		return ( xrefLoadingCollectionEntries != null && !xrefLoadingCollectionEntries.isEmpty() );
+	}
+
+
+	/**
 	 * Get the {@link CollectionLoadContext} associated with the given
 	 * {@link ResultSet}, creating one if needed.
 	 *
@@ -113,7 +186,60 @@
 		}
 	}
 
+
+
+
+	// loading collection xrefs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
 	/**
+	 * Register a loading collection xref.
+	 * <p/>
+	 * This xref map is used because sometimes a collection is in process of
+	 * being loaded from one result set, but needs to be accessed from the
+	 * context of another "nested" result set processing.
+	 * <p/>
+	 * Implementation note: package protected, as this is meant solely for use
+	 * by {@link CollectionLoadContext} to be able to locate collections
+	 * being loaded by other {@link CollectionLoadContext}s/{@link ResultSet}s.
+	 *
+	 * @param entryKey The xref collection key
+	 * @param entry The corresponding loading collection entry
+	 */
+	void registerLoadingCollectionXRef(CollectionKey entryKey, LoadingCollectionEntry entry) {
+		if ( xrefLoadingCollectionEntries == null ) {
+			xrefLoadingCollectionEntries = new HashMap();
+		}
+		xrefLoadingCollectionEntries.put( entryKey, entry );
+	}
+
+	/**
+	 * The inverse of {@link #registerLoadingCollectionXRef}.  Here, we are done
+	 * processing the said collection entry, so we remove it from the
+	 * load context.
+	 * <p/>
+	 * The idea here is that other loading collections can now reference said
+	 * collection directly from the {@link PersistenceContext} because it
+	 * has completed its load cycle.
+	 * <p/>
+	 * Implementation note: package protected, as this is meant solely for use
+	 * by {@link CollectionLoadContext} to be able to locate collections
+	 * being loaded by other {@link CollectionLoadContext}s/{@link ResultSet}s.
+	 *
+	 * @param key The key of the collection we are done processing.
+	 */
+	void unregisterLoadingCollectionXRef(CollectionKey key) {
+		if ( !hasLoadingCollectionEntries() ) {
+			return;
+		}
+		xrefLoadingCollectionEntries.remove(key);
+	 }
+
+	/*package*/Map getLoadingCollectionXRefs() {
+ 		return xrefLoadingCollectionEntries;
+ 	}
+
+
+	/**
 	 * Locate the LoadingCollectionEntry within *any* of the tracked
 	 * {@link CollectionLoadContext}s.
 	 * <p/>
@@ -143,18 +269,7 @@
 		return rtn;
 	}
 
-	/*package*/void registerLoadingCollectionEntry(CollectionKey entryKey, LoadingCollectionEntry entry) {
-		if ( xrefLoadingCollectionEntries == null ) {
-			xrefLoadingCollectionEntries = new HashMap();
-		}
-		xrefLoadingCollectionEntries.put( entryKey, entry );
-	}
-
-	/*package*/Map getLoadingCollectionEntryMap() {
-		return xrefLoadingCollectionEntries;
-	}
-
-	/*package*/void cleanupCollectionEntries(Set entryKeys) {
+	/*package*/void cleanupCollectionXRefs(Set entryKeys) {
 		Iterator itr = entryKeys.iterator();
 		while ( itr.hasNext() ) {
 			final CollectionKey entryKey = ( CollectionKey ) itr.next();
@@ -162,6 +277,10 @@
 		}
 	}
 
+
+	// Entity load contexts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	// 	* currently, not yet used...
+
 	public EntityLoadContext getEntityLoadContext(ResultSet resultSet) {
 		EntityLoadContext context = null;
 		if ( entityLoadContexts == null ) {
@@ -177,23 +296,4 @@
 		return context;
 	}
 
-	public void cleanup(ResultSet resultSet) {
-		if ( collectionLoadContexts != null ) {
-			CollectionLoadContext collectionLoadContext = ( CollectionLoadContext ) collectionLoadContexts.remove( resultSet );
-			collectionLoadContext.cleanup();
-		}
-		if ( entityLoadContexts != null ) {
-			EntityLoadContext entityLoadContext = ( EntityLoadContext ) entityLoadContexts.remove( resultSet );
-			entityLoadContext.cleanup();
-		}
-	}
-
-	private SessionImplementor getSession() {
-		return getPersistenceContext().getSession();
-	}
-
-	private EntityMode getEntityMode() {
-		return getSession().getEntityMode();
-	}
-
 }

Modified: trunk/Hibernate3/code/core/src/main/java/org/hibernate/impl/AbstractScrollableResults.java
===================================================================
--- trunk/Hibernate3/code/core/src/main/java/org/hibernate/impl/AbstractScrollableResults.java	2007-06-07 18:22:50 UTC (rev 11651)
+++ trunk/Hibernate3/code/core/src/main/java/org/hibernate/impl/AbstractScrollableResults.java	2007-06-07 18:26:42 UTC (rev 11652)
@@ -13,6 +13,9 @@
 import java.util.Locale;
 import java.util.TimeZone;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
 import org.hibernate.Hibernate;
 import org.hibernate.HibernateException;
 import org.hibernate.MappingException;
@@ -31,6 +34,8 @@
  */
 public abstract class AbstractScrollableResults implements ScrollableResults {
 
+	private static final Log log = LogFactory.getLog( AbstractScrollableResults.class );
+
 	private final ResultSet resultSet;
 	private final PreparedStatement ps;
 	private final SessionImplementor session;
@@ -91,7 +96,7 @@
 	public final void close() throws HibernateException {
 		try {
 			// not absolutely necessary, but does help with aggressive release
-			session.getBatcher().closeQueryStatement(ps, resultSet);
+			session.getBatcher().closeQueryStatement( ps, resultSet );
 		}
 		catch (SQLException sqle) {
 			throw JDBCExceptionHelper.convert(
@@ -100,6 +105,15 @@
 					"could not close results"
 				);
 		}
+		finally {
+			try {
+				session.getPersistenceContext().getLoadContexts().cleanup( resultSet );
+			}
+			catch( Throwable ignore ) {
+				// ignore this error for now
+				log.trace( "exception trying to cleanup load context : " + ignore.getMessage() );
+			}
+		}
 	}
 
 	public final Object[] get() throws HibernateException {

Modified: trunk/Hibernate3/code/core/src/main/java/org/hibernate/impl/IteratorImpl.java
===================================================================
--- trunk/Hibernate3/code/core/src/main/java/org/hibernate/impl/IteratorImpl.java	2007-06-07 18:22:50 UTC (rev 11651)
+++ trunk/Hibernate3/code/core/src/main/java/org/hibernate/impl/IteratorImpl.java	2007-06-07 18:26:42 UTC (rev 11652)
@@ -76,6 +76,15 @@
 				        "Unable to close iterator"
 					);
 			}
+			finally {
+				try {
+					session.getPersistenceContext().getLoadContexts().cleanup( rs );
+				}
+				catch( Throwable ignore ) {
+					// ignore this error for now
+					log.trace( "exception trying to cleanup load context : " + ignore.getMessage() );
+				}
+			}
 		}
 	}
 




More information about the hibernate-commits mailing list