org.elasticsearch.cluster.ClusterInfo 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 :distribution:archives:integ-test-zip
/*
* 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;
import com.carrotsearch.hppc.ObjectHashSet;
import com.carrotsearch.hppc.cursors.ObjectCursor;
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.routing.ShardRouting;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.index.store.StoreStats;
import org.elasticsearch.xcontent.ToXContentFragment;
import org.elasticsearch.xcontent.XContentBuilder;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
/**
* ClusterInfo is an object representing a map of nodes to {@link DiskUsage}
* and a map of shard ids to shard sizes, see
* InternalClusterInfoService.shardIdentifierFromRouting(String)
* for the key used in the shardSizes map
*/
public class ClusterInfo implements ToXContentFragment, Writeable {
public static final Version DATA_SET_SIZE_SIZE_VERSION = Version.V_7_13_0;
private final ImmutableOpenMap leastAvailableSpaceUsage;
private final ImmutableOpenMap mostAvailableSpaceUsage;
final ImmutableOpenMap shardSizes;
final ImmutableOpenMap shardDataSetSizes;
public static final ClusterInfo EMPTY = new ClusterInfo();
final ImmutableOpenMap routingToDataPath;
final ImmutableOpenMap reservedSpace;
protected ClusterInfo() {
this(
ImmutableOpenMap.of(),
ImmutableOpenMap.of(),
ImmutableOpenMap.of(),
ImmutableOpenMap.of(),
ImmutableOpenMap.of(),
ImmutableOpenMap.of()
);
}
/**
* Creates a new ClusterInfo instance.
*
* @param leastAvailableSpaceUsage a node id to disk usage mapping for the path that has the least available space on the node.
* @param mostAvailableSpaceUsage a node id to disk usage mapping for the path that has the most available space on the node.
* @param shardSizes a shardkey to size in bytes mapping per shard.
* @param shardDataSetSizes a shard id to data set size in bytes mapping per shard
* @param routingToDataPath the shard routing to datapath mapping
* @param reservedSpace reserved space per shard broken down by node and data path
* @see #shardIdentifierFromRouting
*/
public ClusterInfo(
ImmutableOpenMap leastAvailableSpaceUsage,
ImmutableOpenMap mostAvailableSpaceUsage,
ImmutableOpenMap shardSizes,
ImmutableOpenMap shardDataSetSizes,
ImmutableOpenMap routingToDataPath,
ImmutableOpenMap reservedSpace
) {
this.leastAvailableSpaceUsage = leastAvailableSpaceUsage;
this.shardSizes = shardSizes;
this.shardDataSetSizes = shardDataSetSizes;
this.mostAvailableSpaceUsage = mostAvailableSpaceUsage;
this.routingToDataPath = routingToDataPath;
this.reservedSpace = reservedSpace;
}
public ClusterInfo(StreamInput in) throws IOException {
Map leastMap = in.readMap(StreamInput::readString, DiskUsage::new);
Map mostMap = in.readMap(StreamInput::readString, DiskUsage::new);
Map sizeMap = in.readMap(StreamInput::readString, StreamInput::readLong);
Map dataSetSizeMap;
if (in.getVersion().onOrAfter(DATA_SET_SIZE_SIZE_VERSION)) {
dataSetSizeMap = in.readMap(ShardId::new, StreamInput::readLong);
} else {
dataSetSizeMap = org.elasticsearch.core.Map.of();
}
Map routingMap = in.readMap(ShardRouting::new, StreamInput::readString);
Map reservedSpaceMap;
if (in.getVersion().onOrAfter(StoreStats.RESERVED_BYTES_VERSION)) {
reservedSpaceMap = in.readMap(NodeAndPath::new, ReservedSpace::new);
} else {
reservedSpaceMap = org.elasticsearch.core.Map.of();
}
ImmutableOpenMap.Builder leastBuilder = ImmutableOpenMap.builder();
this.leastAvailableSpaceUsage = leastBuilder.putAll(leastMap).build();
ImmutableOpenMap.Builder mostBuilder = ImmutableOpenMap.builder();
this.mostAvailableSpaceUsage = mostBuilder.putAll(mostMap).build();
ImmutableOpenMap.Builder sizeBuilder = ImmutableOpenMap.builder();
this.shardSizes = sizeBuilder.putAll(sizeMap).build();
ImmutableOpenMap.Builder dataSetSizeBuilder = ImmutableOpenMap.builder();
this.shardDataSetSizes = dataSetSizeBuilder.putAll(dataSetSizeMap).build();
ImmutableOpenMap.Builder routingBuilder = ImmutableOpenMap.builder();
this.routingToDataPath = routingBuilder.putAll(routingMap).build();
ImmutableOpenMap.Builder reservedSpaceBuilder = ImmutableOpenMap.builder();
this.reservedSpace = reservedSpaceBuilder.putAll(reservedSpaceMap).build();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeVInt(this.leastAvailableSpaceUsage.size());
for (ObjectObjectCursor c : this.leastAvailableSpaceUsage) {
out.writeString(c.key);
c.value.writeTo(out);
}
out.writeMap(this.mostAvailableSpaceUsage, StreamOutput::writeString, (o, v) -> v.writeTo(o));
out.writeMap(this.shardSizes, StreamOutput::writeString, (o, v) -> out.writeLong(v == null ? -1 : v));
if (out.getVersion().onOrAfter(DATA_SET_SIZE_SIZE_VERSION)) {
out.writeMap(this.shardDataSetSizes, (o, s) -> s.writeTo(o), (o, v) -> out.writeLong(v));
}
out.writeMap(this.routingToDataPath, (o, k) -> k.writeTo(o), StreamOutput::writeString);
if (out.getVersion().onOrAfter(StoreStats.RESERVED_BYTES_VERSION)) {
out.writeMap(this.reservedSpace);
}
}
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject("nodes");
{
for (ObjectObjectCursor c : this.leastAvailableSpaceUsage) {
builder.startObject(c.key);
{ // node
builder.field("node_name", c.value.getNodeName());
builder.startObject("least_available");
{
c.value.toShortXContent(builder);
}
builder.endObject(); // end "least_available"
builder.startObject("most_available");
{
DiskUsage most = this.mostAvailableSpaceUsage.get(c.key);
if (most != null) {
most.toShortXContent(builder);
}
}
builder.endObject(); // end "most_available"
}
builder.endObject(); // end $nodename
}
}
builder.endObject(); // end "nodes"
builder.startObject("shard_sizes");
{
for (ObjectObjectCursor c : this.shardSizes) {
builder.humanReadableField(c.key + "_bytes", c.key, new ByteSizeValue(c.value));
}
}
builder.endObject(); // end "shard_sizes"
builder.startObject("shard_data_set_sizes");
{
for (ObjectObjectCursor c : this.shardDataSetSizes) {
builder.humanReadableField(c.key + "_bytes", c.key.toString(), new ByteSizeValue(c.value));
}
}
builder.endObject(); // end "shard_data_set_sizes"
builder.startObject("shard_paths");
{
for (ObjectObjectCursor c : this.routingToDataPath) {
builder.field(c.key.toString(), c.value);
}
}
builder.endObject(); // end "shard_paths"
builder.startArray("reserved_sizes");
{
for (ObjectObjectCursor c : this.reservedSpace) {
builder.startObject();
{
builder.field("node_id", c.key.nodeId);
builder.field("path", c.key.path);
c.value.toXContent(builder, params);
}
builder.endObject(); // NodeAndPath
}
}
builder.endArray(); // end "reserved_sizes"
return builder;
}
/**
* Returns a node id to disk usage mapping for the path that has the least available space on the node.
* Note that this does not take account of reserved space: there may be another path with less available _and unreserved_ space.
*/
public ImmutableOpenMap getNodeLeastAvailableDiskUsages() {
return this.leastAvailableSpaceUsage;
}
/**
* Returns a node id to disk usage mapping for the path that has the most available space on the node.
* Note that this does not take account of reserved space: there may be another path with more available _and unreserved_ space.
*/
public ImmutableOpenMap getNodeMostAvailableDiskUsages() {
return this.mostAvailableSpaceUsage;
}
/**
* Returns the shard size for the given shard routing or null
it that metric is not available.
*/
public Long getShardSize(ShardRouting shardRouting) {
return shardSizes.get(shardIdentifierFromRouting(shardRouting));
}
/**
* Returns the nodes absolute data-path the given shard is allocated on or null
if the information is not available.
*/
public String getDataPath(ShardRouting shardRouting) {
return routingToDataPath.get(shardRouting);
}
/**
* Returns the shard size for the given shard routing or defaultValue
it that metric is not available.
*/
public long getShardSize(ShardRouting shardRouting, long defaultValue) {
Long shardSize = getShardSize(shardRouting);
return shardSize == null ? defaultValue : shardSize;
}
public Optional getShardDataSetSize(ShardId shardId) {
return Optional.ofNullable(shardDataSetSizes.get(shardId));
}
/**
* Returns the reserved space for each shard on the given node/path pair
*/
public ReservedSpace getReservedSpace(String nodeId, String dataPath) {
final ReservedSpace result = reservedSpace.get(new NodeAndPath(nodeId, dataPath));
return result == null ? ReservedSpace.EMPTY : result;
}
/**
* Method that incorporates the ShardId for the shard into a string that
* includes a 'p' or 'r' depending on whether the shard is a primary.
*/
public static String shardIdentifierFromRouting(ShardRouting shardRouting) {
return shardRouting.shardId().toString() + "[" + (shardRouting.primary() ? "p" : "r") + "]";
}
/**
* Represents a data path on a node
*/
public static class NodeAndPath implements Writeable {
public final String nodeId;
public final String path;
public NodeAndPath(String nodeId, String path) {
this.nodeId = Objects.requireNonNull(nodeId);
this.path = Objects.requireNonNull(path);
}
public NodeAndPath(StreamInput in) throws IOException {
this.nodeId = in.readString();
this.path = in.readString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NodeAndPath that = (NodeAndPath) o;
return nodeId.equals(that.nodeId) && path.equals(that.path);
}
@Override
public int hashCode() {
return Objects.hash(nodeId, path);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeString(nodeId);
out.writeString(path);
}
}
/**
* Represents the total amount of "reserved" space on a particular data path, together with the set of shards considered.
*/
public static class ReservedSpace implements Writeable {
public static final ReservedSpace EMPTY = new ReservedSpace(0, new ObjectHashSet<>());
private final long total;
private final ObjectHashSet shardIds;
private ReservedSpace(long total, ObjectHashSet shardIds) {
this.total = total;
this.shardIds = shardIds;
}
ReservedSpace(StreamInput in) throws IOException {
total = in.readVLong();
final int shardIdCount = in.readVInt();
shardIds = new ObjectHashSet<>(shardIdCount);
for (int i = 0; i < shardIdCount; i++) {
shardIds.add(new ShardId(in));
}
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeVLong(total);
out.writeVInt(shardIds.size());
for (ObjectCursor shardIdCursor : shardIds) {
shardIdCursor.value.writeTo(out);
}
}
public long getTotal() {
return total;
}
public boolean containsShardId(ShardId shardId) {
return shardIds.contains(shardId);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ReservedSpace that = (ReservedSpace) o;
return total == that.total && shardIds.equals(that.shardIds);
}
@Override
public int hashCode() {
return Objects.hash(total, shardIds);
}
void toXContent(XContentBuilder builder, Params params) throws IOException {
builder.field("total", total);
builder.startArray("shards");
{
for (ObjectCursor shardIdCursor : shardIds) {
shardIdCursor.value.toXContent(builder, params);
}
}
builder.endArray(); // end "shards"
}
public static class Builder {
private long total;
private ObjectHashSet shardIds = new ObjectHashSet<>();
public ReservedSpace build() {
assert shardIds != null : "already built";
final ReservedSpace reservedSpace = new ReservedSpace(total, shardIds);
shardIds = null;
return reservedSpace;
}
public Builder add(ShardId shardId, long reservedBytes) {
assert shardIds != null : "already built";
assert reservedBytes >= 0 : reservedBytes;
shardIds.add(shardId);
total += reservedBytes;
return this;
}
}
}
}