[ http://issues.apache.org/jira/browse/IBATIS-286?page=all ]
     
Clinton Begin closed IBATIS-286:
--------------------------------

    Resolution: Fixed

fixed as described

> race-condition bug causing transactions to fail due to SessionScope to be in 
> an inconsistent state.
> ---------------------------------------------------------------------------------------------------
>
>          Key: IBATIS-286
>          URL: http://issues.apache.org/jira/browse/IBATIS-286
>      Project: iBatis for Java
>         Type: Bug

>   Components: SQL Maps
>     Versions: 2.1.7
>  Environment: JDK 1.4.2
> SunOS eqd-dev8.uk.jpmorgan.com 5.8 Generic_117350-28 sun4u sparc 
> SUNW,Sun-Fire-480R
>     Reporter: Scott William Sinclair

>
> Summary:
> Discovered a race-condition bug which causes the 
> com.ibatis.sqlmap.engine.transaction.TransactionManager to throw exceptions 
> due to the com.ibatis.sqlmap.engine.scope.SessionScope being in an 
> inconsistent state.
> The transaction manager checks the 
> com.ibatis.sqlmap.engine.transaction.TransactionState 
> (STATE_STARTED,STATE_COMMITTED,STATE_ENDED,STATE_USER_PROVIDED) of the 
> SessionScope and throws an exception if it is not in the expected state.
> Worked Example:
> a SqlMapSessionImpl s1 is created for a thread t1 and a session scope ss1 is 
> popped from the pool     
>       s1.setUserConnection(con) is called to perform a user-controlled 
> transaction 
>       the transaction executes normally 
>       s1.setUserConnection(null) is called to free up the connection as 
> specified in the iBatis docs 
>       The SessionScope ss1 is pushed back into the pool for later use
> a SqlMapSessionImpl s2 is created for a thread t2 and session scope ss1 is 
> popped from the pool again
>       s2.startTransaction(...) is called to start a conventional iBatis 
> managed transaction on thread t2 with SessionScope ss1
>       s1.startTransaction(...) is called to start a conventional iBatis 
> managed transaction on thread t1 with SessionScope ss1
>       thread t1 throws the exception <INSERT HERE>
>       this is because SessionScope ss1 has been initialized by 
> s2.startTransaction() causing the s1.startTransaction() to fail due to the 
> unexpected state of ss1.  
>       SqlMapSessionImpl s1 is closed and SessionScope ss1 is returned to the 
> pool for later use.
>       s2.execute(...) is called to execute statements
>       s2.commitTransaction(...) is called to commit the iBatis managed 
> transaction
>       s2.endTransaction(...) is called to complete the iBatis managed 
> transaction
>       this closes SqlMapSessionImpl s2, and SessionScope ss1 is returned to 
> the pool for later use.
>       SessionScope ss1 is now in the pool twice, causing ss1 to be available 
> to multiple threads. 
>       This results in the same race condition reoccurring.
>       
> Fix:
> Ensure that SqlMapSessionImpl is closed when 
> SqlMapSessionImpl.setUserConnection(null) is called.
> Class com.ibatis.sqlmap.engine.impl.SqlMapClientImpl:
> public void setUserConnection(Connection connection) throws SQLException {
>   try {
>     getLocalSqlMapSession().setUserConnection(connection);
>   } finally {
>     if (connection == null) {   //bug fix:if connection == null, close the 
> session like we are ending a transaction 
>       getLocalSqlMapSession().close();
>     }
>   }
> }
> Remove the push(SessionScope) call in 
> SqlMapExecutorDelegate.setUserProvidedTransaction(SessionScope session, 
> Connection userConnection) when userConnection is null. This makes sure that 
> the SessionScope is not pushed twice.
> Class com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate:
> public void setUserProvidedTransaction(SessionScope session, Connection 
> userConnection) {
>   if (session.getTransactionState() == TransactionState.STATE_USER_PROVIDED) {
>     session.recallTransactionState();
>   }
>   if (userConnection != null) {
>     Connection conn = userConnection;
>     session.saveTransactionState();
>     session.setTransaction(new UserProvidedTransaction(conn));
>     session.setTransactionState(TransactionState.STATE_USER_PROVIDED);
>   } else {
>     session.setTransaction(null);
>     //pushSession(session); bug fix: commented out done as part of closing 
> the SqlMapSessionImpl
>   }
> }

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
   http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see:
   http://www.atlassian.com/software/jira

Reply via email to