Details
-
Bug
-
Resolution: Obsolete
-
Major
-
JBossAS-4.0.0 Final, JBossAS-4.0.1RC1, JBossAS-4.0.1 Final, JBossAS-4.0.1 SP1, JBossAS-4.0.2RC1, JBossAS-4.0.2 Final, JBossAS-4.0.3RC1, JBossAS-4.0.3RC2, JBossAS-4.0.3 Final, JBossAS-4.0.3 SP1, JBossAS-4.0.4RC1
-
None
-
High
Description
JBoss's implementation of the timer service doesn't account for a potential for SLSB instances of the same bean to concurrently access and modify the same Timer object (I learnt it when inspecting the pertinent source code).
Chapter 22 of the EJB 2.1 spec contains enough information for us to infer how a complaint container must behave provided that a given Timer
object is always accessed and modified in a transactional context:
? If the reading SLSB instance accesses the Timer object before the transaction of the writing (cancelling) SLSB instance has committed, the reading instance mustn?t see that the timer has been cancelled (seeing it would defeat the very concept of a
transaction); otherwise
? If the transaction of the writing (cancelling) SLSB instance has already committed, the container must
make the changes to the Timer object visible to the reading SLSB. The spec prescribes that in this case the reading SLSB instance must receive the javax.ejb.NoSuchObjectLocalException.
Thus changes to the state of a timer object (i.e. cancelling it) must be made visible to other instances of the same bean only when the transaction in which the timer was cancelled has been successfully committed.
When I studied JBoss code what I saw was quite alarming ? no effort is put into ensuring that a Timer object cancellation is not visible to other SLSBs that might read the Timer object until the transaction in which it was cancelled is committed. As soon as a SLSB instance cancells the Timer object (and before the transaction is committed or rolled back), all other SLSB instances of the same bean will see it as cancelled and will get
(potentially spurious) NoSuchObjectLocalExceptions. If the canceling transaction is then rolled back, all reading SLSB instances will suddenly succeed in
accessing it (because then the flag in the Timer object will be cleared) comments are mine:
if (status == Status.STATUS_ROLLEDBACK)
{
log.debug("rollback: " + this);
if (timerState == STARTED_IN_TX)
killTimer();
else if (timerState == CANCELED_IN_TX)
// suddenly again active, even though other beans might already
// have seen it in the cancelled state.
setTimerState(ACTIVE);
I believe the same problem might happend with MDBs too.