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-2014 The original author or authors
* ------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package io.vertx.core.impl;
import io.vertx.core.*;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
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;
/**
*
* 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 String CLUSTER_MAP_NAME = "__vertx.haInfo";
private static final long QUORUM_CHECK_PERIOD = 1000;
private final VertxInternal vertx;
private final DeploymentManager deploymentManager;
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 final boolean enabled;
private long quorumTimerID;
private volatile boolean attainedQuorum;
private volatile FailoverCompleteHandler failoverCompleteHandler;
private volatile FailoverCompleteHandler nodeCrashedHandler;
private volatile boolean failDuringFailover;
private volatile boolean stopped;
private volatile boolean killed;
public HAManager(VertxInternal vertx, DeploymentManager deploymentManager,
ClusterManager clusterManager, int quorumSize, String group, boolean enabled) {
this.vertx = vertx;
this.deploymentManager = deploymentManager;
this.clusterManager = clusterManager;
this.quorumSize = enabled ? quorumSize : 0;
this.group = enabled ? group : "__DISABLED__";
this.enabled = enabled;
this.haInfo = new JsonObject();
haInfo.put("verticles", new JsonArray());
haInfo.put("group", this.group);
this.clusterMap = clusterManager.getSyncMap(CLUSTER_MAP_NAME);
this.nodeID = clusterManager.getNodeID();
clusterManager.nodeListener(new NodeListener() {
@Override
public void nodeAdded(String nodeID) {
HAManager.this.nodeAdded(nodeID);
}
@Override
public void nodeLeft(String leftNodeID) {
HAManager.this.nodeLeft(leftNodeID);
}
});
clusterMap.put(nodeID, haInfo.encode());
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