Return-Path: Delivered-To: apmail-db-derby-commits-archive@www.apache.org Received: (qmail 16860 invoked from network); 26 Jun 2010 18:09:55 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 26 Jun 2010 18:09:55 -0000 Received: (qmail 70042 invoked by uid 500); 26 Jun 2010 18:09:55 -0000 Delivered-To: apmail-db-derby-commits-archive@db.apache.org Received: (qmail 70001 invoked by uid 500); 26 Jun 2010 18:09:55 -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 69994 invoked by uid 99); 26 Jun 2010 18:09:55 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 26 Jun 2010 18:09:55 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED,T_FRT_STOCK2 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; Sat, 26 Jun 2010 18:09:52 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 31DD32388A2C; Sat, 26 Jun 2010 18:08:58 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r958264 - in /db/derby/code/trunk/java/testing/org/apache/derbyTesting: functionTests/tests/engine/LockInterruptTest.java functionTests/tests/engine/_Suite.java junit/BaseTestCase.java Date: Sat, 26 Jun 2010 18:08:58 -0000 To: derby-commits@db.apache.org From: kahatlen@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100626180858.31DD32388A2C@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: kahatlen Date: Sat Jun 26 18:08:57 2010 New Revision: 958264 URL: http://svn.apache.org/viewvc?rev=958264&view=rev Log: DERBY-4711: Hung thread after another thread is interrupted Added JUnit test case. Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/engine/LockInterruptTest.java (with props) Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/engine/_Suite.java db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/BaseTestCase.java Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/engine/LockInterruptTest.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/engine/LockInterruptTest.java?rev=958264&view=auto ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/engine/LockInterruptTest.java (added) +++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/engine/LockInterruptTest.java Sat Jun 26 18:08:57 2010 @@ -0,0 +1,157 @@ +/* + * Derby - Class org.apache.derbyTesting.functionTests.tests.engine.LockInterruptTest + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.derbyTesting.functionTests.tests.engine; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; +import junit.framework.Test; +import org.apache.derbyTesting.junit.BaseJDBCTestCase; +import org.apache.derbyTesting.junit.CleanDatabaseTestSetup; +import org.apache.derbyTesting.junit.DatabasePropertyTestSetup; +import org.apache.derbyTesting.junit.JDBC; +import org.apache.derbyTesting.junit.TestConfiguration; + +/** + * Test that other threads are able to proceed if one thread is interrupted + * when it's waiting for a lock. Regression test case for DERBY-4711. + */ +public class LockInterruptTest extends BaseJDBCTestCase { + /** SQLState for exception thrown because of interrupts. */ + private final static String INTERRUPTED = "08000"; + + /** Lock timeout in seconds used in this test. */ + private final static int LOCK_TIMEOUT = 60; + + /** Deadlock timeout in seconds used in this test. */ + private final static int DEADLOCK_TIMEOUT = LOCK_TIMEOUT / 2; + + public LockInterruptTest(String name) { + super(name); + } + + public static Test suite() { + // Only run in embedded mode since we cannot interrupt the engine + // thread from the network client. + Test test = TestConfiguration.embeddedSuite(LockInterruptTest.class); + + // Set the lock timeout to a known value so that we know what to + // expect for timeouts. + test = DatabasePropertyTestSetup.setLockTimeouts( + test, DEADLOCK_TIMEOUT, LOCK_TIMEOUT); + + return new CleanDatabaseTestSetup(test); + } + + public void testInterruptLockWaiter() throws Exception { + setAutoCommit(false); + Statement s = createStatement(); + s.executeUpdate("create table derby4711(x int)"); + commit(); + + // Obtain a table lock in order to block the waiter threads. + s.executeUpdate("lock table derby4711 in share mode"); + + // Create first waiter thread. + Waiter t1 = new Waiter(); + t1.start(); + Thread.sleep(2000); // give t1 time to become the first waiter + + // Create second waiter thread. + Waiter t2 = new Waiter(); + t2.start(); + Thread.sleep(2000); // give t2 time to enter the wait queue + + // Now that the queue of waiters has been set up, interrupt the + // first thread. + t1.interrupt(); + + // Release the table lock to allow the waiters to proceed. + commit(); + + // Wait for the threads to complete before checking their state. + t1.join(); + t2.join(); + + // The first thread should fail because it was interrupted. + Throwable e1 = t1.throwable; + assertNotNull("First thread should fail because of interrupt", e1); + if (!(e1 instanceof SQLException)) { + fail("Unexpected exception from first thread", e1); + } + assertSQLState(INTERRUPTED, (SQLException) e1); + + // The second thread should be able to complete successfully. + Throwable e2 = t2.throwable; + if (e2 != null) { + fail("Unexpected exception from second thread", e2); + } + + // And the second thread should be able to complete in less time than + // the deadlock timeout (before DERBY-4711, it would wait for a + // timeout before obtaining the lock, even if the lock was available + // long before). + if (t2.elapsedTime >= DEADLOCK_TIMEOUT * 1000) { + fail("Second thread needed " + t2.elapsedTime + + " ms to complete. Probably stuck waiting for a lock."); + } + + // Expect that the second thread managed to insert a row. + JDBC.assertSingleValueResultSet( + s.executeQuery("select * from derby4711"), "1"); + } + + /** + * Thread class that opens a new connection and attempts to insert a + * row into a table. + */ + private class Waiter extends Thread { + private final Connection c; + private final PreparedStatement ps; + + private Throwable throwable; + private long elapsedTime; + + private Waiter() throws SQLException { + c = openDefaultConnection(); + ps = c.prepareStatement("insert into derby4711 values 1"); + } + + public void run() { + try { + runWaiter(); + } catch (Throwable t) { + throwable = t; + } + }; + + private void runWaiter() throws SQLException { + long start = System.currentTimeMillis(); + try { + ps.executeUpdate(); + } finally { + ps.close(); + c.close(); + } + elapsedTime = System.currentTimeMillis() - start; + } + } +} Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/engine/LockInterruptTest.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/engine/_Suite.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/engine/_Suite.java?rev=958264&r1=958263&r2=958264&view=diff ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/engine/_Suite.java (original) +++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/engine/_Suite.java Sat Jun 26 18:08:57 2010 @@ -47,6 +47,7 @@ public class _Suite extends BaseTestCase TestSuite suite = new TestSuite("engine"); suite.addTest(ErrorStreamTest.suite()); + suite.addTest(LockInterruptTest.suite()); suite.addTest(ModuleLoadingTest.suite()); return suite; Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/BaseTestCase.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/BaseTestCase.java?rev=958264&r1=958263&r2=958264&view=diff ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/BaseTestCase.java (original) +++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/BaseTestCase.java Sat Jun 26 18:08:57 2010 @@ -622,15 +622,15 @@ public abstract class BaseTestCase * Fail; attaching an exception for more detail on cause. * * @param msg message explaining the failure - * @param e exception related to the cause + * @param t the cause of the failure * * @exception AssertionFailedError */ - public static void fail(String msg, Exception e) + public static void fail(String msg, Throwable t) throws AssertionFailedError { AssertionFailedError ae = new AssertionFailedError(msg); - ae.initCause(e); + ae.initCause(t); throw ae; } } // End class BaseTestCase