Skip to content

Commit 2302b42

Browse files
committed
HHH-18326 Use instance identity to track immutable enhanced
entities Also, treat immutable, enhanced, reference-cacheable entities as non-enhanced
1 parent 7bffa94 commit 2302b42

File tree

8 files changed

+131
-40
lines changed

8 files changed

+131
-40
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: 83 additions & 39 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.InstanceIdentityStore;
18+
import org.hibernate.persister.entity.EntityPersister;
1719

1820
import java.io.IOException;
1921
import java.io.ObjectInputStream;
@@ -49,7 +51,8 @@ public class EntityEntryContext {
4951

5052
private final transient PersistenceContext persistenceContext;
5153

52-
private transient IdentityHashMap<ManagedEntity,ImmutableManagedEntityHolder> immutableManagedEntityXref;
54+
private transient InstanceIdentityStore<ImmutableManagedEntityHolder> immutableManagedEntityXref;
55+
private transient int currentInstanceId;
5356

5457
private transient ManagedEntity head;
5558
private transient ManagedEntity tail;
@@ -107,21 +110,20 @@ public void addEntityEntry(Object entity, EntityEntry entityEntry) {
107110
else {
108111
// Create a holder for PersistenceContext-related data.
109112
managedEntity = new ImmutableManagedEntityHolder( managed );
110-
if ( immutableManagedEntityXref == null ) {
111-
immutableManagedEntityXref = new IdentityHashMap<>();
113+
if ( !isReferenceCachingEnabled( entityEntry.getPersister() ) ) {
114+
final int instanceId = nextManagedEntityInstanceId();
115+
managed.$$_hibernate_setInstanceId( instanceId );
116+
putImmutableManagedEntity( managed, instanceId, (ImmutableManagedEntityHolder) managedEntity );
117+
}
118+
else {
119+
// When reference caching is enabled we cannot set the instance-id on the entity instance
120+
putManagedEntity( entity, managedEntity );
112121
}
113-
immutableManagedEntityXref.put(
114-
managed,
115-
(ImmutableManagedEntityHolder) managedEntity
116-
);
117122
}
118123
}
119124
else {
120-
if ( nonEnhancedEntityXref == null ) {
121-
nonEnhancedEntityXref = new IdentityHashMap<>();
122-
}
123125
managedEntity = new ManagedEntityImpl( entity );
124-
nonEnhancedEntityXref.put( entity, managedEntity );
126+
putManagedEntity( entity, managedEntity );
125127
}
126128
}
127129

@@ -155,6 +157,12 @@ public void addEntityEntry(Object entity, EntityEntry entityEntry) {
155157
}
156158
}
157159

