| /* |
| * |
| * Derby - Class org.apache.derbyTesting.functionTests.tests.store.Derby3980DeadlockTest |
| * |
| * 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.store; |
| |
| |
| import java.io.File; |
| import java.sql.Connection; |
| import java.sql.ResultSet; |
| import java.sql.SQLException; |
| import java.sql.Statement; |
| import java.util.LinkedList; |
| import java.util.Properties; |
| |
| import junit.framework.Test; |
| |
| import org.apache.derbyTesting.junit.BaseJDBCTestCase; |
| import org.apache.derbyTesting.junit.BaseTestCase; |
| import org.apache.derbyTesting.junit.CleanDatabaseTestSetup; |
| import org.apache.derbyTesting.junit.DatabasePropertyTestSetup; |
| import org.apache.derbyTesting.junit.SecurityManagerSetup; |
| import org.apache.derbyTesting.junit.SystemPropertyTestSetup; |
| import org.apache.derbyTesting.junit.TestConfiguration; |
| |
| /** |
| * Test to test two threads doing select then delete of a row |
| * using REPEATABLE_READ isolation level. We should get a |
| * deadlock (SQLState 40001); |
| * |
| */ |
| public class Derby3980DeadlockTest extends BaseJDBCTestCase { |
| private final int THREAD_COUNT = 2; |
| private final LinkedList<Throwable> listExceptions = |
| new LinkedList<Throwable>(); |
| private final Object syncObject = new Object(); |
| private int startedCount = 0; |
| private static final String fprefix = "javacore"; |
| private static final String POLICY_FILE_NAME = |
| "org/apache/derbyTesting/functionTests/tests/store/Derby3980DeadlockTest.policy"; |
| |
| public Derby3980DeadlockTest(String name) { |
| super(name); |
| } |
| |
| |
| public void test3980Deadlock() { |
| Thread [] t = new Thread[THREAD_COUNT]; |
| createThreads(t); |
| waitForThreads(t); |
| checkExceptions(); |
| } |
| |
| |
| /** |
| * Check we have one deadlock exception. |
| */ |
| private void checkExceptions() { |
| //Due to timing, you might see ERROR 40XL1: A lock could not be obtained |
| //instead of ERROR 40001 (DERBY-3980) |
| for (Throwable t : listExceptions) { |
| if (t instanceof SQLException) { |
| assertSQLState("40001", (SQLException) t); |
| } else { |
| fail("Unexpected exception", t); |
| } |
| } |
| assertEquals("Expected 1 exception, got" + listExceptions.size(), |
| 1,listExceptions.size()); |
| } |
| /** |
| * Decorate a test with SecurityManagerSetup, clientServersuite, and |
| * SupportFilesSetup. |
| * |
| * @return the decorated test |
| */ |
| private static Test decorateTest() { |
| Test test = TestConfiguration.clientServerSuite(Derby3980DeadlockTest.class); |
| Properties diagProperties = new Properties(); |
| diagProperties.setProperty("derby.stream.error.extendedDiagSeverityLevel", "30000"); |
| diagProperties.setProperty("derby.infolog.append", "true"); |
| test = new SystemPropertyTestSetup(test, diagProperties, true); |
| |
| // Install a security manager using the initial policy file. |
| return new SecurityManagerSetup(test, POLICY_FILE_NAME); |
| } |
| |
| private void waitForThreads(Thread[] t) { |
| for (int i = 0; i < THREAD_COUNT; i++) |
| { |
| try { |
| t[i].join(); |
| } catch (InterruptedException e){ |
| fail( |
| "FAIL - InterruptedException thrown waiting for the threads"); |
| } |
| } |
| |
| } |
| |
| private void createThreads(Thread[] t) { |
| for (int i = 0; i < THREAD_COUNT; i++) |
| { |
| t[i] = new Thread(new Runnable() { |
| public void run() {threadWorker(); } |
| |
| private void threadWorker() { |
| Connection threadConnection = null; |
| |
| try { |
| synchronized (syncObject) { |
| |
| /* If a connection hasn't been opened for this thread, open one */ |
| if (threadConnection == null){ |
| threadConnection = openDefaultConnection(); |
| } |
| |
| /* A new thread started, so we increment the counter */ |
| startedCount++; |
| |
| /* Wake all the threads to run the check below */ |
| syncObject.notifyAll(); |
| |
| while (startedCount < THREAD_COUNT) { |
| syncObject.wait(); |
| } |
| } |
| Statement stmt = threadConnection.createStatement(); |
| |
| threadConnection.setAutoCommit(false); |
| /* set isolation level to repeatable read */ |
| threadConnection.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); |
| |
| ResultSet rs = stmt.executeQuery("select * from t where i = 456"); |
| while (rs.next()); |
| |
| //stmt.executeUpdate("update t set i = 456 where i = 456") |
| stmt.executeUpdate("delete from t where i = 456"); |
| threadConnection.commit(); |
| } catch (Exception e) { |
| synchronized(syncObject){ |
| listExceptions.add(e); |
| } |
| } |
| |
| |
| }},"Thread"+i); |
| t[i].start(); |
| } |
| |
| } |
| |
| public static Test suite() { |
| Test suite = decorateTest(); |
| |
| return new CleanDatabaseTestSetup( |
| DatabasePropertyTestSetup.setLockTimeouts(suite, 5, 10)) { |
| /** |
| * Creates the table used in the test cases. |
| * |
| */ |
| protected void decorateSQL(Statement s) throws SQLException { |
| s.executeUpdate("CREATE TABLE T (I INT)"); |
| s.executeUpdate("INSERT INTO T VALUES(456)"); |
| } |
| |
| }; |
| |
| } |
| |
| /** |
| * Use tearDown to cleanup some of the diagnostic information files |
| */ |
| protected void tearDown() throws Exception { |
| String dsh = BaseTestCase.getSystemProperty("user.dir"); |
| try { |
| File basedir = new File(dsh); |
| String[] list = BaseTestCase.getFilesWith(basedir, fprefix); |
| removeFiles(list); |
| } catch (IllegalArgumentException e) { |
| fail("open directory"); |
| } |
| |
| super.tearDown(); |
| } |
| } |
| |