Search in sources :

Example 36 with VotingConfiguration

use of org.elasticsearch.cluster.coordination.CoordinationMetadata.VotingConfiguration in project crate by crate.

the class Coordinator method doStart.

@Override
protected void doStart() {
    synchronized (mutex) {
        CoordinationState.PersistedState persistedState = persistedStateSupplier.get();
        coordinationState.set(new CoordinationState(settings, getLocalNode(), persistedState));
        peerFinder.setCurrentTerm(getCurrentTerm());
        configuredHostsResolver.start();
        final ClusterState lastAcceptedState = coordinationState.get().getLastAcceptedState();
        if (lastAcceptedState.metadata().clusterUUIDCommitted()) {
            LOGGER.info("cluster UUID [{}]", lastAcceptedState.metadata().clusterUUID());
        }
        final VotingConfiguration votingConfiguration = lastAcceptedState.getLastCommittedConfiguration();
        if (singleNodeDiscovery && votingConfiguration.isEmpty() == false && votingConfiguration.hasQuorum(Collections.singleton(getLocalNode().getId())) == false) {
            throw new IllegalStateException("cannot start with [" + DiscoveryModule.DISCOVERY_TYPE_SETTING.getKey() + "] set to [" + DiscoveryModule.SINGLE_NODE_DISCOVERY_TYPE + "] when local node " + getLocalNode() + " does not have quorum in voting configuration " + votingConfiguration);
        }
        ClusterState initialState = ClusterState.builder(ClusterName.CLUSTER_NAME_SETTING.get(settings)).blocks(ClusterBlocks.builder().addGlobalBlock(STATE_NOT_RECOVERED_BLOCK).addGlobalBlock(noMasterBlockService.getNoMasterBlock())).nodes(DiscoveryNodes.builder().add(getLocalNode()).localNodeId(getLocalNode().getId())).build();
        applierState = initialState;
        clusterApplier.setInitialState(initialState);
    }
}
Also used : ClusterState(org.elasticsearch.cluster.ClusterState) VotingConfiguration(org.elasticsearch.cluster.coordination.CoordinationMetadata.VotingConfiguration)

Example 37 with VotingConfiguration

use of org.elasticsearch.cluster.coordination.CoordinationMetadata.VotingConfiguration in project crate by crate.

the class Reconfigurator method reconfigure.

/**
 * Compute an optimal configuration for the cluster.
 *
 * @param liveNodes      The live nodes in the cluster. The optimal configuration prefers live nodes over non-live nodes as far as
 *                       possible.
 * @param retiredNodeIds Nodes that are leaving the cluster and which should not appear in the configuration if possible. Nodes that are
 *                       retired and not in the current configuration will never appear in the resulting configuration; this is useful
 *                       for shifting the vote in a 2-node cluster so one of the nodes can be restarted without harming availability.
 * @param currentMaster  The current master. Unless retired, we prefer to keep the current master in the config.
 * @param currentConfig  The current configuration. As far as possible, we prefer to keep the current config as-is.
 * @return An optimal configuration, or leave the current configuration unchanged if the optimal configuration has no live quorum.
 */
