Skip to content

Commit 268d2fa

Browse files
committed
HHH-19536 Rework all state belonging to LazyAttributeLoadingInterceptor to allow upfront processing
1 parent 3a78d12 commit 268d2fa

File tree

4 files changed

+72
-31
lines changed

4 files changed

+72
-31
lines changed

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

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,28 +28,23 @@
2828
* @author Steve Ebersole
2929
*/
3030
public class LazyAttributeLoadingInterceptor extends AbstractInterceptor implements BytecodeLazyAttributeInterceptor {
31-
private final Object identifier;
32-
private final String entityName;
3331

34-
//N.B. this Set needs to be treated as immutable
35-
private Set<String> lazyFields;
32+
private final Object identifier;
33+
private EntityRelatedState entityMeta;
3634
private Set<String> initializedLazyFields;
37-
private Set<String> mutableLazyFields;
3835

3936
public LazyAttributeLoadingInterceptor(
40-
String entityName,
37+
EntityRelatedState entityMeta,
4138
Object identifier,
42-
Set<String> lazyFields,
4339
SharedSessionContractImplementor session) {
44-
this.entityName = entityName;
4540
this.identifier = identifier;
46-
this.lazyFields = lazyFields;
41+
this.entityMeta = entityMeta;
4742
setSession( session );
4843
}
4944

5045
@Override
5146
public String getEntityName() {
52-
return entityName;
47+
return entityMeta.entityName;
5348
}
5449

5550
@Override
@@ -130,23 +125,23 @@ public boolean isAttributeLoaded(String fieldName) {
130125
}
131126

132127
private boolean isLazyAttribute(String fieldName) {
133-
return lazyFields.contains( fieldName );
128+
return entityMeta.lazyFields.contains( fieldName );
134129
}
135130

136131
private boolean isInitializedLazyField(String fieldName) {
137132
return initializedLazyFields != null && initializedLazyFields.contains( fieldName );
138133
}
139134

140135
public boolean hasAnyUninitializedAttributes() {
141-
if ( lazyFields.isEmpty() ) {
136+
if ( entityMeta.lazyFields.isEmpty() ) {
142137
return false;
143138
}
144139

145140
if ( initializedLazyFields == null ) {
146141
return true;
147142
}
148143

149-
for ( String fieldName : lazyFields ) {
144+
for ( String fieldName : entityMeta.lazyFields ) {
150145
if ( !initializedLazyFields.contains( fieldName ) ) {
151146
return true;
152147
}
@@ -157,7 +152,7 @@ public boolean hasAnyUninitializedAttributes() {
157152

158153
@Override
159154
public String toString() {
160-
return getClass().getSimpleName() + "(entityName=" + getEntityName() + " ,lazyFields=" + lazyFields + ')';
155+
return getClass().getSimpleName() + "(entityName=" + getEntityName() + " ,lazyFields=" + entityMeta.lazyFields + ')';
161156
}
162157

163158
private void takeCollectionSizeSnapshot(Object target, String fieldName, Object value) {
@@ -197,14 +192,43 @@ public Set<String> getInitializedLazyAttributeNames() {
197192
}
198193

199194
public void addLazyFieldByGraph(String fieldName) {
200-
if ( mutableLazyFields == null ) {
201-
mutableLazyFields = new HashSet<>( lazyFields );
202-
lazyFields = mutableLazyFields;
195+
if ( entityMeta.shared ) {
196+
//We need to make a defensive copy first to not affect other entities of the same type;
197+
//as we create a copy we lose some of the efficacy of using a separate class to track this state,
198+
//but this is a corner case so we prefer to optimise for the common case.
199+
entityMeta = entityMeta.toNonSharedMutableState();
203200
}
204-
mutableLazyFields.add( fieldName );
201+
entityMeta.lazyFields.add( fieldName );
205202
}
206203

207204
public void clearInitializedLazyFields() {
208205
initializedLazyFields = null;
209206
}
207+
208+
/**
209+
* This is an helper object to group all state which relates to a particular entity type,
210+
* and which is needed for this interceptor.
211+
* Grouping such state allows for upfront construction as a per-entity singleton:
212+
* this reduces processing work on creation of an interceptor instance and is more
213+
* efficient from a point of view of memory usage and memory layout.
214+
*/
215+
public static class EntityRelatedState {
216+
private final String entityName;
217+
private final Set<String> lazyFields;
218+
private final boolean shared;
219+
220+
public EntityRelatedState(String entityName, Set<String> lazyFields) {
221+
this.entityName = entityName;
222+
this.lazyFields = lazyFields; //N.B. this is an immutable, compact set
223+
this.shared = true;
224+
}
225+
private EntityRelatedState(String entityName, Set<String> lazyFields, boolean shared) {
226+
this.entityName = entityName;
227+
this.lazyFields = lazyFields;
228+
this.shared = shared;
229+
}
230+
private EntityRelatedState toNonSharedMutableState() {
231+
return new EntityRelatedState( entityName, new HashSet<>( lazyFields ), false );
232+
}
233+
}
210234
}

hibernate-core/src/main/java/org/hibernate/bytecode/internal/BytecodeEnhancementMetadataPojoImpl.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ public static BytecodeEnhancementMetadata from(
7272
private final CompositeType nonAggregatedCidMapper;
7373
private final boolean enhancedForLazyLoading;
7474
private final LazyAttributesMetadata lazyAttributesMetadata;
75+
private final LazyAttributeLoadingInterceptor.EntityRelatedState loadingInterceptorState;
7576

7677
BytecodeEnhancementMetadataPojoImpl(
7778
String entityName,
@@ -89,6 +90,8 @@ public static BytecodeEnhancementMetadata from(
8990
this.identifierAttributeNames = identifierAttributeNames;
9091
this.enhancedForLazyLoading = enhancedForLazyLoading;
9192
this.lazyAttributesMetadata = lazyAttributesMetadata;
93+
this.loadingInterceptorState = new LazyAttributeLoadingInterceptor.EntityRelatedState(
94+
getEntityName(), lazyAttributesMetadata.getLazyAttributeNames() );
9295
}
9396

9497
@Override
@@ -217,9 +220,8 @@ public LazyAttributeLoadingInterceptor injectInterceptor(
217220
);
218221
}
219222
final LazyAttributeLoadingInterceptor interceptor = new LazyAttributeLoadingInterceptor(
220-
getEntityName(),
223+
this.loadingInterceptorState,
221224
identifier,
222-
lazyAttributesMetadata.getLazyAttributeNames(),
223225
session
224226
);
225227

hibernate-core/src/main/java/org/hibernate/metamodel/internal/AbstractEntityInstantiatorPojo.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public abstract class AbstractEntityInstantiatorPojo extends AbstractPojoInstant
2323
private final EntityMetamodel entityMetamodel;
2424
private final Class<?> proxyInterface;
2525
private final boolean applyBytecodeInterception;
26+
private final LazyAttributeLoadingInterceptor.EntityRelatedState loadingInterceptorState;
2627

2728
public AbstractEntityInstantiatorPojo(
2829
EntityMetamodel entityMetamodel,
@@ -34,17 +35,25 @@ public AbstractEntityInstantiatorPojo(
3435
//TODO this PojoEntityInstantiator appears to not be reused ?!
3536
this.applyBytecodeInterception =
3637
isPersistentAttributeInterceptableType( persistentClass.getMappedClass() );
38+
if ( applyBytecodeInterception ) {
39+
this.loadingInterceptorState = new LazyAttributeLoadingInterceptor.EntityRelatedState(
40+
entityMetamodel.getName(),
41+
entityMetamodel.getBytecodeEnhancementMetadata()
42+
.getLazyAttributesMetadata()
43+
.getLazyAttributeNames()
44+
);
45+
}
46+
else {
47+
this.loadingInterceptorState = null;
48+
}
3749
}
3850

3951
protected Object applyInterception(Object entity) {
4052
if ( applyBytecodeInterception ) {
4153
asPersistentAttributeInterceptable( entity )
4254
.$$_hibernate_setInterceptor( new LazyAttributeLoadingInterceptor(
43-
entityMetamodel.getName(),
55+
loadingInterceptorState,
4456
null,
45-
entityMetamodel.getBytecodeEnhancementMetadata()
46-
.getLazyAttributesMetadata()
47-
.getLazyAttributeNames(),
4857
null
4958
) );
5059
}

hibernate-core/src/main/java/org/hibernate/metamodel/internal/EntityInstantiatorPojoStandard.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,30 @@
2525
public class EntityInstantiatorPojoStandard extends AbstractEntityInstantiatorPojo {
2626
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( EntityInstantiatorPojoStandard.class );
2727

28-
private final EntityMetamodel entityMetamodel;
2928
private final Class<?> proxyInterface;
3029
private final boolean applyBytecodeInterception;
31-
30+
private final LazyAttributeLoadingInterceptor.EntityRelatedState loadingInterceptorState;
3231
private final Constructor<?> constructor;
3332

3433
public EntityInstantiatorPojoStandard(
3534
EntityMetamodel entityMetamodel,
3635
PersistentClass persistentClass,
3736
JavaType<?> javaType) {
3837
super( entityMetamodel, persistentClass, javaType );
39-
this.entityMetamodel = entityMetamodel;
4038
proxyInterface = persistentClass.getProxyInterface();
4139
constructor = isAbstract() ? null : resolveConstructor( getMappedPojoClass() );
4240
applyBytecodeInterception = isPersistentAttributeInterceptableType( persistentClass.getMappedClass() );
41+
if ( applyBytecodeInterception ) {
42+
this.loadingInterceptorState = new LazyAttributeLoadingInterceptor.EntityRelatedState(
43+
entityMetamodel.getName(),
44+
entityMetamodel.getBytecodeEnhancementMetadata()
45+
.getLazyAttributesMetadata()
46+
.getLazyAttributeNames()
47+
);
48+
}
49+
else {
50+
this.loadingInterceptorState = null;
51+
}
4352
}
4453

4554
protected static Constructor<?> resolveConstructor(Class<?> mappedPojoClass) {
@@ -62,11 +71,8 @@ protected Object applyInterception(Object entity) {
6271
if ( applyBytecodeInterception ) {
6372
asPersistentAttributeInterceptable( entity )
6473
.$$_hibernate_setInterceptor( new LazyAttributeLoadingInterceptor(
65-
entityMetamodel.getName(),
74+
loadingInterceptorState,
6675
null,
67-
entityMetamodel.getBytecodeEnhancementMetadata()
68-
.getLazyAttributesMetadata()
69-
.getLazyAttributeNames(),
7076
null
7177
) );
7278
}

0 commit comments

Comments
 (0)