Skip to content

Commit a2d5831

Browse files
committed
HHH-18546 Clean up any hanging BulkOperationCleanupAction after-txn callbacks on Session close
1 parent 6e85916 commit a2d5831

File tree

6 files changed

+84
-1
lines changed

6 files changed

+84
-1
lines changed

hibernate-core/src/main/java/org/hibernate/action/internal/BulkOperationCleanupAction.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,30 @@ public BeforeTransactionCompletionProcess getBeforeTransactionCompletionProcess(
214214

215215
@Override
216216
public AfterTransactionCompletionProcess getAfterTransactionCompletionProcess() {
217-
return (success, session) -> {
217+
return new BulkOperationCleanUpAfterTransactionCompletionProcess(
218+
entityCleanups,
219+
collectionCleanups,
220+
naturalIdCleanups
221+
);
222+
}
223+
224+
public static final class BulkOperationCleanUpAfterTransactionCompletionProcess
225+
implements AfterTransactionCompletionProcess {
226+
private final Set<EntityCleanup> entityCleanups;
227+
private final Set<CollectionCleanup> collectionCleanups;
228+
private final Set<NaturalIdCleanup> naturalIdCleanups;
229+
230+
public BulkOperationCleanUpAfterTransactionCompletionProcess(
231+
Set<EntityCleanup> entityCleanups,
232+
Set<CollectionCleanup> collectionCleanups,
233+
Set<NaturalIdCleanup> naturalIdCleanups) {
234+
this.entityCleanups = entityCleanups;
235+
this.collectionCleanups = collectionCleanups;
236+
this.naturalIdCleanups = naturalIdCleanups;
237+
}
238+
239+
@Override
240+
public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) {
218241
for ( var cleanup : entityCleanups ) {
219242
cleanup.release();
220243
}

hibernate-core/src/main/java/org/hibernate/engine/internal/AfterTransactionCompletionProcessQueue.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package org.hibernate.engine.internal;
66

77
import org.hibernate.HibernateException;
8+
import org.hibernate.action.internal.BulkOperationCleanupAction;
89
import org.hibernate.cache.CacheException;
910
import org.hibernate.engine.spi.SessionFactoryImplementor;
1011
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@@ -59,4 +60,37 @@ public void afterTransactionCompletion(boolean success) {
5960
}
6061
querySpacesToInvalidate.clear();
6162
}
63+
64+
public void executePendingBulkOperationCleanUpActions() {
65+
AfterCompletionCallback process;
66+
boolean hasPendingBulkOperationCleanUpActions = false;
67+
while ( ( process = processes.poll() ) != null ) {
68+
if ( process instanceof BulkOperationCleanupAction.BulkOperationCleanUpAfterTransactionCompletionProcess ) {
69+
try {
70+
hasPendingBulkOperationCleanUpActions = true;
71+
process.doAfterTransactionCompletion( true, session );
72+
}
73+
catch (CacheException ce) {
74+
CORE_LOGGER.unableToReleaseCacheLock( ce );
75+
// continue loop
76+
}
77+
catch (Exception e) {
78+
throw new HibernateException(
79+
"Unable to perform afterTransactionCompletion callback: " + e.getMessage(),
80+
e
81+
);
82+
}
83+
}
84+
}
85+
86+
if ( hasPendingBulkOperationCleanUpActions ) {
87+
if ( session.getFactory().getSessionFactoryOptions().isQueryCacheEnabled() ) {
88+
session.getFactory().getCache().getTimestampsCache().invalidate(
89+
querySpacesToInvalidate.toArray( new String[0] ),
90+
session
91+
);
92+
}
93+
querySpacesToInvalidate.clear();
94+
}
95+
}
6296
}

hibernate-core/src/main/java/org/hibernate/engine/internal/TransactionCompletionCallbacksImpl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,11 @@ public TransactionCompletionCallbacksImpl forSharing() {
7979
}
8080
return this;
8181
}
82+
83+
@Override
84+
public void executePendingBulkOperationCleanUpActions() {
85+
if ( afterTransactionProcesses != null ) {
86+
afterTransactionProcesses.executePendingBulkOperationCleanUpActions();
87+
}
88+
}
8289
}

hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import org.hibernate.AssertionFailure;
2121
import org.hibernate.HibernateException;
22+
import org.hibernate.Internal;
2223
import org.hibernate.PropertyValueException;
2324
import org.hibernate.TransientPropertyValueException;
2425
import org.hibernate.action.internal.AbstractEntityInsertAction;
@@ -537,6 +538,14 @@ public void afterTransactionCompletion(boolean success) {
537538
}
538539
}
539540

541+
@Internal
542+
public void executePendingBulkOperationCleanUpActions() {
543+
if ( !isTransactionCoordinatorShared && transactionCompletionCallbacks != null ) {
544+
// Execute completion actions only in transaction owner (aka parent session).
545+
transactionCompletionCallbacks.executePendingBulkOperationCleanUpActions();
546+
}
547+
}
548+
540549
/**
541550
* Execute any registered {@link BeforeTransactionCompletionProcess}
542551
*/

hibernate-core/src/main/java/org/hibernate/engine/spi/TransactionCompletionCallbacksImplementor.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,10 @@ public interface TransactionCompletionCallbacksImplementor extends TransactionCo
4444
* the same transaction coordinator. Returns this instance for convenience/fluency.
4545
*/
4646
TransactionCompletionCallbacksImplementor forSharing();
47+
48+
49+
/**
50+
* Execute all pending {@link org.hibernate.action.internal.BulkOperationCleanupAction}
51+
*/
52+
void executePendingBulkOperationCleanUpActions();
4753
}

hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,10 @@ public void closeWithoutOpenChecks() {
403403
}
404404
}
405405
finally {
406+
if ( actionQueue.hasAfterTransactionActions() ) {
407+
SESSION_LOGGER.warn( "Closing session with unprocessed clean up bulk operations, forcing their execution" );
408+
actionQueue.executePendingBulkOperationCleanUpActions();
409+
}
406410
final var statistics = getSessionFactory().getStatistics();
407411
if ( statistics.isStatisticsEnabled() ) {
408412
statistics.closeSession();

0 commit comments

Comments
 (0)