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

org.opensearch.gateway.ClusterStateUpdaters Maven / Gradle / Ivy

There is a newer version: 2.18.0
Show newest version
/*
 * SPDX-License-Identifier: Apache-2.0
 *
 * The OpenSearch Contributors require contributions made to
 * this file be licensed under the Apache-2.0 license or a
 * compatible open source license.
 */

/*
 * Licensed to Elasticsearch under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch licenses this file to you under
 * the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/*
 * Modifications Copyright OpenSearch Contributors. See
 * GitHub history for details.
 */

package org.opensearch.gateway;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.opensearch.cluster.ClusterState;
import org.opensearch.cluster.block.ClusterBlocks;
import org.opensearch.cluster.metadata.IndexMetadata;
import org.opensearch.cluster.metadata.Metadata;
import org.opensearch.cluster.node.DiscoveryNode;
import org.opensearch.cluster.node.DiscoveryNodes;
import org.opensearch.cluster.routing.RecoverySource;
import org.opensearch.cluster.routing.RoutingTable;
import org.opensearch.common.settings.ClusterSettings;

import java.util.Map;

import static org.opensearch.gateway.GatewayService.STATE_NOT_RECOVERED_BLOCK;

/**
 * Updates cluster state
 *
 * @opensearch.internal
 */
public class ClusterStateUpdaters {
    private static final Logger logger = LogManager.getLogger(ClusterStateUpdaters.class);

    static ClusterState setLocalNode(final ClusterState clusterState, DiscoveryNode localNode) {
        return ClusterState.builder(clusterState)
            .nodes(DiscoveryNodes.builder().add(localNode).localNodeId(localNode.getId()).build())
            .build();
    }

    static ClusterState upgradeAndArchiveUnknownOrInvalidSettings(final ClusterState clusterState, final ClusterSettings clusterSettings) {
        final Metadata.Builder metadataBuilder = Metadata.builder(clusterState.metadata());

        metadataBuilder.persistentSettings(
            clusterSettings.archiveUnknownOrInvalidSettings(
                clusterSettings.upgradeSettings(metadataBuilder.persistentSettings()),
                e -> logUnknownSetting("persistent", e),
                (e, ex) -> logInvalidSetting("persistent", e, ex)
            )
        );
        metadataBuilder.transientSettings(
            clusterSettings.archiveUnknownOrInvalidSettings(
                clusterSettings.upgradeSettings(metadataBuilder.transientSettings()),
                e -> logUnknownSetting("transient", e),
                (e, ex) -> logInvalidSetting("transient", e, ex)
            )
        );
        return ClusterState.builder(clusterState).metadata(metadataBuilder).build();
    }

    private static void logUnknownSetting(final String settingType, final Map.Entry e) {
        logger.warn("ignoring unknown {} setting: [{}] with value [{}]; archiving", settingType, e.getKey(), e.getValue());
    }

    private static void logInvalidSetting(final String settingType, final Map.Entry e, final IllegalArgumentException ex) {
        logger.warn(
            () -> new ParameterizedMessage(
                "ignoring invalid {} setting: [{}] with value [{}]; archiving",
                settingType,
                e.getKey(),
                e.getValue()
            ),
            ex
        );
    }

    static ClusterState recoverClusterBlocks(final ClusterState state) {
        final ClusterBlocks.Builder blocks = ClusterBlocks.builder().blocks(state.blocks());

        if (Metadata.SETTING_READ_ONLY_SETTING.get(state.metadata().settings())) {
            blocks.addGlobalBlock(Metadata.CLUSTER_READ_ONLY_BLOCK);
        }

        if (Metadata.SETTING_READ_ONLY_ALLOW_DELETE_SETTING.get(state.metadata().settings())) {
            blocks.addGlobalBlock(Metadata.CLUSTER_READ_ONLY_ALLOW_DELETE_BLOCK);
        }

        for (final IndexMetadata indexMetadata : state.metadata()) {
            blocks.addBlocks(indexMetadata);
        }

        return ClusterState.builder(state).blocks(blocks).build();
    }

    static ClusterState updateRoutingTable(final ClusterState state) {
        // initialize all index routing tables as empty
        final RoutingTable.Builder routingTableBuilder = RoutingTable.builder(state.routingTable());
        for (final IndexMetadata cursor : state.metadata().indices().values()) {
            // Whether IndexMetadata is recovered from local disk or remote it doesn't matter to us at this point.
            // We are only concerned about index data recovery here. Which is why we only check for remote store enabled and not for remote
            // cluster state enabled.
            if (cursor.getSettings().getAsBoolean(IndexMetadata.SETTING_REMOTE_STORE_ENABLED, false) == false
                || state.routingTable().hasIndex(cursor.getIndex()) == false
                || state.routingTable()
                    .index(cursor.getIndex())
                    .shardsMatchingPredicateCount(
                        shardRouting -> shardRouting.primary()
                            // We need to ensure atleast one of the primaries is being recovered from remote.
                            // This ensures we have gone through the RemoteStoreRestoreService and routing table is updated
                            && shardRouting.recoverySource() instanceof RecoverySource.RemoteStoreRecoverySource
                    ) == 0) {
                routingTableBuilder.addAsRecovery(cursor);
            }
        }
        // start with 0 based versions for routing table
        routingTableBuilder.version(0);
        return ClusterState.builder(state).routingTable(routingTableBuilder.build()).build();
    }

    static ClusterState removeStateNotRecoveredBlock(final ClusterState state) {
        return ClusterState.builder(state)
            .blocks(ClusterBlocks.builder().blocks(state.blocks()).removeGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK).build())
            .build();
    }

    public static ClusterState addStateNotRecoveredBlock(ClusterState state) {
        return ClusterState.builder(state)
            .blocks(ClusterBlocks.builder().blocks(state.blocks()).addGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK).build())
            .build();
    }

    static ClusterState mixCurrentStateAndRecoveredState(final ClusterState currentState, final ClusterState recoveredState) {
        assert currentState.metadata().indices().isEmpty();

        final ClusterBlocks.Builder blocks = ClusterBlocks.builder().blocks(currentState.blocks()).blocks(recoveredState.blocks());

        final Metadata.Builder metadataBuilder = Metadata.builder(recoveredState.metadata());
        // automatically generate a UID for the metadata if we need to
        metadataBuilder.generateClusterUuidIfNeeded();

        for (final IndexMetadata indexMetadata : recoveredState.metadata()) {
            metadataBuilder.put(indexMetadata, false);
        }

        return ClusterState.builder(currentState).blocks(blocks).metadata(metadataBuilder).build();
    }

    public static ClusterState hideStateIfNotRecovered(ClusterState state) {
        if (state.blocks().hasGlobalBlock(STATE_NOT_RECOVERED_BLOCK)) {
            final ClusterBlocks.Builder blocks = ClusterBlocks.builder().blocks(state.blocks());
            blocks.removeGlobalBlock(Metadata.CLUSTER_READ_ONLY_BLOCK);
            blocks.removeGlobalBlock(Metadata.CLUSTER_READ_ONLY_ALLOW_DELETE_BLOCK);
            for (IndexMetadata indexMetadata : state.metadata()) {
                blocks.removeIndexBlocks(indexMetadata.getIndex().getName());
            }
            final Metadata metadata = Metadata.builder()
                .clusterUUID(state.metadata().clusterUUID())
                .coordinationMetadata(state.metadata().coordinationMetadata())
                .build();

            return ClusterState.builder(state).metadata(metadata).blocks(blocks.build()).build();
        }
        return state;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy