Skip to content

Commit 2b513e7

Browse files
committed
HHH-18326 Use instance identity to track persistent collections
1 parent e3eba64 commit 2b513e7

File tree

5 files changed

+232
-20
lines changed

5 files changed

+232
-20
lines changed

hibernate-core/src/main/java/org/hibernate/collection/spi/AbstractPersistentCollection.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ public abstract class AbstractPersistentCollection<E> implements Serializable, P
7979
private String sessionFactoryUuid;
8080
private boolean allowLoadOutsideTransaction;
8181

82+
private transient int instanceId;
83+
8284
/**
8385
* Not called by Hibernate, but used by non-JDK serialization,
8486
* eg. SOAP libraries.
@@ -1362,4 +1364,13 @@ public void setOwner(Object owner) {
13621364
this.owner = owner;
13631365
}
13641366

1367+
@Override
1368+
public int $$_hibernate_getInstanceId() {
1369+
return instanceId;
1370+
}
1371+
1372+
@Override
1373+
public void $$_hibernate_setInstanceId(int instanceId) {
1374+
this.instanceId = instanceId;
1375+
}
13651376
}

hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentCollection.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import org.hibernate.HibernateException;
1313
import org.hibernate.Incubating;
14+
import org.hibernate.engine.spi.InstanceIdentity;
1415
import org.hibernate.engine.spi.SharedSessionContractImplementor;
1516
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
1617
import org.hibernate.persister.collection.CollectionPersister;
@@ -52,7 +53,7 @@
5253
* @author Gavin King
5354
*/
5455
@Incubating
55-
public interface PersistentCollection<E> extends LazyInitializable {
56+
public interface PersistentCollection<E> extends LazyInitializable, InstanceIdentity {
5657
/**
5758
* Get the owning entity. Note that the owner is only
5859
* set during the flush cycle, and when a new collection

hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
import org.hibernate.event.spi.PostLoadEventListener;
5656
import org.hibernate.internal.CoreMessageLogger;
5757
import org.hibernate.internal.util.collections.CollectionHelper;
58-
import org.hibernate.internal.util.collections.IdentityMap;
58+
import org.hibernate.internal.util.collections.InstanceIdentityMap;
5959
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
6060
import org.hibernate.persister.collection.CollectionPersister;
6161
import org.hibernate.persister.entity.EntityPersister;
@@ -131,7 +131,10 @@ the following fields are used in all circumstances, and are not worth (or not su
131131
private IdentityHashMap<Object, PersistentCollection<?>> arrayHolders;
132132

133133
// Identity map of CollectionEntry instances, by the collection wrapper
134-
private IdentityMap<PersistentCollection<?>, CollectionEntry> collectionEntries;
134+
private InstanceIdentityMap<PersistentCollection<?>, CollectionEntry> collectionEntries;
135+
136+
// Current collection instance id
137+
private transient int currentCollectionInstanceId;
135138

136139
// Collection wrappers, by the CollectionKey
137140
private HashMap<CollectionKey, PersistentCollection<?>> collectionsByKey;
@@ -255,7 +258,7 @@ public void clear() {
255258

256259
final SharedSessionContractImplementor session = getSession();
257260
if ( collectionEntries != null ) {
258-
IdentityMap.onEachKey( collectionEntries, k -> k.unsetSession( session ) );
261+
collectionEntries.forEach( (k, v) -> k.unsetSession( session ) );
259262
}
260263

261264
arrayHolders = null;
@@ -267,6 +270,7 @@ public void clear() {
267270
collectionsByKey = null;
268271
nonlazyCollections = null;
269272
collectionEntries = null;
273+
currentCollectionInstanceId = 0;
270274
unownedCollections = null;
271275
nullifiableEntityKeys = null;
272276
deletedUnloadedEntityKeys = null;
@@ -614,7 +618,7 @@ public boolean isEntryFor(Object entity) {
614618

615619
@Override
616620
public CollectionEntry getCollectionEntry(PersistentCollection<?> coll) {
617-
return collectionEntries == null ? null : collectionEntries.get( coll );
621+
return collectionEntries == null ? null : collectionEntries.get( coll.$$_hibernate_getInstanceId(), coll );
618622
}
619623

620624
@Override
@@ -726,7 +730,7 @@ public EntityEntry addReferenceEntry(
726730

727731
@Override
728732
public boolean containsCollection(PersistentCollection<?> collection) {
729-
return collectionEntries != null && collectionEntries.containsKey( collection );
733+
return collectionEntries != null && collectionEntries.containsKey( collection.$$_hibernate_getInstanceId(), collection );
730734
}
731735

732736
@Override
@@ -1083,8 +1087,7 @@ public void replaceCollection(CollectionPersister persister, PersistentCollectio
10831087
"Replacement of not directly accessible collection found: " + oldCollection.getRole() );
10841088
}
10851089
assert !collection.isDirectlyAccessible();
1086-
final IdentityMap<PersistentCollection<?>, CollectionEntry> collectionEntries = getOrInitializeCollectionEntries();
1087-
final CollectionEntry oldEntry = collectionEntries.remove( oldCollection );
1090+
final CollectionEntry oldEntry = collectionEntries.remove( oldCollection.$$_hibernate_getInstanceId(), oldCollection );
10881091
final CollectionEntry entry;
10891092
if ( oldEntry.getLoadedPersister() != null ) {
10901093
// This is an already existing/loaded collection so ensure the loadedPersister is initialized
@@ -1094,7 +1097,7 @@ public void replaceCollection(CollectionPersister persister, PersistentCollectio
10941097
// A newly wrapped collection
10951098
entry = new CollectionEntry( persister, collection );
10961099
}
1097-
collectionEntries.put( collection, entry );
1100+
putCollectionEntry( collection, entry );
10981101
final Object key = collection.getKey();
10991102
if ( key != null ) {
11001103
final CollectionKey collectionKey = new CollectionKey( entry.getLoadedPersister(), key );
@@ -1113,7 +1116,7 @@ public void replaceCollection(CollectionPersister persister, PersistentCollectio
11131116
* @param key The key of the collection's entry.
11141117
*/
11151118
private void addCollection(PersistentCollection<?> coll, CollectionEntry entry, Object key) {
1116-
getOrInitializeCollectionEntries().put( coll, entry );
1119+
putCollectionEntry( coll, entry );
11171120
final CollectionKey collectionKey = new CollectionKey( entry.getLoadedPersister(), key );
11181121
final PersistentCollection<?> old = addCollectionByKey( collectionKey, coll );
11191122
if ( old != null ) {
@@ -1126,11 +1129,12 @@ private void addCollection(PersistentCollection<?> coll, CollectionEntry entry,
11261129
}
11271130
}
11281131

1129-
private IdentityMap<PersistentCollection<?>, CollectionEntry> getOrInitializeCollectionEntries() {
1132+
private void putCollectionEntry(PersistentCollection<?> collection, CollectionEntry entry) {
11301133
if ( this.collectionEntries == null ) {
1131-
this.collectionEntries = IdentityMap.instantiateSequenced( INIT_COLL_SIZE );
1134+
this.collectionEntries = new InstanceIdentityMap<>();
11321135
}
1133-
return this.collectionEntries;
1136+
collection.$$_hibernate_setInstanceId( nextCollectionInstanceId() );
1137+
this.collectionEntries.put( collection, entry );
11341138
}
11351139

11361140
/**
@@ -1141,7 +1145,7 @@ private IdentityMap<PersistentCollection<?>, CollectionEntry> getOrInitializeCol
11411145
*/
11421146
private void addCollection(PersistentCollection<?> collection, CollectionPersister persister) {
11431147
final CollectionEntry ce = new CollectionEntry( persister, collection );
1144-
getOrInitializeCollectionEntries().put( collection, ce );
1148+
putCollectionEntry( collection, ce );
11451149
}
11461150

11471151
@Override
@@ -1392,11 +1396,15 @@ public int getNumberOfManagedEntities() {
13921396
return collectionEntries;
13931397
}
13941398

1399+
private int nextCollectionInstanceId() {
1400+
return currentCollectionInstanceId++;
1401+
}
1402+
13951403
@Override
13961404
public void forEachCollectionEntry(BiConsumer<PersistentCollection<?>, CollectionEntry> action, boolean concurrent) {
13971405
if ( collectionEntries != null ) {
13981406
if ( concurrent ) {
1399-
for ( Entry<PersistentCollection<?>,CollectionEntry> entry : IdentityMap.concurrentEntries( collectionEntries ) ) {
1407+
for ( Entry<PersistentCollection<?>,CollectionEntry> entry : collectionEntries.toArray() ) {
14001408
action.accept( entry.getKey(), entry.getValue() );
14011409
}
14021410
}
@@ -2052,7 +2060,7 @@ public static StatefulPersistenceContext deserialize(
20522060
final PersistentCollection<?> pc = (PersistentCollection<?>) ois.readObject();
20532061
final CollectionEntry ce = CollectionEntry.deserialize( ois, session );
20542062
pc.setCurrentSession( session );
2055-
rtn.getOrInitializeCollectionEntries().put( pc, ce );
2063+
rtn.putCollectionEntry( pc, ce );
20562064
}
20572065

20582066
count = ois.readInt();
@@ -2194,7 +2202,12 @@ public int getCollectionEntriesSize() {
21942202

21952203
@Override
21962204
public CollectionEntry removeCollectionEntry(PersistentCollection<?> collection) {
2197-
return collectionEntries == null ? null : collectionEntries.remove(collection);
2205+
if ( collectionEntries != null ) {
2206+
return collectionEntries.remove( collection.$$_hibernate_getInstanceId(), collection );
2207+
}
2208+
else {
2209+
return null;
2210+
}
21982211
}
21992212

22002213
@Override

hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
import org.hibernate.event.spi.PersistContext;
3535
import org.hibernate.internal.CoreMessageLogger;
3636
import org.hibernate.internal.util.EntityPrinter;
37-
import org.hibernate.internal.util.collections.IdentityMap;
37+
import org.hibernate.internal.util.collections.InstanceIdentityMap;
3838
import org.hibernate.persister.entity.EntityPersister;
3939

4040
import org.jboss.logging.Logger;
@@ -190,7 +190,7 @@ private void prepareCollectionFlushes(PersistenceContext persistenceContext) thr
190190
persistenceContext.getCollectionEntries();
191191
if ( collectionEntries != null ) {
192192
for ( Map.Entry<PersistentCollection<?>, CollectionEntry> entry :
193-
( (IdentityMap<PersistentCollection<?>, CollectionEntry>) collectionEntries ).entryArray() ) {
193+
( (InstanceIdentityMap<PersistentCollection<?>, CollectionEntry>) collectionEntries ).toArray() ) {
194194
entry.getValue().preFlush( entry.getKey() );
195195
}
196196
}
@@ -271,7 +271,7 @@ private int flushCollections(final EventSource session, final PersistenceContext
271271
}
272272
else {
273273
count = collectionEntries.size();
274-
for ( Map.Entry<PersistentCollection<?>, CollectionEntry> me : ( (IdentityMap<PersistentCollection<?>, CollectionEntry>) collectionEntries ).entryArray() ) {
274+
for ( Map.Entry<PersistentCollection<?>, CollectionEntry> me : ( (InstanceIdentityMap<PersistentCollection<?>, CollectionEntry>) collectionEntries ).toArray() ) {
275275
final CollectionEntry ce = me.getValue();
276276
if ( !ce.isReached() && !ce.isIgnore() ) {
277277
Collections.processUnreachableCollection( me.getKey(), session );

0 commit comments

Comments
 (0)