[Although the message below has some WebLogic-ism's, I think the problem
described is generically relevant to any container that chooses to employ
the "pessimistic" style of concurrency on entity bean instances.]

WebLogic throws a LockTimeoutException if a method call to a given entity
bean instance remains blocked for more than a given time due to the bean
instance being in-use by a different transaction.  We've been getting frequent
LockTimeoutExceptions for some time now on our entity beans (a problem I have
seen others mention), and I think I have an explanation.

It seems to be the combination of:

1.  TRANSACTION_SERIALIZABLE, and the locking strategy used by most databases
    to implement it.

2.  WebLogic's pessimistic concurrency with regard to bean instances.

As things stand, I can't see how the two can coexist without causing
unpredictable LockTimeoutExceptions.

As an example, consider the most simplistic multi-transaction scenario I can
think of:  two transactions contending to call a method on a single BMP entity
bean.  Both transactions are set to TRANSACTION_SERIALIZABLE.

Transaction T1                          Transaction T2
--------------------------------------------------------------------------------

findByPrimaryKey()
    SELECT ID FROM ... WHERE ID = ?
    <acquires shared row lock>
                                        findByPrimaryKey()
                                            SELECT ID FROM ... WHERE ID = ?
                                            <acquires shared row lock>
                                        businessMethod()
                                            ejbLoad()
                                                SELECT ... WHERE ID = ?
                                                <row already share-locked>
businessMethod()
    <blocked by container waiting for
    bean instance>
                                        <sometime later>
                                            ejbStore()
                                                UPDATE ... WHERE ID = ?
                                                <blocked by RDB waiting for
                                                exclusive row lock>

The two transactions are then deadlocked.  Eventually (after a long wait), T1
fails with a LockTimeoutException and T2 can (probably) proceed.

To avoid this situation, I have seen some suggest that more stringent locking
needs to be used in ejbLoad(), such as that provided by SELECT ... FOR UPDATE.
But that strategy doesn't avoid the problem any better.

Transaction T1                          Transaction T2
--------------------------------------------------------------------------------

findByPrimaryKey()
    SELECT ID FROM ... WHERE ID = ?
    <acquires shared row lock>
                                        findByPrimaryKey()
                                            SELECT ID FROM ... WHERE ID = ?
                                            <acquires shared row lock>
                                        businessMethod()
                                            ejbLoad()
                                                SELECT ... WHERE ID = ? FOR UPDATE
                                                <blocked by RDB waiting for
                                                exclusive row lock>
businessMethod()
    <blocked by container waiting for
    bean instance>

Again, a deadlock.

The problem seems to be the combination of TRANSACTION_SERIALIZABLE (actually
TRANSACTION_REPEATABLE_READ would suffer the same) and pessimistic bean instance
concurrency because:

1.  If the isolation level is READ_COMMITTED or less, the SELECTs done by
    finders do not hold their locks to the end of the transaction, avoiding
    the deadlock.

2.  If the container employed separate bean instances for each transaction (so-
    called optimistic concurrency), the bean instance for T1 would block in
    either its ejbLoad() or ejbStore(), and the resulting deadlock *should* be
    immediately detectable by the database, providing an opportunity to retry
    the transaction (distasteful, but standard practice).

Of course, WebLogic employs the pessimistic concurrency approach.  According
to the EJB 1.1 spec, both approaches are valid, but note what it says about
the pessimistic approach in section 9.1.11 (Concurrent access from multiple
transactions):

    "The container acquires exclusive access to the entity object's state in
    the database.  The container activates a single instance and serializes the
    access from multiple transactions to this instance.  The commit time option
    A in Subsection 9.5.4 applies to this type of container."

I think the problem is, when using BMP the container really has no opportunity
to "acquire exclusive access to the entity object's state in the database".
Without doing so, finder methods (which can be executed by any available
bean instance) in other transactions have the opportunity to acquire database
locks that ultimately interfere with load/store access.

Either I'm missing something real obvious, or TRANSACTION_SERIALIZABLE is near
unusable with WebLogic (at least with BMP).

Ideas?


Regards,

Mike Martin
System Architect
Bal�o, Inc.

===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff EJB-INTEREST".  For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".

Reply via email to