db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From oyste...@apache.org
Subject svn commit: r617501 - in /db/derby/code/trunk/java: engine/org/apache/derby/database/ engine/org/apache/derby/iapi/reference/ engine/org/apache/derby/iapi/services/replication/slave/ engine/org/apache/derby/impl/db/ engine/org/apache/derby/impl/jdbc/ e...
Date Fri, 01 Feb 2008 14:02:22 GMT
Author: oysteing
Date: Fri Feb  1 06:02:01 2008
New Revision: 617501

URL: http://svn.apache.org/viewvc?rev=617501&view=rev
Log:
DERBY-3205: Add the functionality for stopSlave=true. Contributed by Jorgen Loland


Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/database/Database.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/replication/slave/SlaveFactory.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/db/BasicDatabase.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/db/SlaveDatabase.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/net/ReplicationMessageReceive.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/net/SocketConnection.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/slave/SlaveController.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/RawStore.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/log/LogToFile.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/log/ReadOnly.java
    db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml
    db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/Attribute.java
    db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/database/Database.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/database/Database.java?rev=617501&r1=617500&r2=617501&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/database/Database.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/database/Database.java Fri Feb  1 06:02:01
2008
@@ -100,6 +100,12 @@
     boolean wait) 
         throws SQLException;
 
+    /**
+     * Stop the replication slave role for the given database.
+     * 
+     * @exception SQLException Thrown on error
+     */
+    public void stopReplicationSlave() throws SQLException;
 
 	/**
 	 * Disables the log archival process, i.e No old log files

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java?rev=617501&r1=617500&r2=617501&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java Fri Feb
 1 06:02:01 2008
@@ -123,6 +123,12 @@
     String REPLICATION_STOP_SLAVE = "stopSlave";
 
     /**
+     * Attribute name to stop replication slave mode for a database.
+     * Internal use only
+     */
+    String REPLICATION_INTERNAL_SHUTDOWN_SLAVE = "internal_stopslave";
+
+    /**
      * If startMaster is true, this attribute is used to specify the
      * host name the master should connect to. This is a required
      * attribute.

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/replication/slave/SlaveFactory.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/replication/slave/SlaveFactory.java?rev=617501&r1=617500&r2=617501&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/replication/slave/SlaveFactory.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/replication/slave/SlaveFactory.java
Fri Feb  1 06:02:01 2008
@@ -97,9 +97,21 @@
         throws StandardException;
 
     /**
-     * Will perform all work that is needed to stop replication
+     * Stop replication slave mode. Causes the database to abort the
+     * boot process, and should only be used when shutting down this
+     * database. If forcedStop is false, the method will fail with an
+     * exception if connected with the master. If forcedStop is true, the 
+     * slave will be shut down even if connected to the master. A forcedStop 
+     * value of true should only be used by system shutdown.
+     *
+     * @param forcedStop Determines whether or not an exception should
+     * be thrown when this method is called while the network
+     * connection to the master is up.
+     * @exception StandardException Thrown if slave is connected with
+     * master and forcedStop is false.
      */