public VotingConfiguration reconfigure(Set<DiscoveryNode> liveNodes, Set<String> retiredNodeIds, DiscoveryNode currentMaster, VotingConfiguration currentConfig) {
    assert liveNodes.contains(currentMaster) : "liveNodes = " + liveNodes + " master = " + currentMaster;
    LOGGER.trace("{} reconfiguring {} based on liveNodes={}, retiredNodeIds={}, currentMaster={}", this, currentConfig, liveNodes, retiredNodeIds, currentMaster);
    final Set<String> liveNodeIds = liveNodes.stream().filter(DiscoveryNode::isMasterEligibleNode).map(DiscoveryNode::getId).collect(Collectors.toSet());
    final Set<String> currentConfigNodeIds = currentConfig.getNodeIds();
    final Set<VotingConfigNode> orderedCandidateNodes = new TreeSet<>();
    liveNodes.stream().filter(DiscoveryNode::isMasterEligibleNode).filter(n -> retiredNodeIds.contains(n.getId()) == false).forEach(n -> orderedCandidateNodes.add(new VotingConfigNode(n.getId(), true, n.getId().equals(currentMaster.getId()), currentConfigNodeIds.contains(n.getId()))));
    currentConfigNodeIds.stream().filter(nid -> liveNodeIds.contains(nid) == false).filter(nid -> retiredNodeIds.contains(nid) == false).forEach(nid -> orderedCandidateNodes.add(new VotingConfigNode(nid, false, false, true)));
    /*
         * Now we work out how many nodes should be in the configuration:
         */
    final int nonRetiredConfigSize = Math.toIntExact(orderedCandidateNodes.stream().filter(n -> n.inCurrentConfig).count());
    final int minimumConfigEnforcedSize = autoShrinkVotingConfiguration ? (nonRetiredConfigSize < 3 ? 1 : 3) : nonRetiredConfigSize;
    final int nonRetiredLiveNodeCount = Math.toIntExact(orderedCandidateNodes.stream().filter(n -> n.live).count());
    final int targetSize = Math.max(roundDownToOdd(nonRetiredLiveNodeCount), minimumConfigEnforcedSize);
    final VotingConfiguration newConfig = new VotingConfiguration(orderedCandidateNodes.stream().limit(targetSize).map(n -> n.id).collect(Collectors.toSet()));
    // new configuration should have a quorum
    if (newConfig.hasQuorum(liveNodeIds)) {
        return newConfig;
    } else {
        // If there are not enough live nodes to form a quorum in the newly-proposed configuration, it's better to do nothing.
        return currentConfig;
    }
}
Also used : DiscoveryNode(org.elasticsearch.cluster.node.DiscoveryNode) ClusterSettings(org.elasticsearch.common.settings.ClusterSettings) Logger(org.apache.logging.log4j.Logger) Settings(org.elasticsearch.common.settings.Settings) Setting(org.elasticsearch.common.settings.Setting) Property(org.elasticsearch.common.settings.Setting.Property) Set(java.util.Set) VotingConfiguration(org.elasticsearch.cluster.coordination.CoordinationMetadata.VotingConfiguration) LogManager(org.apache.logging.log4j.LogManager) Collectors(java.util.stream.Collectors) TreeSet(java.util.TreeSet) DiscoveryNode(org.elasticsearch.cluster.node.DiscoveryNode) TreeSet(java.util.TreeSet) VotingConfiguration(org.elasticsearch.cluster.coordination.CoordinationMetadata.VotingConfiguration)

Example 38 with VotingConfiguration

use of org.elasticsearch.cluster.coordination.CoordinationMetadata.VotingConfiguration in project crate by crate.

the class CoordinatorTests method testExpandsConfigurationWhenGrowingFromOneNodeToThreeButDoesNotShrink.

public void testExpandsConfigurationWhenGrowingFromOneNodeToThreeButDoesNotShrink() {
    try (Cluster cluster = new Cluster(1)) {
        cluster.runRandomly();
        cluster.stabilise();
        final ClusterNode leader = cluster.getAnyLeader();
        cluster.addNodesAndStabilise(2);
        {
            assertThat(leader.coordinator.getMode(), is(Mode.LEADER));
            final VotingConfiguration lastCommittedConfiguration = leader.getLastAppliedClusterState().getLastCommittedConfiguration();
            assertThat(lastCommittedConfiguration + " should be all nodes", lastCommittedConfiguration.getNodeIds(), equalTo(cluster.clusterNodes.stream().map(ClusterNode::getId).collect(Collectors.toSet())));
        }
        final ClusterNode disconnect1 = cluster.getAnyNode();
        logger.info("--> disconnecting {}", disconnect1);
        disconnect1.disconnect();
        cluster.stabilise();
        {
            final ClusterNode newLeader = cluster.getAnyLeader();
            final VotingConfiguration lastCommittedConfiguration = newLeader.getLastAppliedClusterState().getLastCommittedConfiguration();
            assertThat(lastCommittedConfiguration + " should be all nodes", lastCommittedConfiguration.getNodeIds(), equalTo(cluster.clusterNodes.stream().map(ClusterNode::getId).collect(Collectors.toSet())));
        }
    }
}
Also used : ClusterNode(org.elasticsearch.cluster.coordination.AbstractCoordinatorTestCase.Cluster.ClusterNode) VotingConfiguration(org.elasticsearch.cluster.coordination.CoordinationMetadata.VotingConfiguration)

Example 39 with VotingConfiguration

