org.elasticsearch.cluster.routing.allocation.decider.Decision 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.routing.allocation.decider;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
* This abstract class defining basic {@link Decision} used during shard
* allocation process.
*
* @see AllocationDecider
*/
public abstract class Decision implements ToXContent {
public static final Decision ALWAYS = new Single(Type.YES);
public static final Decision YES = new Single(Type.YES);
public static final Decision NO = new Single(Type.NO);
public static final Decision THROTTLE = new Single(Type.THROTTLE);
/**
* Creates a simple decision
* @param type {@link Type} of the decision
* @param label label for the Decider that produced this decision
* @param explanation explanation of the decision
* @param explanationParams additional parameters for the decision
* @return new {@link Decision} instance
*/
public static Decision single(Type type, String label, String explanation, Object... explanationParams) {
return new Single(type, label, explanation, explanationParams);
}
public static void writeTo(Decision decision, StreamOutput out) throws IOException {
if (decision instanceof Multi) {
// Flag specifying whether it is a Multi or Single Decision
out.writeBoolean(true);
out.writeVInt(((Multi) decision).decisions.size());
for (Decision d : ((Multi) decision).decisions) {
writeTo(d, out);
}
} else {
// Flag specifying whether it is a Multi or Single Decision
out.writeBoolean(false);
Single d = ((Single) decision);
Type.writeTo(d.type, out);
out.writeOptionalString(d.label);
// Flatten explanation on serialization, so that explanationParams
// do not need to be serialized
out.writeOptionalString(d.getExplanation());
}
}
public static Decision readFrom(StreamInput in) throws IOException {
// Determine whether to read a Single or Multi Decision
if (in.readBoolean()) {
Multi result = new Multi();
int decisionCount = in.readVInt();
for (int i = 0; i < decisionCount; i++) {
Decision s = readFrom(in);
result.decisions.add(s);
}
return result;
} else {
Single result = new Single();
result.type = Type.readFrom(in);
result.label = in.readOptionalString();
result.explanationString = in.readOptionalString();
return result;
}
}
/**
* This enumeration defines the
* possible types of decisions
*/
public static enum Type {
YES,
NO,
THROTTLE;
public static Type resolve(String s) {
return Type.valueOf(s.toUpperCase(Locale.ROOT));
}
public static Type readFrom(StreamInput in) throws IOException {
int i = in.readVInt();
switch (i) {
case 0:
return NO;
case 1:
return YES;
case 2:
return THROTTLE;
default:
throw new IllegalArgumentException("No Type for integer [" + i + "]");
}
}
public static void writeTo(Type type, StreamOutput out) throws IOException {
switch (type) {
case NO:
out.writeVInt(0);
break;
case YES:
out.writeVInt(1);
break;
case THROTTLE:
out.writeVInt(2);
break;
default:
throw new IllegalArgumentException("Invalid Type [" + type + "]");
}
}
}
/**
* Get the {@link Type} of this decision
* @return {@link Type} of this decision
*/
public abstract Type type();
public abstract String label();
/**
* Simple class representing a single decision
*/
public static class Single extends Decision {
private Type type;
private String label;
private String explanation;
private String explanationString;
private Object[] explanationParams;
public Single() {
}
/**
* Creates a new {@link Single} decision of a given type
* @param type {@link Type} of the decision
*/
public Single(Type type) {
this(type, null, null, (Object[]) null);
}
/**
* Creates a new {@link Single} decision of a given type
*
* @param type {@link Type} of the decision
* @param explanation An explanation of this {@link Decision}
* @param explanationParams A set of additional parameters
*/
public Single(Type type, String label, String explanation, Object... explanationParams) {
this.type = type;
this.label = label;
this.explanation = explanation;
this.explanationParams = explanationParams;
}
@Override
public Type type() {
return this.type;
}
@Override
public String label() {
return this.label;
}
/**
* Returns the explanation string, fully formatted. Only formats the string once
*/
public String getExplanation() {
if (explanationString == null && explanation != null) {
explanationString = String.format(Locale.ROOT, explanation, explanationParams);
}
return this.explanationString;
}
@Override
public String toString() {
if (explanation == null) {
return type + "()";
}
return type + "(" + getExplanation() + ")";
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field("decider", label);
builder.field("decision", type);
String explanation = getExplanation();
builder.field("explanation", explanation != null ? explanation : "none");
builder.endObject();
return builder;
}
}
/**
* Simple class representing a list of decisions
*/
public static class Multi extends Decision {
private final List decisions = new ArrayList<>();
/**
* Add a decision to this {@link Multi}decision instance
* @param decision {@link Decision} to add
* @return {@link Multi}decision instance with the given decision added
*/
public Multi add(Decision decision) {
decisions.add(decision);
return this;
}
@Override
public Type type() {
Type ret = Type.YES;
for (int i = 0; i < decisions.size(); i++) {
Type type = decisions.get(i).type();
if (type == Type.NO) {
return type;
} else if (type == Type.THROTTLE) {
ret = type;
}
}
return ret;
}
@Override
public String label() {
// Multi decisions have no labels
return null;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Decision decision : decisions) {
sb.append("[").append(decision.toString()).append("]");
}
return sb.toString();
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startArray("decisions");
for (Decision d : decisions) {
d.toXContent(builder, params);
}
builder.endArray();
return builder;
}
}
}