We encountered an interesting deadlock using CMT that took us a while to
track down, so we thought we'd share it with the list. It is our
understanding that it might be fixed in 2.4.1 and 3.0, but it's something to
watch out for all the same.

To drastically simplify our scenario, we have a shared entity bean for which
we had declared the transaction type to be NotSupported. We have two other
entity beans, both of which with transaction type Required, and one of those
invokes methods on the other, and both invoke methods on the shared entity
bean.

I've attached an cooked-up example that illustrates this reference triangle.
In the example, the shared entity bean is SystemStatusBean. It depends on no
other beans and is intended to be completely read-only. SiteBean is intended
to be read-write and depends on SystemStatusBean. PageBean is intended to be
read-write and depends on both SystemStatusBean and SiteBean.

The problem is that even though SystemStatusBean has transaction type
NotSupported, JBoss still associates a transaction with a method invocation
on it, effectively locking it for the course of the outer transaction. This
leads to deadlock in the following way:

1. Client 1 causes invocation of SiteBean.getName()
2. Client 2 causes invocation of PageBean.getName()
        3. PageBean.getName() causes invocation of
SystemStatusBean.getStatus()
        4. PageBean.getName() attempts to invoke SiteBean.getName()
                BLOCKS (client 1 has lock on SiteBean.getName)
5. Client 1 attempts to invoke SystemStatusBean.getName()
        BLOCKS (client 2 still has lock on SystemStatusBean.getStatus)

Voila, deadlock. Both actually get stuck in a busy-wait loop in
EntityInstanceInterceptor.invoke() and one of them will eventually time out.
By the way, the same deadlock occurs if the SystemStatusBean is declared
Required, as well.

We're not sure whether or not to call this a bug in JBoss because the EJB
spec seems kind of vague about NotSupported.

Workaround: Declare the shared, read-only entity bean (SystemStatusBean) to
have transaction type RequiresNew. Works like a charm.

To run my example, unzip bdlrun.zip into a new directory, copy
beandeadlock.ear into your deploy directory, and run the test client by (if
on Windows) running runTest.bat. (Sorry, didn't have time to write a shell
script for the UNIX folks, but it's fairly simple.) Very shortly you should
see the server stop responding.

To view the source (and to try the workaround), unzip bdlsrc.zip into a new
directory. You can easily build and deploy using the included batch file
build.bat (again, Windows only, sorry).


Jack Humphrey
Senior Software Developer, Coremetrics

bdlsrc.zip

bdlrun.zip

Reply via email to