use of org.elasticsearch.cluster.coordination.CoordinationMetadata.VotingConfiguration in project crate by crate.

the class CoordinatorTests method testCannotSetInitialConfigurationWithoutQuorum.

public void testCannotSetInitialConfigurationWithoutQuorum() {
    try (Cluster cluster = new Cluster(randomIntBetween(1, 5))) {
        final Coordinator coordinator = cluster.getAnyNode().coordinator;
        final VotingConfiguration unknownNodeConfiguration = new VotingConfiguration(Set.of(coordinator.getLocalNode().getId(), "unknown-node"));
        final String exceptionMessage = expectThrows(CoordinationStateRejectedException.class, () -> coordinator.setInitialConfiguration(unknownNodeConfiguration)).getMessage();
        assertThat(exceptionMessage, startsWith("not enough nodes discovered to form a quorum in the initial configuration [knownNodes=["));
        assertThat(exceptionMessage, containsString("unknown-node"));
        assertThat(exceptionMessage, containsString(coordinator.getLocalNode().toString()));
        // This is VERY BAD: setting a _different_ initial configuration. Yet it works if the first attempt will never be a quorum.
        assertTrue(coordinator.setInitialConfiguration(new VotingConfiguration(Collections.singleton(coordinator.getLocalNode().getId()))));
        cluster.stabilise();
    }
}
Also used : Matchers.containsString(org.hamcrest.Matchers.containsString) VotingConfiguration(org.elasticsearch.cluster.coordination.CoordinationMetadata.VotingConfiguration)

Example 40 with VotingConfiguration

use of org.elasticsearch.cluster.coordination.CoordinationMetadata.VotingConfiguration in project crate by crate.

the class NodeJoinTests method testJoinWithHigherTermElectsLeader.

public void testJoinWithHigherTermElectsLeader() {
    DiscoveryNode node0 = newNode(0, true);
    DiscoveryNode node1 = newNode(1, true);
    long initialTerm = randomLongBetween(1, 10);
    long initialVersion = randomLongBetween(1, 10);
    setupFakeMasterServiceAndCoordinator(initialTerm, initialState(node0, initialTerm, initialVersion, new VotingConfiguration(Collections.singleton(randomFrom(node0, node1).getId()))));
    assertFalse(isLocalNodeElectedMaster());
    assertNull(coordinator.getStateForMasterService().nodes().getMasterNodeId());
    long newTerm = initialTerm + randomLongBetween(1, 10);
    SimpleFuture fut = joinNodeAsync(new JoinRequest(node1, Optional.of(new Join(node1, node0, newTerm, initialTerm, initialVersion))));
    assertEquals(Coordinator.Mode.LEADER, coordinator.getMode());
    assertNull(coordinator.getStateForMasterService().nodes().getMasterNodeId());
    deterministicTaskQueue.runAllRunnableTasks();
    assertTrue(fut.isDone());
    assertTrue(isLocalNodeElectedMaster());
    assertTrue(coordinator.getStateForMasterService().nodes().isLocalNodeElectedMaster());
}
Also used : DiscoveryNode(org.elasticsearch.cluster.node.DiscoveryNode) VotingConfiguration(org.elasticsearch.cluster.coordination.CoordinationMetadata.VotingConfiguration)

Aggregations

VotingConfiguration (org.elasticsearch.cluster.coordination.CoordinationMetadata.VotingConfiguration)66 ClusterState (org.elasticsearch.cluster.ClusterState)40 DiscoveryNode (org.elasticsearch.cluster.node.DiscoveryNode)19 DiscoveryNodes (org.elasticsearch.cluster.node.DiscoveryNodes)8 Set (java.util.Set)6 HashSet (java.util.HashSet)5 Settings (org.elasticsearch.common.settings.Settings)5 Tuple (io.crate.common.collections.Tuple)4 Collections (java.util.Collections)4 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)4 Collectors (java.util.stream.Collectors)4 ClusterSettings (org.elasticsearch.common.settings.ClusterSettings)4 TimeValue (io.crate.common.unit.TimeValue)3 IOException (java.io.IOException)3 ArrayList (java.util.ArrayList)3 List (java.util.List)3 Optional (java.util.Optional)3 TimeUnit (java.util.concurrent.TimeUnit)3 Stream (java.util.stream.Stream)3 ESTestCase (org.elasticsearch.test.ESTestCase)3