minor cleanups to Actions

This commit is contained in:
Gavin King 2022-01-26 00:12:33 +01:00
parent 8f8ae50e0b
commit ee1d27719c
16 changed files with 132 additions and 109 deletions

View File

@ -34,13 +34,13 @@ import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.sql.ast.tree.insert.InsertStatement; import org.hibernate.sql.ast.tree.insert.InsertStatement;
/** /**
* An {@link org.hibernate.engine.spi.ActionQueue} {@link Executable} for ensuring * An {@link org.hibernate.engine.spi.ActionQueue} {@link Executable} for
* shared cache cleanup in relation to performed bulk HQL queries. * ensuring shared cache cleanup in relation to performed bulk HQL queries.
* <p/> * <p/>
* NOTE: currently this executes for {@code INSERT} queries as well as * NOTE: currently this executes for {@code INSERT} queries as well as
* {@code UPDATE} and {@code DELETE} queries. For {@code INSERT} it is * {@code UPDATE} and {@code DELETE} queries. For {@code INSERT} it is
* really not needed as we'd have no invalid entity/collection data to * really not needed as we'd have no invalid entity/collection data to
* cleanup (we'd still nee to invalidate the appropriate update-timestamps * clean up (we'd still need to invalidate the appropriate update-timestamps
* regions) as a result of this query. * regions) as a result of this query.
* *
* @author Steve Ebersole * @author Steve Ebersole
@ -112,8 +112,7 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
* @param session The session to which this request is tied. * @param session The session to which this request is tied.
* @param tableSpaces The table spaces. * @param tableSpaces The table spaces.
*/ */
@SuppressWarnings( { "unchecked", "rawtypes" } ) public BulkOperationCleanupAction(SharedSessionContractImplementor session, Set<String> tableSpaces) {
public BulkOperationCleanupAction(SharedSessionContractImplementor session, Set tableSpaces) {
final LinkedHashSet<String> spacesList = new LinkedHashSet<>( tableSpaces ); final LinkedHashSet<String> spacesList = new LinkedHashSet<>( tableSpaces );
final SessionFactoryImplementor factory = session.getFactory(); final SessionFactoryImplementor factory = session.getFactory();

View File

@ -113,10 +113,10 @@ public abstract class CollectionAction implements Executable, Serializable, Comp
if ( key instanceof DelayedPostInsertIdentifier ) { if ( key instanceof DelayedPostInsertIdentifier ) {
// need to look it up from the persistence-context // need to look it up from the persistence-context
finalKey = session.getPersistenceContextInternal().getEntry( collection.getOwner() ).getId(); finalKey = session.getPersistenceContextInternal().getEntry( collection.getOwner() ).getId();
if ( finalKey == key ) { // if ( finalKey == key ) {
// we may be screwed here since the collection action is about to execute // we may be screwed here since the collection action is about to execute
// and we do not know the final owner key value // and we do not know the final owner key value
} // }
} }
return finalKey; return finalKey;
} }

View File

