blob: e4571d1881e8e64256455c428287369bf244a58a [file] [log] [blame]
/*-
* Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle Berkeley
* DB Java Edition made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle Berkeley DB Java Edition for a copy of the
* license and additional information.
*/
package com.sleepycat.je.rep;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.Properties;
import com.sleepycat.je.Durability;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.config.ConfigParam;
import com.sleepycat.je.config.EnvironmentParams;
import com.sleepycat.je.dbi.DbConfigManager;
import com.sleepycat.je.rep.impl.RepImpl;
import com.sleepycat.je.rep.impl.RepParams;
/**
* Specifies the attributes that may be changed after a {@link
* ReplicatedEnvironment} has been created. {@code ReplicationMutableConfig} is
* a parameter to {@link ReplicatedEnvironment#setMutableConfig} and is
* returned by {@link ReplicatedEnvironment#getMutableConfig}.
*/
public class ReplicationMutableConfig implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
/*
* Note: all replicated parameters should start with
* EnvironmentParams.REP_PARAMS_PREFIX, which is "je.rep.",
* see SR [#19080].
*/
/**
* Boolean flag if set to true, an Arbiter may acknowledge a transaction if
* a replication node is not available.
*
* <table border="1"
* summary="Information about configuration option">
* <tr><td>Name</td><td>Type</td><td>Mutable</td><td>Default</td></tr>
* <tr>
* <td>{@value}</td>
* <td>Boolean</td>
* <td>Yes</td>
* <td>True</td>
* </tr>
* </table>
*/
public static final String ALLOW_ARBITER_ACK =
EnvironmentParams.REP_PARAM_PREFIX + "allowArbiterAck";
/**
* Identifies the Primary node in a two node group. See the discussion of
* issues when
* <a href= "{@docRoot}/../ReplicationGuide/lifecycle.html#twonode">
* configuring two node groups</a>}
*
* <table border="1"
* summary="Information about configuration option">
* <tr><td>Name</td><td>Type</td><td>Mutable</td><td>Default</td></tr>
* <tr>
* <td>{@value}</td>
* <td>Boolean</td>
* <td>Yes</td>
* <td>False</td>
* </tr>
* </table>
*/
public static final String DESIGNATED_PRIMARY =
EnvironmentParams.REP_PARAM_PREFIX + "designatedPrimary";
/**
* An escape mechanism to modify the way in which the number of electable
* nodes, and consequently the quorum requirements for elections and commit
* acknowledgments, is calculated. The override is accomplished by
* specifying the quorum size via this mutable configuration parameter.
* <p>
* When this parameter is set to a non-zero value at a member node, the
* member will use this value as the electable group size, instead of using
* the metadata stored in the RepGroup database for its quorum
* calculations. This parameter's value should be set to the number of
* electable nodes known to be available. The default value is zero, which
* indicates normal operation with the electable group size being
* calculated from the metadata.
*<p>
* Please keep in mind that this is an escape mechanism, only for use in
* exceptional circumstances, to be used with care. Since JE HA is no
* longer maintaining quorum requirements automatically, there is the
* possibility that the simple majority of unavailable nodes could elect
* their own Master, which would result in a diverging set of changes to
* the same environment being made by multiple Masters. It is essential to
* ensure that the problematic nodes are in fact down before making this
* temporary configuration change.
*
* See the discussion in <a href=
* "{@docRoot}/../ReplicationGuide/election-override.html">Appendix:
* Managing a Failure of the Majority</a>.
* <table border="1"
* summary="Information about configuration option">
* <tr>
* <td>Name</td>
* <td>Type</td>
* <td>Mutable</td>
* <td>Default</td>
* </tr>
* <tr>
* <td>{@value}</td>
* <td>Integer</td>
* <td>Yes</td>
* <td>0</td>
* </tr>
* </table>
*
* @see QuorumPolicy
* @see com.sleepycat.je.Durability.ReplicaAckPolicy
*/
public static final String ELECTABLE_GROUP_SIZE_OVERRIDE =
EnvironmentParams.REP_PARAM_PREFIX + "electableGroupSizeOverride";
/**
* The election priority associated with this node. The election algorithm
* for choosing a new master will pick the participating node that has the
* most current set of log files. When there is a tie, the election
* priority is used as a tie-breaker to select amongst these nodes.
* <p>
* A priority of zero is used to ensure that this node is never elected
* master, even if it has the most up to date log files. Note that the node
* still votes for a Master and participates in quorum requirements. Please
* use this option with care, since it means that some node with less
* current log files could be elected master. As a result, this node would
* be forced to rollback committed data and must be prepared to handle any
* {@link RollbackException} exceptions that might be thrown.
*
* <table border="1"
* summary="Information about configuration option">
* <tr>
* <td>Name</td>
* <td>Type</td>
* <td>Mutable</td>
* <td>Default</td>
* <td>Minimum</td>
* <td>Maximum</td>
* </tr>
* <tr>
* <td>{@value}</td>
* <td>Integer</td>
* <td>Yes</td>
* <td>1</td>
* <td>0</td>
* <td>Integer.MAX_VALUE</td>
* </tr>
* </table>
*
* @see RollbackException
*/
public static final String NODE_PRIORITY =
EnvironmentParams.REP_PARAM_PREFIX + "node.priority";
/**
* If true, JE HA (replication) will flush all committed transactions to
* disk at the specified time interval. This is of interest because the
* default durability for replicated transactions of {@link
* Durability#COMMIT_NO_SYNC}. The default for this behavior is true.
* <p>
* When using {@link Durability#COMMIT_NO_SYNC}, continued activity will
* naturally cause the steady flush of committed transactions, but a pause
* in activity may cause the latest commits to stay in memory. In such a
* case, it is unlikely but possible that all members of the replication
* group have these last transactions in memory and that no members have
* persisted them to disk. A catastrophic failure of all nodes in the
* replication group would cause a loss of these transactions, in this
* unlikely scenario. This background flush task will reduce such a
* possibility.
* <p>
* Note that enabling this feature when using {@link
* Durability#COMMIT_NO_SYNC}, does not constitute a guarantee that
* updates made by a transaction are persisted. For an explicit guarantee,
* transactions should use {@link Durability#COMMIT_SYNC} or {@link
* Durability#COMMIT_WRITE_NO_SYNC}. These more stringent, persistent
* Durability options can be set at the environment or per-transaction
* scope. Using one of these Durability settings for a given transaction
* will also flush all commits that occurred earlier in time.
* <table border="1"
* summary="Information about configuration option">
* <tr>
* <td>Name</td>
* <td>Type</td>
* <td>Mutable</td>
* <td>Default</td>
* </tr>
* <tr>
* <td>{@value}</td>
* <td>Boolean</td>
* <td>No</td>
* <td>true</td>
* </tr>
* </table>
*
* @deprecated as of 7.2. Log flushing can be disabled by setting {@link
* EnvironmentConfig#LOG_FLUSH_SYNC_INTERVAL} and {@link
* EnvironmentConfig#LOG_FLUSH_NO_SYNC_INTERVAL} to zero. For compatibility
* with earlier releases, if this parameter is specified as false, no log
* flushing will be performed; in this case, {@link
* EnvironmentConfig#LOG_FLUSH_SYNC_INTERVAL} and {@link
* EnvironmentConfig#LOG_FLUSH_NO_SYNC_INTERVAL} may not also be specified.
*/
public static final String RUN_LOG_FLUSH_TASK =
EnvironmentParams.REP_PARAM_PREFIX + "runLogFlushTask";
/**
* The interval that JE HA will do a log buffer flush.
* <table border="1"
* summary="Information about configuration option">
* <tr>
* <td>Name</td>
* <td>Type</td>
* <td>Mutable</td>
* <td>Default</td>
* <td>Minimum</td>
* <td>Maximum</td>
* </tr>
* <tr>
* <td>{@value}</td>
* <td>
* <a href="../EnvironmentConfig.html#timeDuration">Duration</a>
* </td>
* <td>Yes</td>
* <td>5 min</td>
* <td>1 s</td>
* <td>-none-</td>
* </tr>
* </table>
*
* @see <a href="../EnvironmentConfig.html#timeDuration">Time Duration
* Properties</a>
*
* @deprecated as of 7.2. Replaced by {@link
* EnvironmentConfig#LOG_FLUSH_SYNC_INTERVAL}. For compatibility with
* earlier releases, if this parameter is specified its value will be used
* as the flush sync interval; in this case, {@link
* EnvironmentConfig#LOG_FLUSH_SYNC_INTERVAL} may not also be specified.
*/
public static final String LOG_FLUSH_TASK_INTERVAL =
EnvironmentParams.REP_PARAM_PREFIX + "logFlushTaskInterval";
/**
* The maximum number of <i>most recently used</i> database handles that
* are kept open during the replay of the replication stream.
*
* <table border="1"
* summary="Information about configuration option">
* <tr><td>Name</td><td>Type</td><td>Mutable</td>
* <td>Default</td><td>Minimum</td><td>Maximum</td></tr>
* <tr>
* <td>{@value}</td>
* <td>Int</td>
* <td>Yes</td>
* <td>10</td>
* <td>1</td>
* <td>-none-</td>
* </tr>
* </table>
*
* @since 5.0.38
*/
public static final String REPLAY_MAX_OPEN_DB_HANDLES =
EnvironmentParams.REP_PARAM_PREFIX + "replayMaxOpenDbHandles";
/**
* The string identifying one or more helper host and port pairs in
* this format:
* <pre>
* hostname[:port][,hostname[:port]]*
* </pre>
* <table border="1"
* summary="Information about configuration option">
* <tr><td>Name</td><td>Type</td><td>Mutable</td><td>Default</td></tr>
* <tr>
* <td>{@value}</td>
* <td>String</td>
* <td>Yes</td>
* <td>""</td>
* </tr>
* </table>
* @see ReplicationMutableConfig#setHelperHosts
* @see ReplicationMutableConfig#getHelperHosts
*/
public static final String HELPER_HOSTS =
EnvironmentParams.REP_PARAM_PREFIX + "helperHosts";
/**
* The maximum amount of time that an inactive database handle is kept open
* during a replay of the replication stream. Handles that are inactive for
* more than this time period are automatically closed. Note that this does
* not impact any handles that may have been opened by the application.
*
* <table border="1"
* summary="Information about configuration option">
* <tr><td>Name</td><td>Type</td><td>Mutable</td>
* <td>Default</td><td>Minimum</td><td>Maximum</td></tr>
* <tr>
* <td>{@value}</td>
* <td><a href="#timeDuration">Duration</a></td>
* <td>No</td>
* <td>30 sec</td>
* <td>1 sec</td>
* <td>-none-</td>
* </tr>
* </table>
*
* @see <a href="../EnvironmentConfig.html#timeDuration">Time Duration
* Properties</a>
*
* @since 5.0.38
*/
public static final String REPLAY_DB_HANDLE_TIMEOUT =
EnvironmentParams.REP_PARAM_PREFIX + "replayOpenHandleTimeout";
/**
* @hidden
*
* For internal use only.
*
* The timeout specifies the amount of time that the
* {@link com.sleepycat.je.rep.util.ReplicationGroupAdmin#transferMaster
* ReplicationGroupAdmin.transferMastership} command can use to
* have the specified replica catch up with the original master.
* <p>
* If the replica has not successfully caught up with the original
* master, the call to {@link
* com.sleepycat.je.rep.util.ReplicationGroupAdmin#transferMaster
* ReplicationGroupAdmin.transferMastership} will throw an exception.
* <table border="1"
* summary="Information about configuration option">
* <tr>
* <td>Name</td>
* <td>Type</td>
* <td>Mutable</td>
* <td>Default</td>
* <td>Minimum</td>
* <td>Maximum</td>
* </tr>
* <tr>
* <td>{@value}</td>
* <td>
* <a href="../EnvironmentConfig.html#timeDuration">Duration</a>
* </td>
* <td>Yes</td>
* <td>100 s</td>
* <td>1 s</td>
* <td>-none-</td>
* </tr>
* </table>
*
* @see <a href="../EnvironmentConfig.html#timeDuration">Time Duration
* Properties</a>
*/
public static final String CATCHUP_MASTER_TIMEOUT =
EnvironmentParams.REP_PARAM_PREFIX + "catchupMasterTimeout";
static {
/*
* Force loading when a ReplicationConfig is used with strings and
* an environment has not been created.
*/
@SuppressWarnings("unused")
ConfigParam forceLoad = RepParams.GROUP_NAME;
}
/**
* @hidden
* Storage for replication related properties.
*/
protected Properties props;
/* For unit testing only: only ever set false when testing. */
transient boolean validateParams = true;
/**
* Create a ReplicationMutableConfig initialized with the system
* default settings. Parameter defaults are documented with the string
* constants in this class.
*/
public ReplicationMutableConfig() {
props = new Properties();
}
/**
* Used by ReplicationConfig to support construction from a property file.
* @param properties Hold replication related properties
*/
ReplicationMutableConfig(Properties properties, boolean validateParams)
throws IllegalArgumentException {
this.validateParams = validateParams;
validateProperties(properties);
/* For safety, copy the passed in properties. */
props = new Properties();
props.putAll(properties);
}
/**
* Fills in the properties calculated by the environment to the given
* config object.
*/
void fillInEnvironmentGeneratedProps(RepImpl repImpl) {
props.put(RepParams.DESIGNATED_PRIMARY.getName(),
Boolean.toString(repImpl.isDesignatedPrimary()));
props.put(RepParams.NODE_PRIORITY.getName(),
Integer.toString(getNodePriority()));
}
/**
* @hidden
* For internal use only
*/
public void copyMutablePropsTo(ReplicationMutableConfig toConfig) {
Properties toProps = toConfig.props;
Enumeration<?> propNames = props.propertyNames();
while (propNames.hasMoreElements()) {
String paramName = (String) propNames.nextElement();
ConfigParam param =
EnvironmentParams.SUPPORTED_PARAMS.get(paramName);
assert param != null;
if (param.isForReplication() &&
param.isMutable()) {
String newVal = props.getProperty(paramName);
toProps.setProperty(paramName, newVal);
}
}
}
/**
* If {@code isPrimary} is true, designate this node as a Primary. This
* setting only takes effect for electable nodes. The application must
* ensure that exactly one electable node is designated to be a Primary at
* any given time. Primary node configuration is only a concern when the
* group has two electable nodes, and there cannot be a simple
* majority. See the overview on <a href=
* "{@docRoot}/../ReplicationGuide/lifecycle.html#twonode">configuring two
* node groups</a>.
*
* @param isPrimary true if this node is to be made the Primary
*
* @return this
*/
public ReplicationMutableConfig setDesignatedPrimary(boolean isPrimary) {
setDesignatedPrimaryVoid(isPrimary);
return this;
}
/**
* @hidden
* The void return setter for use by Bean editors.
*/
public void setDesignatedPrimaryVoid(boolean isPrimary) {
DbConfigManager.setBooleanVal(props, RepParams.DESIGNATED_PRIMARY,
isPrimary, validateParams);
}
/**
* Determines whether this node is the currently designated Primary. See
* the overview on <a href=
* "{@docRoot}/../ReplicationGuide/lifecycle.html#twonode"> issues around
* two node groups</a>
* @return true if this node is a Primary, false otherwise.
*/
public boolean getDesignatedPrimary() {
return DbConfigManager.getBooleanVal(props,
RepParams.DESIGNATED_PRIMARY);
}
/**
* Returns the value associated with the override. A value of zero means
* that the number of electable nodes is determined as usual, that is, from
* the contents of the group metadata.
*
* @return the number of electable nodes as specified by the override
*
* @see #ELECTABLE_GROUP_SIZE_OVERRIDE
*/
public int getElectableGroupSizeOverride() {
return DbConfigManager.
getIntVal(props, RepParams.ELECTABLE_GROUP_SIZE_OVERRIDE);
}
/**
* Sets the size used to determine the number of electable nodes.
*
* @param override the number of electable nodes. A value of zero means
* that the number of electable nodes is determined as usual, that is, from
* the contents of the group metadata.
*
* @return this
*
* @see #ELECTABLE_GROUP_SIZE_OVERRIDE
*/
public ReplicationMutableConfig
setElectableGroupSizeOverride(int override) {
setElectableGroupSizeOverrideVoid(override);
return this;
}
/**
* @hidden
* The void return setter for use by Bean editors.
*/
public void setElectableGroupSizeOverrideVoid(int override) {
DbConfigManager.
setIntVal(props, RepParams.ELECTABLE_GROUP_SIZE_OVERRIDE, override,
validateParams);
}
/**
* Returns the election priority associated with the node.
*
* @return the priority for this node
*
* @see #NODE_PRIORITY
*/
public int getNodePriority() {
return DbConfigManager.getIntVal(props, RepParams.NODE_PRIORITY);
}
/**
* Sets the election priority for the node. The algorithm for choosing a
* new master will pick the participating node that has the most current
* set of log files. When there is a tie, the priority is used as a
* tie-breaker to select amongst these nodes.
* <p>
* A priority of zero is used to ensure that a node is never elected
* master, even if it has the most current set of files. Please use this
* option with caution, since it means that a node with less current log
* files could be elected master potentially forcing this node to rollback
* data that had been committed.
*
* @param priority the priority to be associated with the node. It must be
* zero, or a positive number.
*
* @see #NODE_PRIORITY
*/
public ReplicationMutableConfig setNodePriority(int priority) {
setNodePriorityVoid(priority);;
return this;
}
/**
* @hidden
* The void return setter for use by Bean editors.
*/
public void setNodePriorityVoid(int priority) {
DbConfigManager.setIntVal(props, RepParams.NODE_PRIORITY, priority,
validateParams);
}
/**
* Returns the string identifying one or more helper host and port pairs in
* this format:
* <pre>
* hostname[:port][,hostname[:port]]*
* </pre>
* The port name may be omitted if it's the default port.
*
* @return the string representing the host port pairs
*
*/
public String getHelperHosts() {
return DbConfigManager.getVal(props, RepParams.HELPER_HOSTS);
}
/**
* Identify one or more helpers nodes by their host and port pairs in this
* format:
* <pre>
* hostname[:port][,hostname[:port]]*
* </pre>
* If the port is omitted, the default port defined by XXX is used.
*
* @param hostsAndPorts the string representing the host and port pairs.
*
* @return this
*/
public ReplicationMutableConfig setHelperHosts(String hostsAndPorts) {
setHelperHostsVoid(hostsAndPorts);
return this;
}
/**
* @hidden
* The void return setter for use by Bean editors.
*/
public void setHelperHostsVoid(String hostsAndPorts) {
DbConfigManager.setVal
(props, RepParams.HELPER_HOSTS, hostsAndPorts, validateParams);
}
/**
* Set this configuration parameter with this value. Values are validated
* before setting the parameter.
*
* @param paramName the configuration parameter name, one of the String
* constants in this class
* @param value the configuration value.
*
* @return this;
*
* @throws IllegalArgumentException if the paramName or value is invalid.
*/
public ReplicationMutableConfig setConfigParam(String paramName,
String value)
throws IllegalArgumentException {
DbConfigManager.setConfigParam(props,
paramName,
value,
true, /* require mutability. */
validateParams,
true, /* forReplication */
true); /* verifyForReplication */
return this;
}
/**
* Return the value for this parameter.
* @param paramName a valid configuration parameter, one of the String
* constants in this class.
* @return the configuration value.
*
* @throws IllegalArgumentException if the paramName is invalid.
*/
public String getConfigParam(String paramName)
throws IllegalArgumentException {
return DbConfigManager.getConfigParam(props, paramName);
}
/**
* Validate a property bag passed in a construction time.
*/
void validateProperties(Properties checkProps)
throws IllegalArgumentException {
/* Check that the properties have valid names and values */
Enumeration<?> propNames = checkProps.propertyNames();
while (propNames.hasMoreElements()) {
String name = (String) propNames.nextElement();
/* Is this a valid property name? */
ConfigParam param =
EnvironmentParams.SUPPORTED_PARAMS.get(name);
if (param == null) {
throw new IllegalArgumentException
(name + " is not a valid JE environment configuration");
}
/* Is this a valid property value? */
if (validateParams) {
param.validateValue(checkProps.getProperty(name));
}
}
}
/**
* @hidden
* For internal use only.
* Access the internal property bag, used during startup.
*/
public Properties getProps() {
return props;
}
/**
* List the configuration parameters and values that have been set
* in this configuration object.
*/
@Override
public String toString() {
return props.toString();
}
/**
* For unit testing only
*/
void setOverrideValidateParams(boolean validateParams) {
this.validateParams = validateParams;
}
/**
* @hidden
* For testing only
*/
public boolean getValidateParams() {
return validateParams;
}
/**
* @hidden
* For internal use only.
* Overrides Object.clone() to clone all properties, used by this class and
* ReplicationConfig.
*/
@Override
protected Object clone()
throws CloneNotSupportedException {
ReplicationMutableConfig copy =
(ReplicationMutableConfig) super.clone();
copy.props = (Properties) props.clone();
return copy;
}
}