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/01/18 09:22:07 UTC

svn commit: r613097 - in /db/derby/code/trunk/java: engine/org/apache/derby/iapi/reference/ engine/org/apache/derby/impl/jdbc/ engine/org/apache/derby/loc/ shared/org/apache/derby/shared/common/reference/

Author: oysteing
Date: Fri Jan 18 00:22:06 2008
New Revision: 613097

URL: http://svn.apache.org/viewvc?rev=613097&view=rev
Log:
DERBY-3205: Implement connection url attribute for starting slave. 
(Contributed by Jorgen Loland)

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.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/iapi/reference/Attribute.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java?rev=613097&r1=613096&r2=613097&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 Jan 18 00:22:06 2008
@@ -113,6 +113,16 @@
     String REPLICATION_STOP_MASTER = "stopMaster";
 
     /**
+     * Attribute name to start replication slave mode for a database.
+     */
+    String REPLICATION_START_SLAVE = "startSlave";
+
+    /**
+     * Attribute name to stop replication slave mode for a database.
+     */
+    String REPLICATION_STOP_SLAVE = "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/impl/jdbc/EmbedConnection.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java?rev=613097&r1=613096&r2=613097&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 Jan 18 00:22:06 2008
@@ -48,6 +48,9 @@
 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
 import org.apache.derby.iapi.store.access.XATransactionController;
 
