HHH-18506 Reduce itable stubs during dirty checking

This commit is contained in:
Christian Beikov 2024-08-20 14:37:00 +02:00
parent 94b444b4d8
commit 5d45d19005
3 changed files with 77 additions and 1 deletions

View File

@ -3628,7 +3628,7 @@ public abstract class AbstractEntityPersister
public int[] findDirty(Object[] currentState, Object[] previousState, Object entity, SharedSessionContractImplementor session)
throws HibernateException {
int[] props = DirtyHelper.findDirty(
entityMetamodel.getProperties(),
entityMetamodel.getDirtyCheckablePropertyTypes(),
currentState,
previousState,
propertyColumnUpdateable,

View File

@ -11,6 +11,14 @@ import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.tuple.NonIdentifierAttribute;
import org.hibernate.type.AnyType;
import org.hibernate.type.BasicType;
import org.hibernate.type.CollectionType;
import org.hibernate.type.ComponentType;
import org.hibernate.type.ManyToOneType;
import org.hibernate.type.Type;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Operations for searching an array of property values for modified elements.
@ -72,6 +80,62 @@ class DirtyHelper {
}
}
/**
* Determine if any of the given field values are dirty, returning an array containing
* indices of the dirty fields.
* <p>
* If it is determined that no fields are dirty, null is returned.
*
* @param propertyTypes The property types that are dirty checkable. null entry for non-dirty checkable properties
* @param currentState The current state of the entity
* @param previousState The baseline state of the entity
* @param includeColumns Columns to be included in the dirty checking, per property
* @param session The session from which the dirty check request originated.
*
* @return Array containing indices of the dirty properties, or null if no properties considered dirty.
*/
public static int[] findDirty(
@Nullable Type[] propertyTypes,
final Object[] currentState,
final Object[] previousState,
final boolean[][] includeColumns,
final SharedSessionContractImplementor session) {
int[] results = null;
int count = 0;
int span = propertyTypes.length;
for ( int i = 0; i < span; i++ ) {
if ( isDirty( propertyTypes, currentState, previousState, includeColumns, session, i ) ) {
if ( results == null ) {
results = new int[span];
}
results[count++] = i;
}
}
return count == 0 ? null : ArrayHelper.trim( results, count );
}
private static boolean isDirty(
@Nullable Type[] propertyTypes,
Object[] currentState,
Object[] previousState,
boolean[][] includeColumns,
SharedSessionContractImplementor session, int i) {
final Type propertyType;
if ( currentState[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY
|| ( propertyType = propertyTypes[i] ) == null ) {
return false;
}
else if ( previousState[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
return true;
}
else {
return propertyType.isDirty( previousState[i], currentState[i], includeColumns[i], session );
}
}
/**
* Determine if any of the given field values are modified, returning an array containing
* indices of the modified fields.

View File

@ -54,8 +54,11 @@ import org.hibernate.type.ComponentType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType;
import org.hibernate.type.ManyToOneType;
import org.hibernate.type.OneToOneType;
import org.hibernate.type.Type;
import org.checkerframework.checker.nullness.qual.Nullable;
import static java.util.Collections.singleton;
import static org.hibernate.internal.CoreLogging.messageLogger;
import static org.hibernate.internal.util.ReflectHelper.isAbstractClass;
@ -93,6 +96,7 @@ public class EntityMetamodel implements Serializable {
// temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private final String[] propertyNames;
private final Type[] propertyTypes;
private final @Nullable Type[] dirtyCheckablePropertyTypes;
private final boolean[] propertyLaziness;
private final boolean[] propertyUpdateability;
private final boolean[] nonlazyPropertyUpdateability;
@ -206,6 +210,7 @@ public class EntityMetamodel implements Serializable {
// temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
propertyNames = new String[propertySpan];
propertyTypes = new Type[propertySpan];
dirtyCheckablePropertyTypes = new Type[propertySpan];
propertyUpdateability = new boolean[propertySpan];
propertyInsertability = new boolean[propertySpan];
nonlazyPropertyUpdateability = new boolean[propertySpan];
@ -295,6 +300,9 @@ public class EntityMetamodel implements Serializable {
propertyNames[i] = attribute.getName();
final Type propertyType = attribute.getType();
propertyTypes[i] = propertyType;
if ( attribute.isDirtyCheckable() && !( propertyType instanceof OneToOneType ) ) {
dirtyCheckablePropertyTypes[i] = propertyType;
}
propertyNullability[i] = attribute.isNullable();
propertyUpdateability[i] = attribute.isUpdateable();
propertyInsertability[i] = attribute.isInsertable();
@ -786,6 +794,10 @@ public class EntityMetamodel implements Serializable {
return propertyTypes;
}
public @Nullable Type[] getDirtyCheckablePropertyTypes() {
return dirtyCheckablePropertyTypes;
}
public boolean[] getPropertyLaziness() {
return propertyLaziness;
}