You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by ka...@apache.org on 2012/10/02 13:25:01 UTC

svn commit: r1392847 - in /db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests: Derby5937SlaveShutdownTest.java Derby5937SlaveShutdownTest.policy ReplicationSuite.java build.xml

Author: kahatlen
Date: Tue Oct  2 11:25:01 2012
New Revision: 1392847

URL: http://svn.apache.org/viewvc?rev=1392847&view=rev
Log:
DERBY-5937: File handle is leaked when a Slave replication is shutdown with failover=true

Added a test case that exposes the bug when run on Windows.

Added:
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/Derby5937SlaveShutdownTest.java   (with props)
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/Derby5937SlaveShutdownTest.policy   (with props)
Modified:
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/ReplicationSuite.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/build.xml

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/Derby5937SlaveShutdownTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/Derby5937SlaveShutdownTest.java?rev=1392847&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/Derby5937SlaveShutdownTest.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/Derby5937SlaveShutdownTest.java Tue Oct  2 11:25:01 2012
@@ -0,0 +1,216 @@
+/*
+
+Derby - Class org.apache.derbyTesting.functionTests.tests.replicationTests.Derby5937SlaveShutdownTest
+
+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.replicationTests;
+
+import java.io.File;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Properties;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.apache.derbyTesting.functionTests.util.PrivilegedFileOpsForTests;
+import org.apache.derbyTesting.junit.BaseJDBCTestCase;
+import org.apache.derbyTesting.junit.JDBC;
+import org.apache.derbyTesting.junit.NetworkServerTestSetup;
+import org.apache.derbyTesting.junit.SecurityManagerSetup;
+import org.apache.derbyTesting.junit.TestConfiguration;
+
+/**
+ * <p>
+ * Regression test case for DERBY-5937. After fail-over, the slave database
+ * will leak a file handle for the active log file.
+ * </p>
+ *
+ * <p>
+ * The test case will set up replication between a master database and a
+ * slave database, perform fail-over to the slave, and then shut down the
+ * slave database. Finally, it attempts to delete the slave database. On
+ * Windows, this fails if DERBY-5937 is not fixed, because one of the log
+ * files is still held open, and Windows doesn't allow deletion of open
+ * files.
+ * </p>
+ */
+public class Derby5937SlaveShutdownTest extends BaseJDBCTestCase {
+
+    private static final String MASTER_DB = "d5937-master-db";
+    private static final String SLAVE_DB = "d5937-slave-db";
+
+    private static final String FAILOVER_SUCCESS = "XRE20";
+    private static final String DB_SHUTDOWN_SUCCESS = "08006";
+
+    private static final long RETRY_INTERVAL = 50L;
+
+    public Derby5937SlaveShutdownTest(String name) {
+        super(name);
+    }
+
+    public static Test suite() {
+        if (JDBC.vmSupportsJDBC3()) {
+            Class klass = Derby5937SlaveShutdownTest.class;
+            // The default security policy doesn't allow derby.jar to do
+            // networking, which is needed for replication, so install a custom
+            // policy for this test.
+            return new SecurityManagerSetup(
+                TestConfiguration.singleUseDatabaseDecorator(
+                    TestConfiguration.embeddedSuite(klass), MASTER_DB),
+                klass.getName().replace('.', '/') + ".policy", true);
+        } else {
+            // The test doesn't run on J2ME.
+            return new TestSuite("Derby5937SlaveShutdownTest - skipped");
+        }
+    }
+
+    public void testSlaveFailoverLeak() throws Exception {
+        // First establish a connection so that the database is created.
+        getConnection().close();
+
+        // Then shut down the database cleanly so that it can be used
+        // to seed the replication slave.
+        final TestConfiguration config = TestConfiguration.getCurrent();
+        config.shutdownDatabase();
+
+        // Copy the database to the slave.
+        final String masterDb = config.getDatabasePath(MASTER_DB);
+        final String slaveDb = config.getDatabasePath(SLAVE_DB);
+        PrivilegedFileOpsForTests.copy(new File(masterDb), new File(slaveDb));
+
+        // And start the slave.
+        SlaveThread slave = new SlaveThread(config);
+        slave.start();
+
+        Properties p = new Properties();
+        p.setProperty("startMaster", "true");
+        p.setProperty("slaveHost", config.getHostName());
+        p.setProperty("slavePort", String.valueOf(config.getPort()));
+
+        // Start the master. This will fail until the slave is up, so do
+        // it in a loop until successful or time runs out.
+        long giveUp =
+            System.currentTimeMillis() + NetworkServerTestSetup.getWaitTime();
+        Connection c = null;
+        while (c == null) {
+            try {
+                c = config.openPhysicalConnection(masterDb,
+                        config.getUserName(), config.getUserPassword(), p);
+            } catch (SQLException sqle) {
+                slave.checkError(); // Exit early if the slave has failed
+                if (System.currentTimeMillis() > giveUp) {
+                    fail("Master won't start", sqle);
+                } else {
+                    println("Retrying after startMaster failed with: " + sqle);
+                    Thread.sleep(RETRY_INTERVAL);
+                }
+            }
+        }
+        c.close();
+
+        // Wait for the slave thread to complete, which it will do once
+        // it's connected to the master.
+        slave.join();
+        slave.checkError();
+
+        // Perform fail-over.
+        p.clear();
+        p.setProperty("failover", "true");
+        try {
+            config.openPhysicalConnection(masterDb,
+                    config.getUserName(), config.getUserPassword(), p);
+            fail("failover should receive exception");
+        } catch (SQLException sqle) {
+            assertSQLState(FAILOVER_SUCCESS, sqle);
+        }
+
+        // Shut down the slave database. This will fail until failover is
+        // complete, so do it in a loop until successful or time runs out.
+        giveUp =
+            System.currentTimeMillis() + NetworkServerTestSetup.getWaitTime();
+        p.clear();
+        p.setProperty("shutdown", "true");
+        while (true) {
+            try {
+                config.openPhysicalConnection(slaveDb,
+                        config.getUserName(), config.getUserPassword(), p);
+                fail("Shutdown of slave database didn't throw an exception");
+            } catch (SQLException sqle) {
+                if (DB_SHUTDOWN_SUCCESS.equals(sqle.getSQLState())) {
+                    // The expected shutdown exception was thrown. Break out
+                    // of the loop.
+                    break;
+                } else if (System.currentTimeMillis() > giveUp) {
+                    fail("Could not shut down slave database", sqle);
+                } else {
+                    println("Retrying after failover failed with: " + sqle);
+                    Thread.sleep(RETRY_INTERVAL);
+                }
+            }
+        }
+
+        // This call used to fail on Windows because one of the log files
+        // was still open.
+        assertDirectoryDeleted(new File(slaveDb));
+    }
+
+    /**
+     * Helper thread which starts a replication slave and blocks until the
+     * slave is connected to a master database.
+     */
+    private class SlaveThread extends Thread {
+
+        private final TestConfiguration config;
+        private volatile Throwable error;
+
+        SlaveThread(TestConfiguration config) {
+            this.config = config;
+        }
+
+        public void run() {
+            try {
+                run_();
+            } catch (Throwable t) {
+                error = t;
+            }
+        }
+
+        private void run_() throws Exception {
+            println("Slave thread started.");
+
+            Properties p = new Properties();
+            p.setProperty("startSlave", "true");
+            p.setProperty("slaveHost", config.getHostName());
+            p.setProperty("slavePort", String.valueOf(config.getPort()));
+
+            try {
+                config.openPhysicalConnection(config.getDatabasePath(SLAVE_DB),
+                        config.getUserName(), config.getUserPassword(), p);
+                fail("startSlave should throw exception");
+            } catch (SQLException sqle) {
+                assertSQLState("XRE08", sqle);
+            }
+        }
+
+        void checkError() {
+            if (error != null) {
+                fail("Slave thread failed", error);
+            }
+        }
+    }
+}

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/Derby5937SlaveShutdownTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/Derby5937SlaveShutdownTest.policy
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/Derby5937SlaveShutdownTest.policy?rev=1392847&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/Derby5937SlaveShutdownTest.policy (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/Derby5937SlaveShutdownTest.policy Tue Oct  2 11:25:01 2012
@@ -0,0 +1,29 @@
+//
+// Derby - org/apache/derbyTesting/functionTests/tests/replicationTests/Derby5937SlaveShutdownTest.policy
+//
+// 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.
+//
+// Test specific permissions for test:
+//     replicationTests/Derby5937SlaveShutdownTest.java
+// The permissions below are expected to be added to the set of default
+// permissions granted to the test framework.
+//
+grant codeBase "${derbyTesting.codejar}derby.jar" {
+  permission java.net.SocketPermission "127.0.0.1", "connect,resolve,accept";
+  permission java.net.SocketPermission "localhost", "connect,resolve,accept";
+};

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/Derby5937SlaveShutdownTest.policy
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/ReplicationSuite.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/ReplicationSuite.java?rev=1392847&r1=1392846&r2=1392847&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/ReplicationSuite.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/ReplicationSuite.java Tue Oct  2 11:25:01 2012
@@ -84,6 +84,9 @@ public class ReplicationSuite extends Ba
             suite.addTest(ReplicationRun_Local_3_p6.suite());
 
             suite.addTest(ReplicationRun_Local_Derby4910.suite());
+
+            // Enable when DERBY-5937 has been fixed.
+            //suite.addTest(Derby5937SlaveShutdownTest.suite());
         }
 
 		return suite;

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/build.xml
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/build.xml?rev=1392847&r1=1392846&r2=1392847&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/build.xml (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/build.xml Tue Oct  2 11:25:01 2012
@@ -58,7 +58,7 @@
 
 <!--             ============ Begin Targets ==============                -->
  
-  <target name="FTOtestsubdir" depends="compilet1"/>
+  <target name="FTOtestsubdir" depends="compilet1,copyfiles"/>
 
   <!-- mkdir / init target may not be necessary, just here for reference... -->
   <target name="init">
@@ -87,6 +87,11 @@
     </javac>
   </target>
 
+  <target name="copyfiles">
+    <copy todir="${out.dir}/${this.dir}">
+      <fileset dir="${derby.testing.src.dir}/${this.dir}" includes="*.policy"/>
+    </copy>
+  </target>
 
 <!--             ============= End Targets ==============                -->