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.
/*
* Copyright (c) 2011-2019 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/
package io.vertx.core.impl;
import io.vertx.core.*;
import io.vertx.core.impl.logging.Logger;
import io.vertx.core.impl.logging.LoggerFactory;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.core.spi.cluster.ClusterManager;
import io.vertx.core.spi.cluster.NodeListener;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
/**
*
* Handles HA
*
* We compute failover and whether there is a quorum synchronously as we receive nodeAdded and nodeRemoved events
* from the cluster manager.
*
* It's vital that this is done synchronously as the cluster manager only guarantees that the set of nodes retrieved
* from getNodes() is the same for each node in the cluster when processing the exact same nodeAdded/nodeRemoved
* event.
*
* As HA modules are deployed, if a quorum has been attained they are deployed immediately, otherwise the deployment
* information is added to a list.
*
* Periodically we check the value of attainedQuorum and if true we deploy any HA deploymentIDs waiting for a quorum.
*
* If false, we check if there are any HA deploymentIDs current deployed, and if so undeploy them, and add them to the list
* of deploymentIDs waiting for a quorum.
*
* By doing this check periodically we can avoid race conditions resulting in modules being deployed after a quorum has
* been lost, and without having to resort to exclusive locking which is actually quite tricky here, and prone to
* deadlock·
*
* We maintain a clustered map where the key is the node id and the value is some stringified JSON which describes
* the group of the cluster and an array of the HA modules deployed on that node.
*
* There is an entry in the map for each node of the cluster.
*
* When a node joins the cluster or an HA module is deployed or undeployed that entry is updated.
*
* When a node leaves the cluster cleanly, it removes it's own entry before leaving.
*
* When the cluster manager sends us an event to say a node has left the cluster we check if its entry in the cluster
* map is there, and if so we infer a clean close has happened and no failover will occur.
*
* If the map entry is there it implies the node died suddenly. In that case each node of the cluster must compute
* whether it is the failover node for the failed node.
*
* First each node of the cluster determines whether it is in the same group as the failed node, if not then it will not
* be a candidate for the failover node. Nodes in the cluster only failover to other nodes in the same group.
*
* If the node is in the same group then the node takes the UUID of the failed node, computes the hash-code and chooses
* a node from the list of nodes in the cluster by taking the hash-code modulo the number of nodes as an index to the
* list of nodes.
*
* The cluster manager guarantees each node in the cluster sees the same set of nodes for each membership event that is
* processed. Therefore it is guaranteed that each node in the cluster will compute the same value. It is critical that
* any cluster manager implementation provides this guarantee!
*
* Once the value has been computed, it is compared to the current node, and if it is the same the current node
* assumes failover for the failed node.
*
* During failover the failover node deploys all the HA modules from the failed node, as described in the JSON with the
* same values of config and instances.
*
* Once failover is complete the failover node removes the cluster map entry for the failed node.
*
* If the failover node itself fails while it is processing failover for another node, then this is also checked by
* other nodes when they detect the failure of the second node.
*
* @author Tim Fox
*/
public class HAManager {
private static final Logger log = LoggerFactory.getLogger(HAManager.class);
private static final long QUORUM_CHECK_PERIOD = 1000;
private final VertxInternal vertx;
private final DeploymentManager deploymentManager;
private final VerticleManager verticleFactoryManager;
private final ClusterManager clusterManager;
private final int quorumSize;
private final String group;
private final JsonObject haInfo;
private final Map clusterMap;
private final String nodeID;
private final Queue toDeployOnQuorum = new ConcurrentLinkedQueue<>();
private long quorumTimerID;
private long checkQuorumTimerID = -1L;
private volatile boolean attainedQuorum;
private volatile FailoverCompleteHandler failoverCompleteHandler;
private volatile boolean failDuringFailover;
private volatile boolean stopped;
private volatile boolean killed;
public HAManager(VertxInternal vertx, DeploymentManager deploymentManager, VerticleManager verticleFactoryManager, ClusterManager clusterManager,
Map clusterMap, int quorumSize, String group) {
this.vertx = vertx;
this.deploymentManager = deploymentManager;
this.verticleFactoryManager = verticleFactoryManager;
this.clusterManager = clusterManager;
this.clusterMap = clusterMap;
this.quorumSize = quorumSize;
this.group = group;
this.haInfo = new JsonObject().put("verticles", new JsonArray()).put("group", this.group);
this.nodeID = clusterManager.getNodeId();
}
/**
* Initialize the ha manager, i.e register the node listener to propagates the node events and
* start the quorum timer. The quorum will be checked as well.
*/
void init() {
synchronized (haInfo) {
clusterMap.put(nodeID, haInfo.encode());
}
clusterManager.nodeListener(new NodeListener() {
@Override
public void nodeAdded(String nodeID) {
HAManager.this.nodeAdded(nodeID);
}
@Override
public void nodeLeft(String leftNodeID) {
HAManager.this.nodeLeft(leftNodeID);
}
});
quorumTimerID = vertx.setPeriodic(QUORUM_CHECK_PERIOD, tid -> checkHADeployments());
// Call check quorum to compute whether we have an initial quorum
synchronized (this) {
checkQuorum();
}
}
// Remove the information on the deployment from the cluster - this is called when an HA module is undeployed
public void removeFromHA(String depID) {
Deployment dep = deploymentManager.getDeployment(depID);
if (dep == null || !dep.deploymentOptions().isHa()) {
return;
}
synchronized (haInfo) {
JsonArray haMods = haInfo.getJsonArray("verticles");
Iterator