diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TxPutFromLoadInterceptor.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TxPutFromLoadInterceptor.java index 26109e48bd..23481dceb9 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TxPutFromLoadInterceptor.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TxPutFromLoadInterceptor.java @@ -6,6 +6,10 @@ */ package org.hibernate.cache.infinispan.access; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + import org.hibernate.cache.infinispan.util.CacheCommandInitializer; import org.hibernate.cache.infinispan.util.EndInvalidationCommand; import org.hibernate.cache.infinispan.util.InfinispanMessageLogger; @@ -31,9 +35,6 @@ import org.infinispan.remoting.transport.Address; import org.infinispan.statetransfer.StateTransferManager; import org.infinispan.transaction.xa.GlobalTransaction; -import java.util.Set; -import java.util.List; - /** * Intercepts transactions in Infinispan, calling {@link PutFromLoadValidator#beginInvalidatingKey(Object, Object)} * before locks are acquired (and the entry is invalidated) and sends {@link EndInvalidationCommand} to release @@ -145,26 +146,29 @@ class TxPutFromLoadInterceptor extends BaseRpcInterceptor { return endInvalidationAndInvokeNextInterceptor(ctx, command); } - protected Object endInvalidationAndInvokeNextInterceptor(TxInvocationContext ctx, VisitableCommand command) throws Throwable { + protected Object endInvalidationAndInvokeNextInterceptor(TxInvocationContext ctx, VisitableCommand command) throws Throwable { try { if (ctx.isOriginLocal()) { - // send async Commit - Set affectedKeys = ctx.getAffectedKeys(); + // We cannot use directly ctx.getAffectedKeys() and that includes keys from local-only operations. + // During evictAll inside transaction this would cause unnecessary invalidate command + if (!ctx.getModifications().isEmpty()) { + Object[] keys = ctx.getModifications().stream() + .flatMap(mod -> mod.getAffectedKeys().stream()).distinct().toArray(); - if (log.isTraceEnabled()) { - log.tracef( "Sending end invalidation for keys %s asynchronously, modifications are %s", affectedKeys, ctx.getCacheTransaction().getModifications()); - } + if (log.isTraceEnabled()) { + log.tracef( "Sending end invalidation for keys %s asynchronously, modifications are %s", + Arrays.toString(keys), ctx.getCacheTransaction().getModifications()); + } - if (!affectedKeys.isEmpty()) { GlobalTransaction globalTransaction = ctx.getGlobalTransaction(); EndInvalidationCommand commitCommand = cacheCommandInitializer.buildEndInvalidationCommand( - cacheName, affectedKeys.toArray(), globalTransaction); + cacheName, keys, globalTransaction); List
members = stateTransferManager.getCacheTopology().getMembers(); rpcManager.invokeRemotely(members, commitCommand, asyncUnordered); // If the transaction is not successful, *RegionAccessStrategy would not be called, therefore // we have to end invalidation from here manually (in successful case as well) - for (Object key : affectedKeys) { + for (Object key : keys) { putFromLoadValidator.endInvalidatingKey(globalTransaction, key); } } diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionAccessStrategyTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionAccessStrategyTest.java index 2339f9c68f..156a35ef8e 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionAccessStrategyTest.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionAccessStrategyTest.java @@ -45,12 +45,14 @@ import org.hibernate.test.cache.infinispan.util.BatchModeTransactionCoordinator; import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; import org.hibernate.test.cache.infinispan.util.ExpectingInterceptor; import org.hibernate.test.cache.infinispan.util.JdbcResourceTransactionMock; +import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory; import org.hibernate.test.cache.infinispan.util.TestSynchronization; import org.infinispan.Cache; import org.infinispan.test.TestingUtil; import org.jboss.logging.Logger; -import org.infinispan.AdvancedCache; +import org.hibernate.test.cache.infinispan.util.TestTimeService; import org.infinispan.commands.write.InvalidateCommand; +import org.infinispan.AdvancedCache; import org.infinispan.commands.write.PutKeyValueCommand; import org.junit.After; import org.junit.Before; @@ -83,6 +85,8 @@ public abstract class AbstractRegionAccessStrategyTest { - endInvalidationLatch.countDown(); - return invocation.callRealMethod(); + try { + return invocation.callRealMethod(); + } finally { + endInvalidationLatch.countDown(); + } }).when(mockValidator).endInvalidatingKey(any(), any()); PutFromLoadValidator.addToCache(remoteRegion.getCache(), mockValidator); cleanup.add(() -> { @@ -517,19 +531,17 @@ public abstract class AbstractRegionAccessStrategyTest