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 oy...@apache.org on 2008/02/01 15:02:22 UTC
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...
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";
}