1414import org .hibernate .engine .spi .PersistentAttributeInterceptor ;
1515import org .hibernate .internal .CoreLogging ;
1616import org .hibernate .internal .CoreMessageLogger ;
17+ import org .hibernate .internal .util .collections .InstanceIdentityMap ;
18+ import org .hibernate .internal .util .collections .StandardStack ;
1719
1820import java .io .IOException ;
1921import java .io .ObjectInputStream ;
@@ -49,7 +51,9 @@ public class EntityEntryContext {
4951
5052 private final transient PersistenceContext persistenceContext ;
5153
52- private transient IdentityHashMap <ManagedEntity ,ImmutableManagedEntityHolder > immutableManagedEntityXref ;
54+ private transient InstanceIdentityMap <ManagedEntity , ImmutableManagedEntityHolder > immutableManagedEntityXref ;
55+ private transient StandardStack <Integer > reusableInstanceIds ;
56+ private transient int currentInstanceId ;
5357
5458 private transient ManagedEntity head ;
5559 private transient ManagedEntity tail ;
@@ -107,13 +111,8 @@ public void addEntityEntry(Object entity, EntityEntry entityEntry) {
107111 else {
108112 // Create a holder for PersistenceContext-related data.
109113 managedEntity = new ImmutableManagedEntityHolder ( managed );
110- if ( immutableManagedEntityXref == null ) {
111- immutableManagedEntityXref = new IdentityHashMap <>();
112- }
113- immutableManagedEntityXref .put (
114- managed ,
115- (ImmutableManagedEntityHolder ) managedEntity
116- );
114+ managed .$$_hibernate_setInstanceId ( nextManagedEntityInstanceId () );
115+ putImmutableManagedEntity ( managed , (ImmutableManagedEntityHolder ) managedEntity );
117116 }
118117 }
119118 else {
@@ -171,11 +170,10 @@ private ManagedEntity getAssociatedManagedEntity(Object entity) {
171170 : null ;
172171 }
173172 else {
174- // if managedEntity is associated with this EntityEntryContext, then
175- // it will have an entry in immutableManagedEntityXref and its
176- // holder will be returned.
173+ // if managedEntity is associated with this EntityEntryContext, it may have
174+ // an entry in immutableManagedEntityXref and its holder will be returned.
177175 return immutableManagedEntityXref != null
178- ? immutableManagedEntityXref .get ( managedEntity )
176+ ? immutableManagedEntityXref .get ( managedEntity . $$_hibernate_getInstanceId (), managedEntity )
179177 : null ;
180178 }
181179 }
@@ -186,6 +184,19 @@ private ManagedEntity getAssociatedManagedEntity(Object entity) {
186184 }
187185 }
188186
187+ private int nextManagedEntityInstanceId () {
188+ return reusableInstanceIds != null && !reusableInstanceIds .isEmpty () ?
189+ reusableInstanceIds .pop () :
190+ currentInstanceId ++;
191+ }
192+
193+ private void putImmutableManagedEntity (ManagedEntity managed , ImmutableManagedEntityHolder holder ) {
194+ if ( immutableManagedEntityXref == null ) {
195+ immutableManagedEntityXref = new InstanceIdentityMap <>();
196+ }
197+ immutableManagedEntityXref .put ( managed , holder );
198+ }
199+
189200 private void checkNotAssociatedWithOtherPersistenceContextIfMutable (ManagedEntity managedEntity ) {
190201 // we only have to check mutable managedEntity
191202 final AbstractEntityEntry entityEntry = (AbstractEntityEntry ) managedEntity .$$_hibernate_getEntityEntry ();
@@ -253,15 +264,20 @@ public EntityEntry removeEntityEntry(Object entity) {
253264
254265 dirty = true ;
255266
256- if (managedEntity instanceof ImmutableManagedEntityHolder ) {
257- assert entity == ( (ImmutableManagedEntityHolder ) managedEntity ).managedEntity ;
258- immutableManagedEntityXref .remove ( entity );
259-
267+ if ( managedEntity instanceof ImmutableManagedEntityHolder ) {
268+ assert entity == ((ImmutableManagedEntityHolder ) managedEntity ).managedEntity ;
269+ final int instanceId = managedEntity .$$_hibernate_getInstanceId ();
270+ immutableManagedEntityXref .remove ( instanceId , managedEntity );
271+ reusableInstanceIds .push ( instanceId );
260272 }
261- else if ( ! ( isManagedEntity ( entity ) ) ) {
273+ else if ( !isManagedEntity ( entity ) ) {
262274 nonEnhancedEntityXref .remove ( entity );
263275 }
264276
277+ if ( reusableInstanceIds == null ) {
278+ reusableInstanceIds = new StandardStack <>();
279+ }
280+
265281 // prepare for re-linking...
266282 final ManagedEntity previous = managedEntity .$$_hibernate_getPreviousManagedEntity ();
267283 final ManagedEntity next = managedEntity .$$_hibernate_getNextManagedEntity ();
@@ -387,6 +403,8 @@ public void clear() {
387403 count = 0 ;
388404
389405 reentrantSafeEntries = null ;
406+ currentInstanceId = 0 ;
407+ reusableInstanceIds = null ;
390408 }
391409
392410 private static void clearManagedEntity (final ManagedEntity node ) {
@@ -480,19 +498,13 @@ public static EntityEntryContext deserialize(ObjectInputStream ois, StatefulPers
480498 if ( isEnhanced ) {
481499 if ( entry .getPersister ().isMutable () ) {
482500 managedEntity = ManagedTypeHelper .asManagedEntity ( entity );
501+ managedEntity .$$_hibernate_setInstanceId ( context .nextManagedEntityInstanceId () );
483502 }
484503 else {
485504 final ManagedEntity castedEntity = asManagedEntity ( entity );
505+ castedEntity .$$_hibernate_setInstanceId ( context .nextManagedEntityInstanceId () );
486506 managedEntity = new ImmutableManagedEntityHolder ( castedEntity );
487- if ( context .immutableManagedEntityXref == null ) {
488- context .immutableManagedEntityXref =
489- new IdentityHashMap <>();
490- }
491- context .immutableManagedEntityXref .put (
492- castedEntity ,
493- (ImmutableManagedEntityHolder ) managedEntity
494-
495- );
507+ context .putImmutableManagedEntity ( castedEntity , (ImmutableManagedEntityHolder ) managedEntity );
496508 }
497509 }
498510 else {
@@ -605,6 +617,15 @@ public ManagedEntityImpl(Object entityInstance) {
605617 public void $$_hibernate_setPreviousManagedEntity (ManagedEntity previous ) {
606618 this .previous = previous ;
607619 }
620+
621+ @ Override
622+ public int $$_hibernate_getInstanceId () {
623+ return -1 ;
624+ }
625+
626+ @ Override
627+ public void $$_hibernate_setInstanceId (int id ) {
628+ }
608629 }
609630
610631 private static class ImmutableManagedEntityHolder implements ManagedEntity {
@@ -693,6 +714,16 @@ private boolean canClearEntityEntryReference() {
693714 return !(entityEntry instanceof ImmutableEntityEntry )
694715 || !entityEntry .getPersister ().canUseReferenceCacheEntries ();
695716 }
717+
718+ @ Override
719+ public int $$_hibernate_getInstanceId () {
720+ return managedEntity .$$_hibernate_getInstanceId ();
721+ }
722+
723+ @ Override
724+ public void $$_hibernate_setInstanceId (int id ) {
725+ managedEntity .$$_hibernate_setInstanceId ( id );
726+ }
696727 }
697728
698729 /**
0 commit comments