Skip to content

Commit 87850a7

Browse files
committed
HHH-18326 Use instance identity to track immutable enhanced
entities
1 parent 67e26d5 commit 87850a7

File tree

8 files changed

+105
-27
lines changed

8 files changed

+105
-27
lines changed

hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,14 @@ private DynamicType.Builder<?> doEnhance(Supplier<DynamicType.Builder<?>> builde
225225
EnhancerConstants.USE_TRACKER_SETTER_NAME
226226
);
227227

228+
builder = addFieldWithGetterAndSetter(
229+
builder,
230+
constants.TypeIntegerPrimitive,
231+
EnhancerConstants.INSTANCE_ID_FIELD_NAME,
232+
EnhancerConstants.INSTANCE_ID_GETTER_NAME,
233+
EnhancerConstants.INSTANCE_ID_SETTER_NAME
234+
);
235+
228236
builder = addInterceptorHandling( builder, managedCtClass );
229237

230238
if ( enhancementContext.doDirtyCheckingInline( managedCtClass ) ) {

hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImplConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public Class<? extends Annotation> annotationType() {
7474
//Frequently used Types for method signatures:
7575
final TypeDefinition TypeVoid = TypeDescription.ForLoadedType.of( void.class );
7676
final TypeDefinition TypeBooleanPrimitive = TypeDescription.ForLoadedType.of( boolean.class );
77+
final TypeDefinition TypeIntegerPrimitive = TypeDescription.ForLoadedType.of( int.class );
7778
final TypeDefinition TypeManagedEntity = TypeDescription.ForLoadedType.of( ManagedEntity.class );
7879
final TypeDefinition TypeEntityEntry = TypeDescription.ForLoadedType.of( EntityEntry.class );
7980
final TypeDefinition TypePersistentAttributeInterceptor = TypeDescription.ForLoadedType.of( PersistentAttributeInterceptor.class );

hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/EnhancerConstants.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ public final class EnhancerConstants {
184184
public static final String USE_TRACKER_GETTER_NAME = "$$_hibernate_useTracker";
185185
public static final String USE_TRACKER_SETTER_NAME = "$$_hibernate_setUseTracker";
186186

187+
public static final String INSTANCE_ID_FIELD_NAME = "$$_hibernate_instanceId";
188+
public static final String INSTANCE_ID_GETTER_NAME = "$$_hibernate_getInstanceId";
189+
public static final String INSTANCE_ID_SETTER_NAME = "$$_hibernate_setInstanceId";
190+
187191

188192
private EnhancerConstants() {
189193
}

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

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
1515
import org.hibernate.internal.CoreLogging;
1616
import org.hibernate.internal.CoreMessageLogger;
17+
import org.hibernate.internal.util.collections.InstanceIdentityMap;
18+
import org.hibernate.internal.util.collections.StandardStack;
1719

1820
import java.io.IOException;
1921
import 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
/**

hibernate-core/src/main/java/org/hibernate/engine/spi/ManagedEntity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
*
2222
* @author Steve Ebersole
2323
*/
24-
public interface ManagedEntity extends Managed {
24+
public interface ManagedEntity extends Managed, InstanceIdentity {
2525
/**
2626
* Obtain a reference to the entity instance.
2727
*

hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhance/version/SimpleEntity.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,14 @@ public class SimpleEntity implements ManagedEntity {
6767
public boolean $$_hibernate_useTracker() {
6868
return false;
6969
}
70+
71+
@Override
72+
public int $$_hibernate_getInstanceId() {
73+
return 0;
74+
}
75+
76+
@Override
77+
public void $$_hibernate_setInstanceId(int id) {
78+
79+
}
7080
}

hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/basic/BasicSessionTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ static class MyEntity implements ManagedEntity {
8181
private transient ManagedEntity previous;
8282
@Transient
8383
private transient ManagedEntity next;
84+
@Transient
85+
private transient int instanceId;
8486

8587
MyEntity() {
8688
}
@@ -133,5 +135,15 @@ static class MyEntity implements ManagedEntity {
133135
public boolean $$_hibernate_useTracker() {
134136
return false;
135137
}
138+
139+
@Override
140+
public int $$_hibernate_getInstanceId() {
141+
return instanceId;
142+
}
143+
144+
@Override
145+
public void $$_hibernate_setInstanceId(int id) {
146+
this.instanceId = id;
147+
}
136148
}
137149
}

hibernate-core/src/test/java/org/hibernate/orm/test/cache/ByteCodeEnhancedImmutableReferenceCacheTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,8 @@ public static class MyEnhancedReferenceData implements ManagedEntity {
238238
private transient ManagedEntity previous;
239239
@Transient
240240
private transient ManagedEntity next;
241+
@Transient
242+
private transient int instanceId;
241243

242244
public MyEnhancedReferenceData(Integer id, String name, String theValue) {
243245
this.id = id;
@@ -316,5 +318,15 @@ public void setTheValue(String theValue) {
316318
public boolean $$_hibernate_useTracker() {
317319
return false;
318320
}
321+
322+
@Override
323+
public int $$_hibernate_getInstanceId() {
324+
return instanceId;
325+
}
326+
327+
@Override
328+
public void $$_hibernate_setInstanceId(int id) {
329+
this.instanceId = id;
330+
}
319331
}
320332
}

0 commit comments

Comments
 (0)