Skip to content

Commit c73cf68

Browse files
authored
Add REST API for cache directory stats (#51815)
This commit adds a REST API that exposes the various CacheDirectory stats added in #51637. It adds the necessary action, transport action and request and response objects as well as a new qa:rest project for REST tests. The REST endpoint is _searchable_snapshots/stats and can be filtered by index names.
1 parent 85ec740 commit c73cf68

File tree

18 files changed

+1122
-24
lines changed

18 files changed

+1122
-24
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,398 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
package org.elasticsearch.xpack.core.searchablesnapshots;
7+
8+
import org.elasticsearch.cluster.routing.ShardRouting;
9+
import org.elasticsearch.common.io.stream.StreamInput;
10+
import org.elasticsearch.common.io.stream.StreamOutput;
11+
import org.elasticsearch.common.io.stream.Writeable;
12+
import org.elasticsearch.common.xcontent.ToXContentObject;
13+
import org.elasticsearch.common.xcontent.XContentBuilder;
14+
import org.elasticsearch.repositories.IndexId;
15+
import org.elasticsearch.snapshots.SnapshotId;
16+
17+
import java.io.IOException;
18+
import java.util.Comparator;
19+
import java.util.List;
20+
import java.util.Objects;
21+
22+
import static java.util.Collections.unmodifiableList;
23+
import static java.util.stream.Collectors.toList;
24+
25+
public class SearchableSnapshotShardStats implements Writeable, ToXContentObject {
26+
27+
private final List<CacheIndexInputStats> inputStats;
28+
private final ShardRouting shardRouting;
29+
private final SnapshotId snapshotId;
30+
private final IndexId indexId;
31+
32+
public SearchableSnapshotShardStats(ShardRouting shardRouting, SnapshotId snapshotId, IndexId indexId,
33+
List<CacheIndexInputStats> stats) {
34+
this.shardRouting = Objects.requireNonNull(shardRouting);
35+
this.snapshotId = Objects.requireNonNull(snapshotId);
36+
this.indexId = Objects.requireNonNull(indexId);
37+
this.inputStats = unmodifiableList(Objects.requireNonNull(stats));
38+
}
39+
40+
public SearchableSnapshotShardStats(StreamInput in) throws IOException {
41+
this.shardRouting = new ShardRouting(in);
42+
this.snapshotId = new SnapshotId(in);
43+
this.indexId = new IndexId(in);
44+
this.inputStats = in.readList(CacheIndexInputStats::new);
45+
}
46+
47+
@Override
48+
public void writeTo(StreamOutput out) throws IOException {
49+
shardRouting.writeTo(out);
50+
snapshotId.writeTo(out);
51+
indexId.writeTo(out);
52+
out.writeList(inputStats);
53+
}
54+
55+
public ShardRouting getShardRouting() {
56+
return shardRouting;
57+
}
58+
59+
public SnapshotId getSnapshotId() {
60+
return snapshotId;
61+
}
62+
63+
public IndexId getIndexId() {
64+
return indexId;
65+
}
66+
67+
public List<CacheIndexInputStats> getStats() {
68+
return inputStats;
69+
}
70+
71+
@Override
72+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
73+
builder.startObject();
74+
{
75+
builder.field("snapshot_uuid", getSnapshotId().getUUID());
76+
builder.field("index_uuid", getIndexId().getId());
77+
builder.startObject("shard");
78+
{
79+
builder.field("state", shardRouting.state());
80+
builder.field("primary", shardRouting.primary());
81+
builder.field("node", shardRouting.currentNodeId());
82+
if (shardRouting.relocatingNodeId() != null) {
83+
builder.field("relocating_node", shardRouting.relocatingNodeId());
84+
}
85+
}
86+
builder.endObject();
87+
builder.startArray("files");
88+
{
89+
List<CacheIndexInputStats> stats = inputStats.stream()
90+
.sorted(Comparator.comparing(CacheIndexInputStats::getFileName)).collect(toList());
91+
for (CacheIndexInputStats stat : stats) {
92+
stat.toXContent(builder, params);
93+
}
94+
}
95+
builder.endArray();
96+
}
97+
return builder.endObject();
98+
}
99+
100+
@Override
101+
public boolean equals(Object other) {
102+
if (this == other) {
103+
return true;
104+
}
105+
if (other == null || getClass() != other.getClass()) {
106+
return false;
107+
}
108+
SearchableSnapshotShardStats that = (SearchableSnapshotShardStats) other;
109+
return Objects.equals(shardRouting, that.shardRouting)
110+
&& Objects.equals(snapshotId, that.snapshotId)
111+
&& Objects.equals(indexId, that.indexId)
112+
&& Objects.equals(inputStats, that.inputStats);
113+
}
114+
115+
@Override
116+
public int hashCode() {
117+
return Objects.hash(shardRouting, snapshotId, indexId, inputStats);
118+
}
119+
120+
121+
public static class CacheIndexInputStats implements Writeable, ToXContentObject {
122+
123+
private final String fileName;
124+
private final long fileLength;
125+
126+
private final long openCount;
127+
private final long innerCount;
128+
private final long closeCount;
129+
130+
private final Counter forwardSmallSeeks;
131+
private final Counter backwardSmallSeeks;
132+
private final Counter forwardLargeSeeks;
133+
private final Counter backwardLargeSeeks;
134+
private final Counter contiguousReads;
135+
private final Counter nonContiguousReads;
136+
private final Counter cachedBytesRead;
137+
private final Counter cachedBytesWritten;
138+
private final Counter directBytesRead;
139+
140+
public CacheIndexInputStats(String fileName, long fileLength, long openCount, long innerCount, long closeCount,
141+
Counter forwardSmallSeeks, Counter backwardSmallSeeks,
142+
Counter forwardLargeSeeks, Counter backwardLargeSeeks,
143+
Counter contiguousReads, Counter nonContiguousReads,
144+
Counter cachedBytesRead, Counter cachedBytesWritten,
145+
Counter directBytesRead) {
146+
this.fileName = fileName;
147+
this.fileLength = fileLength;
148+
this.openCount = openCount;
149+
this.innerCount = innerCount;
150+
this.closeCount = closeCount;
151+
this.forwardSmallSeeks = forwardSmallSeeks;
152+
this.backwardSmallSeeks = backwardSmallSeeks;
153+
this.forwardLargeSeeks = forwardLargeSeeks;
154+
this.backwardLargeSeeks = backwardLargeSeeks;
155+
this.contiguousReads = contiguousReads;
156+
this.nonContiguousReads = nonContiguousReads;
157+
this.cachedBytesRead = cachedBytesRead;
158+
this.cachedBytesWritten = cachedBytesWritten;
159+
this.directBytesRead = directBytesRead;
160+
}
161+
162+
CacheIndexInputStats(final StreamInput in) throws IOException {
163+
this.fileName = in.readString();
164+
this.fileLength = in.readVLong();
165+
this.openCount = in.readVLong();
166+
this.innerCount = in.readVLong();
167+
this.closeCount = in.readVLong();
168+
this.forwardSmallSeeks = new Counter(in);
169+
this.backwardSmallSeeks = new Counter(in);
170+
this.forwardLargeSeeks = new Counter(in);
171+
this.backwardLargeSeeks = new Counter(in);
172+
this.contiguousReads = new Counter(in);
173+
this.nonContiguousReads = new Counter(in);
174+
this.cachedBytesRead = new Counter(in);
175+
this.cachedBytesWritten = new Counter(in);
176+
this.directBytesRead = new Counter(in);
177+
}
178+
179+
@Override
180+
public void writeTo(StreamOutput out) throws IOException {
181+
out.writeString(fileName);
182+
out.writeVLong(fileLength);
183+
out.writeVLong(openCount);
184+
out.writeVLong(innerCount);
185+
out.writeVLong(closeCount);
186+
187+
forwardSmallSeeks.writeTo(out);
188+
backwardSmallSeeks.writeTo(out);
189+
forwardLargeSeeks.writeTo(out);
190+
backwardLargeSeeks.writeTo(out);
191+
contiguousReads.writeTo(out);
192+
nonContiguousReads.writeTo(out);
193+
cachedBytesRead.writeTo(out);
194+
cachedBytesWritten.writeTo(out);
195+
directBytesRead.writeTo(out);
196+
}
197+
198+
public String getFileName() {
199+
return fileName;
200+
}
201+
202+
public long getFileLength() {
203+
return fileLength;
204+
}
205+
206+
public long getOpenCount() {
207+
return openCount;
208+
}
209+
210+
public long getInnerCount() {
211+
return innerCount;
212+
}
213+
214+
public long getCloseCount() {
215+
return closeCount;
216+
}
217+
218+
public Counter getForwardSmallSeeks() {
219+
return forwardSmallSeeks;
220+
}
221+
222+
public Counter getBackwardSmallSeeks() {
223+
return backwardSmallSeeks;
224+
}
225+
226+
public Counter getForwardLargeSeeks() {
227+
return forwardLargeSeeks;
228+
}
229+
230+
public Counter getBackwardLargeSeeks() {
231+
return backwardLargeSeeks;
232+
}
233+
234+
public Counter getContiguousReads() {
235+
return contiguousReads;
236+
}
237+
238+
public Counter getNonContiguousReads() {
239+
return nonContiguousReads;
240+
}
241+
242+
public Counter getCachedBytesRead() {
243+
return cachedBytesRead;
244+
}
245+
246+
public Counter getCachedBytesWritten() {
247+
return cachedBytesWritten;
248+
}
249+
250+
public Counter getDirectBytesRead() {
251+
return directBytesRead;
252+
}
253+
254+
@Override
255+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
256+
builder.startObject();
257+
{
258+
builder.field("name", getFileName());
259+
builder.field("length", getFileLength());
260+
builder.field("open_count", getOpenCount());
261+
builder.field("inner_count", getInnerCount());
262+
builder.field("close_count", getCloseCount());
263+
builder.field("contiguous_bytes_read", getContiguousReads());
264+
builder.field("non_contiguous_bytes_read", getNonContiguousReads());
265+
builder.field("cached_bytes_read", getCachedBytesRead());
266+
builder.field("cached_bytes_written", getCachedBytesWritten());
267+
builder.field("direct_bytes_read", getDirectBytesRead());
268+
{
269+
builder.startObject("forward_seeks");
270+
builder.field("small", getForwardSmallSeeks());
271+
builder.field("large", getForwardLargeSeeks());
272+
builder.endObject();
273+
}
274+
{
275+
builder.startObject("backward_seeks");
276+
builder.field("small", getBackwardSmallSeeks());
277+
builder.field("large", getBackwardLargeSeeks());
278+
builder.endObject();
279+
}
280+
}
281+
return builder.endObject();
282+
}
283+
284+
@Override
285+
public boolean equals(Object other) {
286+
if (this == other) {
287+
return true;
288+
}
289+
if (other == null || getClass() != other.getClass()) {
290+
return false;
291+
}
292+
CacheIndexInputStats stats = (CacheIndexInputStats) other;
293+
return fileLength == stats.fileLength
294+
&& openCount == stats.openCount
295+
&& innerCount == stats.innerCount
296+
&& closeCount == stats.closeCount
297+
&& Objects.equals(fileName, stats.fileName)
298+
&& Objects.equals(forwardSmallSeeks, stats.forwardSmallSeeks)
299+
&& Objects.equals(backwardSmallSeeks, stats.backwardSmallSeeks)
300+
&& Objects.equals(forwardLargeSeeks, stats.forwardLargeSeeks)
301+
&& Objects.equals(backwardLargeSeeks, stats.backwardLargeSeeks)
302+
&& Objects.equals(contiguousReads, stats.contiguousReads)
303+
&& Objects.equals(nonContiguousReads, stats.nonContiguousReads)
304+
&& Objects.equals(cachedBytesRead, stats.cachedBytesRead)
305+
&& Objects.equals(cachedBytesWritten, stats.cachedBytesWritten)
306+
&& Objects.equals(directBytesRead, stats.directBytesRead);
307+
}
308+
309+
@Override
310+
public int hashCode() {
311+
return Objects.hash(fileName, fileLength, openCount, innerCount, closeCount,
312+
forwardSmallSeeks, backwardSmallSeeks,
313+
forwardLargeSeeks, backwardLargeSeeks,
314+
contiguousReads, nonContiguousReads,
315+
cachedBytesRead, cachedBytesWritten,
316+
directBytesRead);
317+
}
318+
}
319+
320+
public static class Counter implements Writeable, ToXContentObject {
321+
322+
private final long count;
323+
private final long total;
324+
private final long min;
325+
private final long max;
326+
327+
public Counter(final long count, final long total, final long min, final long max) {
328+
this.count = count;
329+
this.total = total;
330+
this.min = min;
331+
this.max = max;
332+
}
333+
334+
Counter(final StreamInput in) throws IOException {
335+
this.count = in.readZLong();
336+
this.total = in.readZLong();
337+
this.min = in.readZLong();
338+
this.max = in.readZLong();
339+
}
340+
341+
@Override
342+
public void writeTo(final StreamOutput out) throws IOException {
343+
out.writeZLong(count);
344+
out.writeZLong(total);
345+
out.writeZLong(min);
346+
out.writeZLong(max);
347+
}
348+
349+
@Override
350+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
351+
builder.startObject();
352+
{
353+
builder.field("count", count);
354+
builder.field("sum", total);
355+
builder.field("min", min);
356+
builder.field("max", max);
357+
}
358+
builder.endObject();
359+
return builder;
360+
}
361+
362+
public long getCount() {
363+
return count;
364+
}
365+
366+
public long getTotal() {
367+
return total;
368+
}
369+
370+
public long getMin() {
371+
return min;
372+
}
373+
374+
public long getMax() {
375+
return max;
376+
}
377+
378+
@Override
379+
public boolean equals(Object other) {
380+
if (this == other) {
381+
return true;
382+
}
383+
if (other == null || getClass() != other.getClass()) {
384+
return false;
385+
}
386+
Counter that = (Counter) other;
387+
return count == that.count
388+
&& total == that.total
389+
&& min == that.min
390+
&& max == that.max;
391+
}
392+
393+
@Override
394+
public int hashCode() {
395+
return Objects.hash(count, total, min, max);
396+
}
397+
}
398+
}

0 commit comments

Comments
 (0)