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

org.elasticsearch.cluster.routing.allocation.decider.NodeShutdownAllocationDecider Maven / Gradle / Ivy

There is a newer version: 8.14.0
Show newest version
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */

package org.elasticsearch.cluster.routing.allocation.decider;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.metadata.NodesShutdownMetadata;
import org.elasticsearch.cluster.metadata.SingleNodeShutdownMetadata;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.routing.RoutingNode;
import org.elasticsearch.cluster.routing.ShardRouting;
import org.elasticsearch.cluster.routing.allocation.RoutingAllocation;
import org.elasticsearch.core.Nullable;

/**
 * An allocation decider that prevents shards from being allocated to a
 * node that is in the process of shutting down.
 *
 * In short: No shards can be allocated to, or remain on, a node which is
 * shutting down for removal. Primary shards cannot be allocated to, or remain
 * on, a node which is shutting down for restart.
 */
public class NodeShutdownAllocationDecider extends AllocationDecider {
    private static final Logger logger = LogManager.getLogger(NodeShutdownAllocationDecider.class);

    private static final String NAME = "node_shutdown";

    /**
     * Determines if a shard can be allocated to a particular node, based on whether that node is shutting down or not.
     */
    @Override
    public Decision canAllocate(ShardRouting shardRouting, RoutingNode node, RoutingAllocation allocation) {
        final SingleNodeShutdownMetadata thisNodeShutdownMetadata = getNodeShutdownMetadata(allocation.metadata(), node.nodeId());

        if (thisNodeShutdownMetadata == null) {
            // There's no shutdown metadata for this node, return yes.
            return allocation.decision(Decision.YES, NAME, "this node is not currently shutting down");
        }

        switch (thisNodeShutdownMetadata.getType()) {
            case REPLACE:
            case REMOVE:
                return allocation.decision(Decision.NO, NAME, "node [%s] is preparing to be removed from the cluster", node.nodeId());
            case RESTART:
                return allocation.decision(
                    Decision.YES,
                    NAME,
                    "node [%s] is preparing to restart, but will remain in the cluster",
                    node.nodeId()
                );
            default:
                logger.debug(
                    "found unrecognized node shutdown type [{}] while deciding allocation for [{}] shard [{}][{}] on node [{}]",
                    thisNodeShutdownMetadata.getType(),
                    shardRouting.primary() ? "primary" : "replica",
                    shardRouting.getIndexName(),
                    shardRouting.getId(),
                    node.nodeId()
                );
                assert false : "node shutdown type not recognized: " + thisNodeShutdownMetadata.getType();
                return Decision.YES;
        }
    }

    /**
     * Applies the same rules as {@link NodeShutdownAllocationDecider#canAllocate(ShardRouting, RoutingNode, RoutingAllocation)} to
     * determine if shards can remain on their current node.
     */
    @Override
    public Decision canRemain(ShardRouting shardRouting, RoutingNode node, RoutingAllocation allocation) {
        return this.canAllocate(shardRouting, node, allocation);
    }

    /**
     * Prevents indices from being auto-expanded to nodes which are in the process of shutting down, regardless of whether they're shutting
     * down for restart or removal.
     */
    @Override
    public Decision shouldAutoExpandToNode(IndexMetadata indexMetadata, DiscoveryNode node, RoutingAllocation allocation) {
        SingleNodeShutdownMetadata thisNodeShutdownMetadata = getNodeShutdownMetadata(allocation.metadata(), node.getId());

        if (thisNodeShutdownMetadata == null) {
            return allocation.decision(Decision.YES, NAME, "node [%s] is not preparing for removal from the cluster", node.getId());
        }

        switch (thisNodeShutdownMetadata.getType()) {
            case RESTART:
                return allocation.decision(
                    Decision.YES,
                    NAME,
                    "node [%s] is not preparing for removal from the cluster (is restarting)",
                    node.getId()
                );
            case REPLACE:
            case REMOVE:
                return allocation.decision(Decision.NO, NAME, "node [%s] is preparing for removal from the cluster", node.getId());
            default:
                logger.debug(
                    "found unrecognized node shutdown type [{}] while deciding auto-expansion for index [{}] on node [{}]",
                    thisNodeShutdownMetadata.getType(),
                    indexMetadata.getIndex().getName(),
                    node.getId()
                );
                assert false : "node shutdown type not recognized: " + thisNodeShutdownMetadata.getType();
                return Decision.YES;
        }
    }

    @Nullable
    private static SingleNodeShutdownMetadata getNodeShutdownMetadata(Metadata metadata, String nodeId) {
        NodesShutdownMetadata nodesShutdownMetadata = metadata.custom(NodesShutdownMetadata.TYPE);
        if (nodesShutdownMetadata == null || nodesShutdownMetadata.getAllNodeMetadataMap() == null) {
            // There are no nodes in the process of shutting down, return null.
            return null;
        }

        return nodesShutdownMetadata.getAllNodeMetadataMap().get(nodeId);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy