Return-Path: X-Original-To: apmail-db-derby-commits-archive@www.apache.org Delivered-To: apmail-db-derby-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id B4884BE18 for ; Thu, 12 Jan 2012 10:51:46 +0000 (UTC) Received: (qmail 36531 invoked by uid 500); 12 Jan 2012 10:51:45 -0000 Delivered-To: apmail-db-derby-commits-archive@db.apache.org Received: (qmail 36295 invoked by uid 500); 12 Jan 2012 10:51:29 -0000 Mailing-List: contact derby-commits-help@db.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: "Derby Development" List-Id: Delivered-To: mailing list derby-commits@db.apache.org Received: (qmail 36222 invoked by uid 99); 12 Jan 2012 10:51:22 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 12 Jan 2012 10:51:22 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 12 Jan 2012 10:51:15 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 6610723888FE; Thu, 12 Jan 2012 10:50:55 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1230480 - in /db/derby/code/trunk/java: engine/org/apache/derby/jdbc/XATransactionState.java testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATransactionTest.java Date: Thu, 12 Jan 2012 10:50:55 -0000 To: derby-commits@db.apache.org From: kahatlen@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120112105055.6610723888FE@eris.apache.org> Author: kahatlen Date: Thu Jan 12 10:50:54 2012 New Revision: 1230480 URL: http://svn.apache.org/viewvc?rev=1230480&view=rev Log: DERBY-5562: A read-only XA transaction that has a timeout never has the timer canceled when the transaction is complete Cancel the timer when a read-only transaction is prepared and implicitly committed. Based on a fix contributed by Brett Bergquist. Modified: db/derby/code/trunk/java/engine/org/apache/derby/jdbc/XATransactionState.java db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATransactionTest.java Modified: db/derby/code/trunk/java/engine/org/apache/derby/jdbc/XATransactionState.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/jdbc/XATransactionState.java?rev=1230480&r1=1230479&r2=1230480&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/jdbc/XATransactionState.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/jdbc/XATransactionState.java Thu Jan 12 10:50:54 2012 @@ -33,6 +33,7 @@ import org.apache.derby.iapi.services.co import org.apache.derby.iapi.services.context.ContextManager; import org.apache.derby.iapi.error.ExceptionSeverity; import org.apache.derby.iapi.error.StandardException; +import org.apache.derby.iapi.store.access.XATransactionController; import org.apache.derby.iapi.store.access.xa.XAXactId; import org.apache.derby.iapi.reference.SQLState; import java.util.HashMap; @@ -357,13 +358,21 @@ final class XATransactionState extends C */ synchronized int xa_prepare() throws SQLException { int retVal = conn.xa_prepare(); + + if (retVal == XATransactionController.XA_RDONLY) { + // Read-only transactions are implicitly committed when they are + // prepared. Since the transaction has completed, the timeout task + // should be cancelled now. DERBY-5562. + xa_finalize(); + } + return retVal; } /** This method cancels timeoutTask and assigns * 'performTimeoutRollback = false'. */ - synchronized void xa_finalize() { + private void xa_finalize() { if (timeoutTask != null) { timeoutTask.cancel(); timeoutTask = null; Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATransactionTest.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATransactionTest.java?rev=1230480&r1=1230479&r2=1230480&view=diff ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATransactionTest.java (original) +++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATransactionTest.java Thu Jan 12 10:50:54 2012 @@ -498,6 +498,88 @@ public class XATransactionTest extends B } } + /** + *

+ * Regression test case for DERBY-5562. + *

+ * + *

+ * The timer that aborts long-running transactions if a transaction timeout + * has been specified, was not cancelled when preparing a read-only + * transaction. Since read-only transactions are implicitly committed when + * they are prepared, this meant that the timer would try to abort an + * already completed transaction. In addition to printing a confusing + * message in derby.log about the transaction being rolled back, when it + * actually had been committed, this could also make the timer roll back + * the wrong transaction, if a new transaction with the same Xid was + * started later. + *

+ * + *

+ * This test case exposes the bug by running a read-only transaction with + * a timeout and preparing it, and then starting a new transaction with the + * same Xid and no timeout. The bug would cause the second transaction to + * time out. + *

+ */ + public void testDerby5562ReadOnlyTimeout() + throws InterruptedException, SQLException, XAException { + XADataSource xads = J2EEDataSource.getXADataSource(); + XAConnection xac = xads.getXAConnection(); + XAResource xar = xac.getXAResource(); + + Xid xid = createXid(55, 62); + + // Set a transaction timeout. This should be relatively short so that + // the test case doesn't need to wait very long to trigger the timeout. + // However, it needs to be long enough to let the first transaction go + // through without hitting the timeout. Hopefully, four seconds is + // enough. If the test case starts failing intermittently during the + // first transaction, we might have to raise the timeout (and raise the + // sleep time in the second transaction correspondingly). + assertTrue(xar.setTransactionTimeout(4)); + + // Start first transaction. + xar.start(xid, XAResource.TMNOFLAGS); + Connection c = xac.getConnection(); + Statement s = c.createStatement(); + JDBC.assertSingleValueResultSet( + s.executeQuery("select * from sysibm.sysdummy1"), + "Y"); + s.close(); + c.close(); + xar.end(xid, XAResource.TMSUCCESS); + + // Prepare the first transaction. Since it's a read-only transaction, + // it'll be automatically committed, so there's no need to call commit. + assertEquals("XA_RDONLY", XAResource.XA_RDONLY, xar.prepare(xid)); + + // Reset the timeout for the second transaction. + assertTrue(xar.setTransactionTimeout(0)); + + // Start second transaction. + xar.start(xid, XAResource.TMNOFLAGS); + c = xac.getConnection(); + s = c.createStatement(); + JDBC.assertSingleValueResultSet( + s.executeQuery("select * from sysibm.sysdummy1"), + "Y"); + s.close(); + c.close(); + + // Keep the transaction running so long that it must have exceeded the + // timeout for the previous transaction. + Thread.sleep(5000); + + // End the transaction. Since there's no timeout on this transaction, + // it should work. Before DERBY-5562 was fixed, it would fail because + // it had been rolled back by the timer from the previous transaction. + xar.end(xid, XAResource.TMSUCCESS); + assertEquals("XA_RDONLY", XAResource.XA_RDONLY, xar.prepare(xid)); + + xac.close(); + } + /* ------------------- end helper methods -------------------------- */ /** Create the Xid object for global transaction identification