Uploaded image for project: 'WildFly'
  1. WildFly
  2. WFLY-9839

Incorrect lock management in infinispan

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • Major
    • None
    • 10.1.0.Final, 11.0.0.Final
    • None
    • Hide

      1. Create JPA Entity class:

      MyEntity.java
      @Entity
      public class MyEntity {
          @Id
          private Long id;
          private String name;
          @Version
          private int verions;
          // getters and setters omitted
      }
      

      2. One EJB with @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) and long running transactions

      MyEntityManagerEJB.java
      @Stateless
      @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
      public class MyEntityManagerEJB {
          @PersistenceContext
          private EntityManager em;
      
          public void updateMyEntity(Long id, String newName) {
              try {
                  Thread.sleep(15000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              MyEntity e = em.find(MyEntity.class, id);
              e.setName(newName);
              em.flush();
          }
      }
      

      3. Another EJB which calls first EJB. Also with separate transaction. Here we have an exception at commented line on EVERY LongRunningTransactionEJB.doWork() call. Buf if we change doRefresh to false - all operations are performed OK

      LongRunningTransactionEJB.java
      @Stateless
      @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
      public class LongRunningTransactionEJB {
      
          @PersistenceContext
          private EntityManager em;
      
          @EJB
          private MyEntityManagerEJB myEntityManager;
      
          public String doWork(Long entityId, String suffix) {
              final boolean doRefresh = true;// change this to false - it will pass the test
      
              MyEntity e = em.find(MyEntity.class, entityId);
      
              myEntityManager.updateMyEntity(e.getId(), "new name " + suffix);
              if (doRefresh) {
                  em.refresh(e);
              }
              myEntityManager.updateMyEntity(e.getId(), "another new name " + suffix);// <--- here we have an exception
              em.refresh(e);
              return e.getName();
          }
      }
      
      Show
      1. Create JPA Entity class: MyEntity.java @Entity public class MyEntity { @Id private Long id; private String name; @Version private int verions; // getters and setters omitted } 2. One EJB with @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) and long running transactions MyEntityManagerEJB.java @Stateless @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public class MyEntityManagerEJB { @PersistenceContext private EntityManager em; public void updateMyEntity( Long id, String newName) { try { Thread .sleep(15000); } catch (InterruptedException e) { e.printStackTrace(); } MyEntity e = em.find(MyEntity.class, id); e.setName(newName); em.flush(); } } 3. Another EJB which calls first EJB. Also with separate transaction. Here we have an exception at commented line on EVERY LongRunningTransactionEJB.doWork() call. Buf if we change doRefresh to false - all operations are performed OK LongRunningTransactionEJB.java @Stateless @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public class LongRunningTransactionEJB { @PersistenceContext private EntityManager em; @EJB private MyEntityManagerEJB myEntityManager; public String doWork( Long entityId, String suffix) { final boolean doRefresh = true ; // change this to false - it will pass the test MyEntity e = em.find(MyEntity.class, entityId); myEntityManager.updateMyEntity(e.getId(), " new name " + suffix); if (doRefresh) { em.refresh(e); } myEntityManager.updateMyEntity(e.getId(), "another new name " + suffix); // <--- here we have an exception em.refresh(e); return e.getName(); } }

    Description

      If we update one JPA entity with one id (primary key) in several transactions and refresh (via EntityManager.refresh call) loaded entity between them - infinispan does not release lock for the entity - so one can fail on timeout waiting for that lock to be released.

      The root exception is:
      org.infinispan.util.concurrent.TimeoutException: ISPN000299: Unable to acquire lock after 15 seconds for key 10 and requestor GlobalTransaction:<null>:6:local. Lock is held by GlobalTransaction:<null>:4:local
      at org.infinispan.util.concurrent.locks.impl.DefaultLockManager$KeyAwareExtendedLockPromise.lock(DefaultLockManager.java:238)
      at org.infinispan.interceptors.locking.AbstractLockingInterceptor.lockAndRecord(AbstractLockingInterceptor.java:193)
      at org.infinispan.interceptors.locking.AbstractTxLockingInterceptor.checkPendingAndLockKey(AbstractTxLockingInterceptor.java:193)
      at org.infinispan.interceptors.locking.AbstractTxLockingInterceptor.lockOrRegisterBackupLock(AbstractTxLockingInterceptor.java:116)
      at org.infinispan.interceptors.locking.PessimisticLockingInterceptor.visitDataWriteCommand(PessimisticLockingInterceptor.java:134)
      at org.infinispan.interceptors.locking.AbstractTxLockingInterceptor.visitPutKeyValueCommand(AbstractTxLockingInterceptor.java:65)
      at org.infinispan.commands.write.PutKeyValueCommand.acceptVisitor(PutKeyValueCommand.java:78)
      at org.infinispan.interceptors.base.CommandInterceptor.invokeNextInterceptor(CommandInterceptor.java:99)
      at org.infinispan.interceptors.TxInterceptor.enlistWriteAndInvokeNext(TxInterceptor.java:367)
      at org.infinispan.interceptors.TxInterceptor.visitPutKeyValueCommand(TxInterceptor.java:221)
      at org.infinispan.commands.write.PutKeyValueCommand.acceptVisitor(PutKeyValueCommand.java:78)
      at org.infinispan.interceptors.base.CommandInterceptor.invokeNextInterceptor(CommandInterceptor.java:99)
      at org.infinispan.interceptors.InvocationContextInterceptor.handleAll(InvocationContextInterceptor.java:114)
      at org.infinispan.interceptors.InvocationContextInterceptor.handleDefault(InvocationContextInterceptor.java:83)
      at org.infinispan.commands.AbstractVisitor.visitPutKeyValueCommand(AbstractVisitor.java:43)
      at org.infinispan.commands.write.PutKeyValueCommand.acceptVisitor(PutKeyValueCommand.java:78)
      at org.infinispan.interceptors.InterceptorChain.invoke(InterceptorChain.java:335)
      at org.infinispan.cache.impl.CacheImpl.executeCommandAndCommitIfNeeded(CacheImpl.java:1672)
      at org.infinispan.cache.impl.CacheImpl.putInternal(CacheImpl.java:1121)
      at org.infinispan.cache.impl.CacheImpl.put(CacheImpl.java:1111)
      at org.infinispan.cache.impl.DecoratedCache.put(DecoratedCache.java:453)
      at org.infinispan.cache.impl.AbstractDelegatingCache.put(AbstractDelegatingCache.java:291)
      at org.hibernate.cache.infinispan.access.TxInvalidationCacheAccessDelegate.update(TxInvalidationCacheAccessDelegate.java:67)
      at org.hibernate.cache.infinispan.entity.ReadWriteAccess.update(ReadWriteAccess.java:29)
      at org.hibernate.action.internal.EntityUpdateAction.cacheUpdate(EntityUpdateAction.java:222)
      at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:196)
      at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:582)
      at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:456)
      at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337)
      at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
      at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1282)
      at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1300)
      at org.jboss.as.jpa.container.AbstractEntityManager.flush(AbstractEntityManager.java:459)
      at wildfly.infinispan.test.MyEntityManagerEJB.updateMyEntity(MyEntityManagerEJB.java:36)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)

      Attachments

        Activity

          People

            smarlow1@redhat.com Scott Marlow
            seqira77777 Oleg K (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated: