-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Add heap usage estimate to ClusterInfo #128723
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 15 commits
2d60021
542c256
356beb5
81fd063
bc0682c
747b5a2
13d1de8
f4d9db5
bf51e85
c47c0ca
23eb8e6
887bcaf
7275acb
85fd019
f112a3b
3a1ada2
8fa587f
6d4b204
2c42a82
58402bd
63bbea8
0cacdc7
dd73d37
765ade8
e26b62f
55637b6
f4b90b5
0789fef
2d475c8
f56f00e
7b5bf95
08a5ca3
09ca9dc
cd6b7e9
5e2cb9f
c529194
d831194
b8387bb
26dba4d
f15fca2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| /* | ||
| * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public | ||
| * License v3.0 only", or the "Server Side Public License, v 1". | ||
| */ | ||
|
|
||
| package org.elasticsearch.cluster; | ||
|
|
||
| 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.xcontent.ToXContentFragment; | ||
| import org.elasticsearch.xcontent.XContentBuilder; | ||
|
|
||
| import java.io.IOException; | ||
|
|
||
| /** | ||
| * Record representing the heap usage for a single cluster node | ||
| */ | ||
| public record HeapUsage(String nodeId, String nodeName, long totalBytes, long usedBytes) implements ToXContentFragment, Writeable { | ||
|
|
||
| public HeapUsage { | ||
| assert usedBytes <= totalBytes; | ||
|
||
| } | ||
|
|
||
| public HeapUsage(StreamInput in) throws IOException { | ||
| this(in.readString(), in.readString(), in.readVLong(), in.readVLong()); | ||
| } | ||
|
|
||
| @Override | ||
| public void writeTo(StreamOutput out) throws IOException { | ||
| out.writeString(this.nodeId); | ||
| out.writeString(this.nodeName); | ||
| out.writeVLong(this.totalBytes); | ||
| out.writeVLong(this.usedBytes); | ||
| } | ||
|
|
||
| public XContentBuilder toShortXContent(XContentBuilder builder) throws IOException { | ||
| builder.field("node_name", this.nodeName); | ||
| builder.humanReadableField("total_heap_bytes", "total", ByteSizeValue.ofBytes(this.totalBytes)); | ||
| builder.humanReadableField("used_heap_bytes", "used", ByteSizeValue.ofBytes(this.usedBytes)); | ||
| builder.humanReadableField("free_heap_bytes", "free", ByteSizeValue.ofBytes(this.freeBytes())); | ||
| builder.field("free_heap_percent", truncatePercent(this.freeHeapAsPercentage())); | ||
| builder.field("used_heap_percent", truncatePercent(this.usedHeapAsPercentage())); | ||
| return builder; | ||
| } | ||
|
|
||
| @Override | ||
| public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { | ||
| builder.field("node_id", this.nodeId); | ||
| toShortXContent(builder); | ||
| return builder; | ||
| } | ||
|
||
|
|
||
| public double freeHeapAsPercentage() { | ||
| return 100.0 - usedHeapAsPercentage(); | ||
| } | ||
|
|
||
| public double usedHeapAsPercentage() { | ||
| return 100.0 * usedBytes / (double) totalBytes; | ||
| } | ||
|
|
||
| public long freeBytes() { | ||
| return totalBytes - usedBytes; | ||
| } | ||
|
||
|
|
||
| private static double truncatePercent(double pct) { | ||
| return Math.round(pct * 10.0) / 10.0; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| /* | ||
| * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public | ||
| * License v3.0 only", or the "Server Side Public License, v 1". | ||
| */ | ||
|
|
||
| package org.elasticsearch.cluster; | ||
|
|
||
| import org.elasticsearch.action.ActionListener; | ||
|
|
||
| import java.util.Map; | ||
|
|
||
| public interface HeapUsageSupplier { | ||
|
|
||
| /** | ||
| * This will be used when there are no heap usage suppliers available | ||
| */ | ||
| HeapUsageSupplier EMPTY = listener -> listener.onResponse(Map.of()); | ||
|
|
||
| /** | ||
| * Get the heap usage for every node in the cluster | ||
| * | ||
| * @param listener The listener which will receive the results | ||
| */ | ||
| void getClusterHeapUsage(ActionListener<Map<String, HeapUsage>> listener); | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -89,6 +89,7 @@ public class InternalClusterInfoService implements ClusterInfoService, ClusterSt | |||||
| private volatile Map<String, DiskUsage> leastAvailableSpaceUsages; | ||||||
| private volatile Map<String, DiskUsage> mostAvailableSpaceUsages; | ||||||
| private volatile IndicesStatsSummary indicesStatsSummary; | ||||||
| private volatile Map<String, HeapUsage> nodesHeapUsage; | ||||||
|
|
||||||
| private final ThreadPool threadPool; | ||||||
| private final Client client; | ||||||
|
|
@@ -97,13 +98,15 @@ public class InternalClusterInfoService implements ClusterInfoService, ClusterSt | |||||
| private final Object mutex = new Object(); | ||||||
| private final List<ActionListener<ClusterInfo>> nextRefreshListeners = new ArrayList<>(); | ||||||
|
|
||||||
| private HeapUsageSupplier heapUsageSupplier = HeapUsageSupplier.EMPTY; | ||||||
| private AsyncRefresh currentRefresh; | ||||||
| private RefreshScheduler refreshScheduler; | ||||||
|
|
||||||
| @SuppressWarnings("this-escape") | ||||||
| public InternalClusterInfoService(Settings settings, ClusterService clusterService, ThreadPool threadPool, Client client) { | ||||||
| this.leastAvailableSpaceUsages = Map.of(); | ||||||
| this.mostAvailableSpaceUsages = Map.of(); | ||||||
| this.nodesHeapUsage = Map.of(); | ||||||
| this.indicesStatsSummary = IndicesStatsSummary.EMPTY; | ||||||
| this.threadPool = threadPool; | ||||||
| this.client = client; | ||||||
|
|
@@ -131,6 +134,16 @@ void setUpdateFrequency(TimeValue updateFrequency) { | |||||
| this.updateFrequency = updateFrequency; | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * This can be provided by plugins, which are initialised long after the ClusterInfoService is created | ||||||
|
||||||
| * | ||||||
| * @param heapUsageSupplier The HeapUsageSupplier to use | ||||||
| */ | ||||||
| public void setHeapUsageSupplier(HeapUsageSupplier heapUsageSupplier) { | ||||||
| assert this.heapUsageSupplier == HeapUsageSupplier.EMPTY; | ||||||
| this.heapUsageSupplier = heapUsageSupplier; | ||||||
| } | ||||||
|
|
||||||
| @Override | ||||||
| public void clusterChanged(ClusterChangedEvent event) { | ||||||
| final Runnable newRefresh; | ||||||
|
|
@@ -173,6 +186,7 @@ void execute() { | |||||
| logger.trace("skipping collecting info from cluster, notifying listeners with empty cluster info"); | ||||||
| leastAvailableSpaceUsages = Map.of(); | ||||||
| mostAvailableSpaceUsages = Map.of(); | ||||||
| nodesHeapUsage = Map.of(); | ||||||
| indicesStatsSummary = IndicesStatsSummary.EMPTY; | ||||||
| callListeners(); | ||||||
| return; | ||||||
|
|
@@ -187,9 +201,26 @@ void execute() { | |||||
| try (var ignored = threadPool.getThreadContext().clearTraceContext()) { | ||||||
| fetchIndicesStats(); | ||||||
| } | ||||||
| try (var ignored = threadPool.getThreadContext().clearTraceContext()) { | ||||||
| fetchNodesHeapUsage(); | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| private void fetchNodesHeapUsage() { | ||||||
| heapUsageSupplier.getClusterHeapUsage(ActionListener.releaseAfter(new ActionListener<>() { | ||||||
| @Override | ||||||
| public void onResponse(Map<String, HeapUsage> stringHeapUsageMap) { | ||||||
|
||||||
| public void onResponse(Map<String, HeapUsage> stringHeapUsageMap) { | |
| public void onResponse(Map<String, HeapUsage> currentHeapUsageMap) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in e26b62f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add comment to say this field is deliberately ignored in
toXContentChunkedso that another reader knows this is intentional and not a bug.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 63bbea8