Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/* This file is part of VoltDB.
* Copyright (C) 2008-2018 VoltDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with VoltDB. If not, see .
*/
package org.voltcore.messaging;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.ClosedSelectorException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.net.ssl.SSLEngine;
import org.json_voltpatches.JSONArray;
import org.json_voltpatches.JSONException;
import org.json_voltpatches.JSONObject;
import org.voltcore.logging.Level;
import org.voltcore.logging.VoltLogger;
import org.voltcore.network.ReverseDNSCache;
import org.voltcore.utils.CoreUtils;
import org.voltcore.utils.VersionChecker;
import org.voltcore.utils.ssl.MessagingChannel;
import org.voltcore.utils.ssl.SSLConfiguration;
import org.voltdb.client.TLSHandshaker;
import com.google_voltpatches.common.collect.ImmutableMap;
import com.google_voltpatches.common.collect.ImmutableSet;
import com.google_voltpatches.common.collect.Sets;
import com.google_voltpatches.common.net.HostAndPort;
import io.netty.buffer.ByteBufAllocator;
import io.netty.handler.ssl.SslContext;
/**
* SocketJoiner runs all the time listening for new nodes in the cluster. Since it is a dedicated thread
* it is able to block while a new node joins without disrupting other activities.
*
* At startup socket joiner will connect to the rest of the cluster in the start method if it fails
* to bind to the leader address.
*
* If it binds to the leader address and becomes the leader the start method returns immediately and runPrimary
* is run from a separate thread. runPrimary will wait for the countdown latch for bootstrapping zk to count down
* before accepting new connections
*/
public class SocketJoiner {
static final String HOSTS = "hosts";
static final String REPORTED_ADDRESS = "reportedAddress";
static final String NEW_HOST_ID = "newHostId";
static final String REASON = "reason";
static final String MAY_RETRY = "mayRetry";
static final String ACCEPTED = "accepted";
private static final String MAY_EXCHANGE_TS = "mayExchangeTs";
private static final String TYPE = "type";
static final String HOST_ID = "hostId";
static final String PORT = "port";
static final String ADDRESS = "address";
private static final String VERSION_COMPATIBLE = "versionCompatible";
private static final String BUILD_STRING = "buildString";
public static final String VERSION_STRING = "versionString";
private static final int MAX_CLOCKSKEW = Integer.getInteger("MAX_CLOCKSKEW", 200);
private static final int RETRY_INTERVAL = Integer.getInteger("MESH_JOIN_RETRY_INTERVAL", 10);
private static final int RETRY_INTERVAL_SALT = Integer.getInteger("MESH_JOIN_RETRY_INTERVAL_SALT", 30);
private static final int CRITICAL_CLOCKSKEW = 100;
public static final String FAIL_ESTABLISH_MESH_MSG = "Failed to establish socket mesh.";
/**
* Supports quick probes for request host id attempts to seed nodes
*/
enum ConnectStrategy {
CONNECT, PROBE
}
enum ConnectionType {
REQUEST_HOSTID,
PUBLISH_HOSTID,
REQUEST_CONNECTION;
}
/**
* Interface into host messenger to notify it of new connections.
*
*/
public interface JoinHandler {
/*
* Notify that a specific host has joined with the specified host id.
*/
public void notifyOfJoin(
int hostId,
SocketChannel socket,
SSLEngine sslEngine,
InetSocketAddress listeningAddress,
JSONObject jo);
/*
* A node wants to join the socket mesh
*/
public void requestJoin(
SocketChannel socket,
SSLEngine sslEngine,
MessagingChannel messagingChannel,
InetSocketAddress listeningAddress,
JSONObject jo) throws Exception;
/*
* A connection has been made to all of the specified hosts. Invoked by
* nodes connected to the cluster
*/
public void notifyOfHosts(
int yourLocalHostId,
int hosts[],
SocketChannel sockets[],
SSLEngine[] sslEngines,
InetSocketAddress listeningAddresses[],
Map jos) throws Exception;
/*
* Create new connection between given node and current node
*/
public void notifyOfConnection(
int hostId,
SocketChannel socket,
SSLEngine sslEngine,
InetSocketAddress listeningAddress) throws Exception;
}
private static class RequestHostIdResponse {
final private JSONObject m_leaderInfo;
final private JSONObject m_responseBody;
public RequestHostIdResponse(JSONObject leaderInfo, JSONObject responseBody) {
m_leaderInfo = leaderInfo;
m_responseBody = responseBody;
}
JSONObject getLeaderInfo() { return m_leaderInfo; }
JSONObject getResponseBody() { return m_responseBody; }
}
private static final VoltLogger LOG = new VoltLogger("JOINER");
private static final VoltLogger consoleLog = new VoltLogger("CONSOLE");
private static final VoltLogger hostLog = new VoltLogger("HOST");
private final ExecutorService m_es = CoreUtils.getSingleThreadExecutor("Socket Joiner");
InetSocketAddress m_coordIp = null;
int m_localHostId = 0;
private final List m_listenerSockets = new ArrayList();
private Selector m_selector;
private final JoinHandler m_joinHandler;
// from configuration data
int m_internalPort = 3021;
String m_internalInterface = "";
/*
* The interface we connected to the leader on
*/
String m_reportedInternalInterface;
public boolean start(final CountDownLatch externalInitBarrier) {
boolean retval = false;
/*
* probe coordinator host list for leader candidates that may are operational
* (i.e. node state is operational)
*/
m_coordIp = null;
for (String coordHost: m_acceptor.getCoordinators()) {
if (m_coordIp != null) {
break;
}
HostAndPort host = HostAndPort.fromString(coordHost)
.withDefaultPort(org.voltcore.common.Constants.DEFAULT_INTERNAL_PORT);
InetSocketAddress ip = !host.getHost().isEmpty() ?
new InetSocketAddress(host.getHost(), host.getPort())
: new InetSocketAddress(host.getPort());
/*
* On an operational leader (i.e. node is up) the request to join the cluster
* may be rejected, e.g. multiple hosts rejoining at the same time. In this case,
* the code will retry.
*/
long retryInterval = RETRY_INTERVAL;
final Random salt = new Random();
while (true) {
try {
connectToPrimary(ip, ConnectStrategy.PROBE);
break;
} catch (CoreUtils.RetryException e) {
LOG.warn(String.format("Request to join cluster mesh is rejected, retrying in %d seconds. %s",
retryInterval, e.getMessage()));
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(retryInterval));
} catch (InterruptedException ignoreIt) {
}
// exponential back off with a salt to avoid collision. Max is 5 minutes.
retryInterval = (Math.min(retryInterval * 2, TimeUnit.MINUTES.toSeconds(5)) +
salt.nextInt(RETRY_INTERVAL_SALT));
//Over waiting may occur in some cases.
//For example, there are 4 rejoining nodes. Node 1 may take over 5 min to be completed.
//Nodes 2 to 4 continue to wait after they detect that node 1 is still rejoining right before its rejoining is completed
//They will wait 5 min + salt before sending another rejoining request. All the following rejoining requests are sent
//after 5 min + salt. Reset waiting time to avoid over waiting.
if (retryInterval > TimeUnit.MINUTES.toSeconds(5)) {
retryInterval = RETRY_INTERVAL;
}
} catch (Exception e) {
hostLog.error("Failed to establish socket mesh.", e);
throw new RuntimeException("Failed to establish socket mesh with " + m_coordIp, e);
}
}
}
boolean haveMeshedLeader = m_coordIp != null;
/*
* if none were found pick the first one in lexicographical order
*/
if (m_coordIp == null) {
HostAndPort leader = m_acceptor.getLeader();
m_coordIp = !leader.getHost().isEmpty() ?
new InetSocketAddress(leader.getHost(), leader.getPort())
: new InetSocketAddress(leader.getPort());
}
if (!haveMeshedLeader && m_coordIp.getPort() == m_internalPort) {
try {
hostLog.info("Attempting to bind to leader ip " + m_coordIp);
ServerSocketChannel listenerSocket = ServerSocketChannel.open();
listenerSocket.socket().bind(m_coordIp);
listenerSocket.socket().setPerformancePreferences(0, 2, 1);
listenerSocket.configureBlocking(false);
m_listenerSockets.add(listenerSocket);
}
catch (IOException e) {
if (!m_listenerSockets.isEmpty()) {
try {
m_listenerSockets.get(0).close();
m_listenerSockets.clear();
}
catch (IOException ex) {
new VoltLogger(SocketJoiner.class.getName()).l7dlog(Level.FATAL, null, ex);
}
}
}
}
if (!m_listenerSockets.isEmpty()) {
// if an internal interface was specified, see if it matches any
// of the forms of the leader address we've bound to.
if (m_internalInterface != null && !m_internalInterface.equals("")) {
if (!m_internalInterface.equals(ReverseDNSCache.hostnameOrAddress(m_coordIp.getAddress())) &&
!m_internalInterface.equals(m_coordIp.getAddress().getCanonicalHostName()) &&
!m_internalInterface.equals(m_coordIp.getAddress().getHostAddress()))
{
org.voltdb.VoltDB.crashLocalVoltDB(
String.format("The provided internal interface (%s) does not match the "
+ "specified leader address (%s, %s). "
+ "This will result in either a cluster which fails to start or an unintended network topology. "
+ "The leader will now exit; correct your specified leader and interface and try restarting.",
m_internalInterface,
ReverseDNSCache.hostnameOrAddress(m_coordIp.getAddress()),
m_coordIp.getAddress().getHostAddress()),
false, null);
}
}
retval = true;
consoleLog.info("Connecting to VoltDB cluster as the leader...");
/*
* Need to wait for external initialization to complete before
* accepting new connections. This is slang for the leader
* creating an agreement site that agrees with itself
*/
m_es.submit(new Callable