+import org.apache.derby.iapi.services.replication.master.MasterFactory;
+import org.apache.derby.iapi.services.replication.slave.SlaveFactory;
+
 /* can't import due to name overlap:
 import java.sql.Connection;
 import java.sql.ResultSet;
@@ -229,11 +232,38 @@
 												isEncryptionBoot(info));
 			boolean isTwoPhaseUpgradeBoot = (!createBoot &&
 											 isHardUpgradeBoot(info));
+			boolean isStartSlaveBoot = isStartReplicationSlaveBoot(info);
 
 			// Save original properties if we modified them for
 			// two phase encryption or upgrade boot.
 			Properties savedInfo = null;
 
+            if (isStartSlaveBoot) {
+                if (database != null) {
+                    throw StandardException.newException(
+                        SQLState.CANNOT_START_SLAVE_ALREADY_BOOTED,
+                        getTR().getDBName());
+                } else if (createBoot ||
+                           shutdown ||
+                           isTwoPhaseEncryptionBoot ||
+                           isTwoPhaseUpgradeBoot) {
+                    throw StandardException.newException(
+                        SQLState.REPLICATION_CONFLICTING_ATTRIBUTES,
+                        Attribute.REPLICATION_START_SLAVE);
+                }
+
+                // We need to boot the slave database two times. The
+                // first boot will check authentication and
+                // authorization. The second boot will put the
+                // database in replication slave mode. SLAVE_PRE_MODE
+                // ensures that log records are not written to disk
+                // during the first boot. This is necessary because
+                // the second boot needs a log that is exactly equal
+                // to the log at the master.
+                info.setProperty(SlaveFactory.REPLICATION_MODE,
+                                 SlaveFactory.SLAVE_PRE_MODE);
+            }
+
 			if (database != null)
 			{
 				// database already booted by someone else
@@ -312,23 +342,56 @@
 				handleStopReplicationMaster(tr, info);
 			}
 
-			if (isTwoPhaseEncryptionBoot || isTwoPhaseUpgradeBoot) {
-
-				// DERBY-2264: shutdown and boot again with encryption or
-				// upgrade attributes active. This is restricted to the
-				// database owner if authentication and sqlAuthorization is on.
+			if (isTwoPhaseEncryptionBoot ||
+				isTwoPhaseUpgradeBoot ||
+				isStartSlaveBoot) {
+
+				// shutdown and boot again with encryption, upgrade or
+				// start replication slave attributes active. This is
+				// restricted to the database owner if authentication
+				// and sqlAuthorization is on.
 				if (!usingNoneAuth &&
 						getLanguageConnection().usesSqlAuthorization()) {
-					// a failure here leaves database booted, but no
-					// (re)encryption has taken place and the connection is
-					// rejected.
-					checkIsDBOwner(isTwoPhaseEncryptionBoot? OP_ENCRYPT :
-								   OP_HARD_UPGRADE);
+					int operation;
+					if (isTwoPhaseEncryptionBoot) {
+						operation = OP_ENCRYPT;
+					} else if (isTwoPhaseUpgradeBoot) {
+						operation = OP_HARD_UPGRADE;
+					} else {
+						operation = OP_REPLICATION;
+					}
+					try {
+						// a failure here leaves database booted, but no
+						// (re)encryption has taken place and the connection is
+						// rejected.
+						checkIsDBOwner(operation);
+					} catch (SQLException sqle) {
+						if (isStartSlaveBoot) {
+							// If authorization fails for the start
+							// slave command, we want to shutdown the
+							// database which is currently in the
+							// SLAVE_PRE_MODE.
+							handleException(tr.shutdownDatabaseException());
+						}
+						throw sqle;
+					}
+				}
+
+				if (isStartSlaveBoot) {
+					// Let the next boot of the database be
+					// replication slave mode
+					info.setProperty(SlaveFactory.REPLICATION_MODE,
+									 SlaveFactory.SLAVE_MODE);
+					info.setProperty(SlaveFactory.SLAVE_DB,
+									 getTR().getDBName());
+				} else {
+					// reboot using saved properties which
+					// include the (re)encyption or upgrade attribute(s)
+					info = savedInfo;
 				}
 
-				// shutdown and reboot using saved properties which
-				// include the (re)encyption or upgrade attribute(s)
-				info = savedInfo;
+                // Authentication and authorization done - shutdown
+                // the database
 				handleException(tr.shutdownDatabaseException());
 				restoreContextStack();
 				tr = new TransactionResourceImpl(driver, url, info);
@@ -336,6 +399,8 @@
 				setupContextStack();
 				context = pushConnectionContext(tr.getContextManager());
 
+                // Reboot the database in the correct
+                // encrypt/upgrade/slave replication mode
 				if (!bootDatabase(info, false))
 				{
 					if (SanityManager.DEBUG) {
@@ -347,9 +412,20 @@
 					setInactive();
 					return;
 				}
-				// don't need to check user credentials again, did
-				// that on first plain boot, so just start
-				tr.startTransaction();
+
+				if (isStartSlaveBoot) {
+					// We don't return a connection to the client who
+					// called startSlave. Rather, we throw an
+					// exception stating that replication slave mode
+					// has been successfully started for the database
+					throw StandardException.newException(
+						SQLState.REPLICATION_SLAVE_STARTED_OK,
+						getTR().getDBName());
+				} else {
+					// don't need to check user credentials again, did
+					// that on first plain boot, so just start
+					tr.startTransaction();
+				}
 			}
 
 			// now we have the database connection, we can shut down
@@ -482,6 +558,12 @@
 			p.getProperty(Attribute.UPGRADE_ATTR)).booleanValue();
 	}
 
+    private boolean isStartReplicationSlaveBoot(Properties p) {
+        return ((Boolean.valueOf(
+                 p.getProperty(Attribute.REPLICATION_START_SLAVE)).
+                 booleanValue()));
+    }
+
     private boolean isStartReplicationMasterBoot(Properties p) {
         return ((Boolean.valueOf(
                  p.getProperty(Attribute.REPLICATION_START_MASTER)).
@@ -533,9 +615,7 @@
 
         tr.getDatabase().startReplicationMaster(slavehost,
                                                 slaveport,
-                                                org.apache.derby.iapi.
-                                                services.replication.
-                                                master.MasterFactory.
+                                                MasterFactory.
                                                 ASYNCHRONOUS_MODE);
     }
 

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=613097&r1=613096&r2=613097&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 Jan 18 00:22:06 2008
@@ -4763,6 +4763,23 @@
                 <text>Could not stop replication because the database is not in replication master mode.</text>
             </msg>
 
+            <msg>
+                <name>XRE08</name>
+                <text>Replication slave mode started successfully for database '{0}'. Connection refused because the database is in replication slave mode. </text>
+                <arg>dbname</arg>
+            </msg>
+
+            <msg>
+                <name>XRE09</name>
+                <text>Cannot start replication slave mode for database '{0}'. The database has already been booted. </text>
+                <arg>dbname</arg>
+            </msg>
+
+            <msg>
+                <name>XRE10</name>
+                <text>Conflicting attributes specified. See reference manual for attributes allowed in combination with replication attribute '{0}'.</text>
+                <arg>attribute</arg>
+            </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=613097&r1=613096&r2=613097&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 Jan 18 00:22:06 2008
@@ -103,6 +103,16 @@
     String REPLICATION_STOP_MASTER = "stopMaster";
 
     /**
+     * Attribute name to start replication slave mode for a database.
+     */
+    String REPLICATION_START_SLAVE = "startSlave";
+
+    /**
+     * Attribute name to stop replication slave mode for a database.
+     */
+    String REPLICATION_STOP_SLAVE = "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=613097&r1=613096&r2=613097&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 Jan 18 00:22:06 2008
@@ -1765,5 +1765,8 @@
     String REPLICATION_LOG_OUT_OF_SYNCH                            = "XRE05";
     String REPLICATION_MASTER_TIMED_OUT                            = "XRE06";
     String REPLICATION_UNABLE_TO_STOP_MASTER                       = "XRE07";
+    String REPLICATION_SLAVE_STARTED_OK                            = "XRE08";
+    String CANNOT_START_SLAVE_ALREADY_BOOTED                       = "XRE09";
+    String REPLICATION_CONFLICTING_ATTRIBUTES                      = "XRE10";
 }