[JBoss JIRA] (ISPN-5356) Transactional, optimistic-locked caches do not honour Flag.FAIL_SILENTLY
by Pedro Ruivo (JIRA)
[ https://issues.jboss.org/browse/ISPN-5356?page=com.atlassian.jira.plugin.... ]
Pedro Ruivo updated ISPN-5356:
------------------------------
Status: Resolved (was: Pull Request Sent)
Resolution: Done
> Transactional, optimistic-locked caches do not honour Flag.FAIL_SILENTLY
> ------------------------------------------------------------------------
>
> Key: ISPN-5356
> URL: https://issues.jboss.org/browse/ISPN-5356
> Project: Infinispan
> Issue Type: Bug
> Components: Core
> Affects Versions: 6.0.2.Final
> Environment: Infinispan 6.0.2
> Hibernate ORM 4.3.6
> Apache Tomcat 8
> JDK 1.8.0_25
> Reporter: Mitchell Archibald
> Assignee: Galder Zamarreño
> Fix For: 7.2.0.Final
>
>
> There is a related issue in the Hibernate JIRA, which can be found at:
> https://hibernate.atlassian.net/browse/HHH-7898
> However, I believe this to be an Infinispan issue, as per my analysis below.
> The following Exception is thrown when two threads are simultaneously committing a JTA transaction in which an entry has been written to Hibernate's "replicated-query" cache using the same key.
> {code}
> 10:55:02.238 ERROR saction.TransactionCoordinator - ISPN000255: Error while processing prepare
> org.infinispan.util.concurrent.TimeoutException: Unable to acquire lock after [0 milliseconds] on key [sql: select ...; parameters: ...; named parameters: {...}; transformer: org.hibernate.transform.CacheableResultTransformer@110f2] for requestor [GlobalTransaction:<null>:197882:local]! Lock held by [null]
> at org.infinispan.util.concurrent.locks.LockManagerImpl.lock(LockManagerImpl.java:198)
> at org.infinispan.util.concurrent.locks.LockManagerImpl.acquireLock(LockManagerImpl.java:171)
> at org.infinispan.interceptors.locking.AbstractTxLockingInterceptor.lockKeyAndCheckOwnership(AbstractTxLockingInterceptor.java:169)
> at org.infinispan.interceptors.locking.AbstractTxLockingInterceptor.lockAndRegisterBackupLock(AbstractTxLockingInterceptor.java:98)
> at org.infinispan.interceptors.locking.OptimisticLockingInterceptor$LockAcquisitionVisitor.lockAndRecord(OptimisticLockingInterceptor.java:211)
> at org.infinispan.interceptors.locking.OptimisticLockingInterceptor$LockAcquisitionVisitor.visitSingleKeyCommand(OptimisticLockingInterceptor.java:206)
> at org.infinispan.interceptors.locking.OptimisticLockingInterceptor$LockAcquisitionVisitor.visitPutKeyValueCommand(OptimisticLockingInterceptor.java:199)
> at org.infinispan.commands.write.PutKeyValueCommand.acceptVisitor(PutKeyValueCommand.java:70)
> at org.infinispan.interceptors.locking.OptimisticLockingInterceptor.acquireLocksVisitingCommands(OptimisticLockingInterceptor.java:270)
> at org.infinispan.interceptors.locking.OptimisticLockingInterceptor.visitPrepareCommand(OptimisticLockingInterceptor.java:75)
> at org.infinispan.commands.tx.PrepareCommand.acceptVisitor(PrepareCommand.java:124)
> at org.infinispan.interceptors.base.CommandInterceptor.invokeNextInterceptor(CommandInterceptor.java:98)
> at org.infinispan.interceptors.NotificationInterceptor.visitPrepareCommand(NotificationInterceptor.java:36)
> at org.infinispan.commands.tx.PrepareCommand.acceptVisitor(PrepareCommand.java:124)
> at org.infinispan.interceptors.base.CommandInterceptor.invokeNextInterceptor(CommandInterceptor.java:98)
> at org.infinispan.interceptors.TxInterceptor.invokeNextInterceptorAndVerifyTransaction(TxInterceptor.java:114)
> at org.infinispan.interceptors.TxInterceptor.visitPrepareCommand(TxInterceptor.java:101)
> at org.infinispan.commands.tx.PrepareCommand.acceptVisitor(PrepareCommand.java:124)
> at org.infinispan.interceptors.base.CommandInterceptor.invokeNextInterceptor(CommandInterceptor.java:98)
> at org.infinispan.interceptors.base.CommandInterceptor.handleDefault(CommandInterceptor.java:112)
> at org.infinispan.commands.AbstractVisitor.visitPrepareCommand(AbstractVisitor.java:96)
> at org.infinispan.commands.tx.PrepareCommand.acceptVisitor(PrepareCommand.java:124)
> at org.infinispan.interceptors.base.CommandInterceptor.invokeNextInterceptor(CommandInterceptor.java:98)
> at org.infinispan.interceptors.InvocationContextInterceptor.handleAll(InvocationContextInterceptor.java:110)
> at org.infinispan.interceptors.InvocationContextInterceptor.handleDefault(InvocationContextInterceptor.java:73)
> at org.infinispan.commands.AbstractVisitor.visitPrepareCommand(AbstractVisitor.java:96)
> at org.infinispan.commands.tx.PrepareCommand.acceptVisitor(PrepareCommand.java:124)
> at org.infinispan.interceptors.InterceptorChain.invoke(InterceptorChain.java:333)
> at org.infinispan.transaction.TransactionCoordinator.prepare(TransactionCoordinator.java:119)
> at org.infinispan.transaction.TransactionCoordinator.prepare(TransactionCoordinator.java:101)
> at org.infinispan.transaction.synchronization.SynchronizationAdapter.beforeCompletion(SynchronizationAdapter.java:44)
> at com.metiom.core.transaction.TransactionImpl.lambda$commit$0(TransactionImpl.java:115)
> at com.metiom.core.transaction.TransactionImpl$$Lambda$2/330107372.accept(Unknown Source)
> at com.metiom.core.transaction.TransactionImpl.forEachSynchronisation(TransactionImpl.java:264)
> at com.metiom.core.transaction.TransactionImpl.commit(TransactionImpl.java:114)
> at com.metiom.core.transaction.TransactionManagerImpl.commit(TransactionManagerImpl.java:142)
> at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1021)
> at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
> at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
> at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:497)
> at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:277)
> at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
> at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
> ...
> {code}
> The configuration for Hibernate's "replicated-query" cache is as follows (from Hibernate's infinispan-configs.xml)
> {code}
> <!-- An alternative configuration for entity/collection caching that uses replication instead of invalidation -->
> <namedCache name="replicated-entity">
> <clustering mode="replication">
> <stateTransfer fetchInMemoryState="false" timeout="20000"/>
> <sync replTimeout="20000"/>
> </clustering>
> <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000"
> lockAcquisitionTimeout="15000" useLockStriping="false"/>
> <!-- Eviction configuration. WakeupInterval defines how often the eviction thread runs, in milliseconds.
> 0 means the eviction thread will never run. A separate executor is used for eviction in each cache. -->
> <eviction maxEntries="10000" strategy="LRU"/>
> <expiration maxIdle="100000" wakeUpInterval="5000"/>
> <lazyDeserialization enabled="true"/>
> <transaction transactionMode="TRANSACTIONAL" autoCommit="false"
> lockingMode="OPTIMISTIC"/>
> </namedCache>
> {code}
> Additionally, the cache is configured programmatically with:
> * {{Flag.ZERO_LOCK_ACQUISITION_TIMEOUT}}; and
> * {{Flag.FAIL_SILENTLY}}
> The situation is that two threads are concurrently attempting to lock the same key on commit.
> * During a JTA transaction, a Hibernate query is executed, and Hibernate places a result in the query cache.
> * On commit, the {{SynchronizationAdaptor}} creates a {{PrepareCommand}}, which contains one or more "modifications", one of which is a {{PutKeyValueCommand}}. The {{SynchronizationAdapter}} invokes the {{PrepareCommand}}.
> * When visited, the {{OptimisticLockingInterceptor}} loops through the modifications held by the {{PrepareCommand}} and visits each one.
> * When the {{PutKeyValueCommand}} is visited, {{LockManagerImpl}} discovers that the key is locked, and throws {{TimeoutException}}.
> * The Exception is caught by {{InvocationContextInterceptor}}, and attempts to find out whether the command it was invoking is affected by {{Flag.FAIL_SILENTLY}}. {{PrepareCommand}} does not implement {{FlagAffectedCommand}}, so this test fails and the Exception is propagated.
> It is important to note here that the {{PutKeyValueCommand}} _does_ implement {{FlagAffectedCommand}}, and _does_ have the {{Flag.FAIL_SILENTLY}} flag set. So the problem seems to be that {{OptimisticLockingInterceptor}} is unaware that the modifications to the {{PrepareCommand}} could throw Exceptions which can be suppressed.
--
This message was sent by Atlassian JIRA
(v6.3.15#6346)
9 years, 7 months
[JBoss JIRA] (ISPN-5429) Cluster CacheEventFilterConverter wrapping leads to double callbacks
by Adrian Nistor (JIRA)
[ https://issues.jboss.org/browse/ISPN-5429?page=com.atlassian.jira.plugin.... ]
Adrian Nistor updated ISPN-5429:
--------------------------------
Status: Resolved (was: Pull Request Sent)
Resolution: Done
Test for duplicate callbacks are now integrated in master. Thanks [~galder.zamarreno] and [~william.burns]!
> Cluster CacheEventFilterConverter wrapping leads to double callbacks
> --------------------------------------------------------------------
>
> Key: ISPN-5429
> URL: https://issues.jboss.org/browse/ISPN-5429
> Project: Infinispan
> Issue Type: Bug
> Components: Listeners
> Affects Versions: 7.2.0.CR1, 7.1.1.Final
> Reporter: Galder Zamarreño
> Assignee: Galder Zamarreño
> Fix For: 7.2.0.Final
>
>
> This was spotted by Pierre Sutra from University of Neuchatel:
> When a CacheEventFilterConverter is registered with remote event listeners, and running in a cluster, once the CacheEventFilterConverter instance is replicated, the notion that its both a filter AND converter is lost because BaseCacheEntryListenerInvocation's constructor determines that {{filterAndConvert}} is false.
> The reason this happens is because after clustering it, the ClusterListenerReplicateCallable.call() wraps the {{filter}} into an {{AbstractCacheEventFilterConverter}} implementation, which does not keep the referential equality that BaseCacheEntryListenerInvocation's constructor checks.
> A simple way to avoid this is to implement {{equals}} in the AbstractCacheEventFilterConverter implementation and use referential equality. Then, switching BaseCacheEntryListenerInvocation's constructors referential equality by a call to {{equals}} is enough to solve the issue.
> The reason this bug was detected is because without a fix for it, the filter + converter gets two callbacks instead of one. I've added tests to verify that the number callbacks expected is the correct one.
--
This message was sent by Atlassian JIRA
(v6.3.15#6346)
9 years, 7 months
[JBoss JIRA] (ISPN-5429) Cluster CacheEventFilterConverter wrapping leads to double callbacks
by Galder Zamarreño (JIRA)
[ https://issues.jboss.org/browse/ISPN-5429?page=com.atlassian.jira.plugin.... ]
Galder Zamarreño commented on ISPN-5429:
----------------------------------------
The original issue has been solved via ISPN-5352 but double callbacks are still present since now the issue is that both pre/post events are being generated and as a result of that, it calls filter+converter twice (see ISPN-5435). Once that is solved, we'll have a fix for this.
> Cluster CacheEventFilterConverter wrapping leads to double callbacks
> --------------------------------------------------------------------
>
> Key: ISPN-5429
> URL: https://issues.jboss.org/browse/ISPN-5429
> Project: Infinispan
> Issue Type: Bug
> Components: Listeners
> Affects Versions: 7.2.0.CR1, 7.1.1.Final
> Reporter: Galder Zamarreño
> Assignee: Galder Zamarreño
> Fix For: 7.2.0.Final
>
>
> This was spotted by Pierre Sutra from University of Neuchatel:
> When a CacheEventFilterConverter is registered with remote event listeners, and running in a cluster, once the CacheEventFilterConverter instance is replicated, the notion that its both a filter AND converter is lost because BaseCacheEntryListenerInvocation's constructor determines that {{filterAndConvert}} is false.
> The reason this happens is because after clustering it, the ClusterListenerReplicateCallable.call() wraps the {{filter}} into an {{AbstractCacheEventFilterConverter}} implementation, which does not keep the referential equality that BaseCacheEntryListenerInvocation's constructor checks.
> A simple way to avoid this is to implement {{equals}} in the AbstractCacheEventFilterConverter implementation and use referential equality. Then, switching BaseCacheEntryListenerInvocation's constructors referential equality by a call to {{equals}} is enough to solve the issue.
> The reason this bug was detected is because without a fix for it, the filter + converter gets two callbacks instead of one. I've added tests to verify that the number callbacks expected is the correct one.
--
This message was sent by Atlassian JIRA
(v6.3.15#6346)
9 years, 8 months
[JBoss JIRA] (ISPN-5356) Transactional, optimistic-locked caches do not honour Flag.FAIL_SILENTLY
by Galder Zamarreño (JIRA)
[ https://issues.jboss.org/browse/ISPN-5356?page=com.atlassian.jira.plugin.... ]
Galder Zamarreño commented on ISPN-5356:
----------------------------------------
After re-evaluating the fix, we've decided not to apply it since messing up with the result of the transaction at prepare time could mess up things. We're updating the FAIL_SILENTLY javadoc to indicate so.
> Transactional, optimistic-locked caches do not honour Flag.FAIL_SILENTLY
> ------------------------------------------------------------------------
>
> Key: ISPN-5356
> URL: https://issues.jboss.org/browse/ISPN-5356
> Project: Infinispan
> Issue Type: Bug
> Components: Core
> Affects Versions: 6.0.2.Final
> Environment: Infinispan 6.0.2
> Hibernate ORM 4.3.6
> Apache Tomcat 8
> JDK 1.8.0_25
> Reporter: Mitchell Archibald
> Assignee: Galder Zamarreño
> Fix For: 7.2.0.Final
>
>
> There is a related issue in the Hibernate JIRA, which can be found at:
> https://hibernate.atlassian.net/browse/HHH-7898
> However, I believe this to be an Infinispan issue, as per my analysis below.
> The following Exception is thrown when two threads are simultaneously committing a JTA transaction in which an entry has been written to Hibernate's "replicated-query" cache using the same key.
> {code}
> 10:55:02.238 ERROR saction.TransactionCoordinator - ISPN000255: Error while processing prepare
> org.infinispan.util.concurrent.TimeoutException: Unable to acquire lock after [0 milliseconds] on key [sql: select ...; parameters: ...; named parameters: {...}; transformer: org.hibernate.transform.CacheableResultTransformer@110f2] for requestor [GlobalTransaction:<null>:197882:local]! Lock held by [null]
> at org.infinispan.util.concurrent.locks.LockManagerImpl.lock(LockManagerImpl.java:198)
> at org.infinispan.util.concurrent.locks.LockManagerImpl.acquireLock(LockManagerImpl.java:171)
> at org.infinispan.interceptors.locking.AbstractTxLockingInterceptor.lockKeyAndCheckOwnership(AbstractTxLockingInterceptor.java:169)
> at org.infinispan.interceptors.locking.AbstractTxLockingInterceptor.lockAndRegisterBackupLock(AbstractTxLockingInterceptor.java:98)
> at org.infinispan.interceptors.locking.OptimisticLockingInterceptor$LockAcquisitionVisitor.lockAndRecord(OptimisticLockingInterceptor.java:211)
> at org.infinispan.interceptors.locking.OptimisticLockingInterceptor$LockAcquisitionVisitor.visitSingleKeyCommand(OptimisticLockingInterceptor.java:206)
> at org.infinispan.interceptors.locking.OptimisticLockingInterceptor$LockAcquisitionVisitor.visitPutKeyValueCommand(OptimisticLockingInterceptor.java:199)
> at org.infinispan.commands.write.PutKeyValueCommand.acceptVisitor(PutKeyValueCommand.java:70)
> at org.infinispan.interceptors.locking.OptimisticLockingInterceptor.acquireLocksVisitingCommands(OptimisticLockingInterceptor.java:270)
> at org.infinispan.interceptors.locking.OptimisticLockingInterceptor.visitPrepareCommand(OptimisticLockingInterceptor.java:75)
> at org.infinispan.commands.tx.PrepareCommand.acceptVisitor(PrepareCommand.java:124)
> at org.infinispan.interceptors.base.CommandInterceptor.invokeNextInterceptor(CommandInterceptor.java:98)
> at org.infinispan.interceptors.NotificationInterceptor.visitPrepareCommand(NotificationInterceptor.java:36)
> at org.infinispan.commands.tx.PrepareCommand.acceptVisitor(PrepareCommand.java:124)
> at org.infinispan.interceptors.base.CommandInterceptor.invokeNextInterceptor(CommandInterceptor.java:98)
> at org.infinispan.interceptors.TxInterceptor.invokeNextInterceptorAndVerifyTransaction(TxInterceptor.java:114)
> at org.infinispan.interceptors.TxInterceptor.visitPrepareCommand(TxInterceptor.java:101)
> at org.infinispan.commands.tx.PrepareCommand.acceptVisitor(PrepareCommand.java:124)
> at org.infinispan.interceptors.base.CommandInterceptor.invokeNextInterceptor(CommandInterceptor.java:98)
> at org.infinispan.interceptors.base.CommandInterceptor.handleDefault(CommandInterceptor.java:112)
> at org.infinispan.commands.AbstractVisitor.visitPrepareCommand(AbstractVisitor.java:96)
> at org.infinispan.commands.tx.PrepareCommand.acceptVisitor(PrepareCommand.java:124)
> at org.infinispan.interceptors.base.CommandInterceptor.invokeNextInterceptor(CommandInterceptor.java:98)
> at org.infinispan.interceptors.InvocationContextInterceptor.handleAll(InvocationContextInterceptor.java:110)
> at org.infinispan.interceptors.InvocationContextInterceptor.handleDefault(InvocationContextInterceptor.java:73)
> at org.infinispan.commands.AbstractVisitor.visitPrepareCommand(AbstractVisitor.java:96)
> at org.infinispan.commands.tx.PrepareCommand.acceptVisitor(PrepareCommand.java:124)
> at org.infinispan.interceptors.InterceptorChain.invoke(InterceptorChain.java:333)
> at org.infinispan.transaction.TransactionCoordinator.prepare(TransactionCoordinator.java:119)
> at org.infinispan.transaction.TransactionCoordinator.prepare(TransactionCoordinator.java:101)
> at org.infinispan.transaction.synchronization.SynchronizationAdapter.beforeCompletion(SynchronizationAdapter.java:44)
> at com.metiom.core.transaction.TransactionImpl.lambda$commit$0(TransactionImpl.java:115)
> at com.metiom.core.transaction.TransactionImpl$$Lambda$2/330107372.accept(Unknown Source)
> at com.metiom.core.transaction.TransactionImpl.forEachSynchronisation(TransactionImpl.java:264)
> at com.metiom.core.transaction.TransactionImpl.commit(TransactionImpl.java:114)
> at com.metiom.core.transaction.TransactionManagerImpl.commit(TransactionManagerImpl.java:142)
> at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1021)
> at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
> at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
> at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:497)
> at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:277)
> at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
> at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
> ...
> {code}
> The configuration for Hibernate's "replicated-query" cache is as follows (from Hibernate's infinispan-configs.xml)
> {code}
> <!-- An alternative configuration for entity/collection caching that uses replication instead of invalidation -->
> <namedCache name="replicated-entity">
> <clustering mode="replication">
> <stateTransfer fetchInMemoryState="false" timeout="20000"/>
> <sync replTimeout="20000"/>
> </clustering>
> <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000"
> lockAcquisitionTimeout="15000" useLockStriping="false"/>
> <!-- Eviction configuration. WakeupInterval defines how often the eviction thread runs, in milliseconds.
> 0 means the eviction thread will never run. A separate executor is used for eviction in each cache. -->
> <eviction maxEntries="10000" strategy="LRU"/>
> <expiration maxIdle="100000" wakeUpInterval="5000"/>
> <lazyDeserialization enabled="true"/>
> <transaction transactionMode="TRANSACTIONAL" autoCommit="false"
> lockingMode="OPTIMISTIC"/>
> </namedCache>
> {code}
> Additionally, the cache is configured programmatically with:
> * {{Flag.ZERO_LOCK_ACQUISITION_TIMEOUT}}; and
> * {{Flag.FAIL_SILENTLY}}
> The situation is that two threads are concurrently attempting to lock the same key on commit.
> * During a JTA transaction, a Hibernate query is executed, and Hibernate places a result in the query cache.
> * On commit, the {{SynchronizationAdaptor}} creates a {{PrepareCommand}}, which contains one or more "modifications", one of which is a {{PutKeyValueCommand}}. The {{SynchronizationAdapter}} invokes the {{PrepareCommand}}.
> * When visited, the {{OptimisticLockingInterceptor}} loops through the modifications held by the {{PrepareCommand}} and visits each one.
> * When the {{PutKeyValueCommand}} is visited, {{LockManagerImpl}} discovers that the key is locked, and throws {{TimeoutException}}.
> * The Exception is caught by {{InvocationContextInterceptor}}, and attempts to find out whether the command it was invoking is affected by {{Flag.FAIL_SILENTLY}}. {{PrepareCommand}} does not implement {{FlagAffectedCommand}}, so this test fails and the Exception is propagated.
> It is important to note here that the {{PutKeyValueCommand}} _does_ implement {{FlagAffectedCommand}}, and _does_ have the {{Flag.FAIL_SILENTLY}} flag set. So the problem seems to be that {{OptimisticLockingInterceptor}} is unaware that the modifications to the {{PrepareCommand}} could throw Exceptions which can be suppressed.
--
This message was sent by Atlassian JIRA
(v6.3.15#6346)
9 years, 8 months
[JBoss JIRA] (ISPN-5356) Transactional, optimistic-locked caches do not honour Flag.FAIL_SILENTLY
by Galder Zamarreño (JIRA)
[ https://issues.jboss.org/browse/ISPN-5356?page=com.atlassian.jira.plugin.... ]
Galder Zamarreño updated ISPN-5356:
-----------------------------------
Git Pull Request: https://github.com/infinispan/infinispan/pull/3421, https://github.com/infinispan/infinispan/pull/3431 (was: https://github.com/infinispan/infinispan/pull/3421)
> Transactional, optimistic-locked caches do not honour Flag.FAIL_SILENTLY
> ------------------------------------------------------------------------
>
> Key: ISPN-5356
> URL: https://issues.jboss.org/browse/ISPN-5356
> Project: Infinispan
> Issue Type: Bug
> Components: Core
> Affects Versions: 6.0.2.Final
> Environment: Infinispan 6.0.2
> Hibernate ORM 4.3.6
> Apache Tomcat 8
> JDK 1.8.0_25
> Reporter: Mitchell Archibald
> Assignee: Galder Zamarreño
> Fix For: 7.2.0.Final
>
>
> There is a related issue in the Hibernate JIRA, which can be found at:
> https://hibernate.atlassian.net/browse/HHH-7898
> However, I believe this to be an Infinispan issue, as per my analysis below.
> The following Exception is thrown when two threads are simultaneously committing a JTA transaction in which an entry has been written to Hibernate's "replicated-query" cache using the same key.
> {code}
> 10:55:02.238 ERROR saction.TransactionCoordinator - ISPN000255: Error while processing prepare
> org.infinispan.util.concurrent.TimeoutException: Unable to acquire lock after [0 milliseconds] on key [sql: select ...; parameters: ...; named parameters: {...}; transformer: org.hibernate.transform.CacheableResultTransformer@110f2] for requestor [GlobalTransaction:<null>:197882:local]! Lock held by [null]
> at org.infinispan.util.concurrent.locks.LockManagerImpl.lock(LockManagerImpl.java:198)
> at org.infinispan.util.concurrent.locks.LockManagerImpl.acquireLock(LockManagerImpl.java:171)
> at org.infinispan.interceptors.locking.AbstractTxLockingInterceptor.lockKeyAndCheckOwnership(AbstractTxLockingInterceptor.java:169)
> at org.infinispan.interceptors.locking.AbstractTxLockingInterceptor.lockAndRegisterBackupLock(AbstractTxLockingInterceptor.java:98)
> at org.infinispan.interceptors.locking.OptimisticLockingInterceptor$LockAcquisitionVisitor.lockAndRecord(OptimisticLockingInterceptor.java:211)
> at org.infinispan.interceptors.locking.OptimisticLockingInterceptor$LockAcquisitionVisitor.visitSingleKeyCommand(OptimisticLockingInterceptor.java:206)
> at org.infinispan.interceptors.locking.OptimisticLockingInterceptor$LockAcquisitionVisitor.visitPutKeyValueCommand(OptimisticLockingInterceptor.java:199)
> at org.infinispan.commands.write.PutKeyValueCommand.acceptVisitor(PutKeyValueCommand.java:70)
> at org.infinispan.interceptors.locking.OptimisticLockingInterceptor.acquireLocksVisitingCommands(OptimisticLockingInterceptor.java:270)
> at org.infinispan.interceptors.locking.OptimisticLockingInterceptor.visitPrepareCommand(OptimisticLockingInterceptor.java:75)
> at org.infinispan.commands.tx.PrepareCommand.acceptVisitor(PrepareCommand.java:124)
> at org.infinispan.interceptors.base.CommandInterceptor.invokeNextInterceptor(CommandInterceptor.java:98)
> at org.infinispan.interceptors.NotificationInterceptor.visitPrepareCommand(NotificationInterceptor.java:36)
> at org.infinispan.commands.tx.PrepareCommand.acceptVisitor(PrepareCommand.java:124)
> at org.infinispan.interceptors.base.CommandInterceptor.invokeNextInterceptor(CommandInterceptor.java:98)
> at org.infinispan.interceptors.TxInterceptor.invokeNextInterceptorAndVerifyTransaction(TxInterceptor.java:114)
> at org.infinispan.interceptors.TxInterceptor.visitPrepareCommand(TxInterceptor.java:101)
> at org.infinispan.commands.tx.PrepareCommand.acceptVisitor(PrepareCommand.java:124)
> at org.infinispan.interceptors.base.CommandInterceptor.invokeNextInterceptor(CommandInterceptor.java:98)
> at org.infinispan.interceptors.base.CommandInterceptor.handleDefault(CommandInterceptor.java:112)
> at org.infinispan.commands.AbstractVisitor.visitPrepareCommand(AbstractVisitor.java:96)
> at org.infinispan.commands.tx.PrepareCommand.acceptVisitor(PrepareCommand.java:124)
> at org.infinispan.interceptors.base.CommandInterceptor.invokeNextInterceptor(CommandInterceptor.java:98)
> at org.infinispan.interceptors.InvocationContextInterceptor.handleAll(InvocationContextInterceptor.java:110)
> at org.infinispan.interceptors.InvocationContextInterceptor.handleDefault(InvocationContextInterceptor.java:73)
> at org.infinispan.commands.AbstractVisitor.visitPrepareCommand(AbstractVisitor.java:96)
> at org.infinispan.commands.tx.PrepareCommand.acceptVisitor(PrepareCommand.java:124)
> at org.infinispan.interceptors.InterceptorChain.invoke(InterceptorChain.java:333)
> at org.infinispan.transaction.TransactionCoordinator.prepare(TransactionCoordinator.java:119)
> at org.infinispan.transaction.TransactionCoordinator.prepare(TransactionCoordinator.java:101)
> at org.infinispan.transaction.synchronization.SynchronizationAdapter.beforeCompletion(SynchronizationAdapter.java:44)
> at com.metiom.core.transaction.TransactionImpl.lambda$commit$0(TransactionImpl.java:115)
> at com.metiom.core.transaction.TransactionImpl$$Lambda$2/330107372.accept(Unknown Source)
> at com.metiom.core.transaction.TransactionImpl.forEachSynchronisation(TransactionImpl.java:264)
> at com.metiom.core.transaction.TransactionImpl.commit(TransactionImpl.java:114)
> at com.metiom.core.transaction.TransactionManagerImpl.commit(TransactionManagerImpl.java:142)
> at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1021)
> at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
> at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
> at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:497)
> at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:277)
> at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
> at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
> ...
> {code}
> The configuration for Hibernate's "replicated-query" cache is as follows (from Hibernate's infinispan-configs.xml)
> {code}
> <!-- An alternative configuration for entity/collection caching that uses replication instead of invalidation -->
> <namedCache name="replicated-entity">
> <clustering mode="replication">
> <stateTransfer fetchInMemoryState="false" timeout="20000"/>
> <sync replTimeout="20000"/>
> </clustering>
> <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000"
> lockAcquisitionTimeout="15000" useLockStriping="false"/>
> <!-- Eviction configuration. WakeupInterval defines how often the eviction thread runs, in milliseconds.
> 0 means the eviction thread will never run. A separate executor is used for eviction in each cache. -->
> <eviction maxEntries="10000" strategy="LRU"/>
> <expiration maxIdle="100000" wakeUpInterval="5000"/>
> <lazyDeserialization enabled="true"/>
> <transaction transactionMode="TRANSACTIONAL" autoCommit="false"
> lockingMode="OPTIMISTIC"/>
> </namedCache>
> {code}
> Additionally, the cache is configured programmatically with:
> * {{Flag.ZERO_LOCK_ACQUISITION_TIMEOUT}}; and
> * {{Flag.FAIL_SILENTLY}}
> The situation is that two threads are concurrently attempting to lock the same key on commit.
> * During a JTA transaction, a Hibernate query is executed, and Hibernate places a result in the query cache.
> * On commit, the {{SynchronizationAdaptor}} creates a {{PrepareCommand}}, which contains one or more "modifications", one of which is a {{PutKeyValueCommand}}. The {{SynchronizationAdapter}} invokes the {{PrepareCommand}}.
> * When visited, the {{OptimisticLockingInterceptor}} loops through the modifications held by the {{PrepareCommand}} and visits each one.
> * When the {{PutKeyValueCommand}} is visited, {{LockManagerImpl}} discovers that the key is locked, and throws {{TimeoutException}}.
> * The Exception is caught by {{InvocationContextInterceptor}}, and attempts to find out whether the command it was invoking is affected by {{Flag.FAIL_SILENTLY}}. {{PrepareCommand}} does not implement {{FlagAffectedCommand}}, so this test fails and the Exception is propagated.
> It is important to note here that the {{PutKeyValueCommand}} _does_ implement {{FlagAffectedCommand}}, and _does_ have the {{Flag.FAIL_SILENTLY}} flag set. So the problem seems to be that {{OptimisticLockingInterceptor}} is unaware that the modifications to the {{PrepareCommand}} could throw Exceptions which can be suppressed.
--
This message was sent by Atlassian JIRA
(v6.3.15#6346)
9 years, 8 months
[JBoss JIRA] (ISPN-5429) Cluster CacheEventFilterConverter wrapping leads to double callbacks
by Adrian Nistor (JIRA)
[ https://issues.jboss.org/browse/ISPN-5429?page=com.atlassian.jira.plugin.... ]
Adrian Nistor updated ISPN-5429:
--------------------------------
Git Pull Request: https://github.com/infinispan/infinispan/pull/3428, https://github.com/infinispan/infinispan/pull/3430 (was: https://github.com/infinispan/infinispan/pull/3428)
> Cluster CacheEventFilterConverter wrapping leads to double callbacks
> --------------------------------------------------------------------
>
> Key: ISPN-5429
> URL: https://issues.jboss.org/browse/ISPN-5429
> Project: Infinispan
> Issue Type: Bug
> Components: Listeners
> Affects Versions: 7.2.0.CR1, 7.1.1.Final
> Reporter: Galder Zamarreño
> Assignee: Galder Zamarreño
> Fix For: 7.2.0.Final
>
>
> This was spotted by Pierre Sutra from University of Neuchatel:
> When a CacheEventFilterConverter is registered with remote event listeners, and running in a cluster, once the CacheEventFilterConverter instance is replicated, the notion that its both a filter AND converter is lost because BaseCacheEntryListenerInvocation's constructor determines that {{filterAndConvert}} is false.
> The reason this happens is because after clustering it, the ClusterListenerReplicateCallable.call() wraps the {{filter}} into an {{AbstractCacheEventFilterConverter}} implementation, which does not keep the referential equality that BaseCacheEntryListenerInvocation's constructor checks.
> A simple way to avoid this is to implement {{equals}} in the AbstractCacheEventFilterConverter implementation and use referential equality. Then, switching BaseCacheEntryListenerInvocation's constructors referential equality by a call to {{equals}} is enough to solve the issue.
> The reason this bug was detected is because without a fix for it, the filter + converter gets two callbacks instead of one. I've added tests to verify that the number callbacks expected is the correct one.
--
This message was sent by Atlassian JIRA
(v6.3.15#6346)
9 years, 8 months