Skip to content

Commit

Permalink
Regroup searchable snapshot stats by file extension (elastic#68835)
Browse files Browse the repository at this point in the history
The searchable snapshots stats endpoint currently exposes stats information at the level of individual files, which can be
extremely verbose for large indices. Furthermore, the tracking at the per-file level consumes a non-negligible amount of
heap memory.

With this change, the stats are now aggregated per file extension, and can be aggregated both at the index as well as
cluster-level. It introduces a new "level" parameter, similar to indices stats, which defaults to "indices", but can also be
set to "cluster" or "shards", provide details at the respective level.

The commit also fixes a small issue where the backwardsSeeks stats were reported as negative values instead of
positive ones.
  • Loading branch information
ywelsch authored Feb 10, 2021
1 parent 4c2e9a6 commit 6cf33b1
Show file tree
Hide file tree
Showing 16 changed files with 449 additions and 118 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
package org.elasticsearch.xpack.core.searchablesnapshots;

import org.elasticsearch.Version;
import org.elasticsearch.cluster.routing.ShardRouting;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
Expand Down Expand Up @@ -90,7 +91,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
builder.startArray("files");
{
List<CacheIndexInputStats> stats = inputStats.stream()
.sorted(Comparator.comparing(CacheIndexInputStats::getFileName)).collect(toList());
.sorted(Comparator.comparing(CacheIndexInputStats::getFileExt)).collect(toList());
for (CacheIndexInputStats stat : stats) {
stat.toXContent(builder, params);
}
Expand Down Expand Up @@ -122,8 +123,9 @@ public int hashCode() {

public static class CacheIndexInputStats implements Writeable, ToXContentObject {

private final String fileName;
private final long fileLength;
private final String fileExt;
private final long numFiles;
private final long totalSize;

private final long openCount;
private final long closeCount;
Expand All @@ -142,15 +144,16 @@ public static class CacheIndexInputStats implements Writeable, ToXContentObject
private final Counter blobStoreBytesRequested;
private final long currentIndexCacheFills;

public CacheIndexInputStats(String fileName, long fileLength, long openCount, long closeCount,
public CacheIndexInputStats(String fileExt, long numFiles, long totalSize, long openCount, long closeCount,
Counter forwardSmallSeeks, Counter backwardSmallSeeks,
Counter forwardLargeSeeks, Counter backwardLargeSeeks,
Counter contiguousReads, Counter nonContiguousReads,
Counter cachedBytesRead, Counter indexCacheBytesRead,
TimedCounter cachedBytesWritten, TimedCounter directBytesRead, TimedCounter optimizedBytesRead,
Counter blobStoreBytesRequested, long currentIndexCacheFills) {
this.fileName = fileName;
this.fileLength = fileLength;
this.fileExt = fileExt;
this.numFiles = numFiles;
this.totalSize = totalSize;
this.openCount = openCount;
this.closeCount = closeCount;
this.forwardSmallSeeks = forwardSmallSeeks;
Expand All @@ -169,8 +172,15 @@ public CacheIndexInputStats(String fileName, long fileLength, long openCount, lo
}

CacheIndexInputStats(final StreamInput in) throws IOException {
this.fileName = in.readString();
this.fileLength = in.readVLong();
if (in.getVersion().before(Version.V_7_12_0)) {
// This API is currently only used internally for testing, so BWC breaking changes are OK.
// We just throw an exception here to get a better error message in case this would be called
// in a mixed version cluster
throw new IllegalArgumentException("BWC breaking change for internal API");
}
this.fileExt = in.readString();
this.numFiles = in.readVLong();
this.totalSize = in.readVLong();
this.openCount = in.readVLong();
this.closeCount = in.readVLong();
this.forwardSmallSeeks = new Counter(in);
Expand All @@ -188,10 +198,45 @@ public CacheIndexInputStats(String fileName, long fileLength, long openCount, lo
this.currentIndexCacheFills = in.readVLong();
}

public static CacheIndexInputStats combine(CacheIndexInputStats cis1, CacheIndexInputStats cis2) {
if (cis1.getFileExt().equals(cis2.getFileExt()) == false) {
assert false : "can only combine same file extensions";
throw new IllegalArgumentException("can only combine same file extensions but was " +
cis1.fileExt + " and " + cis2.fileExt);
}
return new CacheIndexInputStats(
cis1.fileExt,
cis1.numFiles + cis2.numFiles,
cis1.totalSize + cis2.totalSize,
cis1.openCount + cis2.openCount,
cis1.closeCount + cis2.closeCount,
cis1.forwardSmallSeeks.add(cis2.forwardSmallSeeks),
cis1.backwardSmallSeeks.add(cis2.backwardSmallSeeks),
cis1.forwardLargeSeeks.add(cis2.forwardLargeSeeks),
cis1.backwardLargeSeeks.add(cis2.backwardLargeSeeks),
cis1.contiguousReads.add(cis2.contiguousReads),
cis1.nonContiguousReads.add(cis2.nonContiguousReads),
cis1.cachedBytesRead.add(cis2.cachedBytesRead),
cis1.indexCacheBytesRead.add(cis2.indexCacheBytesRead),
cis1.cachedBytesWritten.add(cis2.cachedBytesWritten),
cis1.directBytesRead.add(cis2.directBytesRead),
cis1.optimizedBytesRead.add(cis2.optimizedBytesRead),
cis1.blobStoreBytesRequested.add(cis2.blobStoreBytesRequested),
cis1.currentIndexCacheFills + cis2.currentIndexCacheFills
);
}

@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeString(fileName);
out.writeVLong(fileLength);
if (out.getVersion().before(Version.V_7_12_0)) {
// This API is currently only used internally for testing, so BWC breaking changes are OK.
// We just throw an exception here to get a better error message in case this would be called
// in a mixed version cluster
throw new IllegalArgumentException("BWC breaking change for internal API");
}
out.writeString(fileExt);
out.writeVLong(numFiles);
out.writeVLong(totalSize);
out.writeVLong(openCount);
out.writeVLong(closeCount);

Expand All @@ -210,12 +255,16 @@ public void writeTo(StreamOutput out) throws IOException {
out.writeVLong(currentIndexCacheFills);
}

public String getFileName() {
return fileName;
public String getFileExt() {
return fileExt;
}

public long getFileLength() {
return fileLength;
public long getNumFiles() {
return numFiles;
}

public long getTotalSize() {
return totalSize;
}

public long getOpenCount() {
Expand Down Expand Up @@ -282,30 +331,31 @@ public long getCurrentIndexCacheFills() {
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
{
builder.field("name", getFileName());
builder.field("length", getFileLength());
builder.field("file_ext", getFileExt());
builder.field("num_files", getNumFiles());
builder.field("total_size", getTotalSize());
builder.field("open_count", getOpenCount());
builder.field("close_count", getCloseCount());
builder.field("contiguous_bytes_read", getContiguousReads());
builder.field("non_contiguous_bytes_read", getNonContiguousReads());
builder.field("cached_bytes_read", getCachedBytesRead());
builder.field("index_cache_bytes_read", getIndexCacheBytesRead());
builder.field("cached_bytes_written", getCachedBytesWritten());
builder.field("direct_bytes_read", getDirectBytesRead());
builder.field("optimized_bytes_read", getOptimizedBytesRead());
builder.field("contiguous_bytes_read", getContiguousReads(), params);
builder.field("non_contiguous_bytes_read", getNonContiguousReads(), params);
builder.field("cached_bytes_read", getCachedBytesRead(), params);
builder.field("index_cache_bytes_read", getIndexCacheBytesRead(), params);
builder.field("cached_bytes_written", getCachedBytesWritten(), params);
builder.field("direct_bytes_read", getDirectBytesRead(), params);
builder.field("optimized_bytes_read", getOptimizedBytesRead(), params);
{
builder.startObject("forward_seeks");
builder.field("small", getForwardSmallSeeks());
builder.field("large", getForwardLargeSeeks());
builder.field("small", getForwardSmallSeeks(), params);
builder.field("large", getForwardLargeSeeks(), params);
builder.endObject();
}
{
builder.startObject("backward_seeks");
builder.field("small", getBackwardSmallSeeks());
builder.field("large", getBackwardLargeSeeks());
builder.field("small", getBackwardSmallSeeks(), params);
builder.field("large", getBackwardLargeSeeks(), params);
builder.endObject();
}
builder.field("blob_store_bytes_requested", getBlobStoreBytesRequested());
builder.field("blob_store_bytes_requested", getBlobStoreBytesRequested(), params);
builder.field("current_index_cache_fills", getCurrentIndexCacheFills());
}
return builder.endObject();
Expand All @@ -320,10 +370,11 @@ public boolean equals(Object other) {
return false;
}
CacheIndexInputStats stats = (CacheIndexInputStats) other;
return fileLength == stats.fileLength
return numFiles == stats.numFiles
&& totalSize == stats.totalSize
&& openCount == stats.openCount
&& closeCount == stats.closeCount
&& Objects.equals(fileName, stats.fileName)
&& Objects.equals(fileExt, stats.fileExt)
&& Objects.equals(forwardSmallSeeks, stats.forwardSmallSeeks)
&& Objects.equals(backwardSmallSeeks, stats.backwardSmallSeeks)
&& Objects.equals(forwardLargeSeeks, stats.forwardLargeSeeks)
Expand All @@ -341,7 +392,7 @@ public boolean equals(Object other) {

@Override
public int hashCode() {
return Objects.hash(fileName, fileLength, openCount, closeCount,
return Objects.hash(fileExt, numFiles, totalSize, openCount, closeCount,
forwardSmallSeeks, backwardSmallSeeks,
forwardLargeSeeks, backwardLargeSeeks,
contiguousReads, nonContiguousReads,
Expand All @@ -353,10 +404,10 @@ public int hashCode() {

public static class Counter implements Writeable, ToXContentObject {

private final long count;
private final long total;
private final long min;
private final long max;
protected final long count;
protected final long total;
protected final long min;
protected final long max;

public Counter(final long count, final long total, final long min, final long max) {
this.count = count;
Expand All @@ -372,6 +423,11 @@ public Counter(final long count, final long total, final long min, final long ma
this.max = in.readZLong();
}

public Counter add(Counter counter) {
return new Counter(count + counter.count, total + counter.total,
Math.min(min, counter.min), Math.max(max, counter.max));
}

@Override
public void writeTo(final StreamOutput out) throws IOException {
out.writeZLong(count);
Expand Down Expand Up @@ -448,6 +504,11 @@ public TimedCounter(long count, long total, long min, long max, long totalNanose
totalNanoseconds = in.readZLong();
}

public TimedCounter add(TimedCounter counter) {
return new TimedCounter(count + counter.count, total + counter.total,
Math.min(min, counter.min), Math.max(max, counter.max), totalNanoseconds + counter.totalNanoseconds);
}

@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ protected SearchableSnapshotShardStats createTestInstance() {
}

private CacheIndexInputStats randomCacheIndexInputStats() {
return new CacheIndexInputStats(randomAlphaOfLength(10), randomNonNegativeLong(),
return new CacheIndexInputStats(randomAlphaOfLength(10), randomNonNegativeLong(), randomNonNegativeLong(),
randomNonNegativeLong(), randomNonNegativeLong(),
randomCounter(), randomCounter(),
randomCounter(), randomCounter(),
Expand Down
Loading

0 comments on commit 6cf33b1

Please sign in to comment.