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 da...@apache.org on 2009/04/30 00:07:37 UTC

svn commit: r769962 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/db/SlaveDatabase.java testing/org/apache/derbyTesting/functionTests/tests/replicationTests/ReplicationRun_Local_3_p3.java

Author: dag
Date: Wed Apr 29 22:07:37 2009
New Revision: 769962

URL: http://svn.apache.org/viewvc?rev=769962&view=rev
Log:
DERBY-4186 After master stop, test fails when it succeeds in connecting (rebooting) shut-down ex-slave

Patch derby-4186-2, which solves this issue by

a) fixing a bug in SlaveDataBase, which loses and exception iff a
command to stop replication arrives from the master to the slave
before the initial connection (successful slave started) command
returns. This is a corner case race condition, and not very likely to
occur in practice, since it makes little sense to stop replication
immediately after starting it.

b) fixing a bug in the test, which switched on its head what is really
expected behavior, and also adds a waiting loop to allow intermediate
state on slave after the master is stopped. Also fixed some erroneous
comment and removed some cruft.


Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/db/SlaveDatabase.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/ReplicationRun_Local_3_p3.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/db/SlaveDatabase.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/db/SlaveDatabase.java?rev=769962&r1=769961&r2=769962&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/db/SlaveDatabase.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/db/SlaveDatabase.java Wed Apr 29 22:07:37 2009
@@ -25,6 +25,7 @@
 import org.apache.derby.iapi.reference.Attribute;
 import org.apache.derby.iapi.reference.SQLState;
 import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.error.ExceptionSeverity;
 import org.apache.derby.iapi.jdbc.AuthenticationService;
 import org.apache.derby.iapi.services.context.ContextManager;
 import org.apache.derby.iapi.services.context.ContextService;
@@ -134,6 +135,7 @@
         // Check that the database was booted successfully, or throw
         // the exception that caused the boot to fail.
         verifySuccessfulBoot();
+
         inBoot = false;
 
         // This module has now been booted (hence active=true) even
@@ -349,6 +351,21 @@
                 }
             }
         }
+
+        if (bootException != null &&
+            SQLState.SHUTDOWN_DATABASE.startsWith(
+                bootException.getSQLState()) &&
+            bootException.getSeverity() == ExceptionSeverity.DATABASE_SEVERITY) {
+
+            // DERBY-4186: This is a corner case. Master made us shut down
+            // before the initial connect which establishes the slave has
+            // finalized it setting up of the slave and returned control to the
+            // application. bootException is set while we (application thread)
+            // are waiting in the sleep in the loop above (by the
+            // SlaveDatabaseBootThread thread in its call to handleShutdown),
+            // and this was previously ignored.
+            throw bootException;
+        }
     }
 
     /** 

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/ReplicationRun_Local_3_p3.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/ReplicationRun_Local_3_p3.java?rev=769962&r1=769961&r2=769962&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/ReplicationRun_Local_3_p3.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/replicationTests/ReplicationRun_Local_3_p3.java Wed Apr 29 22:07:37 2009
@@ -20,8 +20,10 @@
  */
 package org.apache.derbyTesting.functionTests.tests.replicationTests;
 
+import java.sql.SQLException;
 import junit.framework.Test;
 import junit.framework.TestSuite;
+import org.apache.derby.jdbc.ClientDataSource;
 import org.apache.derbyTesting.junit.SecurityManagerSetup;
 
 
