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

org.elasticsearch.reservedstate.service.ReservedStateUpdateTask Maven / Gradle / Ivy

There is a newer version: 8.13.4
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.reservedstate.service;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.ClusterStateTaskListener;
import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.metadata.ReservedStateErrorMetadata;
import org.elasticsearch.cluster.metadata.ReservedStateHandlerMetadata;
import org.elasticsearch.cluster.metadata.ReservedStateMetadata;
import org.elasticsearch.reservedstate.NonStateTransformResult;
import org.elasticsearch.reservedstate.ReservedClusterStateHandler;
import org.elasticsearch.reservedstate.TransformState;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;

import static org.elasticsearch.ExceptionsHelper.stackTrace;
import static org.elasticsearch.core.Strings.format;

/**
 * Generic task to update and reserve parts of the cluster state
 *
 * 

* Reserved cluster state can only be modified by using the {@link ReservedClusterStateService}. Updating * the reserved cluster state through REST APIs is not permitted. */ public class ReservedStateUpdateTask implements ClusterStateTaskListener { private static final Logger logger = LogManager.getLogger(ReservedStateUpdateTask.class); private final String namespace; private final ReservedStateChunk stateChunk; private final Map> handlers; private final Collection orderedHandlers; private final BiConsumer errorReporter; private final ActionListener listener; private final Collection nonStateTransformResults; public ReservedStateUpdateTask( String namespace, ReservedStateChunk stateChunk, Collection nonStateTransformResults, Map> handlers, Collection orderedHandlers, BiConsumer errorReporter, ActionListener listener ) { this.namespace = namespace; this.stateChunk = stateChunk; this.nonStateTransformResults = nonStateTransformResults; this.handlers = handlers; this.orderedHandlers = orderedHandlers; this.errorReporter = errorReporter; this.listener = listener; } @Override public void onFailure(Exception e) { listener.onFailure(e); } ActionListener listener() { return listener; } protected ClusterState execute(final ClusterState currentState) { ReservedStateMetadata existingMetadata = currentState.metadata().reservedStateMetadata().get(namespace); Map reservedState = stateChunk.state(); ReservedStateVersion reservedStateVersion = stateChunk.metadata(); if (checkMetadataVersion(namespace, existingMetadata, reservedStateVersion) == false) { return currentState; } var reservedMetadataBuilder = new ReservedStateMetadata.Builder(namespace).version(reservedStateVersion.version()); List errors = new ArrayList<>(); ClusterState state = currentState; // Transform the cluster state first for (var handlerName : orderedHandlers) { ReservedClusterStateHandler handler = handlers.get(handlerName); try { Set existingKeys = keysForHandler(existingMetadata, handlerName); TransformState transformState = handler.transform(reservedState.get(handlerName), new TransformState(state, existingKeys)); state = transformState.state(); reservedMetadataBuilder.putHandler(new ReservedStateHandlerMetadata(handlerName, transformState.keys())); } catch (Exception e) { errors.add(format("Error processing %s state change: %s", handler.name(), stackTrace(e))); } } checkAndThrowOnError(errors, currentState, reservedStateVersion); // Once we have set all of the handler state from the cluster state update tasks, we add the reserved keys // from the non cluster state transforms. for (var transform : nonStateTransformResults) { reservedMetadataBuilder.putHandler(new ReservedStateHandlerMetadata(transform.handlerName(), transform.updatedKeys())); } // Remove the last error if we had previously encountered any in prior processing of reserved state reservedMetadataBuilder.errorMetadata(null); ClusterState.Builder stateBuilder = new ClusterState.Builder(state); Metadata.Builder metadataBuilder = Metadata.builder(state.metadata()).put(reservedMetadataBuilder.build()); return stateBuilder.metadata(metadataBuilder).build(); } private void checkAndThrowOnError(List errors, ClusterState currentState, ReservedStateVersion reservedStateVersion) { // Any errors should be discovered through validation performed in the transform calls if (errors.isEmpty() == false) { logger.debug("Error processing state change request for [{}] with the following errors [{}]", namespace, errors); var errorState = new ErrorState( namespace, reservedStateVersion.version(), errors, ReservedStateErrorMetadata.ErrorKind.VALIDATION ); errorReporter.accept(currentState, errorState); throw new IllegalStateException("Error processing state change request for " + namespace + ", errors: " + errorState); } } static Set keysForHandler(ReservedStateMetadata reservedStateMetadata, String handlerName) { if (reservedStateMetadata == null || reservedStateMetadata.handlers().get(handlerName) == null) { return Collections.emptySet(); } return reservedStateMetadata.handlers().get(handlerName).keys(); } static boolean checkMetadataVersion( String namespace, ReservedStateMetadata existingMetadata, ReservedStateVersion reservedStateVersion ) { if (Version.CURRENT.before(reservedStateVersion.minCompatibleVersion())) { logger.warn( () -> format( "Reserved cluster state version [%s] for namespace [%s] is not compatible with this Elasticsearch node", reservedStateVersion.minCompatibleVersion(), namespace ) ); return false; } // Version 0 is special, snapshot restores will reset to 0. if (reservedStateVersion.version() <= 0L) { logger.warn( () -> format( "Not updating reserved cluster state for namespace [%s], because version [%s] is less or equal to 0", namespace, reservedStateVersion.version(), existingMetadata.version() ) ); return false; } if (existingMetadata != null && existingMetadata.version() >= reservedStateVersion.version()) { logger.warn( () -> format( "Not updating reserved cluster state for namespace [%s], because version [%s] is less or equal" + " to the current metadata version [%s]", namespace, reservedStateVersion.version(), existingMetadata.version() ) ); return false; } return true; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy