Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 81 additions & 43 deletions hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,8 @@ private void addResolvedEntityInsertAction(AbstractEntityInsertAction insert) {
}
insert.makeEntityManaged();
if( unresolvedInsertions != null ) {
for (AbstractEntityInsertAction resolvedAction : unresolvedInsertions.resolveDependentActions(insert.getInstance(), session)) {
addResolvedEntityInsertAction(resolvedAction);
for ( AbstractEntityInsertAction resolvedAction : unresolvedInsertions.resolveDependentActions( insert.getInstance(), session ) ) {
addResolvedEntityInsertAction( resolvedAction );
}
}
}
Expand Down Expand Up @@ -383,7 +383,7 @@ private void registerCleanupActions(Executable executable) {
if( beforeTransactionProcesses == null ) {
beforeTransactionProcesses = new BeforeTransactionCompletionProcessQueue( session );
}
beforeTransactionProcesses.register(executable.getBeforeTransactionCompletionProcess());
beforeTransactionProcesses.register( executable.getBeforeTransactionCompletionProcess() );
}
if ( session.getFactory().getSessionFactoryOptions().isQueryCacheEnabled() ) {
invalidateSpaces( executable.getPropertySpaces() );
Expand All @@ -392,7 +392,7 @@ private void registerCleanupActions(Executable executable) {
if( afterTransactionProcesses == null ) {
afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session );
}
afterTransactionProcesses.register(executable.getAfterTransactionCompletionProcess());
afterTransactionProcesses.register( executable.getAfterTransactionCompletionProcess() );
}
}

Expand Down Expand Up @@ -495,7 +495,7 @@ public void afterTransactionCompletion(boolean success) {
if ( !isTransactionCoordinatorShared ) {
// Execute completion actions only in transaction owner (aka parent session).
if( afterTransactionProcesses != null ) {
afterTransactionProcesses.afterTransactionCompletion(success);
afterTransactionProcesses.afterTransactionCompletion( success );
}
}
}
Expand Down Expand Up @@ -593,13 +593,13 @@ private <E extends Executable & Comparable<?> & Serializable> void executeAction
if( beforeTransactionProcesses == null ) {
beforeTransactionProcesses = new BeforeTransactionCompletionProcessQueue( session );
}
beforeTransactionProcesses.register(e.getBeforeTransactionCompletionProcess());
beforeTransactionProcesses.register( e.getBeforeTransactionCompletionProcess() );
}
if( e.getAfterTransactionCompletionProcess() != null ) {
if( afterTransactionProcesses == null ) {
afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session );
}
afterTransactionProcesses.register(e.getAfterTransactionCompletionProcess());
afterTransactionProcesses.register( e.getAfterTransactionCompletionProcess() );
}
}
}
Expand Down Expand Up @@ -655,14 +655,14 @@ private void invalidateSpaces(Serializable... spaces) {
*/
@Override
public String toString() {
return "ActionQueue[insertions=" + toString(insertions)
+ " updates=" + toString(updates)
+ " deletions=" + toString(deletions)
+ " orphanRemovals=" + toString(orphanRemovals)
+ " collectionCreations=" + toString(collectionCreations)
+ " collectionRemovals=" + toString(collectionRemovals)
+ " collectionUpdates=" + toString(collectionUpdates)
+ " collectionQueuedOps=" + toString(collectionQueuedOps)
return "ActionQueue[insertions=" + toString( insertions )
+ " updates=" + toString( updates )
+ " deletions=" + toString( deletions )
+ " orphanRemovals=" + toString( orphanRemovals )
+ " collectionCreations=" + toString( collectionCreations )
+ " collectionRemovals=" + toString( collectionRemovals )
+ " collectionUpdates=" + toString( collectionUpdates )
+ " collectionQueuedOps=" + toString( collectionQueuedOps )
+ " unresolvedInsertDependencies=" + unresolvedInsertions
+ "]";
}
Expand Down Expand Up @@ -811,25 +811,25 @@ public boolean hasAnyQueuedActions() {

public void unScheduleDeletion(EntityEntry entry, Object rescuedEntity) {
if ( rescuedEntity instanceof HibernateProxy ) {
LazyInitializer initializer = ( ( HibernateProxy ) rescuedEntity ).getHibernateLazyInitializer();
LazyInitializer initializer = ( (HibernateProxy) rescuedEntity ).getHibernateLazyInitializer();
if ( !initializer.isUninitialized() ) {
rescuedEntity = initializer.getImplementation( session );
}
}
if( deletions != null ) {
for ( int i = 0; i < deletions.size(); i++ ) {
EntityDeleteAction action = deletions.get(i);
EntityDeleteAction action = deletions.get( i );
if (action.getInstance() == rescuedEntity) {
deletions.remove(i);
deletions.remove( i );
return;
}
}
}
if( orphanRemovals != null ) {
for ( int i = 0; i < orphanRemovals.size(); i++ ) {
EntityDeleteAction action = orphanRemovals.get(i);
EntityDeleteAction action = orphanRemovals.get( i );
if (action.getInstance() == rescuedEntity) {
orphanRemovals.remove(i);
orphanRemovals.remove( i );
return;
}
}
Expand All @@ -851,9 +851,9 @@ public void serialize(ObjectOutputStream oos) throws IOException {
unresolvedInsertions.serialize( oos );

for ( ListProvider p : EXECUTABLE_LISTS_MAP.values() ) {
ExecutableList<?> l = p.get(this);
ExecutableList<?> l = p.get( this );
if( l == null ) {
oos.writeBoolean(false);
oos.writeBoolean( false );
}
else {
oos.writeBoolean( true );
Expand All @@ -874,18 +874,18 @@ public void serialize(ObjectOutputStream oos) throws IOException {
public static ActionQueue deserialize(ObjectInputStream ois, SessionImplementor session) throws IOException, ClassNotFoundException {
final boolean traceEnabled = LOG.isTraceEnabled();
if ( traceEnabled ) {
LOG.trace("Deserializing action-queue");
LOG.trace( "Deserializing action-queue" );
}
ActionQueue rtn = new ActionQueue( session );

rtn.unresolvedInsertions = UnresolvedEntityInsertActions.deserialize( ois, session );

for ( ListProvider provider : EXECUTABLE_LISTS_MAP.values() ) {
ExecutableList<?> l = provider.get(rtn);
ExecutableList<?> l = provider.get( rtn );
boolean notNull = ois.readBoolean();
if( notNull ) {
if(l == null) {
l = provider.init(rtn);
l = provider.init( rtn );
}
l.readExternal( ois );

Expand All @@ -899,7 +899,7 @@ public static ActionQueue deserialize(ObjectInputStream ois, SessionImplementor
return rtn;
}

private static abstract class AbstractTransactionCompletionProcessQueue<T> {
private abstract static class AbstractTransactionCompletionProcessQueue<T> {
protected SessionImplementor session;
// Concurrency handling required when transaction completion process is dynamically registered
// inside event listener (HHH-7478).
Expand Down Expand Up @@ -1018,14 +1018,15 @@ private static class InsertActionSorter implements ExecutableList.Sorter<Abstrac
private static class BatchIdentifier {

private final String entityName;
private final String rootEntityName;

private Set<String> parentEntityNames = new HashSet<String>( );

private Set<String> childEntityNames = new HashSet<String>( );

public BatchIdentifier(
String entityName) {
BatchIdentifier(String entityName, String rootEntityName) {
this.entityName = entityName;
this.rootEntityName = rootEntityName;
}

@Override
Expand All @@ -1045,17 +1046,30 @@ public int hashCode() {
return entityName.hashCode();
}

public String getEntityName() {
String getEntityName() {
return entityName;
}

public Set<String> getParentEntityNames() {
String getRootEntityName() {
return rootEntityName;
}

Set<String> getParentEntityNames() {
return parentEntityNames;
}

public Set<String> getChildEntityNames() {
Set<String> getChildEntityNames() {
return childEntityNames;
}

boolean hasAnyParentEntityNames(BatchIdentifier batchIdentifier) {
return parentEntityNames.contains( batchIdentifier.getEntityName() ) ||
parentEntityNames.contains( batchIdentifier.getRootEntityName() );
}

boolean hasAnyChildEntityNames(BatchIdentifier batchIdentifier) {
return childEntityNames.contains( batchIdentifier.getEntityName() );
}
}

// the mapping of entity names to their latest batch numbers.
Expand All @@ -1079,7 +1093,10 @@ public void sort(List<AbstractEntityInsertAction> insertions) {
this.actionBatches = new HashMap<BatchIdentifier, List<AbstractEntityInsertAction>>();

for ( AbstractEntityInsertAction action : insertions ) {
BatchIdentifier batchIdentifier = new BatchIdentifier( action.getEntityName() );
BatchIdentifier batchIdentifier = new BatchIdentifier(
action.getEntityName(),
action.getSession().getFactory().getEntityPersister( action.getEntityName() ).getRootEntityName()
);

// the entity associated with the current action.
Object currentEntity = action.getInstance();
Expand All @@ -1093,30 +1110,40 @@ public void sort(List<AbstractEntityInsertAction> insertions) {
}
addParentChildEntityNames( action, batchIdentifier );
entityBatchIdentifier.put( currentEntity, batchIdentifier );
addToBatch(batchIdentifier, action);
addToBatch( batchIdentifier, action );
}
insertions.clear();

// Examine each entry in the batch list, sorting them based on parent/child associations.
for ( int i = 0; i < latestBatches.size(); i++ ) {
BatchIdentifier batchIdentifier = latestBatches.get( i );
String entityName = batchIdentifier.getEntityName();

//Make sure that child entries are not before parents
// Iterate previous batches and make sure that parent types are before children
// Since the outer loop looks at each batch entry individually, we need to verify that any
// prior batches in the list are not considered children (or have a parent) of the current
// batch. If so, we reordered them.
for ( int j = i - 1; j >= 0; j-- ) {
BatchIdentifier prevBatchIdentifier = latestBatches.get( j );
if(prevBatchIdentifier.getParentEntityNames().contains( entityName )) {
latestBatches.remove( i );
if ( prevBatchIdentifier.hasAnyParentEntityNames( batchIdentifier ) ) {
latestBatches.remove( batchIdentifier );
latestBatches.add( j, batchIdentifier );
}
}

//Make sure that parent entries are not after children
// Iterate next batches and make sure that children types are after parents.
// Since the outer loop looks at each batch entry individually and the prior loop will reorder
// entries as well, we need to look and verify if the current batch is a child of the next
// batch or if the current batch is seen as a parent or child of the next batch.
for ( int j = i + 1; j < latestBatches.size(); j++ ) {
BatchIdentifier nextBatchIdentifier = latestBatches.get( j );
//Take care of unidirectional @OneToOne associations but exclude bidirectional @ManyToMany
if(nextBatchIdentifier.getChildEntityNames().contains( entityName ) &&
!batchIdentifier.getChildEntityNames().contains( nextBatchIdentifier.getEntityName() )) {
latestBatches.remove( i );

final boolean nextBatchHasChild = nextBatchIdentifier.hasAnyChildEntityNames( batchIdentifier );
final boolean batchHasChild = batchIdentifier.hasAnyChildEntityNames( nextBatchIdentifier );
final boolean batchHasParent = batchIdentifier.hasAnyParentEntityNames( nextBatchIdentifier );

// Take care of unidirectional @OneToOne associations but exclude bidirectional @ManyToMany
if ( ( nextBatchHasChild && !batchHasChild ) || batchHasParent ) {
latestBatches.remove( batchIdentifier );
latestBatches.add( j, batchIdentifier );
}
}
Expand Down Expand Up @@ -1148,21 +1175,32 @@ private void addParentChildEntityNames(AbstractEntityInsertAction action, BatchI
if ( type.isEntityType() && value != null ) {
EntityType entityType = (EntityType) type;
String entityName = entityType.getName();
String rootEntityName = action.getSession().getFactory().getEntityPersister( entityName ).getRootEntityName();

if ( entityType.isOneToOne() &&
OneToOneType.class.cast( entityType ).getForeignKeyDirection() == ForeignKeyDirection.TO_PARENT ) {
batchIdentifier.getChildEntityNames().add( entityName );
if ( !rootEntityName.equals( entityName ) ) {
batchIdentifier.getChildEntityNames().add( rootEntityName );
}
}
else {
batchIdentifier.getParentEntityNames().add( entityName );
if ( !rootEntityName.equals( entityName ) ) {
batchIdentifier.getParentEntityNames().add( rootEntityName );
}
}
}
else if ( type.isCollectionType() && value != null ) {
CollectionType collectionType = (CollectionType) type;
final SessionFactoryImplementor sessionFactory = action.getSession().getFactory();
if ( collectionType.getElementType( sessionFactory ).isEntityType() ) {
String entityName = collectionType.getAssociatedEntityName( sessionFactory );
String rootEntityName = action.getSession().getFactory().getEntityPersister( entityName ).getRootEntityName();
batchIdentifier.getChildEntityNames().add( entityName );
if ( !rootEntityName.equals( entityName ) ) {
batchIdentifier.getChildEntityNames().add( rootEntityName );
}
}
}
}
Expand All @@ -1181,7 +1219,7 @@ private void addToBatch(BatchIdentifier batchIdentifier, AbstractEntityInsertAct

}

private static abstract class ListProvider<T extends Executable & Comparable & Serializable> {
private abstract static class ListProvider<T extends Executable & Comparable & Serializable> {
abstract ExecutableList<T> get(ActionQueue instance);
abstract ExecutableList<T> init(ActionQueue instance);
ExecutableList<T> getOrInit( ActionQueue instance ) {
Expand Down
Loading