
org.elasticsearch.cluster.ClusterInfo Maven / Gradle / Ivy
/*
* 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.common.xcontent.ToXContentFragment;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.index.store.StoreStats;
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.common.collect.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.common.collect.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;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy