From 4c2a43b86f7f47be1a2e96c322f57cb1740acf9e Mon Sep 17 00:00:00 2001 From: Filip Nguyen Date: Wed, 10 Aug 2016 14:51:58 +0200 Subject: [PATCH] HHH-11032 performance improvements of PersistentBag.equalsSnapshot --- .../collection/internal/PersistentBag.java | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/PersistentBag.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/PersistentBag.java index c958ccd904..3c4f9380ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/internal/PersistentBag.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/PersistentBag.java @@ -11,9 +11,13 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; +import java.util.Map; +import java.util.stream.Collectors; import org.hibernate.HibernateException; import org.hibernate.engine.spi.SessionImplementor; @@ -128,21 +132,45 @@ public class PersistentBag extends AbstractPersistentCollection implements List } @Override + @SuppressWarnings( "unchecked" ) public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException { - final Type elementType = persister.getElementType(); - final List sn = (List) getSnapshot(); + Type elementType = persister.getElementType(); + List sn = (List) getSnapshot(); if ( sn.size() != bag.size() ) { return false; } + + // HHH-11032 - Group objects by Type.getHashCode() to reduce the complexity of the search + Map> instanceCountBag = groupByEqualityHash( bag, elementType ); + Map> instanceCountSn = groupByEqualityHash( sn, elementType ); + if ( instanceCountBag.size() != instanceCountSn.size() ) { + return false; + } + for ( Object elt : bag ) { - final boolean unequal = countOccurrences( elt, bag, elementType ) != countOccurrences( elt, sn, elementType ); - if ( unequal ) { + List candidatesBag = getItemsWithSameHash( instanceCountBag, elt, elementType ); + List candidatesSn = getItemsWithSameHash( instanceCountSn, elt, elementType ); + + if ( countOccurrences( elt, candidatesBag, elementType ) != countOccurrences( elt, candidatesSn, elementType ) ) { return false; } } return true; } + private List getItemsWithSameHash(Map> instanceCountBag, Object elt, Type elementType) { + return instanceCountBag.getOrDefault( elementType.getHashCode( elt ), Collections.emptyList() ); + } + + /** + * Groups items in searchedBag according to persistence "equality" as defined in Type.isSame and Type.getHashCode + * + * @return Map of "equality" hashCode to List of objects + */ + private Map> groupByEqualityHash(List searchedBag, Type elementType) { + return searchedBag.stream().collect( Collectors.groupingBy( elementType::getHashCode ) ); + } + @Override public boolean isSnapshotEmpty(Serializable snapshot) { return ( (Collection) snapshot ).isEmpty();