@ -22,7 +22,7 @@ import org.hibernate.stat.spi.StatisticsImplementor;
*/ */
public final class CollectionRemoveAction extends CollectionAction { public final class CollectionRemoveAction extends CollectionAction {
private final Object affectedOwner; private final Object affectedOwner;
private boolean emptySnapshot; private final boolean emptySnapshot;
/** /**
* Removes a persistent collection from its loaded owner. * Removes a persistent collection from its loaded owner.

View File

@ -10,8 +10,6 @@ import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PostCollectionUpdateEvent; import org.hibernate.event.spi.PostCollectionUpdateEvent;
import org.hibernate.event.spi.PostCollectionUpdateEventListener; import org.hibernate.event.spi.PostCollectionUpdateEventListener;
import org.hibernate.event.spi.PreCollectionUpdateEvent; import org.hibernate.event.spi.PreCollectionUpdateEvent;

View File

@ -12,23 +12,25 @@ import java.util.concurrent.atomic.AtomicLong;
/** /**
* Acts as a stand-in for an entity identifier which is supposed to be * Acts as a stand-in for an entity identifier which is supposed to be
* generated on insert (like an IDENTITY column) where the insert needed to * generated on insert (like an IDENTITY column) where the insert needed to
* be delayed because we were outside a transaction when the persist * be delayed because we were outside a transaction when the persist operation
* occurred (save currently still performs the insert). * was called (save currently still performs the insert).
* <p/> * <p/>
* The stand-in is only used within the {@link org.hibernate.engine.spi.PersistenceContext} * The stand-in is only used within the {@link org.hibernate.engine.spi.PersistenceContext}
* in order to distinguish one instance from another; it is never injected into * in order to distinguish one instance from another; it is never injected into
* the entity instance or returned to the client... * the entity instance or returned to the client.
* *
* @author Steve Ebersole * @author Steve Ebersole
* @author Sanne Grinovero * @author Sanne Grinovero
*/ */
public class DelayedPostInsertIdentifier implements Serializable, Comparable<DelayedPostInsertIdentifier> { public class DelayedPostInsertIdentifier
implements Serializable, Comparable<DelayedPostInsertIdentifier> {
private static final AtomicLong SEQUENCE = new AtomicLong(); private static final AtomicLong SEQUENCE = new AtomicLong();
private final long identifier; private final long identifier;
/** /**
* Constructs a DelayedPostInsertIdentifier * Constructs a {@link DelayedPostInsertIdentifier}
*/ */
public DelayedPostInsertIdentifier() { public DelayedPostInsertIdentifier() {
long value = SEQUENCE.incrementAndGet(); long value = SEQUENCE.incrementAndGet();

View File

@ -14,10 +14,7 @@ import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
import org.hibernate.action.spi.Executable; import org.hibernate.action.spi.Executable;
import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.EventType;
import org.hibernate.internal.FastSessionServices; import org.hibernate.internal.FastSessionServices;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
@ -30,7 +27,7 @@ import org.hibernate.pretty.MessageHelper;
* @author Gavin King * @author Gavin King
*/ */
public abstract class EntityAction public abstract class EntityAction
implements Executable, Serializable, Comparable, AfterTransactionCompletionProcess { implements Executable, Serializable, Comparable<EntityAction>, AfterTransactionCompletionProcess {
private final String entityName; private final String entityName;
private final Object id; private final Object id;
@ -49,7 +46,11 @@ public abstract class EntityAction
* @param instance The entity instance * @param instance The entity instance
* @param persister The entity persister * @param persister The entity persister
*/ */
protected EntityAction(SharedSessionContractImplementor session, Object id, Object instance, EntityPersister persister) { protected EntityAction(
SharedSessionContractImplementor session,
Object id,
Object instance,
EntityPersister persister) {
this.entityName = persister.getEntityName(); this.entityName = persister.getEntityName();
this.id = id; this.id = id;
this.instance = instance; this.instance = instance;
@ -107,8 +108,8 @@ public abstract class EntityAction
} }
public final DelayedPostInsertIdentifier getDelayedId() { public final DelayedPostInsertIdentifier getDelayedId() {
return DelayedPostInsertIdentifier.class.isInstance( id ) return id instanceof DelayedPostInsertIdentifier
? DelayedPostInsertIdentifier.class.cast( id ) ? (DelayedPostInsertIdentifier) id
: null; : null;
} }
@ -155,8 +156,7 @@ public abstract class EntityAction
} }
@Override @Override
public int compareTo(Object other) { public int compareTo(EntityAction action) {
final EntityAction action = (EntityAction) other;
//sort first by entity name //sort first by entity name
final int roleComparison = entityName.compareTo( action.entityName ); final int roleComparison = entityName.compareTo( action.entityName );
if ( roleComparison != 0 ) { if ( roleComparison != 0 ) {

View File

@ -34,7 +34,6 @@ public class EntityDeleteAction extends EntityAction {
private SoftLock lock; private SoftLock lock;
private final NaturalIdMapping naturalIdMapping;
private Object naturalIdValues; private Object naturalIdValues;
/** /**
@ -60,14 +59,15 @@ public class EntityDeleteAction extends EntityAction {
this.isCascadeDeleteEnabled = isCascadeDeleteEnabled; this.isCascadeDeleteEnabled = isCascadeDeleteEnabled;
this.state = state; this.state = state;
this.naturalIdMapping = persister.getNaturalIdMapping(); NaturalIdMapping naturalIdMapping = persister.getNaturalIdMapping();
if ( naturalIdMapping != null ) { if ( naturalIdMapping != null ) {
naturalIdValues = session.getPersistenceContextInternal().getNaturalIdResolutions().removeLocalResolution( naturalIdValues = session.getPersistenceContextInternal().getNaturalIdResolutions()
getId(), .removeLocalResolution(
naturalIdMapping.extractNaturalIdFromEntityState( state, session ), getId(),
getPersister() naturalIdMapping.extractNaturalIdFromEntityState( state, session ),
); getPersister()
);
} }
} }

View File

@ -12,8 +12,6 @@ import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.service.spi.EventListenerGroup; import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PostCommitInsertEventListener; import org.hibernate.event.spi.PostCommitInsertEventListener;
import org.hibernate.event.spi.PostInsertEvent; import org.hibernate.event.spi.PostInsertEvent;
import org.hibernate.event.spi.PostInsertEventListener; import org.hibernate.event.spi.PostInsertEventListener;

View File

@ -12,8 +12,9 @@ import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
/** /**
* A BeforeTransactionCompletionProcess impl to verify and increment an entity version as party * A {@link BeforeTransactionCompletionProcess} implementation to verify and
* of before-transaction-completion processing * increment an entity version as party of before-transaction-completion
* processing.
* *
* @author Scott Marlow * @author Scott Marlow
*/ */

View File

@ -18,7 +18,6 @@ import org.hibernate.engine.spi.SessionEventListenerManager;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.service.spi.EventListenerGroup; import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PostCommitInsertEventListener; import org.hibernate.event.spi.PostCommitInsertEventListener;
import org.hibernate.event.spi.PostInsertEvent; import org.hibernate.event.spi.PostInsertEvent;
import org.hibernate.event.spi.PostInsertEventListener; import org.hibernate.event.spi.PostInsertEventListener;

View File

@ -14,8 +14,8 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
/** /**
* A BeforeTransactionCompletionProcess impl to verify an entity version as part of * A {@link BeforeTransactionCompletionProcess} impl to verify an entity
* before-transaction-completion processing * version as part of before-transaction-completion processing.
* *
* @author Scott Marlow * @author Scott Marlow
*/ */

View File

@ -15,8 +15,10 @@ import org.hibernate.persister.collection.CollectionPersister;
/** /**
* If a collection is extra lazy and has queued ops, we still need to * If a collection is extra lazy and has queued ops, we still need to
* process them. Ex: OneToManyPersister needs to insert indexes for List * process them.
* collections. See HHH-8083. * <p>
* For example, {@link org.hibernate.persister.collection.OneToManyPersister}
* needs to insert indexes for lists. See HHH-8083.
* *
* @author Brett Meyer * @author Brett Meyer
*/ */

View File

@ -45,6 +45,7 @@ import org.hibernate.cache.CacheException;
import org.hibernate.engine.internal.NonNullableTransientDependencies; import org.hibernate.engine.internal.NonNullableTransientDependencies;
import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer; import org.hibernate.proxy.LazyInitializer;
@ -52,7 +53,6 @@ import org.hibernate.type.CollectionType;
import org.hibernate.type.CompositeType; import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType; import org.hibernate.type.EntityType;
import org.hibernate.type.ForeignKeyDirection; import org.hibernate.type.ForeignKeyDirection;
import org.hibernate.type.OneToOneType;
import org.hibernate.type.Type; import org.hibernate.type.Type;
/** /**
@ -68,7 +68,7 @@ import org.hibernate.type.Type;
public class ActionQueue { public class ActionQueue {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( ActionQueue.class ); private static final CoreMessageLogger LOG = CoreLogging.messageLogger( ActionQueue.class );
private SessionImplementor session; private final SessionImplementor session;
private UnresolvedEntityInsertActions unresolvedInsertions; private UnresolvedEntityInsertActions unresolvedInsertions;
@ -103,7 +103,7 @@ public class ActionQueue {
/** /**
* A LinkedHashMap containing providers for all the ExecutableLists, inserted in execution order * A LinkedHashMap containing providers for all the ExecutableLists, inserted in execution order
*/ */
private static final LinkedHashMap<Class<? extends Executable>,ListProvider> EXECUTABLE_LISTS_MAP; private static final LinkedHashMap<Class<? extends Executable>,ListProvider<?>> EXECUTABLE_LISTS_MAP;
static { static {
EXECUTABLE_LISTS_MAP = CollectionHelper.linkedMapOfSize( 8 ); EXECUTABLE_LISTS_MAP = CollectionHelper.linkedMapOfSize( 8 );
@ -302,9 +302,13 @@ public class ActionQueue {
} }
} }
private <T extends Executable & Comparable<? super T> & Serializable> void addAction(Class<T> executableClass, T action) {
listProvider( executableClass ).getOrInit( this ).add( action );
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <T extends Executable & Comparable & Serializable> void addAction(Class<T> executableClass, T action) { private <T extends Executable & Comparable<? super T> & Serializable> ListProvider<T> listProvider(Class<T> actionClass) {
EXECUTABLE_LISTS_MAP.get( executableClass ).getOrInit( this ).add( action ); return (ListProvider<T>) EXECUTABLE_LISTS_MAP.get(actionClass);
} }
/** /**
@ -533,7 +537,10 @@ public class ActionQueue {
* @return {@code true} if insertions or deletions are currently queued; {@code false} otherwise. * @return {@code true} if insertions or deletions are currently queued; {@code false} otherwise.
*/ */
public boolean areInsertionsOrDeletionsQueued() { public boolean areInsertionsOrDeletionsQueued() {
return ( insertions != null && !insertions.isEmpty() ) || hasUnresolvedEntityInsertActions() || (deletions != null && !deletions.isEmpty()) || (orphanRemovals != null && !orphanRemovals.isEmpty()); return insertions != null && !insertions.isEmpty()
|| hasUnresolvedEntityInsertActions()
|| deletions != null && !deletions.isEmpty()
|| orphanRemovals != null && !orphanRemovals.isEmpty();
} }
/** /**
@ -543,11 +550,11 @@ public class ActionQueue {
* *
* @return {@code true} if we contain pending actions against any of the given tables; {@code false} otherwise. * @return {@code true} if we contain pending actions against any of the given tables; {@code false} otherwise.
*/ */
public boolean areTablesToBeUpdated(@SuppressWarnings("rawtypes") Set tables) { public boolean areTablesToBeUpdated(Set<Serializable> tables) {
if ( tables.isEmpty() ) { if ( tables.isEmpty() ) {
return false; return false;
} }
for ( ListProvider listProvider : EXECUTABLE_LISTS_MAP.values() ) { for ( ListProvider<?> listProvider : EXECUTABLE_LISTS_MAP.values() ) {
ExecutableList<?> l = listProvider.get( this ); ExecutableList<?> l = listProvider.get( this );
if ( areTablesToBeUpdated( l, tables ) ) { if ( areTablesToBeUpdated( l, tables ) ) {
return true; return true;
@ -559,7 +566,7 @@ public class ActionQueue {
return areTablesToBeUpdated( unresolvedInsertions, tables ); return areTablesToBeUpdated( unresolvedInsertions, tables );
} }
private static boolean areTablesToBeUpdated(ExecutableList<?> actions, @SuppressWarnings("rawtypes") Set tableSpaces) { private static boolean areTablesToBeUpdated(ExecutableList<?> actions, Set<Serializable> tableSpaces) {
if ( actions == null || actions.isEmpty() ) { if ( actions == null || actions.isEmpty() ) {
return false; return false;
} }
@ -574,7 +581,7 @@ public class ActionQueue {
return false; return false;
} }
private static boolean areTablesToBeUpdated(UnresolvedEntityInsertActions actions, @SuppressWarnings("rawtypes") Set tableSpaces) { private static boolean areTablesToBeUpdated(UnresolvedEntityInsertActions actions, Set<Serializable> tableSpaces) {
for ( Executable action : actions.getDependentEntityInsertActions() ) { for ( Executable action : actions.getDependentEntityInsertActions() ) {
final Serializable[] spaces = action.getPropertySpaces(); final Serializable[] spaces = action.getPropertySpaces();
for ( Serializable space : spaces ) { for ( Serializable space : spaces ) {
@ -593,7 +600,8 @@ public class ActionQueue {
* @param list The list of Executable elements to be performed * @param list The list of Executable elements to be performed
* *
*/ */
private <E extends Executable & Comparable<?> & Serializable> void executeActions(ExecutableList<E> list) throws HibernateException { private <E extends Executable & Comparable<? super E> & Serializable> void executeActions(ExecutableList<E> list)
throws HibernateException {
// todo : consider ways to improve the double iteration of Executables here: // todo : consider ways to improve the double iteration of Executables here:
// 1) we explicitly iterate list here to perform Executable#execute() // 1) we explicitly iterate list here to perform Executable#execute()
// 2) ExecutableList#getQuerySpaces also iterates the Executables to collect query spaces. // 2) ExecutableList#getQuerySpaces also iterates the Executables to collect query spaces.
@ -632,8 +640,8 @@ public class ActionQueue {
session.getJdbcCoordinator().executeBatch(); session.getJdbcCoordinator().executeBatch();
} }
private static String[] convertTimestampSpaces(Set spaces) { private static String[] convertTimestampSpaces(Set<String> spaces) {
return (String[]) spaces.toArray( new String[ spaces.size() ] ); return spaces.toArray(StringHelper.EMPTY_STRINGS);
} }
/** /**
@ -655,11 +663,11 @@ public class ActionQueue {
*/ */
private void invalidateSpaces(String... spaces) { private void invalidateSpaces(String... spaces) {
if ( spaces != null && spaces.length > 0 ) { if ( spaces != null && spaces.length > 0 ) {
for ( Serializable s : spaces ) { for ( String space : spaces ) {
if ( afterTransactionProcesses == null ) { if ( afterTransactionProcesses == null ) {
afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session ); afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session );
} }
afterTransactionProcesses.addSpaceToInvalidate( (String) s ); afterTransactionProcesses.addSpaceToInvalidate( space );
} }
// Performance win: If we are processing an ExecutableList, this will only be called once // Performance win: If we are processing an ExecutableList, this will only be called once
session.getFactory().getCache().getTimestampsCache().preInvalidate( spaces, session ); session.getFactory().getCache().getTimestampsCache().preInvalidate( spaces, session );
@ -685,7 +693,7 @@ public class ActionQueue {
+ "]"; + "]";
} }
private static String toString(ExecutableList q) { private static String toString(ExecutableList<?> q) {
return q == null ? "ExecutableList{size=0}" : q.toString(); return q == null ? "ExecutableList{size=0}" : q.toString();
} }
@ -748,7 +756,9 @@ public class ActionQueue {
* @param processes Transaction completion processes. * @param processes Transaction completion processes.
* @param isTransactionCoordinatorShared Flag indicating shared transaction context. * @param isTransactionCoordinatorShared Flag indicating shared transaction context.
*/ */
public void setTransactionCompletionProcesses(TransactionCompletionProcesses processes, boolean isTransactionCoordinatorShared) { public void setTransactionCompletionProcesses(
TransactionCompletionProcesses processes,
boolean isTransactionCoordinatorShared) {
this.isTransactionCoordinatorShared = isTransactionCoordinatorShared; this.isTransactionCoordinatorShared = isTransactionCoordinatorShared;
this.beforeTransactionProcesses = processes.beforeTransactionCompletionProcesses; this.beforeTransactionProcesses = processes.beforeTransactionCompletionProcesses;
this.afterTransactionProcesses = processes.afterTransactionCompletionProcesses; this.afterTransactionProcesses = processes.afterTransactionCompletionProcesses;
@ -812,12 +822,14 @@ public class ActionQueue {
@SuppressWarnings("SimplifiableConditionalExpression") @SuppressWarnings("SimplifiableConditionalExpression")
public boolean hasAfterTransactionActions() { public boolean hasAfterTransactionActions() {
return isTransactionCoordinatorShared ? false : afterTransactionProcesses != null && afterTransactionProcesses.hasActions(); return isTransactionCoordinatorShared ? false
: afterTransactionProcesses != null && afterTransactionProcesses.hasActions();
} }
@SuppressWarnings("SimplifiableConditionalExpression") @SuppressWarnings("SimplifiableConditionalExpression")
public boolean hasBeforeTransactionActions() { public boolean hasBeforeTransactionActions() {
return isTransactionCoordinatorShared ? false : beforeTransactionProcesses != null && beforeTransactionProcesses.hasActions(); return isTransactionCoordinatorShared ? false
: beforeTransactionProcesses != null && beforeTransactionProcesses.hasActions();
} }
public boolean hasAnyQueuedActions() { public boolean hasAnyQueuedActions() {
@ -868,7 +880,7 @@ public class ActionQueue {
} }
unresolvedInsertions.serialize( oos ); unresolvedInsertions.serialize( oos );
for ( ListProvider p : EXECUTABLE_LISTS_MAP.values() ) { for ( ListProvider<?> p : EXECUTABLE_LISTS_MAP.values() ) {
ExecutableList<?> l = p.get( this ); ExecutableList<?> l = p.get( this );
if ( l == null ) { if ( l == null ) {
oos.writeBoolean( false ); oos.writeBoolean( false );
@ -889,7 +901,8 @@ public class ActionQueue {
* @throws IOException indicates a problem reading from the stream * @throws IOException indicates a problem reading from the stream
* @throws ClassNotFoundException Generally means we were unable to locate user classes. * @throws ClassNotFoundException Generally means we were unable to locate user classes.
*/ */
public static ActionQueue deserialize(ObjectInputStream ois, SessionImplementor session) throws IOException, ClassNotFoundException { public static ActionQueue deserialize(ObjectInputStream ois, SessionImplementor session)
throws IOException, ClassNotFoundException {
final boolean traceEnabled = LOG.isTraceEnabled(); final boolean traceEnabled = LOG.isTraceEnabled();
if ( traceEnabled ) { if ( traceEnabled ) {
LOG.trace( "Deserializing action-queue" ); LOG.trace( "Deserializing action-queue" );
@ -898,7 +911,7 @@ public class ActionQueue {
rtn.unresolvedInsertions = UnresolvedEntityInsertActions.deserialize( ois, session ); rtn.unresolvedInsertions = UnresolvedEntityInsertActions.deserialize( ois, session );
for ( ListProvider provider : EXECUTABLE_LISTS_MAP.values() ) { for ( ListProvider<?> provider : EXECUTABLE_LISTS_MAP.values() ) {
ExecutableList<?> l = provider.get( rtn ); ExecutableList<?> l = provider.get( rtn );
boolean notNull = ois.readBoolean(); boolean notNull = ois.readBoolean();
if ( notNull ) { if ( notNull ) {
@ -921,7 +934,7 @@ public class ActionQueue {
protected SessionImplementor session; protected SessionImplementor session;
// Concurrency handling required when transaction completion process is dynamically registered // Concurrency handling required when transaction completion process is dynamically registered
// inside event listener (HHH-7478). // inside event listener (HHH-7478).
protected Queue<T> processes = new ConcurrentLinkedQueue<T>(); protected Queue<T> processes = new ConcurrentLinkedQueue<>();
private AbstractTransactionCompletionProcessQueue(SessionImplementor session) { private AbstractTransactionCompletionProcessQueue(SessionImplementor session) {
this.session = session; this.session = session;
@ -965,8 +978,9 @@ public class ActionQueue {
/** /**
* Encapsulates behavior needed for after transaction processing * Encapsulates behavior needed for after transaction processing
*/ */
private static class AfterTransactionCompletionProcessQueue extends AbstractTransactionCompletionProcessQueue<AfterTransactionCompletionProcess> { private static class AfterTransactionCompletionProcessQueue
private Set<String> querySpacesToInvalidate = new HashSet<>(); extends AbstractTransactionCompletionProcessQueue<AfterTransactionCompletionProcess> {
private final Set<String> querySpacesToInvalidate = new HashSet<>();
private AfterTransactionCompletionProcessQueue(SessionImplementor session) { private AfterTransactionCompletionProcessQueue(SessionImplementor session) {
super( session ); super( session );
@ -992,7 +1006,7 @@ public class ActionQueue {
if ( session.getFactory().getSessionFactoryOptions().isQueryCacheEnabled() ) { if ( session.getFactory().getSessionFactoryOptions().isQueryCacheEnabled() ) {
session.getFactory().getCache().getTimestampsCache().invalidate( session.getFactory().getCache().getTimestampsCache().invalidate(
querySpacesToInvalidate.toArray( new String[querySpacesToInvalidate.size()] ), querySpacesToInvalidate.toArray(StringHelper.EMPTY_STRINGS),
session session
); );
} }
@ -1038,9 +1052,9 @@ public class ActionQueue {
private final String entityName; private final String entityName;
private final String rootEntityName; private final String rootEntityName;
private Set<String> parentEntityNames = new HashSet<>( ); private final Set<String> parentEntityNames = new HashSet<>( );
private Set<String> childEntityNames = new HashSet<>( ); private final Set<String> childEntityNames = new HashSet<>( );
private BatchIdentifier parent; private BatchIdentifier parent;
@ -1111,7 +1125,8 @@ public class ActionQueue {
return ( return (
parent == batchIdentifier parent == batchIdentifier
|| parentEntityNames.contains( batchIdentifier.getEntityName() ) || parentEntityNames.contains( batchIdentifier.getEntityName() )
|| ( parentEntityNames.contains( batchIdentifier.getRootEntityName() ) && !this.getEntityName().equals( batchIdentifier.getRootEntityName() ) ) || ( parentEntityNames.contains( batchIdentifier.getRootEntityName() )
&& !this.getEntityName().equals( batchIdentifier.getRootEntityName() ) )
|| parent != null && parent.hasParent( batchIdentifier, new ArrayList<>() ) || parent != null && parent.hasParent( batchIdentifier, new ArrayList<>() )
); );
} }
@ -1233,8 +1248,12 @@ public class ActionQueue {
while ( !sorted && iterations <= maxIterations ); while ( !sorted && iterations <= maxIterations );
if ( iterations > maxIterations ) { if ( iterations > maxIterations ) {
LOG.warn( "The batch containing " + latestBatches.size() + " statements could not be sorted after " + maxIterations + " iterations. " + LOG.warn( "The batch containing "
"This might indicate a circular entity relationship." ); + latestBatches.size()
+ " statements could not be sorted after "
+ maxIterations
+ " iterations. "
+ "This might indicate a circular entity relationship." );
} }
// Now, rebuild the insertions list. There is a batch for each entry in the name list. // Now, rebuild the insertions list. There is a batch for each entry in the name list.
@ -1277,13 +1296,18 @@ public class ActionQueue {
} }
} }
private void addParentChildEntityNameByPropertyAndValue(AbstractEntityInsertAction action, BatchIdentifier batchIdentifier, Type type, Object value) { private void addParentChildEntityNameByPropertyAndValue(
AbstractEntityInsertAction action,
BatchIdentifier batchIdentifier,
Type type,
Object value) {
if ( type.isEntityType() ) { if ( type.isEntityType() ) {
final EntityType entityType = (EntityType) type; final EntityType entityType = (EntityType) type;
final String entityName = entityType.getName(); final String entityName = entityType.getName();
final String rootEntityName = action.getSession().getFactory().getMetamodel().entityPersister( entityName ).getRootEntityName(); final String rootEntityName = action.getSession().getFactory().getMetamodel().
entityPersister( entityName ).getRootEntityName();
if ( entityType.isOneToOne() && OneToOneType.class.cast( entityType ).getForeignKeyDirection() == ForeignKeyDirection.TO_PARENT ) { if ( entityType.isOneToOne() && entityType.getForeignKeyDirection() == ForeignKeyDirection.TO_PARENT ) {
if ( !entityType.isReferenceToPrimaryKey() ) { if ( !entityType.isReferenceToPrimaryKey() ) {
batchIdentifier.getChildEntityNames().add( entityName ); batchIdentifier.getChildEntityNames().add( entityName );
} }
@ -1308,12 +1332,12 @@ public class ActionQueue {
} }
else if ( type.isCollectionType() ) { else if ( type.isCollectionType() ) {
CollectionType collectionType = (CollectionType) type; CollectionType collectionType = (CollectionType) type;
final SessionFactoryImplementor sessionFactory = ( (SessionImplementor) action.getSession() ) final SessionFactoryImplementor sessionFactory = action.getSession().getSessionFactory();
.getSessionFactory();
if ( collectionType.getElementType( sessionFactory ).isEntityType() && if ( collectionType.getElementType( sessionFactory ).isEntityType() &&
!sessionFactory.getMetamodel().collectionPersister( collectionType.getRole() ).isManyToMany() ) { !sessionFactory.getMetamodel().collectionPersister( collectionType.getRole() ).isManyToMany() ) {
String entityName = collectionType.getAssociatedEntityName( sessionFactory ); String entityName = collectionType.getAssociatedEntityName( sessionFactory );
String rootEntityName = action.getSession().getFactory().getMetamodel().entityPersister( entityName ).getRootEntityName(); String rootEntityName = action.getSession().getFactory().getMetamodel()
.entityPersister( entityName ).getRootEntityName();
batchIdentifier.getChildEntityNames().add( entityName ); batchIdentifier.getChildEntityNames().add( entityName );
if ( !rootEntityName.equals( entityName ) ) { if ( !rootEntityName.equals( entityName ) ) {
batchIdentifier.getChildEntityNames().add( rootEntityName ); batchIdentifier.getChildEntityNames().add( rootEntityName );
@ -1345,7 +1369,7 @@ public class ActionQueue {
} }
private abstract static class ListProvider<T extends Executable & Comparable & Serializable> { private abstract static class ListProvider<T extends Executable & Comparable<? super T> & Serializable> {
abstract ExecutableList<T> get(ActionQueue instance); abstract ExecutableList<T> get(ActionQueue instance);
abstract ExecutableList<T> init(ActionQueue instance); abstract ExecutableList<T> init(ActionQueue instance);
ExecutableList<T> getOrInit( ActionQueue instance ) { ExecutableList<T> getOrInit( ActionQueue instance ) {

View File

@ -16,8 +16,8 @@ import java.io.Serializable;
* @author Gavin King * @author Gavin King
*/ */
public final class AssociationKey implements Serializable { public final class AssociationKey implements Serializable {
private EntityKey ownerKey; private final EntityKey ownerKey;
private String propertyName; private final String propertyName;
/** /**
* Constructs an AssociationKey * Constructs an AssociationKey

View File

@ -22,29 +22,26 @@ import org.hibernate.action.spi.Executable;
import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.CollectionHelper;
/** /**
* Specialized encapsulating of the state pertaining to each Executable list. * A list of {@link Executable executeble actions}. Responsible for
* <p/> * {@linkplain #sort() sorting} the executables, and calculating the
* Manages sorting the executables (lazily) * affected {@linkplain #getQuerySpaces() query spaces}.
* <p/>
* Manages the querySpaces affected by the executables in the list, and caches this too.
* *
* @author Steve Ebersole * @author Steve Ebersole
* @author Anton Marsden * @author Anton Marsden
* *
* @param <E> Intersection type describing Executable implementations * @param <E> Intersection type describing {@link Executable} implementations
*/ */
@SuppressWarnings("rawtypes") public class ExecutableList<E extends Executable & Comparable<? super E> & Serializable>
public class ExecutableList<E extends Executable & Comparable & Serializable> implements Serializable, Iterable<E>, Externalizable { implements Serializable, Iterable<E>, Externalizable {
public static final int INIT_QUEUE_LIST_SIZE = 5; public static final int INIT_QUEUE_LIST_SIZE = 5;
/** /**
* Provides a sorting interface for ExecutableList. * Provides a sorting interface for {@link ExecutableList}.
* *
* @param <E> * @param <E>
*/ */
public interface Sorter<E extends Executable> { public interface Sorter<E extends Executable> {
/** /**
* Sorts the list. * Sorts the list.
*/ */
@ -58,22 +55,22 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
private boolean sorted; private boolean sorted;
/** /**
* Used to hold the query spaces (table names, roughly) that all the Executable instances contained * Used to hold the query spaces (table names, roughly) that all the {@link Executable}
* in this list define. This information is ultimately used to invalidate cache regions as it is * instances contained in this list define. This information is ultimately used to
* exposed from {@link #getQuerySpaces}. This value being {@code null} indicates that the * invalidate cache regions as it is exposed from {@link #getQuerySpaces}. This value
* query spaces should be calculated. * being {@code null} indicates that the query spaces should be calculated.
*/ */
private transient Set<Serializable> querySpaces; private transient Set<Serializable> querySpaces;
/** /**
* Creates a new ExecutableList with the default settings. * Creates a new instance with the default settings.
*/ */
public ExecutableList() { public ExecutableList() {
this( INIT_QUEUE_LIST_SIZE ); this( INIT_QUEUE_LIST_SIZE );
} }
/** /**
* Creates a new ExecutableList with the specified initialCapacity. * Creates a new instance with the given initial capacity.
* *
* @param initialCapacity The initial capacity for instantiating the internal List * @param initialCapacity The initial capacity for instantiating the internal List
*/ */
@ -95,7 +92,7 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
} }
/** /**
* Creates a new ExecutableList using the specified Sorter. * Creates a new instance using the given {@link Sorter}.
* *
* @param sorter The Sorter to use; may be {@code null} * @param sorter The Sorter to use; may be {@code null}
*/ */
@ -104,7 +101,7 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
} }
/** /**
* Creates a new ExecutableList with the specified initialCapacity and Sorter. * Creates a new instance with the given initial capacity and {@link Sorter}.
* *
* @param initialCapacity The initial capacity for instantiating the internal List * @param initialCapacity The initial capacity for instantiating the internal List
* @param sorter The Sorter to use; may be {@code null} * @param sorter The Sorter to use; may be {@code null}
@ -156,7 +153,7 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
* @return the entry that was removed * @return the entry that was removed
*/ */
public E remove(int index) { public E remove(int index) {
// removals are generally safe in regards to sorting... // removals are generally safe with regard to sorting...
final E e = executables.remove( index ); final E e = executables.remove( index );
@ -201,7 +198,7 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
} }
/** /**
* Add an Executable to this list. * Add an {@link Executable} to this list.
* *
* @param executable the executable to add to the list * @param executable the executable to add to the list
* *
@ -235,13 +232,13 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
Collections.addAll( this.querySpaces, querySpaces ); Collections.addAll( this.querySpaces, querySpaces );
} }
return added; return true;
} }
/** /**
* Sorts the list using the natural ordering or using the Sorter if it's not null. * Sorts the list using the natural ordering or using the {@link Sorter}
* if it's not null.
*/ */
@SuppressWarnings("unchecked")
public void sort() { public void sort() {
if ( sorted || !requiresSorting ) { if ( sorted || !requiresSorting ) {
// nothing to do // nothing to do
@ -311,12 +308,12 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
} }
/** /**
* Read this object state back in from the given stream as part of de-serialization * Read this object state back in from the given stream as part of
* the deserialization process.
* *
* @param in The stream from which to read our serial state * @param in The stream from which to read our serial state
*/ */
@Override @Override
@SuppressWarnings("unchecked")
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
sorted = in.readBoolean(); sorted = in.readBoolean();
@ -324,6 +321,7 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
executables.ensureCapacity( numberOfExecutables ); executables.ensureCapacity( numberOfExecutables );
if ( numberOfExecutables > 0 ) { if ( numberOfExecutables > 0 ) {
for ( int i = 0; i < numberOfExecutables; i++ ) { for ( int i = 0; i < numberOfExecutables; i++ ) {
@SuppressWarnings("unchecked")
E e = (E) in.readObject(); E e = (E) in.readObject();
executables.add( e ); executables.add( e );
} }
@ -342,9 +340,10 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
} }
/** /**
* Allow the Executables to re-associate themselves with the Session after deserialization. * Allow the {@link Executable}s to reassociate themselves with the
* session after deserialization.
* *
* @param session The session to which to associate the Executables * @param session The session with which to associate the {@code Executable}s
*/ */
public void afterDeserialize(SessionImplementor session) { public void afterDeserialize(SessionImplementor session) {
for ( E e : executables ) { for ( E e : executables ) {

View File

@ -67,7 +67,7 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
* *
*/ */
public void onDelete(DeleteEvent event) throws HibernateException { public void onDelete(DeleteEvent event) throws HibernateException {
onDelete( event, new IdentitySet() ); onDelete( event, new IdentitySet<>() );
} }
/** /**
@ -281,7 +281,8 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
persistenceContext.registerNullifiableEntityKey( key ); persistenceContext.registerNullifiableEntityKey( key );
if ( isOrphanRemovalBeforeUpdates ) { if ( isOrphanRemovalBeforeUpdates ) {
// TODO: The removeOrphan concept is a temporary "hack" for HHH-6484. This should be removed once action/task // TODO: The removeOrphan concept is a temporary "hack" for HHH-6484.
// This should be removed once action/task
// ordering is improved. // ordering is improved.
session.getActionQueue().addAction( session.getActionQueue().addAction(
new OrphanRemovalAction( new OrphanRemovalAction(