Skip to content

Commit 65a8e1e

Browse files
committed
HHH-18326 Use instance identity to track immutable enhanced
entities
1 parent a126dc8 commit 65a8e1e

File tree

8 files changed

+100
-25
lines changed

8 files changed

+100
-25
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: 52 additions & 24 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,9 +170,8 @@ 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
178176
? immutableManagedEntityXref.get( managedEntity )
179177
: null;
@@ -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,12 +264,15 @@ public EntityEntry removeEntityEntry(Object entity) {
253264

254265
dirty = true;
255266

256-
if (managedEntity instanceof ImmutableManagedEntityHolder) {
257-
assert entity == ( (ImmutableManagedEntityHolder) managedEntity ).managedEntity;
267+
if ( managedEntity instanceof ImmutableManagedEntityHolder ) {
268+
assert entity == ((ImmutableManagedEntityHolder) managedEntity).managedEntity;
258269
immutableManagedEntityXref.remove( entity );
259-
270+
if ( reusableInstanceIds == null ) {
271+
reusableInstanceIds = new StandardStack<>();
272+
}
273+
reusableInstanceIds.push( managedEntity.$$_hibernate_getInstanceId() );
260274
}
261-
else if ( ! ( isManagedEntity( entity ) ) ) {
275+
else if ( !isManagedEntity( entity ) ) {
262276
nonEnhancedEntityXref.remove( entity );
263277
}
264278

@@ -387,6 +401,8 @@ public void clear() {
387401
count = 0;
388402

389403
reentrantSafeEntries = null;
404+
currentInstanceId = 0;
405+
reusableInstanceIds = null;
390406
}
391407

392408
private static void clearManagedEntity(final ManagedEntity node) {
@@ -483,16 +499,9 @@ public static EntityEntryContext deserialize(ObjectInputStream ois, StatefulPers
483499
}
484500
else {
485501
final ManagedEntity castedEntity = asManagedEntity( entity );
502+
castedEntity.$$_hibernate_setInstanceId( context.nextManagedEntityInstanceId() );
486503
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-
);
504+
context.putImmutableManagedEntity( castedEntity, (ImmutableManagedEntityHolder) managedEntity );
496505
}
497506
}
498507
else {
@@ -605,6 +614,15 @@ public ManagedEntityImpl(Object entityInstance) {
605614
public void $$_hibernate_setPreviousManagedEntity(ManagedEntity previous) {
606615
this.previous = previous;
607616
}
617+
618+
@Override
619+
public int $$_hibernate_getInstanceId() {
620+
return -1;
621+
}
622+
623+
@Override
624+
public void $$_hibernate_setInstanceId(int id) {
625+
}
608626
}
609627

610628
private static class ImmutableManagedEntityHolder implements ManagedEntity {
@@ -693,6 +711,16 @@ private boolean canClearEntityEntryReference() {
693711
return !(entityEntry instanceof ImmutableEntityEntry)
694712
|| !entityEntry.getPersister().canUseReferenceCacheEntries();
695713
}
714+
715+
@Override
716+
public int $$_hibernate_getInstanceId() {
717+
return managedEntity.$$_hibernate_getInstanceId();
718+
}
719+
720+
@Override
721+
public void $$_hibernate_setInstanceId(int id) {
722+
managedEntity.$$_hibernate_setInstanceId( id );
723+
}
696724
}
697725

698726
/**

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)