All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sleepycat.je.rep.InsufficientLogException Maven / Gradle / Ivy

The newest version!
/*-
 * 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.File;
import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;

import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.EnvironmentFailureException;
import com.sleepycat.je.config.EnvironmentParams;
import com.sleepycat.je.dbi.EnvironmentFailureReason;
import com.sleepycat.je.rep.impl.RepImpl;
import com.sleepycat.je.rep.impl.RepParams;
import com.sleepycat.je.rep.impl.node.RepNode;
import com.sleepycat.je.rep.utilint.HostPortPair;
import com.sleepycat.je.utilint.VLSN;

/**
 * This exception indicates that the log files constituting the Environment are
 * insufficient and cannot be used as the basis for continuing with the
 * replication stream provided by the current master.
 * 

* This exception is typically thrown by the ReplicatedEnvironment constructor * when a node has been down for a long period of time and is being started up * again. It may also be thrown when a brand new node attempts to become a * member of the group and it does not have a sufficiently current set of log * files. If the group experiences sustained network connectivity problems, * this exception may also be thrown by an active Replica that has been unable * to stay in touch with the members of its group for an extended period of * time. *

* In the typical case, application handles the exception by invoking * {@link NetworkRestore#execute} to obtain the log files it needs from one of * the members of the replication group. After the log files are obtained, the * node recreates its environment handle and resumes participation as an active * member of the group. * * @see NetworkRestore */ public class InsufficientLogException extends RestartRequiredException { private static final long serialVersionUID = 1; /* * These properties store information to serialize the ILE and save it in a * RestoreRequired log entry. * * The properties named P_* describe a log provider. An ILE may have one or * more log providers, and a more structured format like Json would make it * easier to describe an array of items. Since we're currently constrained * to using a property list, we follow the convention of suffixing each * provider property with a number. For example, if there are two * providers, P_NUMPROVIDERS=2, and there would be P_NODENAME0, * P_NODENAME1, etc. */ private static final String P_NUMPROVIDERS = "P_NUMPROVIDERS"; private static final String P_NODENAME = "P_NODENAME"; private static final String P_NODETYPE = "P_NODETYPE"; private static final String P_HOSTNAME = "P_HOSTNAME"; private static final String P_PORT = "P_PORT"; /* * Properties needed to create an environment handle for the node which * needs new logs, and is the target for a backup. */ private static final String GROUP_NAME = "GROUP_NAME"; private static final String NODE_NAME = "NODE_NAME"; private static final String HOSTNAME = "HOSTNAME"; private static final String PORT = "PORT"; private static final String ENV_DIR = "ENV_DIR"; private static final String REFRESH_VLSN = "REFRESH_VLSN"; /* * A handle to the replication environment which is the target for the * network restore. May be null. If repImpl was created by the ILE, the * caller has the responsibility for closing the environment. Note that a * RepImpl rather than RepNode is used as the environment handle. RepNodes * are only available for nodes which are a member of a group. In some * cases, an ILE is used by a node which is detached, and is not currently * connected to its group. */ private transient RepImpl repImpl; private boolean openedByILE; /* Attributes used by the network restore, in serialized format */ private final transient Properties props; /* * The network configuration basic, ssl, etc. to use during the network * restore. */ private final transient ReplicationNetworkConfig repNetConfig; /* * No longer used as of JE 7.5, but the field is retained for serializable * compatibility. */ private final VLSN refreshVLSN; /* * Candidate nodes for a log file refresh. Note that this field is only * used by a thread that is synchronously processing the caught exception, * which is safely after the instance has been initialized. */ private final Set logProviders; /** * For KVS test use only. * @hidden */ public InsufficientLogException(String message) { super(null, EnvironmentFailureReason.UNEXPECTED_STATE, message); this.repImpl = null; this.refreshVLSN = null; this.logProviders = null; this.props = null; this.repNetConfig = ReplicationNetworkConfig.createDefault(); } /** * @hidden * * Creates an instance of the exception and packages up the information * needed by NetworkRestore. */ public InsufficientLogException(RepNode repNode, Set logProviders) { super(repNode.getRepImpl(), EnvironmentFailureReason.INSUFFICIENT_LOG); this.repImpl = repNode.getRepImpl(); this.refreshVLSN = VLSN.NULL_VLSN; this.logProviders = logProviders; props = initProperties(repNode.getGroup().getName()); this.repNetConfig = repImpl.getRepNetConfig(); } private Properties initProperties(String groupName) { Properties p = new Properties(); /* * These apply to the destination node which is experiencing the * insufficient logs. */ p.setProperty(GROUP_NAME, groupName); p.setProperty(NODE_NAME, repImpl.getNameIdPair().getName()); p.setProperty(HOSTNAME, repImpl.getHostName()); p.setProperty(PORT, Integer.toString(repImpl.getPort())); p.setProperty(ENV_DIR, repImpl.getEnvironmentHome().getPath()); p.setProperty(REFRESH_VLSN, Long.toString(refreshVLSN.getSequence())); /* * There is a set of nodes which might act as the source for the * network restore. Since we can't store arrays, append an index * to the property name for each log provider. */ p.setProperty(P_NUMPROVIDERS, Integer.toString(logProviders.size())); int i = 0; for (ReplicationNode rn: logProviders) { p.setProperty(P_NODENAME + i, rn.getName()); p.setProperty(P_HOSTNAME + i, rn.getHostName()); p.setProperty(P_PORT + i, Integer.toString(rn.getPort())); p.setProperty(P_NODETYPE + i, rn.getType().name()); i++; } return p; } /** * @hidden * * Creates an instance of the exception and packages up the information * needed by Subscription API. The target is not a replication node, so the * repImpl field is a shell which represents the subscription target. */ public InsufficientLogException(RepImpl repImpl, VLSN refreshVLSN) { super(repImpl, EnvironmentFailureReason.INSUFFICIENT_LOG); this.repImpl = repImpl; this.refreshVLSN = refreshVLSN; /* * No log providers in this use case, but initialize the set for * initProperties, and for robustness. */ this.logProviders = new HashSet<>(); props = initProperties("NO_GROUP"); this.repNetConfig = repImpl.getRepNetConfig(); } /** * @hidden * * Creates an instance of the exception when a LOG_RESTORE_REQUIRED was * found at recovery, and network restore must be initiated before the * recovery can succeed. The flow is: * 0. A network restore is underway. It writes a marker file, essentially * serializing this ILE as a property list, and writing it into the log. * Something then interrupts this network restore. The process dies, * so all knowledge of the interrupted network restore is lost in * memory but the the marker file acts as a persistent breadcrumb. * 1. Since knowledge of the network restore was lost, the application tries * to open and recover the target node. The LOG_RESTORE_REQUIRED entry * is seen, which means that recovery can't continue. * 2. Within recovery, a new ILE is created using information from the * LOG_RESTORE_REQUIRED. It's thrown, which ends recovery. * 3. The caller realizes that a network restore has to be carried out * before this environment can be recovered. It uses the ILE instance * created in step 2 to start a new invocation of network restore. * 4. Network restore starts. Since network restore needs a RepImpl, one * is instantiated using info from the ILE * 5. When Network restore succeeds, it removes the marker file. * * @param restoreProperties the properties extracted from the * RestoreRequired record in the log * @param helperHosts extra helper hosts are derived from those used * to open the environment. * @param repNetConfig the network configuration to use when contacting log * suppliers for jdb files. */ public InsufficientLogException(Properties restoreProperties, String helperHosts, ReplicationNetworkConfig repNetConfig) { super(null, EnvironmentFailureReason.INSUFFICIENT_LOG); /* * Don't initialize the repImpl until it's needed. If we try to do * so in step2, we'll be in a loop, trying to recover an environment * from within recovery. */ String vlsnVal = restoreProperties.getProperty(REFRESH_VLSN); this.refreshVLSN = new VLSN(Long.parseLong(vlsnVal)); this.logProviders = new HashSet<>(); if (helperHosts != null) { for (String hostPortPair : helperHosts.split(",")) { final String hpp = hostPortPair.trim(); if (hpp.length() > 0) { LogFileSource source = new LogFileSource("NoName", // not important NodeType.ELECTABLE.name(), HostPortPair.getHostname(hpp), HostPortPair.getPort(hpp)); logProviders.add(source); } } } this.props = restoreProperties; this.repNetConfig = repNetConfig; } private void initRepImpl() { /* * Setup log providers. Since can't use something that supports array * types like JSON, and must use a property list, the provider flags * are named NODE_NAME0, HOSTNAME0, etc. */ int numLogProviders = Integer.parseInt(props.getProperty(P_NUMPROVIDERS)); for (int i = 0; i < numLogProviders; i++) { String name = props.getProperty(P_NODENAME + i); String nodeType = props.getProperty(P_NODETYPE + i); String hostname = props.getProperty(P_HOSTNAME + i); int port = Integer.parseInt(props.getProperty(P_PORT + i)); logProviders.add(new LogFileSource(name, nodeType, hostname, port)); } /* * Create new, read only, internal handle type environment for use * by the network backup. */ EnvironmentConfig envConfig = new EnvironmentConfig(); envConfig.setReadOnly(true); envConfig.setConfigParam(EnvironmentParams.ENV_RECOVERY.getName(), "false"); envConfig.setTransactional(true); String hostname = props.getProperty(HOSTNAME); int portVal = Integer.parseInt(props.getProperty(PORT)); ReplicationConfig repConfig = new ReplicationConfig(props.getProperty(GROUP_NAME), props.getProperty(NODE_NAME), HostPortPair.getString(hostname, portVal)); repConfig.setConfigParam(RepParams.NETWORKBACKUP_USE.getName(), "true"); repConfig.setRepNetConfig(repNetConfig); File envDir = new File(props.getProperty(ENV_DIR)); ReplicatedEnvironment restoreEnv = RepInternal.createInternalEnvHandle(envDir, repConfig, envConfig); this.repImpl = RepInternal.getRepImpl(restoreEnv); final String nrChannelType = repImpl.getRepNetConfig().getChannelType(); final String preNRChannelType = repNetConfig.getChannelType(); if (! nrChannelType.equals(preNRChannelType)) { /* * The je.properties value differs with the one specified by the * Network Restore code path. */ throw new IllegalStateException("Network Restore channel state: " + nrChannelType + ", pre network restore state:" + preNRChannelType); } openedByILE = true; } /** * For internal use only. * @hidden */ private InsufficientLogException(String message, InsufficientLogException cause) { super(message, cause); this.repImpl = cause.repImpl; this.openedByILE = cause.openedByILE; this.refreshVLSN = cause.refreshVLSN; this.logProviders = cause.logProviders; this.props = cause.props; this.repNetConfig = cause.repNetConfig; } /** * For internal use only. * @hidden */ @Override public EnvironmentFailureException wrapSelf(String msg) { return new InsufficientLogException(msg, this); } /** * Returns the members of the replication group that can serve as candidate * log providers to supply the logs needed by this node. * * @return a list of members that can provide logs */ public Set getLogProviders() { return logProviders; } /** * For internal use only. * @hidden * * Returns the replication node whose log files need to be refreshed. */ public RepImpl getRepImpl() { if (repImpl == null) { initRepImpl(); } return repImpl; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(super.toString()); sb.append("refreshVLSN=").append(refreshVLSN); sb.append(" logProviders=").append(logProviders); sb.append(" repImpl=").append(repImpl); sb.append(" props=").append(props); return sb.toString(); } /** * For internal use only. * @hidden */ public Properties getProperties() { return props; } /* * A standin for a ReplicationNode, so NetworkRestore can establish a * protocol connection with the source of the log files. */ private class LogFileSource implements ReplicationNode { private final String name; private final NodeType type; private final String hostname; private final int port; LogFileSource(String name, String nodeTypeName, String hostname, int port) { this.name = name; this.type = NodeType.valueOf(nodeTypeName); this.hostname = hostname; this.port = port; } @Override public String getName() { return name; } @Override public NodeType getType() { return type; } @Override public InetSocketAddress getSocketAddress() { return new InetSocketAddress(hostname, port); } @Override public String getHostName() { return hostname; } @Override public int getPort() { return port; } } /** * Called when network restore is complete to close the env if it was * opened via this exception. * * Also sets the repImpl field to null, to avoid OOME when opening the * restored environment. This is important whether or not the env was * opened via this exception. [#26305] */ void releaseRepImpl() { if (repImpl == null) { return; } try { if (openedByILE) { repImpl.close(); } } finally { repImpl = null; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy