HHH-16884 Improve efficiency of UpdateCoordinatorStandard in tracking tables to be updated

This commit is contained in:
Sanne Grinovero 2023-07-03 14:36:00 +01:00 committed by Sanne Grinovero
parent 9056695f70
commit db0427173b
3 changed files with 95 additions and 11 deletions

View File

@ -0,0 +1,85 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.persister.entity.mutation;
import java.util.Arrays;
import java.util.BitSet;
import org.hibernate.sql.model.MutationTarget;
import org.hibernate.sql.model.TableMapping;
/**
* Represents a Set of TableMapping(s); table mappings are
* identified by an ordered unique id: the order in which
* they are updated within the scope of a particular persister.
* This makes it possible to store a set of them as a bitset,
* which is typically more efficient than using a {@link java.util.Set}.
* These table ids relate to the use in method {@link MutationTarget#forEachMutableTable}
* and {@link MutationTarget#forEachMutableTableReverse}.
* <p>N.B. Make sure to not store TableMappings from different
* persisters, as their unique identifiers will overlap:
* we'll only verify a mismatch if assertions are enabled.</p>
*/
public final class TableSet {
private BitSet bits;
private Object[] checks; //Meant for assertions only
public void add(final TableMapping tableMapping) {
if ( bits == null ) {
bits = new BitSet();
}
assert addForChecks( tableMapping );
bits.set( tableMapping.getRelativePosition() );
}
public boolean isEmpty() {
return bits == null;
}
public boolean contains(final TableMapping tableMapping) {
assert matchRead( tableMapping );
return bits != null && bits.get( tableMapping.getRelativePosition() );
}
//Meant for assertions only
private boolean matchRead(final TableMapping tableMapping) {
if ( bits != null ) {
final int index = tableMapping.getRelativePosition();
if ( bits.get( index ) ) {
return checks[index] == tableMapping;
}
}
return true; //to make the assertion happy
}
//Meant for assertions only
private boolean addForChecks(final TableMapping tableMapping) {
final int position = tableMapping.getRelativePosition();
ensureCapacity( position );
if ( checks[position] != null ) {
//pre-existing in the set: verify it's the same one.
if ( checks[position] != tableMapping ) {
return false;//fail the assertion
}
}
checks[position] = tableMapping;
return true; //to make the assertion happy
}
//Meant for assertions only
private void ensureCapacity(final int position) {
final int increments = 3; //Needs to be at least 1.
if ( checks == null ) {
checks = new Object[position + increments];
}
else if ( checks.length <= position ) {
checks = Arrays.copyOf( checks, position + increments );
}
}
}

View File

@ -1274,10 +1274,10 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
private final int[] dirtyAttributeIndexes;
private final InclusionChecker dirtinessChecker;
private final Set<EntityTableMapping> tablesNeedingUpdate = new HashSet<>();
private final Set<EntityTableMapping> tablesNeedingDynamicUpdate = new HashSet<>();
private final Set<EntityTableMapping> tablesWithNonNullValues = new HashSet<>();
private final Set<EntityTableMapping> tablesWithPreviousNonNullValues = new HashSet<>();
private final TableSet tablesNeedingUpdate = new TableSet();
private final TableSet tablesNeedingDynamicUpdate = new TableSet();
private final TableSet tablesWithNonNullValues = new TableSet();
private final TableSet tablesWithPreviousNonNullValues = new TableSet();
private final List<AttributeAnalysis> attributeAnalyses = new ArrayList<>();
@ -1348,17 +1348,17 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
}
@Override
public Set<EntityTableMapping> getTablesNeedingUpdate() {
public TableSet getTablesNeedingUpdate() {
return tablesNeedingUpdate;
}
@Override
public Set<EntityTableMapping> getTablesWithNonNullValues() {
public TableSet getTablesWithNonNullValues() {
return tablesWithNonNullValues;
}
@Override
public Set<EntityTableMapping> getTablesWithPreviousNonNullValues() {
public TableSet getTablesWithPreviousNonNullValues() {
return tablesWithPreviousNonNullValues;
}

View File

@ -7,7 +7,6 @@
package org.hibernate.persister.entity.mutation;
import java.util.List;
import java.util.Set;
import org.hibernate.Incubating;
import org.hibernate.sql.model.TableMapping;
@ -29,17 +28,17 @@ public interface UpdateValuesAnalysis extends ValuesAnalysis {
*
* @apiNote {@linkplain TableMapping#isInverse() Inverse tables} are not included in the result
*/
Set<EntityTableMapping> getTablesNeedingUpdate();
TableSet getTablesNeedingUpdate();
/**
* Descriptor of the tables which had any non-null value bindings
*/
Set<EntityTableMapping> getTablesWithNonNullValues();
TableSet getTablesWithNonNullValues();
/**
* Descriptor of the tables which had any non-null value bindings
*/
Set<EntityTableMapping> getTablesWithPreviousNonNullValues();
TableSet getTablesWithPreviousNonNullValues();
/**
* Descriptors for the analysis of each attribute