-    public void stopSlave();
+    public void stopSlave(boolean forcedStop) 
+            throws StandardException;
 
     /**
      * <p>

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/db/BasicDatabase.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/db/BasicDatabase.java?rev=617501&r1=617500&r2=617501&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/db/BasicDatabase.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/db/BasicDatabase.java Fri Feb  1
06:02:01 2008
@@ -390,6 +390,19 @@
             throw PublicAPI.wrapStandardException(se);
         }
     }
+    
+    /**
+     * Only a SlaveDatabase can be in replication slave mode. Always 
+     * throws an exception
+     * 
+     * @exception SQLException Always thrown because BasicDatabase cannot 
+     * be in replication slave mode
+     */
+    public void stopReplicationSlave() throws SQLException {
+        StandardException se = StandardException.
+            newException(SQLState.REPLICATION_NOT_IN_SLAVE_MODE);
+        throw PublicAPI.wrapStandardException(se);
+    }
 
 	public void freeze() throws SQLException
 	{

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=617501&r1=617500&r2=617501&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 Fri Feb  1
06:02:01 2008
@@ -21,18 +21,21 @@
 
 package org.apache.derby.impl.db;
 
-import org.apache.derby.iapi.reference.MessageId;
+import org.apache.derby.iapi.error.PublicAPI;
+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.jdbc.AuthenticationService;
 import org.apache.derby.iapi.services.context.ContextManager;
 import org.apache.derby.iapi.services.context.ContextService;
 import org.apache.derby.iapi.services.monitor.Monitor;
-import org.apache.derby.impl.services.replication.ReplicationLogger;
 import org.apache.derby.iapi.services.replication.slave.SlaveFactory;
 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
 import org.apache.derby.impl.services.monitor.UpdateServiceProperties;
 
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.SQLException;
 import java.util.Properties;
 
 /**
@@ -70,7 +73,9 @@
      * database. Does not happen until the failover command has been
      * executed for this database */
     private volatile boolean inReplicationSlaveMode;
+    private volatile boolean shutdownInitiated;
     private String dbname; // The name of the replicated database
+    private volatile SlaveFactory slaveFac;
 
     /////////////////////////////
     // ModuleControl interface //
@@ -104,6 +109,8 @@
         throws StandardException {
 
         inReplicationSlaveMode = true;
+        shutdownInitiated = false;
+
         dbname = startParams.getProperty(SlaveFactory.SLAVE_DB);
 
         // SlaveDatabaseBootThread is an internal class
@@ -134,12 +141,37 @@
         active=true;
     }
 
+    /**
+     * Called by Monitor when this module is stopped, i.e. when the
+     * database is shut down. When the database is shut down using the
+     * stopSlave command, the stopReplicationSlave method has already
+     * been called when this method is called. In this case, the
+     * replication functionality has already been stopped. If the
+     * database is shutdown as part of a system shutdown, however, we
+     * need to cleanup slave replication as part of database shutdown.
+     */
+    public void stop() {
+        if (inReplicationSlaveMode && slaveFac != null) {
+            try {
+                slaveFac.stopSlave(true);
+            } catch (StandardException ex) {
+            } finally {
+                slaveFac = null;
+            }
+        }
+        super.stop();
+    }
+    
     /////////////////////
     // Class interface //
     /////////////////////
     public SlaveDatabase() {
     }
 
+    public void setSlaveFactory(SlaveFactory f) {
+        slaveFac = f;
+    }
+
     ////////////////////////
     // Database interface //
     ////////////////////////
@@ -169,6 +201,59 @@
         return super.getAuthenticationService();
     }
 
+    /**
+     * Verify that a connection to stop the slave has been made from
+     * here. If verified, the database context is given to the method
+     * caller. This will ensure this database is shutdown when an
+     * exception with database severity is thrown. If not verified, an
+     * exception is thrown.
+     * 
+     * @exception StandardException Thrown if a stop slave connection
+     * attempt was not made from this class
+     */
+    public void verifyShutdownSlave() throws StandardException {
+        if (!shutdownInitiated) {
+            throw StandardException.
+                newException(SQLState.REPLICATION_STOPSLAVE_NOT_INITIATED);
+        }
+        pushDbContext(ContextService.getFactory().
+                      getCurrentContextManager());
+    }
+
+    /**
+     * Stop replication slave mode if replication slave mode is active and 
+     * the network connection with the master is down
+     * 
+     * @exception SQLException Thrown on error, if not in replication 
+     * slave mode or if the network connection with the master is not down
+     */
+    public  void stopReplicationSlave() throws SQLException {
+
+        if (shutdownInitiated) {
+            // The boot thread has failed or stopReplicationSlave has
+            // already been called. There is nothing more to do to
+            // stop slave replication mode.
+            return;
+        }
+        
+        if (!inReplicationSlaveMode) {
+            StandardException se = StandardException.
+                newException(SQLState.REPLICATION_NOT_IN_SLAVE_MODE);
+            throw PublicAPI.wrapStandardException(se);
+        }
+
+        // stop slave without using force, meaning that this method
+        // call will fail with an exception if the network connection
+        // with the master is up
+        try {
+            slaveFac.stopSlave(false);
+        } catch (StandardException se) {
+            throw PublicAPI.wrapStandardException(se);
+        }
+
+        slaveFac = null;
+    }
+
     /////////////////
     // Inner Class //
     /////////////////
@@ -200,18 +285,46 @@
 
                 bootBasicDatabase(create, params); // will be blocked
 
-            } catch (StandardException se) {
-                ReplicationLogger.logError(MessageId.REPLICATION_FATAL_ERROR,
-                                           se, dbname);
-                // todo: shutdown this database
-            } finally {
-                inReplicationSlaveMode = false;
+                // if we get here, failover has been called and the
+                // database can now be connected to
+                inReplicationSlaveMode = false; 
+
                 if (bootThreadCm != null) {
                     ContextService.getFactory().
                         resetCurrentContextManager(bootThreadCm);
                     bootThreadCm = null;
                 }
+            } catch (StandardException se) {
+                // We get here when SlaveController#stopSlave has been
+                // called, or if a fatal exception has been thrown.
+                handleShutdown ();
             }
+        }
+    }
+
+    /**
+     * Shutdown this database
+     */
+    private void handleShutdown() {
+
+        try {
+            shutdownInitiated = true;
+            String driverName = 
+                "org.apache.derby.jdbc.EmbeddedDriver";
+
+            Class.forName(driverName).newInstance();
+
+            Driver embedDriver = 
+                DriverManager.getDriver(Attribute.PROTOCOL);
+
+            String conStr = "jdbc:derby:"+dbname+";"+
+                Attribute.REPLICATION_INTERNAL_SHUTDOWN_SLAVE+
+                "=true";
+
+            embedDriver.connect(conStr, (Properties) null);
+        } catch (Exception e) {
+            // Todo: report error to derby.log if exception is not
+            // SQLState.SHUTDOWN_DATABASE
         }
     }
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java?rev=617501&r1=617500&r2=617501&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java Fri Feb
 1 06:02:01 2008
@@ -40,6 +40,7 @@
 import org.apache.derby.iapi.jdbc.EngineConnection;
 
 import org.apache.derby.iapi.db.Database;
+import org.apache.derby.impl.db.SlaveDatabase;
 import org.apache.derby.iapi.error.ExceptionSeverity;
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.services.i18n.MessageService;
@@ -290,6 +291,12 @@
 				}
 			}
 
+			if (isStopReplicationSlaveBoot(info)) {
+				handleStopReplicationSlave(info);
+			} else if (isInternalShutdownSlaveDatabase(info)) {
+				internalStopReplicationSlave(info);
+				return;
+			}
 
 			if (createBoot && !shutdown)
 			{
@@ -317,11 +324,7 @@
 
 
 			if (tr.getDatabase() == null) {
-				String dbname = tr.getDBName();
-				// do not clear the TransactionResource context. It will be restored
-                // as part of the finally clause below.
-				this.setInactive();
-				throw newSQLException(SQLState.DATABASE_NOT_FOUND, dbname);
+				handleDBNotFound();
 			}
 
 
@@ -530,6 +533,14 @@
 		return (createCount - restoreCount) == 1;
 	}
 
+    private void handleDBNotFound() throws SQLException {
+        String dbname = tr.getDBName();
+        // do not clear the TransactionResource context. It will be restored
+        // as part of the finally clause of the object creator. 
+        this.setInactive();
+        throw newSQLException(SQLState.DATABASE_NOT_FOUND, dbname);
+    }
+
 	/**
 	 * Examine boot properties and determine if a boot with the given
 	 * attributes would entail an encryption operation.
@@ -575,6 +586,38 @@
                  p.getProperty(Attribute.REPLICATION_STOP_MASTER)).
                  booleanValue()));
     }
+    
+    /**
+     * Examine the boot properties and determine if a boot with the
+     * given attributes should stop slave replication mode.
+     * 
+     * @param p The attribute set.
+     * @return true if the stopSlave attribute has been set, false
+     * otherwise.
+     */
+    private boolean isStopReplicationSlaveBoot(Properties p) {
+        return Boolean.valueOf(
+               p.getProperty(Attribute.REPLICATION_STOP_SLAVE)).
+               booleanValue();
+    }
+
+    /**
+     * Examine the boot properties and determine if a boot with the
+     * given attributes should stop slave replication mode. A
+     * connection with this property should only be made from
+     * SlaveDatabase. Make sure to call
+     * SlaveDatabase.verifyShutdownSlave() to verify that this
+     * connection is not made from a client.
+     * 
+     * @param p The attribute set.
+     * @return true if the shutdownslave attribute has been set, false
+     * otherwise.
+     */
+    private boolean isInternalShutdownSlaveDatabase(Properties p) {
+        return Boolean.valueOf(
+               p.getProperty(Attribute.REPLICATION_INTERNAL_SHUTDOWN_SLAVE)).
+               booleanValue();
+    }
 
     private void handleStartReplicationMaster(TransactionResourceImpl tr,
                                               Properties p)
@@ -639,6 +682,89 @@
         // Derby is running under.
 
         tr.getDatabase().stopReplicationMaster();
+    }
+
+    /**
+     * Stop replication slave when called from a client. Stops
+     * replication slave mode, provided that the database is in
+     * replication slave mode and has lost connection with the master
+     * database. If the connection with the master is up, the call to
+     * this method will be refused by raising an exception. The reason
+     * for refusing the stop command if the slave is connected with
+     * the master is that we cannot authenticate the user on the slave
+     * side (because the slave database has not been fully booted)
+     * whereas authentication is not a problem on the master side. If
+     * not refused, this operation will cause SlaveDatabase to call
+     * internalStopReplicationSlave
+     * 
+     * @param p The Attribute set.
+     * @exception StandardException Thrown on error, if not in replication 
+     * slave mode or if the network connection with the master is not down
+     * @exception SQLException Thrown if the database is not found
+     */
+    private void handleStopReplicationSlave(Properties p)
+        throws StandardException, SQLException {
+
+        // We cannot check authentication and authorization for
+        // databases in slave mode since the AuthenticationService has
+        // not been booted for the database
+
+        if (getTR().getDatabase() == null) {
+            handleDBNotFound();
+        }
+
+        Database database = getTR().getDatabase();
+
+        database.stopReplicationSlave();
+        // throw an exception to the client
+        throw newSQLException(SQLState.REPLICATION_SLAVE_SHUTDOWN_OK,
+                              getTR().getDBName());
+    }
+
+    /**
+     * Stop replication slave when called from SlaveDatabase. Called
+     * when slave replication mode has been stopped, and all that
+     * remains is to shutdown the database. This happens if
+     * handleStopReplicationSlave has successfully requested the slave
+     * to stop, if the replication master has requested the slave to
+     * stop using the replication network, or if a fatal exception has
+     * occurred in the database.
+     *    
+     * @param p The Attribute set.
+     * @exception StandardException Thrown on error or if not in replication 
+     * slave mode
+     * @exception SQLException Thrown if the database is not found
+     */
+    private void internalStopReplicationSlave(Properties p)
+        throws StandardException, SQLException {
+
+        // We cannot check authentication and authorization for
+        // databases in slave mode since the AuthenticationService has
+        // not been booted for the database
+
+        if (getTR().getDatabase() == null) {
+            handleDBNotFound();
+        }
+
+        Database database = getTR().getDatabase();
+
+        if (isInternalShutdownSlaveDatabase(p)) {
+            // We should only get here if the connection is made from
+            // inside SlaveDatabase. To verify, we ask SlaveDatabase
+            // if it requested this shutdown. If it didn't,
+            // verifyShutdownSlave will throw an exception
+            if (! (database instanceof SlaveDatabase)) {
+                throw newSQLException(
+                           SQLState.REPLICATION_NOT_IN_SLAVE_MODE,
+                           getTR().getDBName());
+            }
+            ((SlaveDatabase)database).verifyShutdownSlave();
+
+            // Will shutdown the database without writing to the log
+            // since the SQLException with state
+            // REPLICATION_SLAVE_SHUTDOWN_OK will be reported anyway
+            handleException(tr.shutdownDatabaseException());
+        }
     }
 
 	/**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/net/ReplicationMessageReceive.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/net/ReplicationMessageReceive.java?rev=617501&r1=617500&r2=617501&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/net/ReplicationMessageReceive.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/net/ReplicationMessageReceive.java
Fri Feb  1 06:02:01 2008
@@ -165,6 +165,22 @@
     }
     
     /**
+     * Used to close the <code>ServerSocket</code> and the resources
+     * associated with it.
+     *
+     * @throws IOException If an exception occurs while trying to
+     *                     close the socket or the associated resources.
+     */
+    public void tearDown() throws IOException {
+        if (socketConn != null) {
+            socketConn.tearDown();
+        }
+        if (serverSocket != null) {
+            serverSocket.close();
+        }
+    }
+    
+    /**
      * Used to parse the initiator message from the master and check if the
      * slave is compatible with the master by comparing the UID of the 
      * <code>ReplicationMessage</code> class of the master, that is wrapped

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/net/SocketConnection.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/net/SocketConnection.java?rev=617501&r1=617500&r2=617501&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/net/SocketConnection.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/net/SocketConnection.java
Fri Feb  1 06:02:01 2008
@@ -99,4 +99,17 @@
         //in this stream.
         objOutputStream.flush();
     }
+    
+    /**
+     * Closes the <code>Socket</code> and the object streams obtained
+     * from it.
+     *
+     * @throws IOException if an exception occurs while trying to close
+     *                     the socket or the streams.
+     */
+    public void tearDown() throws IOException {
+        objInputStream.close();
+        objOutputStream.close();
+        socket.close();
+    }
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/slave/SlaveController.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/slave/SlaveController.java?rev=617501&r1=617500&r2=617501&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/slave/SlaveController.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/slave/SlaveController.java
Fri Feb  1 06:02:01 2008
@@ -25,6 +25,7 @@
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.reference.Attribute;
 import org.apache.derby.iapi.reference.MessageId;
+import org.apache.derby.iapi.reference.Property;
 import org.apache.derby.iapi.reference.SQLState;
 import org.apache.derby.iapi.services.monitor.ModuleControl;
 import org.apache.derby.iapi.services.monitor.ModuleSupportable;
@@ -34,12 +35,14 @@
 import org.apache.derby.iapi.store.raw.log.LogFactory;
 import org.apache.derby.impl.store.raw.log.LogToFile;
 
+import org.apache.derby.impl.db.SlaveDatabase;
 import org.apache.derby.impl.services.replication.ReplicationLogger;
 import org.apache.derby.impl.services.replication.net.ReplicationMessage;
 import org.apache.derby.impl.services.replication.net.ReplicationMessageReceive;
 import org.apache.derby.iapi.services.replication.slave.SlaveFactory;
 
 import java.io.EOFException;
+import java.io.IOException;
 import java.net.SocketTimeoutException;
 import java.util.Properties;
 
@@ -72,7 +75,9 @@
     private RawStoreFactory rawStoreFactory;
     private LogToFile logToFile;
     private ReplicationMessageReceive receiver;
+    private SlaveDatabase slaveDb;
 
+    private volatile boolean connectedToMaster = false;
     private String slavehost;
     private int slaveport;
     private String dbname; // The name of the replicated database
@@ -124,12 +129,19 @@
     }
 
     /**
-     * Will tear down the replication slave service. Should be called
-     * after either stopSlave or failover have been called.
-     *
-     * Not implemented yet
+     * Will tear down the replication slave service. 
      */
-    public void stop() { }
+    public void stop() { 
+        if (inReplicationSlaveMode) {
+            // For some reason, stopSlave or failover have not been
+            // called yet. Force slave to stop.
+            try {
+                stopSlave(true);
+            } catch (StandardException se) {
+                // do nothing
+            }
+        }
+    }
 
     ////////////////////////////////////////////////////////////////
     // Implementation of methods from interface ModuleSupportable //
@@ -180,6 +192,24 @@
     public void startSlave(RawStoreFactory rawStore, LogFactory logFac)
         throws StandardException {
 
+        slaveDb = (SlaveDatabase)
+                Monitor.findService(Property.DATABASE_MODULE, dbname);
+        slaveDb.setSlaveFactory(this);
+
+        rawStoreFactory = rawStore;
+
+        try {
+            logToFile = (LogToFile)logFac;
+        } catch (ClassCastException cce) {
+            // Since there are only two implementing classes of
+            // LogFactory, the class type has to be ReadOnly if it is
+            // not LogToFile.
+            throw StandardException.newException(
+                SQLState.LOGMODULE_DOES_NOT_SUPPORT_REPLICATION);
+        }
+
+        logToFile.initializeReplicationSlaveRole();
+
         // Retry to setup a connection with the master until a
         // connection has been established or until we are no longer
         // in replication slave mode
@@ -199,19 +229,6 @@
         // from the master
         logScan = new ReplicationLogScan();
 
-        rawStoreFactory = rawStore;
-
-        try {
-            logToFile = (LogToFile)logFac;
-        } catch (ClassCastException cce) {
-            // Since there are only two implementing classes of
-            // LogFactory, the class type has to be ReadOnly if it is
-            // not LogToFile.
-            throw StandardException.newException(
-                SQLState.CANNOT_REPLICATE_READONLY_DATABASE);
-        }
-
-        logToFile.initializeReplicationSlaveRole();
         startLogReceiverThread();
 
         Monitor.logTextMessage(MessageId.REPLICATION_SLAVE_STARTED, dbname);
@@ -219,17 +236,45 @@
 
     /**
      * Will perform all work that is needed to stop replication
-     *
-     * Not implemented yet
      */
-    public void stopSlave() {
+    private void stopSlave() throws StandardException {
         inReplicationSlaveMode = false;
 
-        // todo: shutdown slave
+        try {
+            if (logReceiverThread != null) {
+                logReceiverThread.interrupt();
+            }
+        } catch (SecurityException se) {
+            // Do nothing - the logReceiverThread will get an
+            // exception when receiver.tearDown is called below
+        }
+
+        try {
+            // Unplug the replication network connection layer
+            receiver.tearDown(); 
+        } catch (IOException ioe) {
+            ReplicationLogger.logError(null, ioe, dbname);
+        }
+
+        logToFile.flushAll();
+        logToFile.stopReplicationSlaveMode();
+
         Monitor.logTextMessage(MessageId.REPLICATION_SLAVE_STOPPED, dbname);
     }
 
     /**
+     * @see SlaveFactory#stopSlave
+     */
+    public void stopSlave(boolean forcedStop) 
+            throws StandardException {
+        if (!forcedStop && connectedToMaster){
+            throw StandardException.newException(
+                    SQLState.SLAVE_STOP_DENIED_WHILE_CONNECTED);
+        }
+        stopSlave();
+    }
+
+    /**
      * <p>
      * Used to turn this slave instance of the database into a normal
      * instance that clients can connect to. This is typically done in
@@ -256,7 +301,7 @@
      */
     public void failover() {
         inReplicationSlaveMode = false;
-        logToFile.stopReplicationSlaveRole();
+        logToFile.failoverSlave();
         Monitor.logTextMessage
                 (MessageId.REPLICATION_FAILOVER_SUCCESSFUL, dbname);
     }
@@ -281,6 +326,7 @@
         try {
             // timeout to check if still in replication slave mode
             receiver.initConnection(DEFAULT_SOCKET_TIMEOUT);
+            connectedToMaster = true;
             return true; // will not reach this if timeout
         } catch (StandardException se) {
             throw se;
@@ -305,16 +351,17 @@
      * without doing anything if inReplicationSlaveMode=false, which
      * means that stopSlave() has been called by another thread.
      *
-     * @param eofe The reason the connection to the master was lost
+     * @param e The reason the connection to the master was lost
      */
 
-    private void handleDisconnect(EOFException eofe) {
+    private void handleDisconnect(Exception e) {
+        connectedToMaster = false;
         if (!inReplicationSlaveMode) {
             return;
         }
 
         ReplicationLogger.
-            logError(MessageId.REPLICATION_SLAVE_LOST_CONN, eofe, dbname);
+            logError(MessageId.REPLICATION_SLAVE_LOST_CONN, e, dbname);
 
         try {
             while (!setupConnection()) {

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/RawStore.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/RawStore.java?rev=617501&r1=617500&r2=617501&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/RawStore.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/RawStore.java Fri Feb
 1 06:02:01 2008
@@ -482,7 +482,7 @@
 
         if (isReadOnly()) {
             throw StandardException.newException(
-                      SQLState.CANNOT_REPLICATE_READONLY_DATABASE);
+                      SQLState.LOGMODULE_DOES_NOT_SUPPORT_REPLICATION);
         }
 
         Properties replicationProps = new Properties();
@@ -512,7 +512,7 @@
         
         if (isReadOnly()) {
             throw StandardException.newException(
-                      SQLState.CANNOT_REPLICATE_READONLY_DATABASE);
+                      SQLState.LOGMODULE_DOES_NOT_SUPPORT_REPLICATION);
         }
 
         try {

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/log/LogToFile.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/log/LogToFile.java?rev=617501&r1=617500&r2=617501&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/log/LogToFile.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/log/LogToFile.java Fri
Feb  1 06:02:01 2008
@@ -424,6 +424,10 @@
 
     // initialized if this Derby has the SLAVE role for this database
     private boolean inReplicationSlaveMode = false;
+    /** If this exception is set while in replication slave mode, the 
+     * exception will be thrown by the thread doing recovery will. 
+     * Effectively, this whill shut down the database */
+    private volatile StandardException replicationSlaveException = null;
 
     /** True if the database has been booted in replication slave pre
      * mode, effectively turning off writes to the log file.
@@ -701,6 +705,9 @@
                 while (inReplicationSlaveMode &&
                        (allowedToReadFileNumber<bootTimeLogFileNumber)) {
                     // Wait until the first log file can be read.
+                    if (replicationSlaveException != null) {
+                        throw replicationSlaveException;
+                    }
                     try {
                         slaveRecoveryMonitor.wait();
                     } catch (InterruptedException ie) {
@@ -2892,6 +2899,9 @@
                 // may have changed while the thread was waiting.
                 while (inReplicationSlaveMode &&
                        (filenumber > allowedToReadFileNumber)) {
+                    if (replicationSlaveException != null) {
+                        throw replicationSlaveException;
+                    }
                     try {
                         slaveRecoveryMonitor.wait();
                     } catch (InterruptedException ie) {
@@ -5070,6 +5080,28 @@
     }
 
     /**
+     * Stop the slave functionality for this LogFactory. Calling this
+     * method causes the thread currently doing recovery to stop the
+     * recovery process and throw a StandardException with SQLState
+     * SHUTDOWN_DATABASE. This should only be done when the database
+     * will be shutdown.
+     * @see org.apache.derby.impl.db.SlaveDatabase
+     */
+    public void stopReplicationSlaveMode() {
+        // Do not set inReplicationSlaveMode=false here because that
+        // will let the thread currently doing recover complete the
+        // boot process. Setting replicationSlaveException aborts the
+        // boot process.
+        replicationSlaveException =
+                StandardException.newException(
+                SQLState.SHUTDOWN_DATABASE);
+
+        synchronized (slaveRecoveryMonitor) {
+            slaveRecoveryMonitor.notify();
+        }
+    }
+
+    /**
      * Used by LogAccessFile to check if it should take the
      * replication master role, and thereby send log records to the
      * MasterFactory.
@@ -5185,7 +5217,7 @@
      * Used to make the slave stop appending log records, complete recovery 
      * and boot the database.
      */
-    public void stopReplicationSlaveRole() {
+    public void failoverSlave() {
         inReplicationSlaveMode = false;
     }
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/log/ReadOnly.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/log/ReadOnly.java?rev=617501&r1=617500&r2=617501&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/log/ReadOnly.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/log/ReadOnly.java Fri
Feb  1 06:02:01 2008
@@ -454,7 +454,7 @@
     public void startReplicationMasterRole(MasterFactory masterFactory)
         throws StandardException {
         throw StandardException.newException(
-                  SQLState.CANNOT_REPLICATE_READONLY_DATABASE);
+                  SQLState.LOGMODULE_DOES_NOT_SUPPORT_REPLICATION);
     }
 
     /** Replication not applicable on readonly databases */

Modified: db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml?rev=617501&r1=617500&r2=617501&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml Fri Feb  1 06:02:01
2008
@@ -4723,7 +4723,7 @@
 
             <msg>
                 <name>XRE00</name>
-                <text>Cannot start replication for a read-only database.</text>
+                <text>This LogFactory module does not support replicatiosn.</text>
             </msg>
             <msg>
                 <name>XRE01</name>
@@ -4791,6 +4791,27 @@
                 <name>XRE21</name>
                 <text>Error occurred while performing failover for database '{0}',
Failover attempt was aborted.</text>
                 <arg>dbname</arg>
+            </msg>
+
+            <msg>
+                <name>XRE40</name>
+                <text>Could not perform operation because the database is not in replication
slave mode.</text>
+            </msg>
+
+            <msg>
+                <name>XRE41</name>
+                <text>Replication operation 'failover' or 'stopSlave' refused on the
slave database because the connection with the master is working. Issue the 'failover' or
'stopMaster' operation on the master database instead.</text>
+            </msg>
+
+            <msg>
+                <name>XRE42</name>
+                <text>Replicated database '{0}' shutdown.</text>
+                <arg>dbname</arg>
+            </msg>
+
+            <msg>
+                <name>XRE43</name>
+                <text>Unexpected error when trying to stop replication slave mode.
To stop repliation slave mode, use operation 'stopSlave' or 'failover'.</text>
             </msg>
 
         </family>

Modified: db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/Attribute.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/Attribute.java?rev=617501&r1=617500&r2=617501&view=diff
==============================================================================
--- db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/Attribute.java
(original)
+++ db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/Attribute.java
Fri Feb  1 06:02:01 2008
@@ -113,6 +113,12 @@
     String REPLICATION_STOP_SLAVE = "stopSlave";
 
     /**
+     * Attribute name to stop replication slave mode for a database.
+     * Internal use only
+     */
+    String REPLICATION_INTERNAL_SHUTDOWN_SLAVE = "internal_stopslave";
+
+    /**
      * If startMaster is true, this attribute is used to specify the
      * host name the master should connect to. This is a required
      * attribute.

Modified: db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java?rev=617501&r1=617500&r2=617501&view=diff
==============================================================================
--- db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
(original)
+++ db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
Fri Feb  1 06:02:01 2008
@@ -1757,7 +1757,7 @@
     /*
     ** Replication XRExx
     */
-    String CANNOT_REPLICATE_READONLY_DATABASE                      = "XRE00";
+    String LOGMODULE_DOES_NOT_SUPPORT_REPLICATION                  = "XRE00";
     String REPLICATION_LOG_CORRUPTED                               = "XRE01";
     String REPLICATION_MASTER_SLAVE_VERSION_MISMATCH               = "XRE02";
     String REPLICATION_UNEXPECTED_EXCEPTION                        = "XRE03";
@@ -1770,5 +1770,9 @@
     String REPLICATION_CONFLICTING_ATTRIBUTES                      = "XRE10";
     String REPLICATION_FAILOVER_SUCCESSFUL                         = "XRE20.D";
     String REPLICATION_FAILOVER_UNSUCCESSFUL                       = "XRE21";
+    String REPLICATION_NOT_IN_SLAVE_MODE                           = "XRE40";
+    String SLAVE_STOP_DENIED_WHILE_CONNECTED                       = "XRE41";
+    String REPLICATION_SLAVE_SHUTDOWN_OK                           = "XRE42";
+    String REPLICATION_STOPSLAVE_NOT_INITIATED                     = "XRE43";
 }
 



Mime
View raw message