org.elasticsearch.cluster.ClusterStateTaskExecutor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elasticsearch Show documentation
Show all versions of elasticsearch Show documentation
Elasticsearch subproject :server
/*
* 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.
*/
package org.elasticsearch.cluster;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
public interface ClusterStateTaskExecutor {
/**
* Update the cluster state based on the current state and the given tasks. Return the *same instance* if no state
* should be changed.
*/
BatchResult execute(ClusterState currentState, List tasks) throws Exception;
/**
* indicates whether this task should only run if current node is master
*/
default boolean runOnlyOnMaster() {
return true;
}
/**
* Callback invoked after new cluster state is published. Note that
* this method is not invoked if the cluster state was not updated.
* @param clusterChangedEvent the change event for this cluster state change, containing
* both old and new states
*/
default void clusterStatePublished(ClusterChangedEvent clusterChangedEvent) {
}
/**
* Builds a concise description of a list of tasks (to be used in logging etc.).
*
* Note that the tasks given are not necessarily the same as those that will be passed to {@link #execute(ClusterState, List)}.
* but are guaranteed to be a subset of them. This method can be called multiple times with different lists before execution.
* This allows groupd task description but the submitting source.
*/
default String describeTasks(List tasks) {
return tasks.stream().map(T::toString).reduce((s1,s2) -> {
if (s1.isEmpty()) {
return s2;
} else if (s2.isEmpty()) {
return s1;
} else {
return s1 + ", " + s2;
}
}).orElse("");
}
/**
* Represents the result of a batched execution of cluster state update tasks
* @param the type of the cluster state update task
*/
class BatchResult {
public final ClusterState resultingState;
public final Map executionResults;
/**
* Construct an execution result instance with a correspondence between the tasks and their execution result
* @param resultingState the resulting cluster state
* @param executionResults the correspondence between tasks and their outcome
*/
BatchResult(ClusterState resultingState, Map executionResults) {
this.resultingState = resultingState;
this.executionResults = executionResults;
}
public static Builder builder() {
return new Builder<>();
}
public static class Builder {
private final Map executionResults = new IdentityHashMap<>();
public Builder success(T task) {
return result(task, TaskResult.success());
}
public Builder successes(Iterable tasks) {
for (T task : tasks) {
success(task);
}
return this;
}
public Builder failure(T task, Exception e) {
return result(task, TaskResult.failure(e));
}
public Builder failures(Iterable tasks, Exception e) {
for (T task : tasks) {
failure(task, e);
}
return this;
}
private Builder result(T task, TaskResult executionResult) {
TaskResult existing = executionResults.put(task, executionResult);
assert existing == null : task + " already has result " + existing;
return this;
}
public BatchResult build(ClusterState resultingState) {
return new BatchResult<>(resultingState, executionResults);
}
}
}
final class TaskResult {
private final Exception failure;
private static final TaskResult SUCCESS = new TaskResult(null);
public static TaskResult success() {
return SUCCESS;
}
public static TaskResult failure(Exception failure) {
return new TaskResult(failure);
}
private TaskResult(Exception failure) {
this.failure = failure;
}
public boolean isSuccess() {
return this == SUCCESS;
}
public Exception getFailure() {
assert !isSuccess();
return failure;
}
/**
* Handle the execution result with the provided consumers
* @param onSuccess handler to invoke on success
* @param onFailure handler to invoke on failure; the throwable passed through will not be null
*/
public void handle(Runnable onSuccess, Consumer onFailure) {
if (failure == null) {
onSuccess.run();
} else {
onFailure.accept(failure);
}
}
}
}