You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ibatis.apache.org by "Clinton Begin (JIRA)" <ib...@incubator.apache.org> on 2006/06/13 20:33:32 UTC
[jira] Closed: (IBATIS-286) race-condition bug causing transactions
to fail due to SessionScope to be in an inconsistent state.
[ 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