@@ -34,6 +36,10 @@
 
 public class ReplicationRun_Local_3_p3 extends ReplicationRun_Local_3
 {
+
+    final static String CANNOT_CONNECT_TO_DB_IN_SLAVE_MODE = "08004";
+    final static String REPLICATION_NOT_IN_MASTER_MODE     = "XRE07";
+    final static int MAX_TRIES = 20;
     
     /**
      * Creates a new instance of ReplicationRun_Local
@@ -150,11 +156,11 @@
         
         // 3 separate test
         // stopMaster
-        // failover on slave
+        // shutdown on slave
         assertException(
             _stopMaster(masterServerHost, masterServerPort,
                 masterDatabasePath + FS + masterDbSubPath + FS + replicatedDb),
-            null); // Implies failover. // OK to continue.
+            null); // Implies slave should shut down. // OK to continue.
         /* showCurrentState("Post stopMaster +1s", 1000L,
             masterDatabasePath + FS + masterDbSubPath + FS + replicatedDb, 
             masterServerHost, masterServerPort); */
@@ -167,49 +173,78 @@
         showCurrentState("Post stopMaster +5s", 5000L,
             slaveDatabasePath + FS + slaveDbSubPath + FS + replicatedDb, 
             slaveServerHost, slaveServerPort); */
-        waitForSQLState("08004", 1000L, 20, // 08004.C.7 - CANNOT_CONNECT_TO_DB_IN_SLAVE_MODE
-                slaveDatabasePath + FS + slaveDbSubPath + FS + replicatedDb, 
-                slaveServerHost, slaveServerPort);
-        /* Got it above... showCurrentState("Post stopMaster +30s", 30000L,
-            slaveDatabasePath + FS + slaveDbSubPath + FS + replicatedDb, 
-            slaveServerHost, slaveServerPort); // 08004 */
-        /* Got it above... showCurrentState("Post stopMaster +60s", 30000L,
-            masterDatabasePath + FS + masterDbSubPath + FS + replicatedDb, 
-            masterServerHost, masterServerPort); // CONNECTED */
+
+        // Connect to the ex-slave db, to verify that we can boot it and
+        // connect to it.
+        //
+        // DERBY-4186: We use a loop below, to allow for intermediate state on
+        // the slave db after master stopped and before slave reaches the
+        // expected final state.
+        //
+        // If we get here quick enough we see this error state:
+        //     CANNOT_CONNECT_TO_DB_IN_SLAVE_MODE
+        //
+        // The final end state is successful connect (i.e. a reboot) after
+        // stopped slave and db shutdown.
+
+        SQLException gotEx = null;
+        int tries = MAX_TRIES;
+
+        while (tries-- > 0) {
+            gotEx = null;
+            try
+            {
+                String connectionURL =
+                    slaveDatabasePath + FS + slaveDbSubPath + FS + replicatedDb;
+                ClientDataSource ds = new ClientDataSource();
+                ds.setDatabaseName(connectionURL);
+                ds.setServerName(slaveServerHost);
+                ds.setPortNumber(slaveServerPort);
+                ds.getConnection().close();
+                util.DEBUG("Successfully connected after shutdown: " +
+                           connectionURL);
+                break;
+            }
+            catch (SQLException se)
+            {
+                if (se.getSQLState().
+                        equals(CANNOT_CONNECT_TO_DB_IN_SLAVE_MODE)) {
+                    // Try again, shutdown did not complete yet..
+                    gotEx = se;
+                    util.DEBUG(
+                        "got SLAVE_OPERATION_DENIED_WHILE_CONNECTED, sleep");
+                    Thread.sleep(1000L);
+                    continue;
+
+                } else {
+                    // Something else, so report.
+                    gotEx = se;
+                    break;
+                }
+            }
+        }
+
+        if (gotEx != null) {
+            String reason;
+            if (gotEx.getSQLState().
+                    equals(CANNOT_CONNECT_TO_DB_IN_SLAVE_MODE)) {
+                reason = "Tried " + MAX_TRIES + " times...";
+            } else {
+                reason = "Unexpected SQL state: " + gotEx.getSQLState();
+            }
+
+            util.DEBUG(reason);
+            throw gotEx;
+        }
+
+        // A failover on ex-master db should fail now
         assertException(
             _failOver(masterServerHost, masterServerPort, 
                 masterDatabasePath+FS+masterDbSubPath+FS+replicatedDb),
-            "XRE07");
-        /* _p2: assertException(
-            _failOver(slaveServerHost, slaveServerPort, 
-                slaveDatabasePath+FS+slaveDbSubPath+FS+replicatedDb),
-                "XRE07"); // Hangs!? even after killMaster server. */
-        
-        // 5 separate test
-        // slave: "normal" connect to slave db
-        
-        // 6 separate test
-        // slave: 'internal-stopslave=true'
-        
-        /* failOver(jvmVersion,
-                masterDatabasePath, masterDbSubPath, replicatedDb,
-                masterServerHost,  // Where the master db is run.
-                masterServerPort,
-                testClientHost); //  XRE07 Could not perform operation because the database is not in replication master mode.
-        */
-        
-        waitForSQLState("08004", 1000L, 20, // 08004.C.7 - CANNOT_CONNECT_TO_DB_IN_SLAVE_MODE
-                slaveDatabasePath + FS + slaveDbSubPath + FS + replicatedDb,
-                slaveServerHost, slaveServerPort); // _failOver above fails...
-        /*
-        connectPing(slaveDatabasePath+FS+slaveDbSubPath+FS+replicatedDb,
-        slaveServerHost,slaveServerPort,
-        testClientHost); // 
-         */
-        
-        // Not relevant as we  can not connect. verifySlave();
-        
-        // We should verify the master as well, at least to see that we still can connect.
+            REPLICATION_NOT_IN_MASTER_MODE);
+
+        // We should verify the master as well, at least to see that we still
+        // can connect.
         verifyMaster();
         
         stopServer(jvmVersion, derbyVersion,