160+
private static boolean isReferenceCachingEnabled(EntityPersister persister) {
161+
// Immutable entities which can use reference caching are treated as non-enhanced entities, as setting
162+
// the instance-id on them would be problematic in different sessions
163+
return persister.canUseReferenceCacheEntries() && persister.canReadFromCache();
164+
}
165+
158166
private ManagedEntity getAssociatedManagedEntity(Object entity) {
159167
if ( isManagedEntity( entity ) ) {
160168
final ManagedEntity managedEntity = asManagedEntity( entity );
@@ -170,20 +178,35 @@ private ManagedEntity getAssociatedManagedEntity(Object entity) {
170178
? managedEntity // it is associated
171179
: null;
172180
}
173-
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.
181+
else if ( !isReferenceCachingEnabled( entityEntry.getPersister() ) ) {
182+
// if managedEntity is associated with this EntityEntryContext, it may have
183+
// an entry in immutableManagedEntityXref and its holder will be returned.
177184
return immutableManagedEntityXref != null
178-
? immutableManagedEntityXref.get( managedEntity )
185+
? immutableManagedEntityXref.get( managedEntity.$$_hibernate_getInstanceId(), managedEntity )
179186
: null;
180187
}
181188
}
182-
else {
183-
return nonEnhancedEntityXref != null
184-
? nonEnhancedEntityXref.get( entity )
185-
: null;
189+
return nonEnhancedEntityXref != null
190+
? nonEnhancedEntityXref.get( entity )
191+
: null;
192+
}
193+
194+
private void putManagedEntity(Object entity, ManagedEntity managedEntity) {
195+
if ( nonEnhancedEntityXref == null ) {
196+
nonEnhancedEntityXref = new IdentityHashMap<>();
186197
}
198+
nonEnhancedEntityXref.put( entity, managedEntity );
199+
}
200+
201+
private int nextManagedEntityInstanceId() {
202+
return currentInstanceId++;
203+
}
204+
205+
private void putImmutableManagedEntity(ManagedEntity managed, int instanceId, ImmutableManagedEntityHolder holder) {
206+
if ( immutableManagedEntityXref == null ) {
207+
immutableManagedEntityXref = new InstanceIdentityStore<>();
208+
}
209+
immutableManagedEntityXref.put( instanceId, managed, holder );
187210
}
188211

189212
private void checkNotAssociatedWithOtherPersistenceContextIfMutable(ManagedEntity managedEntity) {
@@ -253,12 +276,16 @@ public EntityEntry removeEntityEntry(Object entity) {
253276

254277
dirty = true;
255278

256-
if (managedEntity instanceof ImmutableManagedEntityHolder) {
257-
assert entity == ( (ImmutableManagedEntityHolder) managedEntity ).managedEntity;
258-
immutableManagedEntityXref.remove( entity );
259-
279+
if ( managedEntity instanceof ImmutableManagedEntityHolder holder ) {
280+
assert entity == holder.managedEntity;
281+
if ( !isReferenceCachingEnabled( holder.$$_hibernate_getEntityEntry().getPersister() ) ) {
282+
immutableManagedEntityXref.remove( managedEntity.$$_hibernate_getInstanceId(), entity );
283+
}
284+
else {
285+
nonEnhancedEntityXref.remove( entity );
286+
}
260287
}
261-
else if ( ! ( isManagedEntity( entity ) ) ) {
288+
else if ( !isManagedEntity( entity ) ) {
262289
nonEnhancedEntityXref.remove( entity );
263290
}
264291

@@ -387,6 +414,7 @@ public void clear() {
387414
count = 0;
388415

389416
reentrantSafeEntries = null;
417+
currentInstanceId = 0;
390418
}
391419

392420
private static void clearManagedEntity(final ManagedEntity node) {
@@ -478,30 +506,27 @@ public static EntityEntryContext deserialize(ObjectInputStream ois, StatefulPers
478506

479507
final ManagedEntity managedEntity;
480508
if ( isEnhanced ) {
509+
final ManagedEntity castedEntity = asManagedEntity( entity );
481510
if ( entry.getPersister().isMutable() ) {
482-
managedEntity = ManagedTypeHelper.asManagedEntity( entity );
511+
managedEntity = castedEntity;
483512
}
484513
else {
485-
final ManagedEntity castedEntity = asManagedEntity( entity );
486514
managedEntity = new ImmutableManagedEntityHolder( castedEntity );
487-
if ( context.immutableManagedEntityXref == null ) {
488-
context.immutableManagedEntityXref =
489-
new IdentityHashMap<>();
515+
if ( !isReferenceCachingEnabled( entry.getPersister() ) ) {
516+
final int instanceId = context.nextManagedEntityInstanceId();
517+
castedEntity.$$_hibernate_setInstanceId( instanceId );
518+
context.putImmutableManagedEntity( castedEntity, instanceId, (ImmutableManagedEntityHolder) managedEntity );
519+
}
520+
else {
521+
context.putManagedEntity( entity, castedEntity );
490522
}
491-
context.immutableManagedEntityXref.put(
492-
castedEntity,
493-
(ImmutableManagedEntityHolder) managedEntity
494-
495-
);
496523
}
497524
}
498525
else {
499526
managedEntity = new ManagedEntityImpl( entity );
500-
if ( context.nonEnhancedEntityXref == null ) {
501-
context.nonEnhancedEntityXref = new IdentityHashMap<>();
502-
}
503-
context.nonEnhancedEntityXref.put( entity, managedEntity );
527+
context.putManagedEntity( entity, managedEntity );
504528
}
529+
505530
managedEntity.$$_hibernate_setEntityEntry( entry );
506531

507532
if ( previous == null ) {
@@ -605,6 +630,15 @@ public ManagedEntityImpl(Object entityInstance) {
605630
public void $$_hibernate_setPreviousManagedEntity(ManagedEntity previous) {
606631
this.previous = previous;
607632
}
633+
634+
@Override
635+
public int $$_hibernate_getInstanceId() {
636+
return -1;
637+
}
638+
639+
@Override
640+
public void $$_hibernate_setInstanceId(int id) {
641+
}
608642
}
609643

610644
private static class ImmutableManagedEntityHolder implements ManagedEntity {
@@ -693,6 +727,16 @@ private boolean canClearEntityEntryReference() {
693727
return !(entityEntry instanceof ImmutableEntityEntry)
694728
|| !entityEntry.getPersister().canUseReferenceCacheEntries();
695729
}
730+
731+
@Override
732+
public int $$_hibernate_getInstanceId() {
733+
return managedEntity.$$_hibernate_getInstanceId();
734+
}
735+
736+
@Override
737+
public void $$_hibernate_setInstanceId(int id) {
738+
managedEntity.$$_hibernate_setInstanceId( id );
739+
}
696740
}
697741

698742
/**

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)