HHH-16099 Introduce three-state handling for dirty levels to avoid excessive warnings
We now differentiate between an Attribute which has been marked as "real dirty" from one which needs to be "treated like dirty", so to not bother end users with a WARN log when a non-updateable property had not been updated explicitly by them.
This commit is contained in:
parent
4fc7293c66
commit
ae37509b11
|
@ -37,7 +37,7 @@ public interface AttributeAnalysis {
|
||||||
/**
|
/**
|
||||||
* Whether the attribute is considered dirty
|
* Whether the attribute is considered dirty
|
||||||
*/
|
*/
|
||||||
boolean isDirty();
|
DirtynessStatus getDirtynessStatus();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the attribute be skipped completely.
|
* Whether the attribute be skipped completely.
|
||||||
|
@ -48,4 +48,30 @@ public interface AttributeAnalysis {
|
||||||
default boolean isSkipped() {
|
default boolean isSkipped() {
|
||||||
return !includeInSet() && !includeInLocking();
|
return !includeInSet() && !includeInLocking();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dirty-ness status of each attribute:
|
||||||
|
* it's useful to differentiate when it's definitely dirty,
|
||||||
|
* when it's definitely not dirty, and when we need to treat
|
||||||
|
* it like dirty but there is no certainty - for example
|
||||||
|
* because we didn't actually load the value from the database.
|
||||||
|
*/
|
||||||
|
enum DirtynessStatus {
|
||||||
|
DIRTY,
|
||||||
|
NOT_DIRTY {
|
||||||
|
@Override
|
||||||
|
boolean isDirty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CONSIDER_LIKE_DIRTY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return both DIRTY and CONSIDER_LIKE_DIRTY states will return {@code true}
|
||||||
|
*/
|
||||||
|
boolean isDirty() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -596,10 +596,11 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
try {
|
try {
|
||||||
if ( attributeMapping.getJdbcTypeCount() > 0
|
if ( attributeMapping.getJdbcTypeCount() > 0
|
||||||
&& attributeMapping instanceof SingularAttributeMapping ) {
|
&& attributeMapping instanceof SingularAttributeMapping ) {
|
||||||
|
SingularAttributeMapping asSingularAttributeMapping = (SingularAttributeMapping) attributeMapping;
|
||||||
processAttribute(
|
processAttribute(
|
||||||
analysis,
|
analysis,
|
||||||
attributeIndex,
|
attributeIndex,
|
||||||
(SingularAttributeMapping) attributeMapping,
|
asSingularAttributeMapping,
|
||||||
oldVersion,
|
oldVersion,
|
||||||
oldValues,
|
oldValues,
|
||||||
inclusionChecker,
|
inclusionChecker,
|
||||||
|
@ -607,7 +608,8 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
session
|
session
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( analysis.currentAttributeAnalysis.isDirty() ) {
|
// In this case we check for exactly DirtynessStatus.DIRTY so to not log warnings when the user didn't get it wrong:
|
||||||
|
if ( analysis.currentAttributeAnalysis.getDirtynessStatus() == AttributeAnalysis.DirtynessStatus.DIRTY ) {
|
||||||
if ( !propertyUpdateability[attributeIndex] ) {
|
if ( !propertyUpdateability[attributeIndex] ) {
|
||||||
LOG.ignoreImmutablePropertyModification( attributeMapping.getAttributeName(), persister.getEntityName() );
|
LOG.ignoreImmutablePropertyModification( attributeMapping.getAttributeName(), persister.getEntityName() );
|
||||||
}
|
}
|
||||||
|
@ -702,7 +704,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
mutationExecutor,
|
mutationExecutor,
|
||||||
staticUpdateGroup,
|
staticUpdateGroup,
|
||||||
// (position, attribute) -> valuesAnalysis.getAttributeAnalyses().get( position ).isDirty(),
|
// (position, attribute) -> valuesAnalysis.getAttributeAnalyses().get( position ).isDirty(),
|
||||||
(position, attribute) -> true,
|
(position, attribute) -> AttributeAnalysis.DirtynessStatus.CONSIDER_LIKE_DIRTY,
|
||||||
session
|
session
|
||||||
);
|
);
|
||||||
bindPartitionColumnValueBindings( oldValues, session, mutationExecutor.getJdbcValueBindings() );
|
bindPartitionColumnValueBindings( oldValues, session, mutationExecutor.getJdbcValueBindings() );
|
||||||
|
@ -880,7 +882,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if ( entityPersister().getEntityMetamodel().isDynamicUpdate() && dirtinessChecker != null ) {
|
else if ( entityPersister().getEntityMetamodel().isDynamicUpdate() && dirtinessChecker != null ) {
|
||||||
return attributeAnalysis.includeInSet() && dirtinessChecker.isDirty( attributeIndex, attributeMapping );
|
return attributeAnalysis.includeInSet() && dirtinessChecker.isDirty( attributeIndex, attributeMapping ).isDirty();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return true;
|
return true;
|
||||||
|
@ -916,7 +918,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
valuesAnalysis,
|
valuesAnalysis,
|
||||||
mutationExecutor,
|
mutationExecutor,
|
||||||
dynamicUpdateGroup,
|
dynamicUpdateGroup,
|
||||||
(attributeIndex, attribute) -> dirtinessChecker.include( attributeIndex, (SingularAttributeMapping) attribute ),
|
(attributeIndex, attribute) -> dirtinessChecker.include( attributeIndex, (SingularAttributeMapping) attribute ) ? AttributeAnalysis.DirtynessStatus.CONSIDER_LIKE_DIRTY : AttributeAnalysis.DirtynessStatus.NOT_DIRTY,
|
||||||
session
|
session
|
||||||
);
|
);
|
||||||
bindPartitionColumnValueBindings( oldValues, session, mutationExecutor.getJdbcValueBindings() );
|
bindPartitionColumnValueBindings( oldValues, session, mutationExecutor.getJdbcValueBindings() );
|
||||||
|
@ -986,7 +988,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
updateGroupBuilder,
|
updateGroupBuilder,
|
||||||
oldValues,
|
oldValues,
|
||||||
valuesAnalysis,
|
valuesAnalysis,
|
||||||
(position, attribute) -> valuesAnalysis.getAttributeAnalyses().get( position ).isDirty(),
|
(position, attribute) -> valuesAnalysis.getAttributeAnalyses().get( position ).getDirtynessStatus(),
|
||||||
session
|
session
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1134,7 +1136,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
else {
|
else {
|
||||||
return versionability[attributeIndex]
|
return versionability[attributeIndex]
|
||||||
&& attributeAnalysis.includeInLocking()
|
&& attributeAnalysis.includeInLocking()
|
||||||
&& dirtinessChecker.isDirty(attributeIndex, attributeMapping);
|
&& dirtinessChecker.isDirty( attributeIndex, attributeMapping ).isDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1160,7 +1162,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
else {
|
else {
|
||||||
final boolean includeInSet = !entityPersister().getEntityMetamodel().isDynamicUpdate()
|
final boolean includeInSet = !entityPersister().getEntityMetamodel().isDynamicUpdate()
|
||||||
|| dirtinessChecker == null
|
|| dirtinessChecker == null
|
||||||
|| dirtinessChecker.isDirty( attributeIndex, attributeMapping );
|
|| dirtinessChecker.isDirty( attributeIndex, attributeMapping ).isDirty();
|
||||||
if ( includeInSet ) {
|
if ( includeInSet ) {
|
||||||
attributeMapping.forEachUpdatable( tableUpdateBuilder );
|
attributeMapping.forEachUpdatable( tableUpdateBuilder );
|
||||||
}
|
}
|
||||||
|
@ -1289,7 +1291,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
currentAttributeAnalysis = new IncludedAttributeAnalysis( (SingularAttributeMapping) attribute );
|
currentAttributeAnalysis = new IncludedAttributeAnalysis( (SingularAttributeMapping) attribute );
|
||||||
if ( dirtyAttributeIndexes == null
|
if ( dirtyAttributeIndexes == null
|
||||||
|| contains( dirtyAttributeIndexes, attribute.getStateArrayPosition() ) ) {
|
|| contains( dirtyAttributeIndexes, attribute.getStateArrayPosition() ) ) {
|
||||||
currentAttributeAnalysis.markDirty();
|
currentAttributeAnalysis.markDirty( dirtyAttributeIndexes != null );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1343,7 +1345,12 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
* Local extension to AttributeAnalysis
|
* Local extension to AttributeAnalysis
|
||||||
*/
|
*/
|
||||||
private interface AttributeAnalysisImplementor extends AttributeAnalysis {
|
private interface AttributeAnalysisImplementor extends AttributeAnalysis {
|
||||||
void markDirty();
|
/**
|
||||||
|
* @param asCertain set to true when we're sure, false when we merely need to treat the attribute
|
||||||
|
* as dirty but couldn't actually run the comparison.
|
||||||
|
* Once it's marked at least once "with certainty", there is no option to revert to a lower state.
|
||||||
|
*/
|
||||||
|
void markDirty(boolean asCertain);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1376,12 +1383,12 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDirty() {
|
public DirtynessStatus getDirtynessStatus() {
|
||||||
return false;
|
return DirtynessStatus.NOT_DIRTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void markDirty() {
|
public void markDirty(boolean certainty) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1403,7 +1410,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
private final List<ColumnSetAnalysis> columnValueAnalyses;
|
private final List<ColumnSetAnalysis> columnValueAnalyses;
|
||||||
private final List<ColumnLockingAnalysis> columnLockingAnalyses;
|
private final List<ColumnLockingAnalysis> columnLockingAnalyses;
|
||||||
|
|
||||||
private boolean dirty;
|
private DirtynessStatus dirty = DirtynessStatus.NOT_DIRTY;
|
||||||
|
|
||||||
public IncludedAttributeAnalysis(SingularAttributeMapping attribute) {
|
public IncludedAttributeAnalysis(SingularAttributeMapping attribute) {
|
||||||
this.attribute = attribute;
|
this.attribute = attribute;
|
||||||
|
@ -1428,14 +1435,19 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDirty() {
|
public DirtynessStatus getDirtynessStatus() {
|
||||||
return dirty;
|
return dirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Internal
|
@Internal
|
||||||
@Override
|
@Override
|
||||||
public void markDirty() {
|
public void markDirty(boolean certain) {
|
||||||
this.dirty = true;
|
if ( certain ) {
|
||||||
|
this.dirty = DirtynessStatus.DIRTY;
|
||||||
|
}
|
||||||
|
else if ( this.dirty == DirtynessStatus.NOT_DIRTY ) {
|
||||||
|
this.dirty = DirtynessStatus.CONSIDER_LIKE_DIRTY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1529,7 +1541,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
// oldValues
|
// oldValues
|
||||||
null,
|
null,
|
||||||
valuesAnalysis,
|
valuesAnalysis,
|
||||||
(position, attribute) -> valuesAnalysis.getAttributeAnalyses().get( position ).isDirty(),
|
(position, attribute) -> valuesAnalysis.getAttributeAnalyses().get( position ).getDirtynessStatus(),
|
||||||
// session
|
// session
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
@ -1591,7 +1603,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
protected interface DirtinessChecker {
|
protected interface DirtinessChecker {
|
||||||
boolean isDirty(int position, AttributeMapping attribute);
|
AttributeAnalysis.DirtynessStatus isDirty(int position, AttributeMapping attribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue