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 2007/09/14 15:19:28 UTC
svn commit: r575670 - in /db/derby/code/trunk/java: engine/org/apache/derby/
engine/org/apache/derby/iapi/services/replication/slave/
engine/org/apache/derby/impl/db/
engine/org/apache/derby/impl/services/replication/slave/
engine/org/apache/derby/impl...
Author: oysteing
Date: Fri Sep 14 06:19:26 2007
New Revision: 575670
URL: http://svn.apache.org/viewvc?rev=575670&view=rev
Log:
DERBY-3021: Add a ReplicationSlave controller that will manage
replication on the slave side
Contributed by Jørgen Løland
Added:
db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/replication/slave/
db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/replication/slave/SlaveFactory.java (with props)
db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/slave/SlaveController.java (with props)
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/impl/db/BasicDatabase.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/loc/messages.xml
db/derby/code/trunk/java/engine/org/apache/derby/modules.properties
db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ErrorCodeTest.java
Added: 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=575670&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/replication/slave/SlaveFactory.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/replication/slave/SlaveFactory.java Fri Sep 14 06:19:26 2007
@@ -0,0 +1,116 @@
+/*
+
+ Derby - Class
+ org.apache.derby.iapi.services.replication.slave.SlaveFactory
+
+ 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.derby.iapi.services.replication.slave;
+
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.reference.Property;
+
+import org.apache.derby.iapi.store.raw.RawStoreFactory;
+import org.apache.derby.iapi.store.raw.log.LogFactory;
+import org.apache.derby.iapi.store.raw.data.DataFactory;
+
+/**
+ * <p>
+ * This is the interface for the replication slave controller
+ * service. The slave controller service is booted when this instance
+ * of Derby will have the replication slave role for this database.
+ * </p>
+ * <p>
+ * The replication slave service is responsible for managing all
+ * replication related functionality on the slave side of replication.
+ * This includes connecting to the master and apply log records
+ * received from the master.
+ * </p>
+ */
+public interface SlaveFactory {
+
+ /** The name of the Slave Factory, used to boot the service. */
+ public static final String MODULE =
+ "org.apache.derby.iapi.services.replication.slave.SlaveFactory";
+
+ /* Strings used as keys in the Properties objects*/
+
+ /** Property key to specify which port to listen to */
+ public static final String SLAVE_PORT =
+ Property.PROPERTY_RUNTIME_PREFIX + "replication.slave.slaveport";
+
+ /** Property key to specify replication mode */
+ public static final String REPLICATION_MODE =
+ Property.PROPERTY_RUNTIME_PREFIX + "replication.slave.mode";
+
+ /* Strings used as values in the Properties objects */
+
+ /**
+ * Property value used to indicate that the service should be
+ * booted in asynchronous replication mode.
+ */
+ public static final String SLAVE_MODE =
+ Property.PROPERTY_RUNTIME_PREFIX + "slavemode";
+
+
+ /* Required methods */
+
+ /**
+ * Start slave replication. This method establishes a network
+ * connection with the associated replication master and starts a
+ * daemon that applies operations received from the master (in the
+ * form of log records) to the local slave database.
+ *
+ * @param rawStore The RawStoreFactory for the database
+ * @param logFac The LogFactory ensuring recoverability for this database
+ */
+ public void startSlave(RawStoreFactory rawStore, LogFactory logFac);
+
+ /**
+ * Will perform all work that is needed to stop replication
+ */
+ public void 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
+ * cases where a fatal error has happened on the master instance
+ * of the database, or when the master database is unreachable due
+ * to network problems.
+ * </p>
+ * <p>
+ * By calling failover, this slave instance of the database will
+ * be recovered so that all committed operations that have been
+ * received from the master are reflected here. On the other hand,
+ * operations from transactions where the commit log record has
+ * not been received from the master will not be reflected.
+ * </p>
+ * <p>
+ * Note that even though an operation has been executed (and even
+ * committed) on the master, it is not neccessarily reflected in
+ * the slave instance of the database. This depends on the
+ * replication strategy used by the MasterFactory.
+ * </p>
+ *
+ * @see org.apache.derby.iapi.services.replication.master.MasterFactory
+ * @see org.apache.derby.impl.services.replication.master.MasterController#flushedTo
+ */
+ public void failover();
+
+}
Propchange: db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/replication/slave/SlaveFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
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=575670&r1=575669&r2=575670&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 Sep 14 06:19:26 2007
@@ -73,6 +73,8 @@
import org.apache.derby.io.StorageFile;
import org.apache.derby.catalog.UUID;
+import org.apache.derby.iapi.services.replication.slave.SlaveFactory;
+
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
@@ -133,6 +135,7 @@
private DateFormat timestampFormat;
private UUID myUUID;
private boolean normalizeToUpper = true;
+ private boolean inReplicationSlaveMode = false;
protected boolean lastToBoot; // is this class last to boot
@@ -147,6 +150,14 @@
public void boot(boolean create, Properties startParams)
throws StandardException
{
+
+ // Database is booted in replication slave mode. Make sure
+ // other clients are not able to connect
+ String slave = startParams.getProperty(SlaveFactory.REPLICATION_MODE);
+ if (slave != null && slave.equals(SlaveFactory.SLAVE_MODE)) {
+ inReplicationSlaveMode = true;
+ }
+
ModuleFactory monitor = Monitor.getMonitor();
if (create)
{
@@ -285,6 +296,13 @@
public LanguageConnectionContext setupConnection(ContextManager cm, String user, String drdaID, String dbname)
throws StandardException {
+
+ if (inReplicationSlaveMode) {
+ // do not allow connections to a database that is
+ // currently in replication slave move
+ throw StandardException.newException(
+ SQLState.CANNOT_CONNECT_TO_DB_IN_SLAVE_MODE, dbname);
+ }
TransactionController tc = getConnectionTransaction(cm);
Added: 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=575670&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/slave/SlaveController.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/slave/SlaveController.java Fri Sep 14 06:19:26 2007
@@ -0,0 +1,212 @@
+/*
+
+ Derby - Class
+ org.apache.derby.impl.services.replication.slave.SlaveController
+
+ 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.derby.impl.services.replication.slave;
+
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.reference.SQLState;
+import org.apache.derby.iapi.services.monitor.ModuleControl;
+import org.apache.derby.iapi.services.monitor.ModuleSupportable;
+
+import org.apache.derby.iapi.store.raw.RawStoreFactory;
+import org.apache.derby.iapi.store.raw.log.LogFactory;
+
+import org.apache.derby.iapi.services.replication.slave.SlaveFactory;
+
+import java.util.Properties;
+
+/**
+ * <p>
+ * This is an implementation of the replication slave controller
+ * service. The service is booted when this instance of Derby will
+ * have the replication slave role for this database.
+ * </p>
+ * <p>
+ * Note: The current version of the class is far from complete. Code
+ * to control the replication slave behavior will be added as more
+ * parts of the replication functionality is added to Derby.
+ * </p>
+ *
+ * @see SlaveFactory
+ */
+public class SlaveController implements SlaveFactory, ModuleControl,
+ ModuleSupportable {
+
+ private RawStoreFactory rawStoreFactory;
+ private LogFactory logFactory;
+ // waiting for code to go into trunk:
+ // private NetworkReceive connection;
+
+ private int slaveport;
+
+ /**
+ * Empty constructor required by Monitor.bootServiceModule
+ */
+ public SlaveController() { }
+
+ ////////////////////////////////////////////////////////////
+ // Implementation of methods from interface ModuleControl //
+ ////////////////////////////////////////////////////////////
+
+ /**
+ * Used by Monitor.bootServiceModule to start the service. It will
+ * set up basic variables
+ *
+ * Not implemented yet
+ *
+ * @param create Currently ignored
+ * @param properties Properties used to start the service in the
+ * correct mode
+ * @exception StandardException Standard Derby exception policy,
+ * thrown on error.
+ */
+ public void boot(boolean create, Properties properties)
+ throws StandardException {
+
+ String port = properties.getProperty(SlaveFactory.SLAVE_PORT);
+ if (port != null) {
+ slaveport = new Integer(port).intValue();
+ }
+
+ // Added when Network Service has been committed to trunk
+ // connection = new NetworkReceive();
+
+ System.out.println("SlaveController booted");
+ }
+
+ /**
+ * Will tear down the replication slave service. Should be called
+ * after either stopSlave or failover have been called.
+ *
+ * Not implemented yet
+ */
+ public void stop() { }
+
+ ////////////////////////////////////////////////////////////////
+ // Implementation of methods from interface ModuleSupportable //
+ ////////////////////////////////////////////////////////////////
+
+ /**
+ * Used by Monitor.bootServiceModule to check if this class is
+ * usable for replication. To be usable, we require that slave
+ * replication mode is specified in startParams by checking that a
+ * property with key SlaveFactory.REPLICATION_MODE has the value
+ * SlaveFactory.SLAVE_MODE.
+ * @param startParams The properties used to start replication
+ * @return true if slave repliation is specified, meaning that
+ * this MasterController is a suitable implementation for the
+ * SlaveFactory service. False otherwise.
+ * @see ModuleSupportable#canSupport
+ */
+ public boolean canSupport(Properties startParams) {
+ String modeParam =
+ startParams.getProperty(SlaveFactory.REPLICATION_MODE);
+
+ // currently only one attribute: slave replication mode
+ if (modeParam != null &&
+ modeParam.equals(SlaveFactory.SLAVE_MODE)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////
+ // Implementation of methods from interface SlaveFactory //
+ ///////////////////////////////////////////////////////////
+
+ /**
+ * Start slave replication. This method establishes a network
+ * connection with the associated replication master and starts a
+ * daemon that applies operations received from the master (in the
+ * form of log records) to the local slave database.
+ *
+ * Not implemented yet
+ *
+ * @param rawStore The RawStoreFactory for the database
+ * @param logFac The LogFactory ensuring recoverability for this database
+ */
+ public void startSlave(RawStoreFactory rawStore, LogFactory logFac) {
+ // Added when Network Service has been committed to trunk:
+ // connection.connect(); // sets up a network connection to the slave
+
+ rawStoreFactory = rawStore;
+ logFactory = logFac;
+
+ // Add code that initializes replication by setting up a
+ // network connection with the master, receiving the database
+ // from the master, make a DaemonService for applying log
+ // records etc. Repliation should be up and running when this
+ // method returns.
+
+ System.out.println("SlaveController started");
+ }
+
+ /**
+ * Will perform all work that is needed to stop replication
+ *
+ * Not implemented yet
+ */
+ public void stopSlave() {
+ System.out.println("SlaveController stopped");
+ }
+
+ /**
+ * <p>
+ * Used to turn this slave instance of the database into a normal
+ * instance that clients can connect to. This is typically done in
+ * cases where a fatal error has happened on the master instance
+ * of the database, or when the master database is unreachable due
+ * to network problems.
+ * </p>
+ * <p>
+ * By calling failover, this slave instance of the database will
+ * be recovered so that all committed operations that have been
+ * received from the master are reflected here. On the other hand,
+ * operations from transactions where the commit log record has
+ * not been received from the master will not be reflected.
+ * </p>
+ * <p>
+ * Note that even though an operation has been executed (and even
+ * committed) on the master, it is not neccessarily reflected in
+ * the slave instance of the database. This depends on the
+ * replication strategy used by the MasterFactory.
+ * </p>
+ *
+ * @see org.apache.derby.iapi.services.replication.master.MasterFactory
+ * @see org.apache.derby.impl.services.replication.master.MasterController#flushedTo
+ */
+ public void failover() {
+ // Apply all received log records, thus completing the boot of
+ // this database. The database can be connected to after this.
+
+ // // complete recovery of the database
+ // logFactory.setReplicationMode(false);
+
+ // Added when Network Service has been committed to trunk:
+ // connection.shutdown();
+
+ System.out.println("SlaveController failover");
+ }
+
+
+}
Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/services/replication/slave/SlaveController.java
------------------------------------------------------------------------------
svn:eol-style = native
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=575670&r1=575669&r2=575670&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 Sep 14 06:19:26 2007
@@ -89,6 +89,7 @@
import java.lang.SecurityException;
import org.apache.derby.iapi.services.replication.master.MasterFactory;
+import org.apache.derby.iapi.services.replication.slave.SlaveFactory;
/**
A Raw store that implements the RawStoreFactory module by delegating all the
@@ -108,6 +109,7 @@
protected TransactionFactory xactFactory;
protected DataFactory dataFactory;
protected LogFactory logFactory;
+ private SlaveFactory slaveFactory;
private StorageFactory storageFactory;
private SecureRandom random;
@@ -173,6 +175,14 @@
public void boot(boolean create, Properties properties)
throws StandardException
{
+
+ boolean inReplicationSlaveMode = false;
+
+ String slave = properties.getProperty(SlaveFactory.REPLICATION_MODE);
+ if (slave != null && slave.equals(SlaveFactory.SLAVE_MODE)) {
+ inReplicationSlaveMode = true;
+ }
+
dataDirectory = properties.getProperty(PersistentService.ROOT);
DaemonFactory daemonFactory =
(DaemonFactory)Monitor.startSystemModule(org.apache.derby.iapi.reference.Module.DaemonFactory);
@@ -315,6 +325,18 @@
configureDatabaseForEncryption(properties,
newCipherFactory);
}
+
+ if (inReplicationSlaveMode) {
+ // The LogFactory has already been booted in slave mode.
+ // Can now start slave replication by booting the
+ // SlaveFactory service
+ slaveFactory = (SlaveFactory)
+ Monitor.bootServiceModule(create, this,
+ getSlaveFactoryModule(),
+ properties);
+ slaveFactory.startSlave(this, logFactory);
+ }
+
}
public void stop() {
@@ -2023,6 +2045,10 @@
{
return TransactionFactory.MODULE;
}
+
+ public String getSlaveFactoryModule() {
+ return SlaveFactory.MODULE;
+ }
public String getMasterFactoryModule()
{
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=575670&r1=575669&r2=575670&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 Sep 14 06:19:26 2007
@@ -38,6 +38,8 @@
import org.apache.derby.iapi.reference.Property;
import org.apache.derby.iapi.reference.SQLState;
+import org.apache.derby.iapi.services.replication.slave.SlaveFactory;
+
import org.apache.derby.iapi.services.daemon.DaemonService;
import org.apache.derby.iapi.services.daemon.Serviceable;
import org.apache.derby.iapi.services.context.ContextManager;
@@ -474,6 +476,8 @@
private volatile boolean backupInProgress = false;
+ private boolean inSlaveMode = false;
+
/**
MT- not needed for constructor
*/
@@ -2843,6 +2847,13 @@
*/
public void boot(boolean create, Properties startParams) throws StandardException
{
+ // Is the database booted in replication slave mode?
+ String mode = startParams.getProperty(SlaveFactory.REPLICATION_MODE);
+ if (mode != null && mode.equals(SlaveFactory.SLAVE_MODE)) {
+ inSlaveMode = true;
+ // will be used when slave functionality is added to this class
+ }
+
dataDirectory = startParams.getProperty(PersistentService.ROOT);
logDevice = startParams.getProperty(Attribute.LOG_DEVICE);
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=575670&r1=575669&r2=575670&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 Sep 14 06:19:26 2007
@@ -365,6 +365,12 @@
</msg>
<msg>
+ <name>08004.C.7</name>
+ <text>Connection refused to database '{0}' because it is in replication slave mode.</text>
+ <arg>databaseName</arg>
+ </msg>
+
+ <msg>
<name>08006.C.1</name>
<text>An error occurred during connect reset and the connection has been terminated. See chained exceptions for details.</text>
</msg>
Modified: db/derby/code/trunk/java/engine/org/apache/derby/modules.properties
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/modules.properties?rev=575670&r1=575669&r2=575670&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/modules.properties (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/modules.properties Fri Sep 14 06:19:26 2007
@@ -306,9 +306,12 @@
derby.module.rawStore=org.apache.derby.impl.store.raw.RawStore
cloudscape.config.rawStore=derby
-# Replication
+# Replication Master
derby.module.replication.master=org.apache.derby.impl.services.replication.master.MasterController
cloudscape.config.replication.master=derby
+# Replication Slave
+derby.module.replication.slave=org.apache.derby.impl.services.replication.slave.SlaveController
+cloudscape.config.replication.slave=derby
#
# Support for read-only databases
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=575670&r1=575669&r2=575670&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 Sep 14 06:19:26 2007
@@ -1582,6 +1582,7 @@
String AUTH_ENCRYPT_NOT_DB_OWNER = "08004.C.5";
String AUTH_HARD_UPGRADE_NOT_DB_OWNER = "08004.C.6";
//DERBY-1828: AUTH_x_NOT_DB_OWNER used to be "2850H/I/J.C";
+ String CANNOT_CONNECT_TO_DB_IN_SLAVE_MODE = "08004.C.7";
// There can be multiple causes for 08003, which according
// to SQL2003 spec means "connection does not exist"
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ErrorCodeTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ErrorCodeTest.java?rev=575670&r1=575669&r2=575670&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ErrorCodeTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ErrorCodeTest.java Fri Sep 14 06:19:26 2007
@@ -122,6 +122,7 @@
{"08004","User '{0}' cannot shut down database '{1}'. Only the database owner can perform this operation.","40000"},
{"08004","User '{0}' cannot (re)encrypt database '{1}'. Only the database owner can perform this operation.","40000"},
{"08004","User '{0}' cannot hard upgrade database '{1}'. Only the database owner can perform this operation.","40000"},
+ {"08004","Connect refused to database '{0}' because it is in replication slave mode.","40000"},
{"08006","An error occurred during connect reset and the connection has been terminated. See chained exceptions for details.","40000"},
{"08006","Database '{0}' shutdown.","45000"},
{"0A000","The DRDA command {0} is not currently implemented. The connection has been terminated.","40000"},