0 Replies Latest reply on Nov 22, 2002 2:21 AM by tliebeck

    Deadlocks with Sequence Block Primary Key Generator Implemen

    tliebeck

      I've developed an implementation of the "sequence blocks" primary key generation pattern. I am encountering deadlock errors when I use it after deploying it with the appropriate transaction requirement settings.

      The sequence blocks pattern simply uses a database table to store the next available primary key for each table that makes use of it. I have a session bean "UidSession" whose interface provides a single method:

      public Long getNextValue(String objectName);

      This method is called from the ejbCreate() methods of other entity beans in this fashion:

      this.setId(uidSession.getNextValue("Project"));

      The UidSession bean relies on a fairly trivial "Uid" entity bean that tracks the next available primary key for each table. The local interface to the "Uid" bean has a single publicly accessible method:

      public long getNextKeyAfterIncrementingBy(int blockSize) {
      long value = getValue();
      setValue(getValue() + blockSize);
      return value;
      }

      As you can see, it simply returns the present value of its "value" property and increments it.

      Getting to the point, this whole setup works, providing I don't set the transaction attributes properly. When I do it will fail the first time it's called with a deadlock exception:

      21:54:16,684 ERROR [LogInterceptor] RuntimeException:
      java.lang.reflect.UndeclaredThrowableException:
      org.jboss.ejb.plugins.lock.ApplicationDeadlockException: Application deadlock detected: Current thread already has tx lock in different transaction.
      at org.jboss.ejb.plugins.lock.BeanLockSupport.deadlockDetection(BeanLockSupport.java:118)
      at org.jboss.ejb.plugins.lock.QueuedPessimisticEJBLock.waitForTx(QueuedPessimisticEJBLock.java:263)
      at org.jboss.ejb.plugins.lock.QueuedPessimisticEJBLock.doSchedule(QueuedPessimisticEJBLock.java:196)
      at org.jboss.ejb.plugins.lock.QueuedPessimisticEJBLock.schedule(QueuedPessimisticEJBLock.java:143)
      at org.jboss.ejb.plugins.EntityLockInterceptor.invoke(EntityLockInterceptor.java:103)
      ....
      (if you *really* want the whole stacktrace I'll provide it upon request)

      The UidSession bean is deployed with a transaction attribute of "Required". The getNextKeyAfterIncrementingBy() method of the Uid bean is deployed with a transaction attribute of "RequiresNew". So we have a call being made from an object with a "Required" transaction attribute into one with a "RequiresNew" transaction attribute. It was my understanding that this is a perfectly legitimate action, which results in the transaction of the calling object being suspended until the second, new transaction has completed. Is this correct?

      I've tried this with JBoss 3.0.3 and 3.0.4 on two RedHat 8 machines, running on Sun's 1.3.1 VM. The database is the built-in HyperSonic SQL, and I'm using pure 2.0 CMP.

      My code is based on the EJB pattern "Sequence Blocks" discussed in the "EJB Design Patterns" book (http://www2.theserverside.com/books/EJBDesignPatterns/index.jsp) by Floyd Marinescu. My implementation is very similar to the example code.

      I'd be happy to provide more information if necessary. I apologize for having to post this here, as I'm fairly certain that a great number of people here have implemented this pattern without a hitch.

      Thanks for any help.
      --Tod