From 690a9b481fe9200a08d281b88489198b928d492e Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Mon, 3 Feb 2020 15:36:22 +0100 Subject: [PATCH 01/12] Add REST API for cache directory stats --- .../SearchableSnapshotStats.java | 475 ++++++++++++++++++ .../SearchableSnapshotStatsTests.java | 61 +++ .../plugin/searchable-snapshots/build.gradle | 9 + .../searchable-snapshots/qa/build.gradle | 17 + .../searchable-snapshots/qa/rest/build.gradle | 12 + .../rest/SearchableSnapshotsRestIT.java | 23 + .../resources/rest-api-spec/test/stats.yml | 149 ++++++ .../InMemoryNoOpCommitDirectory.java | 5 + .../SearchableSnapshots.java | 28 +- .../action/SeachableSnapshotsStatsAction.java | 18 + .../SeachableSnapshotsStatsRequest.java | 33 ++ .../SeachableSnapshotsStatsResponse.java | 86 ++++ ...ransportSeachableSnapshotsStatsAction.java | 132 +++++ .../cache/CacheDirectory.java | 16 + .../cache/IndexInputStats.java | 36 +- .../RestSeachableSnapshotsStatsAction.java | 35 ++ .../api/searchable_snapshots.stats.json | 30 ++ 17 files changed, 1146 insertions(+), 19 deletions(-) create mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStats.java create mode 100644 x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStatsTests.java create mode 100644 x-pack/plugin/searchable-snapshots/qa/build.gradle create mode 100644 x-pack/plugin/searchable-snapshots/qa/rest/build.gradle create mode 100644 x-pack/plugin/searchable-snapshots/qa/rest/src/test/java/org/elasticsearch/xpack/searchablesnapshots/rest/SearchableSnapshotsRestIT.java create mode 100644 x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml create mode 100644 x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsAction.java create mode 100644 x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsRequest.java create mode 100644 x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsResponse.java create mode 100644 x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSeachableSnapshotsStatsAction.java create mode 100644 x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/rest/RestSeachableSnapshotsStatsAction.java create mode 100644 x-pack/plugin/searchable-snapshots/src/test/resources/rest-api-spec/api/searchable_snapshots.stats.json diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStats.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStats.java new file mode 100644 index 0000000000000..3f80b2fedd085 --- /dev/null +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStats.java @@ -0,0 +1,475 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.core.searchablesnapshots; + +import org.elasticsearch.common.Strings; +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.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.index.Index; +import org.elasticsearch.index.shard.ShardId; +import org.elasticsearch.repositories.IndexId; +import org.elasticsearch.snapshots.SnapshotId; + +import java.io.IOException; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import static java.util.Collections.unmodifiableList; +import static java.util.stream.Collectors.toList; + +public class SearchableSnapshotStats implements Writeable, ToXContentObject { + + private final List directoryStats; + + public SearchableSnapshotStats(final List directoryStats) { + this.directoryStats = unmodifiableList(Objects.requireNonNull(directoryStats)); + } + + public SearchableSnapshotStats(final StreamInput in) throws IOException { + this.directoryStats = unmodifiableList(in.readList(CacheDirectoryStats::new)); + } + + public List getStats() { + return directoryStats; + } + + public boolean isEmpty() { + if (directoryStats.isEmpty()) { + return true; + } + return directoryStats.stream().map(CacheDirectoryStats::getStats).allMatch(List::isEmpty); + } + + @Override + public void writeTo(final StreamOutput out) throws IOException { + out.writeList(directoryStats); + } + + @Override + public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException { + final List indices = getStats().stream() + .filter(stats -> stats.getStats().isEmpty() == false) + .map(CacheDirectoryStats::getShardId) + .map(ShardId::getIndex) + .sorted(Comparator.comparing(Index::getName)) + .collect(toList()); + builder.startObject(); + { + builder.startObject("indices"); + for (Index index : indices) { + builder.startObject(index.getName()); + { + builder.startArray("shards"); + { + List listOfDirectoryStats = getStats().stream() + .filter(dirStats -> dirStats.getShardId().getIndex().equals(index)) + .sorted(Comparator.comparingInt(dir -> dir.getShardId().id())) + .collect(Collectors.toList()); + for (CacheDirectoryStats stats : listOfDirectoryStats) { + builder.value(stats); + } + } + builder.endArray(); + } + builder.endObject(); + } + builder.endObject(); + } + builder.endObject(); + return builder; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + SearchableSnapshotStats that = (SearchableSnapshotStats) other; + return Objects.equals(directoryStats, that.directoryStats); + } + + @Override + public int hashCode() { + return Objects.hash(directoryStats); + } + + @Override + public String toString() { + return Strings.toString(this); + } + + public static class CacheDirectoryStats implements Writeable, ToXContentObject { + + private final List inputStats; + private final SnapshotId snapshotId; + private final IndexId indexId; + private final ShardId shardId; + + public CacheDirectoryStats(SnapshotId snapshotId, IndexId indexId, ShardId shardId, List inputStats) { + this.snapshotId = Objects.requireNonNull(snapshotId); + this.indexId = Objects.requireNonNull(indexId); + this.shardId = Objects.requireNonNull(shardId); + this.inputStats = unmodifiableList(Objects.requireNonNull(inputStats)); + } + + CacheDirectoryStats(final StreamInput in) throws IOException { + this.snapshotId = new SnapshotId(in); + this.indexId = new IndexId(in); + this.shardId = new ShardId(in); + this.inputStats = in.readList(CacheIndexInputStats::new); + } + + @Override + public void writeTo(final StreamOutput out) throws IOException { + snapshotId.writeTo(out); + indexId.writeTo(out); + shardId.writeTo(out); + out.writeList(inputStats); + } + + public SnapshotId getSnapshotId() { + return snapshotId; + } + + public IndexId getIndexId() { + return indexId; + } + + public ShardId getShardId() { + return shardId; + } + + public List getStats() { + return inputStats; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + { + builder.field("snapshot_uuid", getSnapshotId().getUUID()); + builder.field("index_uuid", getIndexId().getId()); + builder.field("shard", getShardId().getId()); + builder.startArray("files"); + { + List stats = inputStats.stream() + .sorted(Comparator.comparing(CacheIndexInputStats::getFileName)).collect(toList()); + for (CacheIndexInputStats stat : stats) { + stat.toXContent(builder, params); + } + } + builder.endArray(); + } + return builder.endObject(); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + CacheDirectoryStats that = (CacheDirectoryStats) other; + return Objects.equals(inputStats, that.inputStats) + && Objects.equals(snapshotId, that.snapshotId) + && Objects.equals(indexId, that.indexId) + && Objects.equals(shardId, that.shardId); + } + + @Override + public int hashCode() { + return Objects.hash(inputStats, snapshotId, indexId, shardId); + } + } + + public static class CacheIndexInputStats implements Writeable, ToXContentObject { + + private final String fileName; + private final long fileLength; + + private final long openCount; + private final long innerCount; + private final long closeCount; + + private final Counter forwardSmallSeeks; + private final Counter backwardSmallSeeks; + private final Counter forwardLargeSeeks; + private final Counter backwardLargeSeeks; + private final Counter contiguousReads; + private final Counter nonContiguousReads; + private final Counter cachedBytesRead; + private final Counter cachedBytesWritten; + private final Counter directBytesRead; + + public CacheIndexInputStats(String fileName, long fileLength, long openCount, long innerCount, long closeCount, + Counter forwardSmallSeeks, Counter backwardSmallSeeks, + Counter forwardLargeSeeks, Counter backwardLargeSeeks, + Counter contiguousReads, Counter nonContiguousReads, + Counter cachedBytesRead, Counter cachedBytesWritten, + Counter directBytesRead) { + this.fileName = fileName; + this.fileLength = fileLength; + this.openCount = openCount; + this.innerCount = innerCount; + this.closeCount = closeCount; + this.forwardSmallSeeks = forwardSmallSeeks; + this.backwardSmallSeeks = backwardSmallSeeks; + this.forwardLargeSeeks = forwardLargeSeeks; + this.backwardLargeSeeks = backwardLargeSeeks; + this.contiguousReads = contiguousReads; + this.nonContiguousReads = nonContiguousReads; + this.cachedBytesRead = cachedBytesRead; + this.cachedBytesWritten = cachedBytesWritten; + this.directBytesRead = directBytesRead; + } + + CacheIndexInputStats(final StreamInput in) throws IOException { + this.fileName = in.readString(); + this.fileLength = in.readVLong(); + this.openCount = in.readVLong(); + this.innerCount = in.readVLong(); + this.closeCount = in.readVLong(); + this.forwardSmallSeeks = new Counter(in); + this.backwardSmallSeeks = new Counter(in); + this.forwardLargeSeeks = new Counter(in); + this.backwardLargeSeeks = new Counter(in); + this.contiguousReads = new Counter(in); + this.nonContiguousReads = new Counter(in); + this.cachedBytesRead = new Counter(in); + this.cachedBytesWritten = new Counter(in); + this.directBytesRead = new Counter(in); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeString(fileName); + out.writeVLong(fileLength); + out.writeVLong(openCount); + out.writeVLong(innerCount); + out.writeVLong(closeCount); + + forwardSmallSeeks.writeTo(out); + backwardSmallSeeks.writeTo(out); + forwardLargeSeeks.writeTo(out); + backwardLargeSeeks.writeTo(out); + contiguousReads.writeTo(out); + nonContiguousReads.writeTo(out); + cachedBytesRead.writeTo(out); + cachedBytesWritten.writeTo(out); + directBytesRead.writeTo(out); + } + + public String getFileName() { + return fileName; + } + + public long getFileLength() { + return fileLength; + } + + public long getOpenCount() { + return openCount; + } + + public long getInnerCount() { + return innerCount; + } + + public long getCloseCount() { + return closeCount; + } + + public Counter getForwardSmallSeeks() { + return forwardSmallSeeks; + } + + public Counter getBackwardSmallSeeks() { + return backwardSmallSeeks; + } + + public Counter getForwardLargeSeeks() { + return forwardLargeSeeks; + } + + public Counter getBackwardLargeSeeks() { + return backwardLargeSeeks; + } + + public Counter getContiguousReads() { + return contiguousReads; + } + + public Counter getNonContiguousReads() { + return nonContiguousReads; + } + + public Counter getCachedBytesRead() { + return cachedBytesRead; + } + + public Counter getCachedBytesWritten() { + return cachedBytesWritten; + } + + public Counter getDirectBytesRead() { + return directBytesRead; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + { + builder.field("name", getFileName()); + builder.field("length", getFileLength()); + builder.field("open_count", getOpenCount()); + builder.field("inner_count", getInnerCount()); + 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("cached_bytes_written", getCachedBytesWritten()); + builder.field("direct_bytes_read", getDirectBytesRead()); + { + builder.startObject("forward_seeks"); + builder.field("small", getForwardSmallSeeks()); + builder.field("large", getForwardLargeSeeks()); + builder.endObject(); + } + { + builder.startObject("backward_seeks"); + builder.field("small", getBackwardSmallSeeks()); + builder.field("large", getBackwardLargeSeeks()); + builder.endObject(); + } + } + return builder.endObject(); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + CacheIndexInputStats stats = (CacheIndexInputStats) other; + return fileLength == stats.fileLength + && openCount == stats.openCount + && innerCount == stats.innerCount + && closeCount == stats.closeCount + && Objects.equals(fileName, stats.fileName) + && Objects.equals(forwardSmallSeeks, stats.forwardSmallSeeks) + && Objects.equals(backwardSmallSeeks, stats.backwardSmallSeeks) + && Objects.equals(forwardLargeSeeks, stats.forwardLargeSeeks) + && Objects.equals(backwardLargeSeeks, stats.backwardLargeSeeks) + && Objects.equals(contiguousReads, stats.contiguousReads) + && Objects.equals(nonContiguousReads, stats.nonContiguousReads) + && Objects.equals(cachedBytesRead, stats.cachedBytesRead) + && Objects.equals(cachedBytesWritten, stats.cachedBytesWritten) + && Objects.equals(directBytesRead, stats.directBytesRead); + } + + @Override + public int hashCode() { + return Objects.hash(fileName, fileLength, openCount, innerCount, closeCount, + forwardSmallSeeks, backwardSmallSeeks, + forwardLargeSeeks, backwardLargeSeeks, + contiguousReads, nonContiguousReads, + cachedBytesRead, cachedBytesWritten, + directBytesRead); + } + } + + public static class Counter implements Writeable, ToXContentObject { + + private final long count; + private final long total; + private final long min; + private final long max; + + public Counter(final long count, final long total, final long min, final long max) { + this.count = count; + this.total = total; + this.min = min; + this.max = max; + } + + Counter(final StreamInput in) throws IOException { + this.count = in.readZLong(); + this.total = in.readZLong(); + this.min = in.readZLong(); + this.max = in.readZLong(); + } + + @Override + public void writeTo(final StreamOutput out) throws IOException { + out.writeZLong(count); + out.writeZLong(total); + out.writeZLong(min); + out.writeZLong(max); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + { + builder.field("count", count); + builder.field("sum", total); + builder.field("min", min); + builder.field("max", max); + } + builder.endObject(); + return builder; + } + + public long getCount() { + return count; + } + + public long getTotal() { + return total; + } + + public long getMin() { + return min; + } + + public long getMax() { + return max; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + Counter that = (Counter) other; + return count == that.count + && total == that.total + && min == that.min + && max == that.max; + } + + @Override + public int hashCode() { + return Objects.hash(count, total, min, max); + } + } +} diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStatsTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStatsTests.java new file mode 100644 index 0000000000000..dea03d1b4d154 --- /dev/null +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStatsTests.java @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.core.searchablesnapshots; + +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.index.shard.ShardId; +import org.elasticsearch.repositories.IndexId; +import org.elasticsearch.snapshots.SnapshotId; +import org.elasticsearch.test.AbstractWireSerializingTestCase; +import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.CacheDirectoryStats; +import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.CacheIndexInputStats; +import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.Counter; + +import java.util.ArrayList; +import java.util.List; + +public class SearchableSnapshotStatsTests extends AbstractWireSerializingTestCase { + + @Override + protected Writeable.Reader instanceReader() { + return SearchableSnapshotStats::new; + } + + @Override + protected SearchableSnapshotStats createTestInstance() { + final List directoryStats = new ArrayList<>(); + for (int i = 0; i < randomInt(20); i++) { + directoryStats.add(randomCacheDirectoryStats()); + } + return new SearchableSnapshotStats(directoryStats); + } + + private CacheDirectoryStats randomCacheDirectoryStats() { + SnapshotId snapshotId = new SnapshotId(randomAlphaOfLength(5), randomAlphaOfLength(5)); + IndexId indexId = new IndexId(randomAlphaOfLength(5), randomAlphaOfLength(5)); + ShardId shardId = new ShardId(randomAlphaOfLength(5), randomAlphaOfLength(5), randomInt(10)); + + final List inputStats = new ArrayList<>(); + for (int j = 0; j < randomInt(20); j++) { + inputStats.add(randomCacheIndexInputStats()); + } + return new CacheDirectoryStats(snapshotId, indexId, shardId, inputStats); + } + + private CacheIndexInputStats randomCacheIndexInputStats() { + return new CacheIndexInputStats(randomAlphaOfLength(10), randomNonNegativeLong(), + randomNonNegativeLong(), randomNonNegativeLong(), randomNonNegativeLong(), + randomCounter(), randomCounter(), + randomCounter(), randomCounter(), + randomCounter(), randomCounter(), + randomCounter(), randomCounter(), + randomCounter()); + } + + private Counter randomCounter() { + return new Counter(randomNonNegativeLong(), randomNonNegativeLong(), randomNonNegativeLong(), randomNonNegativeLong()); + } +} diff --git a/x-pack/plugin/searchable-snapshots/build.gradle b/x-pack/plugin/searchable-snapshots/build.gradle index dd928bfbcc41c..dcb22ec38a51f 100644 --- a/x-pack/plugin/searchable-snapshots/build.gradle +++ b/x-pack/plugin/searchable-snapshots/build.gradle @@ -18,3 +18,12 @@ dependencies { // installing them as individual plugins for integ tests doesn't make sense, // so we disable integ tests integTest.enabled = false + +// add all sub-projects of the qa sub-project +gradle.projectsEvaluated { + project.subprojects + .find { it.path == project.path + ":qa" } + .subprojects + .findAll { it.path.startsWith(project.path + ":qa") } + .each { check.dependsOn it.check } +} diff --git a/x-pack/plugin/searchable-snapshots/qa/build.gradle b/x-pack/plugin/searchable-snapshots/qa/build.gradle new file mode 100644 index 0000000000000..b2e39e506a5b0 --- /dev/null +++ b/x-pack/plugin/searchable-snapshots/qa/build.gradle @@ -0,0 +1,17 @@ +import org.elasticsearch.gradle.test.RestIntegTestTask + +apply plugin: 'elasticsearch.build' +test.enabled = false + +dependencies { + compile project(':test:framework') +} + +subprojects { + project.tasks.withType(RestIntegTestTask) { + final File xPackResources = new File(xpackProject('plugin:searchable-snapshots').projectDir, 'src/test/resources') + project.copyRestSpec.from(xPackResources) { + include 'rest-api-spec/api/**' + } + } +} diff --git a/x-pack/plugin/searchable-snapshots/qa/rest/build.gradle b/x-pack/plugin/searchable-snapshots/qa/rest/build.gradle new file mode 100644 index 0000000000000..bbc35ade30a0b --- /dev/null +++ b/x-pack/plugin/searchable-snapshots/qa/rest/build.gradle @@ -0,0 +1,12 @@ +apply plugin: 'elasticsearch.testclusters' +apply plugin: 'elasticsearch.standalone-rest-test' +apply plugin: 'elasticsearch.rest-test' + +dependencies { + testCompile project(path: xpackModule('searchable-snapshots'), configuration: 'runtime') +} + +testClusters.integTest { + testDistribution = 'DEFAULT' + setting 'xpack.license.self_generated.type', 'basic' +} diff --git a/x-pack/plugin/searchable-snapshots/qa/rest/src/test/java/org/elasticsearch/xpack/searchablesnapshots/rest/SearchableSnapshotsRestIT.java b/x-pack/plugin/searchable-snapshots/qa/rest/src/test/java/org/elasticsearch/xpack/searchablesnapshots/rest/SearchableSnapshotsRestIT.java new file mode 100644 index 0000000000000..025f594ef669a --- /dev/null +++ b/x-pack/plugin/searchable-snapshots/qa/rest/src/test/java/org/elasticsearch/xpack/searchablesnapshots/rest/SearchableSnapshotsRestIT.java @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +package org.elasticsearch.xpack.searchablesnapshots.rest; + +import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate; +import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase; + +public class SearchableSnapshotsRestIT extends ESClientYamlSuiteTestCase { + + public SearchableSnapshotsRestIT(final ClientYamlTestCandidate testCandidate) { + super(testCandidate); + } + + @ParametersFactory + public static Iterable parameters() throws Exception { + return ESClientYamlSuiteTestCase.createParameters(); + } +} diff --git a/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml b/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml new file mode 100644 index 0000000000000..1380f6af0a8ac --- /dev/null +++ b/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml @@ -0,0 +1,149 @@ +--- +setup: + + - do: + indices.create: + index: index + body: + settings: + number_of_shards: 1 + + - do: + bulk: + body: + - index: + _index: index + - field: foo + - index: + _index: index + - field: bar + - index: + _index: index + - field: baz + + - do: + snapshot.create_repository: + repository: repository-fs + body: + type: fs + settings: + location: "repository-fs" + + - do: + snapshot.create: + repository: repository-fs + snapshot: snapshot + wait_for_completion: true + + - do: + snapshot.delete_repository: + repository: repository-fs + + - do: + indices.delete: + index: index + +--- +"Tests searchable snapshots stats": + - skip: + version: " - 7.99.99" + reason: searchable snapshots introduced in 8.0 + + - do: + searchable_snapshots.stats: {} + + - length: { nodes: 0 } + + - do: + snapshot.create_repository: + repository: repository-searchable-snapshots + body: + type: searchable + settings: + delegate_type: fs + location: "repository-fs" + + - match: { acknowledged: true } + + - do: + snapshot.restore: + repository: repository-searchable-snapshots + snapshot: snapshot + wait_for_completion: true + + - match: { snapshot.snapshot: snapshot } + - match: { snapshot.shards.failed: 0 } + - match: { snapshot.shards.successful: 1 } + + - do: + search: + rest_total_hits_as_int: true + index: index + body: + query: + match_all: {} + + - match: { hits.total: 3 } + + - do: + nodes.info: {} + - set: + nodes._arbitrary_key_: node_id + + - do: + searchable_snapshots.stats: {} + + - length: { nodes: 1 } + - length: { nodes.$node_id.indices.index.shards: 1 } + - is_true: nodes.$node_id.indices.index.shards.0.snapshot_uuid + - is_true: nodes.$node_id.indices.index.shards.0.index_uuid + - match: { nodes.$node_id.indices.index.shards.0.shard: 0 } + + - is_true: nodes.$node_id.indices.index.shards.0.files.0.name + - gt: { nodes.$node_id.indices.index.shards.0.files.0.length: 0 } + - gt: { nodes.$node_id.indices.index.shards.0.files.0.open_count: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.inner_count: 0 } + - gt: { nodes.$node_id.indices.index.shards.0.files.0.close_count: 0 } + + - gte: { nodes.$node_id.indices.index.shards.0.files.0.contiguous_bytes_read.count: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.contiguous_bytes_read.sum: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.contiguous_bytes_read.min: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.contiguous_bytes_read.max: 0 } + + - gte: { nodes.$node_id.indices.index.shards.0.files.0.non_contiguous_bytes_read.count: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.non_contiguous_bytes_read.sum: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.non_contiguous_bytes_read.min: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.non_contiguous_bytes_read.max: 0 } + + - gte: { nodes.$node_id.indices.index.shards.0.files.0.cached_bytes_read.count: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.cached_bytes_read.sum: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.cached_bytes_read.min: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.cached_bytes_read.max: 0 } + + - gte: { nodes.$node_id.indices.index.shards.0.files.0.cached_bytes_written.count: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.cached_bytes_written.sum: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.cached_bytes_written.min: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.cached_bytes_written.max: 0 } + + - gte: { nodes.$node_id.indices.index.shards.0.files.0.direct_bytes_read.count: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.direct_bytes_read.sum: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.direct_bytes_read.min: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.direct_bytes_read.max: 0 } + + - gte: { nodes.$node_id.indices.index.shards.0.files.0.forward_seeks.small.count: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.forward_seeks.small.sum: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.forward_seeks.small.min: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.forward_seeks.small.max: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.forward_seeks.large.count: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.forward_seeks.large.sum: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.forward_seeks.large.min: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.forward_seeks.large.max: 0 } + + - gte: { nodes.$node_id.indices.index.shards.0.files.0.backward_seeks.small.count: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.backward_seeks.small.sum: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.backward_seeks.small.min: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.backward_seeks.small.max: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.backward_seeks.large.count: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.backward_seeks.large.sum: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.backward_seeks.large.min: 0 } + - gte: { nodes.$node_id.indices.index.shards.0.files.0.backward_seeks.large.max: 0 } diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/InMemoryNoOpCommitDirectory.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/InMemoryNoOpCommitDirectory.java index bab3b0e53f270..802c2a471dc7f 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/InMemoryNoOpCommitDirectory.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/InMemoryNoOpCommitDirectory.java @@ -25,6 +25,7 @@ * of the same, so that we can start a shard on a completely readonly data set. */ public class InMemoryNoOpCommitDirectory extends FilterDirectory { + private final Directory realDirectory; InMemoryNoOpCommitDirectory(Directory realDirectory) { @@ -32,6 +33,10 @@ public class InMemoryNoOpCommitDirectory extends FilterDirectory { this.realDirectory = realDirectory; } + public Directory getRealDirectory() { + return realDirectory; + } + @Override public String[] listAll() throws IOException { final String[] ephemeralFiles = in.listAll(); diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshots.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshots.java index 61e277bb8ae4d..660205cad14d4 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshots.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshots.java @@ -6,11 +6,18 @@ package org.elasticsearch.xpack.searchablesnapshots; import org.apache.lucene.util.SetOnce; +import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionResponse; import org.elasticsearch.client.Client; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.settings.ClusterSettings; +import org.elasticsearch.common.settings.IndexScopedSettings; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.settings.SettingsFilter; import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.env.Environment; import org.elasticsearch.env.NodeEnvironment; @@ -18,6 +25,7 @@ import org.elasticsearch.index.engine.EngineFactory; import org.elasticsearch.index.engine.ReadOnlyEngine; import org.elasticsearch.index.translog.TranslogStats; +import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.plugins.EnginePlugin; import org.elasticsearch.plugins.IndexStorePlugin; import org.elasticsearch.plugins.Plugin; @@ -25,10 +33,15 @@ import org.elasticsearch.repositories.RepositoriesModule; import org.elasticsearch.repositories.RepositoriesService; import org.elasticsearch.repositories.Repository; +import org.elasticsearch.rest.RestController; +import org.elasticsearch.rest.RestHandler; import org.elasticsearch.script.ScriptService; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.watcher.ResourceWatcherService; +import org.elasticsearch.xpack.searchablesnapshots.action.SeachableSnapshotsStatsAction; +import org.elasticsearch.xpack.searchablesnapshots.action.TransportSeachableSnapshotsStatsAction; import org.elasticsearch.xpack.searchablesnapshots.cache.CacheService; +import org.elasticsearch.xpack.searchablesnapshots.rest.RestSeachableSnapshotsStatsAction; import java.util.Collection; import java.util.Collections; @@ -36,13 +49,14 @@ import java.util.Map; import java.util.Optional; import java.util.function.Function; +import java.util.function.Supplier; import static org.elasticsearch.index.IndexModule.INDEX_STORE_TYPE_SETTING; /** * Plugin for Searchable Snapshots feature */ -public class SearchableSnapshots extends Plugin implements IndexStorePlugin, RepositoryPlugin, EnginePlugin { +public class SearchableSnapshots extends Plugin implements IndexStorePlugin, RepositoryPlugin, EnginePlugin, ActionPlugin { private final SetOnce repositoriesService; private final SetOnce cacheService; @@ -107,5 +121,17 @@ public Map getRepositories(Environment env, NamedXCo ClusterService clusterService) { return Collections.singletonMap(SearchableSnapshotRepository.TYPE, SearchableSnapshotRepository.getRepositoryFactory()); } + + @Override + public List> getActions() { + return List.of(new ActionHandler<>(SeachableSnapshotsStatsAction.INSTANCE, TransportSeachableSnapshotsStatsAction.class)); + } + + public List getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings, + IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter, + IndexNameExpressionResolver indexNameExpressionResolver, + Supplier nodesInCluster) { + return List.of(new RestSeachableSnapshotsStatsAction(restController)); + } } diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsAction.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsAction.java new file mode 100644 index 0000000000000..dec0e79ec61b6 --- /dev/null +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsAction.java @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.searchablesnapshots.action; + +import org.elasticsearch.action.ActionType; + +public class SeachableSnapshotsStatsAction extends ActionType { + + public static final SeachableSnapshotsStatsAction INSTANCE = new SeachableSnapshotsStatsAction(); + static final String NAME = "cluster:monitor/xpack/searchable_snapshots/stats"; + + private SeachableSnapshotsStatsAction() { + super(NAME, SeachableSnapshotsStatsResponse::new); + } +} diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsRequest.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsRequest.java new file mode 100644 index 0000000000000..e565c8fa55c0e --- /dev/null +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsRequest.java @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.searchablesnapshots.action; + +import org.elasticsearch.action.support.nodes.BaseNodeRequest; +import org.elasticsearch.action.support.nodes.BaseNodesRequest; +import org.elasticsearch.common.io.stream.StreamInput; + +import java.io.IOException; + +public class SeachableSnapshotsStatsRequest extends BaseNodesRequest { + + SeachableSnapshotsStatsRequest(StreamInput in) throws IOException { + super(in); + } + + public SeachableSnapshotsStatsRequest(String... nodesIds) { + super(nodesIds); + } + + static class NodeStatsRequest extends BaseNodeRequest { + + NodeStatsRequest() { + } + + NodeStatsRequest(StreamInput in) throws IOException { + super(in); + } + } +} diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsResponse.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsResponse.java new file mode 100644 index 0000000000000..7ae0892880be6 --- /dev/null +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsResponse.java @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.searchablesnapshots.action; + +import org.elasticsearch.action.FailedNodeException; +import org.elasticsearch.action.support.nodes.BaseNodeResponse; +import org.elasticsearch.action.support.nodes.BaseNodesResponse; +import org.elasticsearch.cluster.ClusterName; +import org.elasticsearch.cluster.node.DiscoveryNode; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.ToXContentFragment; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats; + +import java.io.IOException; +import java.util.List; + +public class SeachableSnapshotsStatsResponse + extends BaseNodesResponse implements ToXContentObject { + + SeachableSnapshotsStatsResponse(StreamInput in) throws IOException { + super(in); + } + + SeachableSnapshotsStatsResponse(ClusterName clusterName, List nodes, List failures) { + super(clusterName, nodes, failures); + } + + @Override + protected List readNodesFrom(StreamInput in) throws IOException { + return in.readList(NodeStatsResponse::readNodeResponse); + } + + @Override + protected void writeNodesTo(StreamOutput out, List nodes) throws IOException { + out.writeList(nodes); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject("nodes"); + for (NodeStatsResponse node : getNodes()) { + node.toXContent(builder, params); + } + builder.endObject(); + return builder; + } + + static class NodeStatsResponse extends BaseNodeResponse implements ToXContentFragment { + + private final SearchableSnapshotStats stats; + + NodeStatsResponse(StreamInput in) throws IOException { + super(in); + this.stats = in.readOptionalWriteable(SearchableSnapshotStats::new); + } + + NodeStatsResponse(DiscoveryNode node, SearchableSnapshotStats stats) { + super(node); + this.stats = stats; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeOptionalWriteable(stats); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + if (stats != null && stats.isEmpty() == false) { + builder.field(getNode().getId(), stats); + } + return builder; + } + + static NodeStatsResponse readNodeResponse(StreamInput in) throws IOException { + return new NodeStatsResponse(in); + } + } +} diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSeachableSnapshotsStatsAction.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSeachableSnapshotsStatsAction.java new file mode 100644 index 0000000000000..06c6c73f5f3d9 --- /dev/null +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSeachableSnapshotsStatsAction.java @@ -0,0 +1,132 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.searchablesnapshots.action; + +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.FilterDirectory; +import org.elasticsearch.action.FailedNodeException; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.nodes.TransportNodesAction; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.index.IndexService; +import org.elasticsearch.index.shard.IndexShard; +import org.elasticsearch.indices.IndicesService; +import org.elasticsearch.tasks.Task; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats; +import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.CacheDirectoryStats; +import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.CacheIndexInputStats; +import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.Counter; +import org.elasticsearch.xpack.searchablesnapshots.InMemoryNoOpCommitDirectory; +import org.elasticsearch.xpack.searchablesnapshots.action.SeachableSnapshotsStatsRequest.NodeStatsRequest; +import org.elasticsearch.xpack.searchablesnapshots.action.SeachableSnapshotsStatsResponse.NodeStatsResponse; +import org.elasticsearch.xpack.searchablesnapshots.cache.CacheDirectory; +import org.elasticsearch.xpack.searchablesnapshots.cache.IndexInputStats; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.elasticsearch.index.IndexModule.INDEX_STORE_TYPE_SETTING; +import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshotRepository.SNAPSHOT_DIRECTORY_FACTORY_KEY; + +public class TransportSeachableSnapshotsStatsAction extends TransportNodesAction { + + private final IndicesService indicesService; + + @Inject + public TransportSeachableSnapshotsStatsAction(final ThreadPool threadPool, + final ClusterService clusterService, + final TransportService transportService, + final ActionFilters actionFilters, + final IndicesService indicesService) { + super(SeachableSnapshotsStatsAction.NAME, threadPool, clusterService, transportService, actionFilters, + SeachableSnapshotsStatsRequest::new, NodeStatsRequest::new, ThreadPool.Names.GENERIC, NodeStatsResponse.class); + this.indicesService = Objects.requireNonNull(indicesService); + } + + @Override + protected SeachableSnapshotsStatsResponse newResponse(SeachableSnapshotsStatsRequest request, List responses, + List failures) { + return new SeachableSnapshotsStatsResponse(clusterService.getClusterName(), responses, failures); + } + + @Override + protected NodeStatsRequest newNodeRequest(SeachableSnapshotsStatsRequest request) { + return new NodeStatsRequest(); + } + + @Override + protected NodeStatsResponse newNodeResponse(StreamInput in) throws IOException { + return new NodeStatsResponse(in); + } + + @Override + protected NodeStatsResponse nodeOperation(final NodeStatsRequest request, final Task task) { + final List directoryStats = new ArrayList<>(); + if (clusterService.localNode().isDataNode()) { + for (IndexService indexService : indicesService) { + Settings indexSettings = indexService.getIndexSettings().getSettings(); + if (INDEX_STORE_TYPE_SETTING.get(indexSettings).equals(SNAPSHOT_DIRECTORY_FACTORY_KEY)) { + for (IndexShard indexShard : indexService) { + CacheDirectory cacheDirectory = unwrap(indexShard.store().directory()); + if (cacheDirectory != null) { + directoryStats.add(toDirectoryStats(cacheDirectory)); + } + } + } + } + } + return new NodeStatsResponse(clusterService.localNode(), new SearchableSnapshotStats(directoryStats)); + } + + private static CacheDirectoryStats toDirectoryStats(final CacheDirectory cacheDirectory) { + return new CacheDirectoryStats(cacheDirectory.getSnapshotId(), cacheDirectory.getIndexId(), cacheDirectory.getShardId(), + cacheDirectory.getStats().entrySet().stream() + .map(entry -> toCacheIndexInputStats(entry.getKey(), entry.getValue())) + .collect(Collectors.toList())); + } + + private static CacheIndexInputStats toCacheIndexInputStats(final String fileName, final IndexInputStats inputStats) { + return new CacheIndexInputStats(fileName, inputStats.getFileLength(), + inputStats.getOpened().sum(), inputStats.getInnerOpened().sum(), inputStats.getClosed().sum(), + toCounter(inputStats.getForwardSmallSeeks()), toCounter(inputStats.getBackwardSmallSeeks()), + toCounter(inputStats.getForwardLargeSeeks()), toCounter(inputStats.getBackwardLargeSeeks()), + toCounter(inputStats.getContiguousReads()), toCounter(inputStats.getNonContiguousReads()), + toCounter(inputStats.getCachedBytesRead()), toCounter(inputStats.getCachedBytesWritten()), + toCounter(inputStats.getDirectBytesRead())); + } + + private static Counter toCounter(final IndexInputStats.Counter counter) { + return new Counter(counter.count(), counter.total(), counter.min(), counter.max()); + } + + @Nullable + private static CacheDirectory unwrap(Directory dir) { + while (dir != null) { + if (dir instanceof CacheDirectory) { + return (CacheDirectory) dir; + } else if (dir instanceof InMemoryNoOpCommitDirectory) { + dir = ((InMemoryNoOpCommitDirectory) dir).getRealDirectory(); + } else if (dir instanceof FilterDirectory) { + dir = ((FilterDirectory) dir).getDelegate(); + } else { + dir = null; + } + } + return null; + } +} diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/CacheDirectory.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/CacheDirectory.java index 2246244000d7f..44fd414f84765 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/CacheDirectory.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/CacheDirectory.java @@ -64,6 +64,22 @@ private CacheKey createCacheKey(String fileName) { return new CacheKey(snapshotId, indexId, shardId, fileName); } + public SnapshotId getSnapshotId() { + return snapshotId; + } + + public IndexId getIndexId() { + return indexId; + } + + public ShardId getShardId() { + return shardId; + } + + public Map getStats() { + return stats; + } + // pkg private for tests @Nullable IndexInputStats getStats(String name) { return stats.get(name); diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/IndexInputStats.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/IndexInputStats.java index f4a5d1d87cc89..b27d5b7c64682 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/IndexInputStats.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/IndexInputStats.java @@ -96,55 +96,55 @@ public void incrementSeeks(long currentPosition, long newPosition) { } } - long getFileLength() { + public long getFileLength() { return fileLength; } - LongAdder getOpened() { + public LongAdder getOpened() { return opened; } - LongAdder getInnerOpened() { + public LongAdder getInnerOpened() { return inner; } - LongAdder getClosed() { + public LongAdder getClosed() { return closed; } - Counter getForwardSmallSeeks() { + public Counter getForwardSmallSeeks() { return forwardSmallSeeks; } - Counter getBackwardSmallSeeks() { + public Counter getBackwardSmallSeeks() { return backwardSmallSeeks; } - Counter getForwardLargeSeeks() { + public Counter getForwardLargeSeeks() { return forwardLargeSeeks; } - Counter getBackwardLargeSeeks() { + public Counter getBackwardLargeSeeks() { return backwardLargeSeeks; } - Counter getContiguousReads() { + public Counter getContiguousReads() { return contiguousReads; } - Counter getNonContiguousReads() { + public Counter getNonContiguousReads() { return nonContiguousReads; } - Counter getDirectBytesRead() { + public Counter getDirectBytesRead() { return directBytesRead; } - Counter getCachedBytesRead() { + public Counter getCachedBytesRead() { return cachedBytesRead; } - Counter getCachedBytesWritten() { + public Counter getCachedBytesWritten() { return cachedBytesWritten; } @@ -153,7 +153,7 @@ boolean isLargeSeek(long delta) { return delta != Long.MIN_VALUE && Math.abs(delta) > SEEKING_THRESHOLD.getBytes(); } - static class Counter { + public static class Counter { private final LongAdder count = new LongAdder(); private final LongAdder total = new LongAdder(); @@ -167,15 +167,15 @@ void add(final long value) { max.updateAndGet(prev -> Math.max(prev, value)); } - long count() { + public long count() { return count.sum(); } - long total() { + public long total() { return total.sum(); } - long min() { + public long min() { final long value = min.get(); if (value == Long.MAX_VALUE) { return 0L; @@ -183,7 +183,7 @@ long min() { return value; } - long max() { + public long max() { final long value = max.get(); if (value == Long.MIN_VALUE) { return 0L; diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/rest/RestSeachableSnapshotsStatsAction.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/rest/RestSeachableSnapshotsStatsAction.java new file mode 100644 index 0000000000000..83c17b2be01ec --- /dev/null +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/rest/RestSeachableSnapshotsStatsAction.java @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.searchablesnapshots.rest; + +import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.Strings; +import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.rest.RestController; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.action.RestActions; +import org.elasticsearch.xpack.searchablesnapshots.action.SeachableSnapshotsStatsAction; +import org.elasticsearch.xpack.searchablesnapshots.action.SeachableSnapshotsStatsRequest; + +public class RestSeachableSnapshotsStatsAction extends BaseRestHandler { + + public RestSeachableSnapshotsStatsAction(final RestController controller) { + controller.registerHandler(RestRequest.Method.GET, "/_searchable_snapshots/stats", this); + controller.registerHandler(RestRequest.Method.GET, "/_searchable_snapshots/{nodes}/stats", this); + } + + @Override + public String getName() { + return "searchable_snapshots_stats_action"; + } + + @Override + public RestChannelConsumer prepareRequest(final RestRequest restRequest, final NodeClient client) { + String[] nodes = Strings.splitStringByCommaToArray(restRequest.param("nodes")); + return channel -> client.execute(SeachableSnapshotsStatsAction.INSTANCE, + new SeachableSnapshotsStatsRequest(nodes), new RestActions.NodesResponseRestListener<>(channel)); + } +} diff --git a/x-pack/plugin/searchable-snapshots/src/test/resources/rest-api-spec/api/searchable_snapshots.stats.json b/x-pack/plugin/searchable-snapshots/src/test/resources/rest-api-spec/api/searchable_snapshots.stats.json new file mode 100644 index 0000000000000..3c91234c5cc4c --- /dev/null +++ b/x-pack/plugin/searchable-snapshots/src/test/resources/rest-api-spec/api/searchable_snapshots.stats.json @@ -0,0 +1,30 @@ +{ + "searchable_snapshots.stats":{ + "documentation":{ + "url":"https://www.elastic.co/guide/en/elasticsearch/reference/current/searchable-snapshots-get-stats.html //NORELEASE" + }, + "stability":"experimental", + "url":{ + "paths":[ + { + "path":"/_searchable_snapshots/stats", + "methods":[ + "GET" + ] + }, + { + "path":"/_searchable_snapshots/{node_id}/stats", + "methods":[ + "GET" + ], + "parts":{ + "node_id":{ + "type":"list", + "description":"A comma-separated list of node IDs or names to limit the returned information; use `_local` to return information from the node you're connecting to, leave empty to get information from all nodes" + } + } + } + ] + } + } +} From 2dfb3fde2f8739f3f06ed7dfc6a7ebe512a086a0 Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Mon, 3 Feb 2020 15:45:34 +0100 Subject: [PATCH 02/12] Fix typos --- .../SearchableSnapshots.java | 10 +++---- ...va => SearchableSnapshotsStatsAction.java} | 8 ++--- ...a => SearchableSnapshotsStatsRequest.java} | 6 ++-- ... => SearchableSnapshotsStatsResponse.java} | 8 ++--- ...nsportSearchableSnapshotsStatsAction.java} | 30 +++++++++---------- ...> RestSearchableSnapshotsStatsAction.java} | 12 ++++---- 6 files changed, 37 insertions(+), 37 deletions(-) rename x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/{SeachableSnapshotsStatsAction.java => SearchableSnapshotsStatsAction.java} (58%) rename x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/{SeachableSnapshotsStatsRequest.java => SearchableSnapshotsStatsRequest.java} (76%) rename x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/{SeachableSnapshotsStatsResponse.java => SearchableSnapshotsStatsResponse.java} (88%) rename x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/{TransportSeachableSnapshotsStatsAction.java => TransportSearchableSnapshotsStatsAction.java} (78%) rename x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/rest/{RestSeachableSnapshotsStatsAction.java => RestSearchableSnapshotsStatsAction.java} (67%) diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshots.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshots.java index 660205cad14d4..7374a36fd722d 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshots.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshots.java @@ -38,10 +38,10 @@ import org.elasticsearch.script.ScriptService; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.watcher.ResourceWatcherService; -import org.elasticsearch.xpack.searchablesnapshots.action.SeachableSnapshotsStatsAction; -import org.elasticsearch.xpack.searchablesnapshots.action.TransportSeachableSnapshotsStatsAction; +import org.elasticsearch.xpack.searchablesnapshots.action.SearchableSnapshotsStatsAction; +import org.elasticsearch.xpack.searchablesnapshots.action.TransportSearchableSnapshotsStatsAction; import org.elasticsearch.xpack.searchablesnapshots.cache.CacheService; -import org.elasticsearch.xpack.searchablesnapshots.rest.RestSeachableSnapshotsStatsAction; +import org.elasticsearch.xpack.searchablesnapshots.rest.RestSearchableSnapshotsStatsAction; import java.util.Collection; import java.util.Collections; @@ -124,14 +124,14 @@ public Map getRepositories(Environment env, NamedXCo @Override public List> getActions() { - return List.of(new ActionHandler<>(SeachableSnapshotsStatsAction.INSTANCE, TransportSeachableSnapshotsStatsAction.class)); + return List.of(new ActionHandler<>(SearchableSnapshotsStatsAction.INSTANCE, TransportSearchableSnapshotsStatsAction.class)); } public List getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings, IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter, IndexNameExpressionResolver indexNameExpressionResolver, Supplier nodesInCluster) { - return List.of(new RestSeachableSnapshotsStatsAction(restController)); + return List.of(new RestSearchableSnapshotsStatsAction(restController)); } } diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsAction.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsAction.java similarity index 58% rename from x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsAction.java rename to x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsAction.java index dec0e79ec61b6..f59e001cea23b 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsAction.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsAction.java @@ -7,12 +7,12 @@ import org.elasticsearch.action.ActionType; -public class SeachableSnapshotsStatsAction extends ActionType { +public class SearchableSnapshotsStatsAction extends ActionType { - public static final SeachableSnapshotsStatsAction INSTANCE = new SeachableSnapshotsStatsAction(); + public static final SearchableSnapshotsStatsAction INSTANCE = new SearchableSnapshotsStatsAction(); static final String NAME = "cluster:monitor/xpack/searchable_snapshots/stats"; - private SeachableSnapshotsStatsAction() { - super(NAME, SeachableSnapshotsStatsResponse::new); + private SearchableSnapshotsStatsAction() { + super(NAME, SearchableSnapshotsStatsResponse::new); } } diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsRequest.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsRequest.java similarity index 76% rename from x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsRequest.java rename to x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsRequest.java index e565c8fa55c0e..a250a3faf46b7 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsRequest.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsRequest.java @@ -11,13 +11,13 @@ import java.io.IOException; -public class SeachableSnapshotsStatsRequest extends BaseNodesRequest { +public class SearchableSnapshotsStatsRequest extends BaseNodesRequest { - SeachableSnapshotsStatsRequest(StreamInput in) throws IOException { + SearchableSnapshotsStatsRequest(StreamInput in) throws IOException { super(in); } - public SeachableSnapshotsStatsRequest(String... nodesIds) { + public SearchableSnapshotsStatsRequest(String... nodesIds) { super(nodesIds); } diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsResponse.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsResponse.java similarity index 88% rename from x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsResponse.java rename to x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsResponse.java index 7ae0892880be6..3a7a4367a7508 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SeachableSnapshotsStatsResponse.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsResponse.java @@ -20,14 +20,14 @@ import java.io.IOException; import java.util.List; -public class SeachableSnapshotsStatsResponse - extends BaseNodesResponse implements ToXContentObject { +public class SearchableSnapshotsStatsResponse + extends BaseNodesResponse implements ToXContentObject { - SeachableSnapshotsStatsResponse(StreamInput in) throws IOException { + SearchableSnapshotsStatsResponse(StreamInput in) throws IOException { super(in); } - SeachableSnapshotsStatsResponse(ClusterName clusterName, List nodes, List failures) { + SearchableSnapshotsStatsResponse(ClusterName clusterName, List nodes, List failures) { super(clusterName, nodes, failures); } diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSeachableSnapshotsStatsAction.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java similarity index 78% rename from x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSeachableSnapshotsStatsAction.java rename to x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java index 06c6c73f5f3d9..9140ea238cc2a 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSeachableSnapshotsStatsAction.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java @@ -26,8 +26,8 @@ import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.CacheIndexInputStats; import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.Counter; import org.elasticsearch.xpack.searchablesnapshots.InMemoryNoOpCommitDirectory; -import org.elasticsearch.xpack.searchablesnapshots.action.SeachableSnapshotsStatsRequest.NodeStatsRequest; -import org.elasticsearch.xpack.searchablesnapshots.action.SeachableSnapshotsStatsResponse.NodeStatsResponse; +import org.elasticsearch.xpack.searchablesnapshots.action.SearchableSnapshotsStatsRequest.NodeStatsRequest; +import org.elasticsearch.xpack.searchablesnapshots.action.SearchableSnapshotsStatsResponse.NodeStatsResponse; import org.elasticsearch.xpack.searchablesnapshots.cache.CacheDirectory; import org.elasticsearch.xpack.searchablesnapshots.cache.IndexInputStats; @@ -40,32 +40,32 @@ import static org.elasticsearch.index.IndexModule.INDEX_STORE_TYPE_SETTING; import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshotRepository.SNAPSHOT_DIRECTORY_FACTORY_KEY; -public class TransportSeachableSnapshotsStatsAction extends TransportNodesAction { private final IndicesService indicesService; @Inject - public TransportSeachableSnapshotsStatsAction(final ThreadPool threadPool, - final ClusterService clusterService, - final TransportService transportService, - final ActionFilters actionFilters, - final IndicesService indicesService) { - super(SeachableSnapshotsStatsAction.NAME, threadPool, clusterService, transportService, actionFilters, - SeachableSnapshotsStatsRequest::new, NodeStatsRequest::new, ThreadPool.Names.GENERIC, NodeStatsResponse.class); + public TransportSearchableSnapshotsStatsAction(final ThreadPool threadPool, + final ClusterService clusterService, + final TransportService transportService, + final ActionFilters actionFilters, + final IndicesService indicesService) { + super(SearchableSnapshotsStatsAction.NAME, threadPool, clusterService, transportService, actionFilters, + SearchableSnapshotsStatsRequest::new, NodeStatsRequest::new, ThreadPool.Names.GENERIC, NodeStatsResponse.class); this.indicesService = Objects.requireNonNull(indicesService); } @Override - protected SeachableSnapshotsStatsResponse newResponse(SeachableSnapshotsStatsRequest request, List responses, - List failures) { - return new SeachableSnapshotsStatsResponse(clusterService.getClusterName(), responses, failures); + protected SearchableSnapshotsStatsResponse newResponse(SearchableSnapshotsStatsRequest request, List responses, + List failures) { + return new SearchableSnapshotsStatsResponse(clusterService.getClusterName(), responses, failures); } @Override - protected NodeStatsRequest newNodeRequest(SeachableSnapshotsStatsRequest request) { + protected NodeStatsRequest newNodeRequest(SearchableSnapshotsStatsRequest request) { return new NodeStatsRequest(); } diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/rest/RestSeachableSnapshotsStatsAction.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/rest/RestSearchableSnapshotsStatsAction.java similarity index 67% rename from x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/rest/RestSeachableSnapshotsStatsAction.java rename to x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/rest/RestSearchableSnapshotsStatsAction.java index 83c17b2be01ec..186dd7de522eb 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/rest/RestSeachableSnapshotsStatsAction.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/rest/RestSearchableSnapshotsStatsAction.java @@ -11,12 +11,12 @@ import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.action.RestActions; -import org.elasticsearch.xpack.searchablesnapshots.action.SeachableSnapshotsStatsAction; -import org.elasticsearch.xpack.searchablesnapshots.action.SeachableSnapshotsStatsRequest; +import org.elasticsearch.xpack.searchablesnapshots.action.SearchableSnapshotsStatsAction; +import org.elasticsearch.xpack.searchablesnapshots.action.SearchableSnapshotsStatsRequest; -public class RestSeachableSnapshotsStatsAction extends BaseRestHandler { +public class RestSearchableSnapshotsStatsAction extends BaseRestHandler { - public RestSeachableSnapshotsStatsAction(final RestController controller) { + public RestSearchableSnapshotsStatsAction(final RestController controller) { controller.registerHandler(RestRequest.Method.GET, "/_searchable_snapshots/stats", this); controller.registerHandler(RestRequest.Method.GET, "/_searchable_snapshots/{nodes}/stats", this); } @@ -29,7 +29,7 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(final RestRequest restRequest, final NodeClient client) { String[] nodes = Strings.splitStringByCommaToArray(restRequest.param("nodes")); - return channel -> client.execute(SeachableSnapshotsStatsAction.INSTANCE, - new SeachableSnapshotsStatsRequest(nodes), new RestActions.NodesResponseRestListener<>(channel)); + return channel -> client.execute(SearchableSnapshotsStatsAction.INSTANCE, + new SearchableSnapshotsStatsRequest(nodes), new RestActions.NodesResponseRestListener<>(channel)); } } From 88d5c2e5f19aa11cef774396ad3b543c127f69c1 Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Tue, 4 Feb 2020 13:33:39 +0100 Subject: [PATCH 03/12] TransportBroadcastByNodeAction --- .../SearchableSnapshotStats.java | 194 ++++++------------ .../SearchableSnapshotStatsTests.java | 20 +- .../resources/rest-api-spec/test/stats.yml | 123 ++++++----- .../SearchableSnapshotsStatsRequest.java | 20 +- .../SearchableSnapshotsStatsResponse.java | 106 +++++----- ...ansportSearchableSnapshotsStatsAction.java | 96 +++++---- .../RestSearchableSnapshotsStatsAction.java | 8 +- .../api/searchable_snapshots.stats.json | 28 +-- 8 files changed, 262 insertions(+), 333 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStats.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStats.java index 3f80b2fedd085..79ded8468b10c 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStats.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStats.java @@ -5,14 +5,12 @@ */ package org.elasticsearch.xpack.core.searchablesnapshots; -import org.elasticsearch.common.Strings; +import org.elasticsearch.cluster.routing.ShardRouting; 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.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.index.Index; -import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.repositories.IndexId; import org.elasticsearch.snapshots.SnapshotId; @@ -20,71 +18,82 @@ import java.util.Comparator; import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; import static java.util.Collections.unmodifiableList; import static java.util.stream.Collectors.toList; public class SearchableSnapshotStats implements Writeable, ToXContentObject { - private final List directoryStats; + private final List inputStats; + private final ShardRouting shardRouting; + private final SnapshotId snapshotId; + private final IndexId indexId; - public SearchableSnapshotStats(final List directoryStats) { - this.directoryStats = unmodifiableList(Objects.requireNonNull(directoryStats)); + public SearchableSnapshotStats(ShardRouting shardRouting, SnapshotId snapshotId, IndexId indexId, List stats) { + this.shardRouting = Objects.requireNonNull(shardRouting); + this.snapshotId = Objects.requireNonNull(snapshotId); + this.indexId = Objects.requireNonNull(indexId); + this.inputStats = unmodifiableList(Objects.requireNonNull(stats)); } - public SearchableSnapshotStats(final StreamInput in) throws IOException { - this.directoryStats = unmodifiableList(in.readList(CacheDirectoryStats::new)); + public SearchableSnapshotStats(StreamInput in) throws IOException { + this.shardRouting = new ShardRouting(in); + this.snapshotId = new SnapshotId(in); + this.indexId = new IndexId(in); + this.inputStats = in.readList(CacheIndexInputStats::new); } - public List getStats() { - return directoryStats; + @Override + public void writeTo(StreamOutput out) throws IOException { + shardRouting.writeTo(out); + snapshotId.writeTo(out); + indexId.writeTo(out); + out.writeList(inputStats); } - public boolean isEmpty() { - if (directoryStats.isEmpty()) { - return true; - } - return directoryStats.stream().map(CacheDirectoryStats::getStats).allMatch(List::isEmpty); + public ShardRouting getShardRouting() { + return shardRouting; } - @Override - public void writeTo(final StreamOutput out) throws IOException { - out.writeList(directoryStats); + public SnapshotId getSnapshotId() { + return snapshotId; + } + + public IndexId getIndexId() { + return indexId; + } + + public List getStats() { + return inputStats; } @Override - public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException { - final List indices = getStats().stream() - .filter(stats -> stats.getStats().isEmpty() == false) - .map(CacheDirectoryStats::getShardId) - .map(ShardId::getIndex) - .sorted(Comparator.comparing(Index::getName)) - .collect(toList()); + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); { - builder.startObject("indices"); - for (Index index : indices) { - builder.startObject(index.getName()); - { - builder.startArray("shards"); - { - List listOfDirectoryStats = getStats().stream() - .filter(dirStats -> dirStats.getShardId().getIndex().equals(index)) - .sorted(Comparator.comparingInt(dir -> dir.getShardId().id())) - .collect(Collectors.toList()); - for (CacheDirectoryStats stats : listOfDirectoryStats) { - builder.value(stats); - } - } - builder.endArray(); + builder.field("snapshot_uuid", getSnapshotId().getUUID()); + builder.field("index_uuid", getIndexId().getId()); + builder.startObject("shard"); + { + builder.field("state", shardRouting.state()); + builder.field("primary", shardRouting.primary()); + builder.field("node", shardRouting.currentNodeId()); + if (shardRouting.relocatingNodeId() != null) { + builder.field("relocating_node", shardRouting.relocatingNodeId()); } - builder.endObject(); } builder.endObject(); + builder.startArray("files"); + { + List stats = inputStats.stream() + .sorted(Comparator.comparing(CacheIndexInputStats::getFileName)).collect(toList()); + for (CacheIndexInputStats stat : stats) { + stat.toXContent(builder, params); + } + } + builder.endArray(); } - builder.endObject(); - return builder; + return builder.endObject(); } @Override @@ -96,104 +105,17 @@ public boolean equals(Object other) { return false; } SearchableSnapshotStats that = (SearchableSnapshotStats) other; - return Objects.equals(directoryStats, that.directoryStats); + return Objects.equals(shardRouting, that.shardRouting) + && Objects.equals(snapshotId, that.snapshotId) + && Objects.equals(indexId, that.indexId) + && Objects.equals(inputStats, that.inputStats); } @Override public int hashCode() { - return Objects.hash(directoryStats); + return Objects.hash(shardRouting, snapshotId, indexId, inputStats); } - @Override - public String toString() { - return Strings.toString(this); - } - - public static class CacheDirectoryStats implements Writeable, ToXContentObject { - - private final List inputStats; - private final SnapshotId snapshotId; - private final IndexId indexId; - private final ShardId shardId; - - public CacheDirectoryStats(SnapshotId snapshotId, IndexId indexId, ShardId shardId, List inputStats) { - this.snapshotId = Objects.requireNonNull(snapshotId); - this.indexId = Objects.requireNonNull(indexId); - this.shardId = Objects.requireNonNull(shardId); - this.inputStats = unmodifiableList(Objects.requireNonNull(inputStats)); - } - - CacheDirectoryStats(final StreamInput in) throws IOException { - this.snapshotId = new SnapshotId(in); - this.indexId = new IndexId(in); - this.shardId = new ShardId(in); - this.inputStats = in.readList(CacheIndexInputStats::new); - } - - @Override - public void writeTo(final StreamOutput out) throws IOException { - snapshotId.writeTo(out); - indexId.writeTo(out); - shardId.writeTo(out); - out.writeList(inputStats); - } - - public SnapshotId getSnapshotId() { - return snapshotId; - } - - public IndexId getIndexId() { - return indexId; - } - - public ShardId getShardId() { - return shardId; - } - - public List getStats() { - return inputStats; - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - { - builder.field("snapshot_uuid", getSnapshotId().getUUID()); - builder.field("index_uuid", getIndexId().getId()); - builder.field("shard", getShardId().getId()); - builder.startArray("files"); - { - List stats = inputStats.stream() - .sorted(Comparator.comparing(CacheIndexInputStats::getFileName)).collect(toList()); - for (CacheIndexInputStats stat : stats) { - stat.toXContent(builder, params); - } - } - builder.endArray(); - } - return builder.endObject(); - } - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (other == null || getClass() != other.getClass()) { - return false; - } - CacheDirectoryStats that = (CacheDirectoryStats) other; - return Objects.equals(inputStats, that.inputStats) - && Objects.equals(snapshotId, that.snapshotId) - && Objects.equals(indexId, that.indexId) - && Objects.equals(shardId, that.shardId); - } - - @Override - public int hashCode() { - return Objects.hash(inputStats, snapshotId, indexId, shardId); - } - } public static class CacheIndexInputStats implements Writeable, ToXContentObject { diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStatsTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStatsTests.java index dea03d1b4d154..5a7569cd1dc23 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStatsTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStatsTests.java @@ -5,18 +5,21 @@ */ package org.elasticsearch.xpack.core.searchablesnapshots; +import org.elasticsearch.cluster.routing.ShardRouting; +import org.elasticsearch.cluster.routing.ShardRoutingState; +import org.elasticsearch.cluster.routing.TestShardRouting; import org.elasticsearch.common.io.stream.Writeable; -import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.repositories.IndexId; import org.elasticsearch.snapshots.SnapshotId; import org.elasticsearch.test.AbstractWireSerializingTestCase; -import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.CacheDirectoryStats; import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.CacheIndexInputStats; import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.Counter; import java.util.ArrayList; import java.util.List; +; + public class SearchableSnapshotStatsTests extends AbstractWireSerializingTestCase { @Override @@ -26,23 +29,16 @@ protected Writeable.Reader instanceReader() { @Override protected SearchableSnapshotStats createTestInstance() { - final List directoryStats = new ArrayList<>(); - for (int i = 0; i < randomInt(20); i++) { - directoryStats.add(randomCacheDirectoryStats()); - } - return new SearchableSnapshotStats(directoryStats); - } - - private CacheDirectoryStats randomCacheDirectoryStats() { SnapshotId snapshotId = new SnapshotId(randomAlphaOfLength(5), randomAlphaOfLength(5)); IndexId indexId = new IndexId(randomAlphaOfLength(5), randomAlphaOfLength(5)); - ShardId shardId = new ShardId(randomAlphaOfLength(5), randomAlphaOfLength(5), randomInt(10)); + ShardRouting shardRouting = TestShardRouting.newShardRouting(randomAlphaOfLength(5), randomInt(10), randomAlphaOfLength(5), + randomBoolean(), ShardRoutingState.STARTED); final List inputStats = new ArrayList<>(); for (int j = 0; j < randomInt(20); j++) { inputStats.add(randomCacheIndexInputStats()); } - return new CacheDirectoryStats(snapshotId, indexId, shardId, inputStats); + return new SearchableSnapshotStats(shardRouting, snapshotId, indexId, inputStats); } private CacheIndexInputStats randomCacheIndexInputStats() { diff --git a/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml b/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml index 1380f6af0a8ac..0b6e27adcdb12 100644 --- a/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml +++ b/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml @@ -52,7 +52,12 @@ setup: - do: searchable_snapshots.stats: {} - - length: { nodes: 0 } + - length: { indices: 0 } + + - do: + catch: missing + searchable_snapshots.stats: + index: "unkown" - do: snapshot.create_repository: @@ -91,59 +96,63 @@ setup: nodes._arbitrary_key_: node_id - do: - searchable_snapshots.stats: {} - - - length: { nodes: 1 } - - length: { nodes.$node_id.indices.index.shards: 1 } - - is_true: nodes.$node_id.indices.index.shards.0.snapshot_uuid - - is_true: nodes.$node_id.indices.index.shards.0.index_uuid - - match: { nodes.$node_id.indices.index.shards.0.shard: 0 } - - - is_true: nodes.$node_id.indices.index.shards.0.files.0.name - - gt: { nodes.$node_id.indices.index.shards.0.files.0.length: 0 } - - gt: { nodes.$node_id.indices.index.shards.0.files.0.open_count: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.inner_count: 0 } - - gt: { nodes.$node_id.indices.index.shards.0.files.0.close_count: 0 } - - - gte: { nodes.$node_id.indices.index.shards.0.files.0.contiguous_bytes_read.count: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.contiguous_bytes_read.sum: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.contiguous_bytes_read.min: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.contiguous_bytes_read.max: 0 } - - - gte: { nodes.$node_id.indices.index.shards.0.files.0.non_contiguous_bytes_read.count: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.non_contiguous_bytes_read.sum: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.non_contiguous_bytes_read.min: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.non_contiguous_bytes_read.max: 0 } - - - gte: { nodes.$node_id.indices.index.shards.0.files.0.cached_bytes_read.count: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.cached_bytes_read.sum: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.cached_bytes_read.min: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.cached_bytes_read.max: 0 } - - - gte: { nodes.$node_id.indices.index.shards.0.files.0.cached_bytes_written.count: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.cached_bytes_written.sum: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.cached_bytes_written.min: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.cached_bytes_written.max: 0 } - - - gte: { nodes.$node_id.indices.index.shards.0.files.0.direct_bytes_read.count: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.direct_bytes_read.sum: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.direct_bytes_read.min: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.direct_bytes_read.max: 0 } - - - gte: { nodes.$node_id.indices.index.shards.0.files.0.forward_seeks.small.count: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.forward_seeks.small.sum: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.forward_seeks.small.min: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.forward_seeks.small.max: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.forward_seeks.large.count: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.forward_seeks.large.sum: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.forward_seeks.large.min: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.forward_seeks.large.max: 0 } - - - gte: { nodes.$node_id.indices.index.shards.0.files.0.backward_seeks.small.count: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.backward_seeks.small.sum: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.backward_seeks.small.min: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.backward_seeks.small.max: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.backward_seeks.large.count: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.backward_seeks.large.sum: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.backward_seeks.large.min: 0 } - - gte: { nodes.$node_id.indices.index.shards.0.files.0.backward_seeks.large.max: 0 } + searchable_snapshots.stats: + index: "ind*" + + - length: { indices: 1 } + - length: { indices.index.shards: 1 } + - length: { indices.index.shards.0: 1 } + - is_true: indices.index.shards.0.0.snapshot_uuid + - is_true: indices.index.shards.0.0.index_uuid + - match: { indices.index.shards.0.0.shard.state: STARTED } + - match: { indices.index.shards.0.0.shard.primary: true } + - match: { indices.index.shards.0.0.shard.node: $node_id } + + - is_true: indices.index.shards.0.0.files.0.name + - gt: { indices.index.shards.0.0.files.0.length: 0 } + - gt: { indices.index.shards.0.0.files.0.open_count: 0 } + - gte: { indices.index.shards.0.0.files.0.inner_count: 0 } + - gt: { indices.index.shards.0.0.files.0.close_count: 0 } + + - gte: { indices.index.shards.0.0.files.0.contiguous_bytes_read.count: 0 } + - gte: { indices.index.shards.0.0.files.0.contiguous_bytes_read.sum: 0 } + - gte: { indices.index.shards.0.0.files.0.contiguous_bytes_read.min: 0 } + - gte: { indices.index.shards.0.0.files.0.contiguous_bytes_read.max: 0 } + + - gte: { indices.index.shards.0.0.files.0.non_contiguous_bytes_read.count: 0 } + - gte: { indices.index.shards.0.0.files.0.non_contiguous_bytes_read.sum: 0 } + - gte: { indices.index.shards.0.0.files.0.non_contiguous_bytes_read.min: 0 } + - gte: { indices.index.shards.0.0.files.0.non_contiguous_bytes_read.max: 0 } + + - gte: { indices.index.shards.0.0.files.0.cached_bytes_read.count: 0 } + - gte: { indices.index.shards.0.0.files.0.cached_bytes_read.sum: 0 } + - gte: { indices.index.shards.0.0.files.0.cached_bytes_read.min: 0 } + - gte: { indices.index.shards.0.0.files.0.cached_bytes_read.max: 0 } + + - gte: { indices.index.shards.0.0.files.0.cached_bytes_written.count: 0 } + - gte: { indices.index.shards.0.0.files.0.cached_bytes_written.sum: 0 } + - gte: { indices.index.shards.0.0.files.0.cached_bytes_written.min: 0 } + - gte: { indices.index.shards.0.0.files.0.cached_bytes_written.max: 0 } + + - gte: { indices.index.shards.0.0.files.0.direct_bytes_read.count: 0 } + - gte: { indices.index.shards.0.0.files.0.direct_bytes_read.sum: 0 } + - gte: { indices.index.shards.0.0.files.0.direct_bytes_read.min: 0 } + - gte: { indices.index.shards.0.0.files.0.direct_bytes_read.max: 0 } + + - gte: { indices.index.shards.0.0.files.0.forward_seeks.small.count: 0 } + - gte: { indices.index.shards.0.0.files.0.forward_seeks.small.sum: 0 } + - gte: { indices.index.shards.0.0.files.0.forward_seeks.small.min: 0 } + - gte: { indices.index.shards.0.0.files.0.forward_seeks.small.max: 0 } + - gte: { indices.index.shards.0.0.files.0.forward_seeks.large.count: 0 } + - gte: { indices.index.shards.0.0.files.0.forward_seeks.large.sum: 0 } + - gte: { indices.index.shards.0.0.files.0.forward_seeks.large.min: 0 } + - gte: { indices.index.shards.0.0.files.0.forward_seeks.large.max: 0 } + + - gte: { indices.index.shards.0.0.files.0.backward_seeks.small.count: 0 } + - gte: { indices.index.shards.0.0.files.0.backward_seeks.small.sum: 0 } + - gte: { indices.index.shards.0.0.files.0.backward_seeks.small.min: 0 } + - gte: { indices.index.shards.0.0.files.0.backward_seeks.small.max: 0 } + - gte: { indices.index.shards.0.0.files.0.backward_seeks.large.count: 0 } + - gte: { indices.index.shards.0.0.files.0.backward_seeks.large.sum: 0 } + - gte: { indices.index.shards.0.0.files.0.backward_seeks.large.min: 0 } + - gte: { indices.index.shards.0.0.files.0.backward_seeks.large.max: 0 } diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsRequest.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsRequest.java index a250a3faf46b7..3659c9641d040 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsRequest.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsRequest.java @@ -5,29 +5,23 @@ */ package org.elasticsearch.xpack.searchablesnapshots.action; -import org.elasticsearch.action.support.nodes.BaseNodeRequest; -import org.elasticsearch.action.support.nodes.BaseNodesRequest; +import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.action.support.broadcast.BroadcastRequest; import org.elasticsearch.common.io.stream.StreamInput; import java.io.IOException; -public class SearchableSnapshotsStatsRequest extends BaseNodesRequest { +public class SearchableSnapshotsStatsRequest extends BroadcastRequest { SearchableSnapshotsStatsRequest(StreamInput in) throws IOException { super(in); } - public SearchableSnapshotsStatsRequest(String... nodesIds) { - super(nodesIds); + public SearchableSnapshotsStatsRequest(String... indices) { + super(indices); } - static class NodeStatsRequest extends BaseNodeRequest { - - NodeStatsRequest() { - } - - NodeStatsRequest(StreamInput in) throws IOException { - super(in); - } + public SearchableSnapshotsStatsRequest(String[] indices, IndicesOptions indicesOptions) { + super(indices, indicesOptions); } } diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsResponse.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsResponse.java index 3a7a4367a7508..501f7d969d0f0 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsResponse.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsResponse.java @@ -5,82 +5,78 @@ */ package org.elasticsearch.xpack.searchablesnapshots.action; -import org.elasticsearch.action.FailedNodeException; -import org.elasticsearch.action.support.nodes.BaseNodeResponse; -import org.elasticsearch.action.support.nodes.BaseNodesResponse; -import org.elasticsearch.cluster.ClusterName; -import org.elasticsearch.cluster.node.DiscoveryNode; +import org.elasticsearch.action.support.DefaultShardOperationFailedException; +import org.elasticsearch.action.support.broadcast.BroadcastResponse; +import org.elasticsearch.cluster.routing.ShardRouting; import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.common.xcontent.ToXContentFragment; -import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.index.Index; import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats; import java.io.IOException; +import java.util.Comparator; import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; -public class SearchableSnapshotsStatsResponse - extends BaseNodesResponse implements ToXContentObject { +import static java.util.stream.Collectors.toList; + +public class SearchableSnapshotsStatsResponse extends BroadcastResponse { + + private List stats; SearchableSnapshotsStatsResponse(StreamInput in) throws IOException { super(in); + this.stats = in.readList(SearchableSnapshotStats::new); } - SearchableSnapshotsStatsResponse(ClusterName clusterName, List nodes, List failures) { - super(clusterName, nodes, failures); + SearchableSnapshotsStatsResponse(List stats, int totalShards, int successfulShards, int failedShards, + List shardFailures) { + super(totalShards, successfulShards, failedShards, shardFailures); + this.stats = Objects.requireNonNull(stats); } - @Override - protected List readNodesFrom(StreamInput in) throws IOException { - return in.readList(NodeStatsResponse::readNodeResponse); + public List getStats() { + return stats; } @Override - protected void writeNodesTo(StreamOutput out, List nodes) throws IOException { - out.writeList(nodes); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject("nodes"); - for (NodeStatsResponse node : getNodes()) { - node.toXContent(builder, params); - } - builder.endObject(); - return builder; - } + protected void addCustomXContentFields(XContentBuilder builder, Params params) throws IOException { + final List indices = getStats().stream() + .filter(stats -> stats.getStats().isEmpty() == false) + .map(SearchableSnapshotStats::getShardRouting) + .map(ShardRouting::index) + .sorted(Comparator.comparing(Index::getName)) + .collect(toList()); - static class NodeStatsResponse extends BaseNodeResponse implements ToXContentFragment { + builder.startObject("indices"); + for (Index index : indices) { + builder.startObject(index.getName()); + { + builder.startObject("shards"); + { + List listOfStats = getStats().stream() + .filter(dirStats -> dirStats.getShardRouting().index().equals(index)) + .sorted(Comparator.comparingInt(dir -> dir.getShardRouting().getId())) + .collect(Collectors.toList()); - private final SearchableSnapshotStats stats; + int minShard = listOfStats.stream().map(stat -> stat.getShardRouting().getId()).min(Integer::compareTo).orElse(0); + int maxShard = listOfStats.stream().map(stat -> stat.getShardRouting().getId()).max(Integer::compareTo).orElse(0); - NodeStatsResponse(StreamInput in) throws IOException { - super(in); - this.stats = in.readOptionalWriteable(SearchableSnapshotStats::new); - } - - NodeStatsResponse(DiscoveryNode node, SearchableSnapshotStats stats) { - super(node); - this.stats = stats; - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - super.writeTo(out); - out.writeOptionalWriteable(stats); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - if (stats != null && stats.isEmpty() == false) { - builder.field(getNode().getId(), stats); + for (int i = minShard; i <= maxShard; i++) { + builder.startArray(Integer.toString(i)); + for (SearchableSnapshotStats stat : listOfStats) { + if (stat.getShardRouting().getId() == i) { + stat.toXContent(builder, params); + } + } + builder.endArray(); + } + } + builder.endObject(); } - return builder; - } - - static NodeStatsResponse readNodeResponse(StreamInput in) throws IOException { - return new NodeStatsResponse(in); + builder.endObject(); } + builder.endObject(); } } diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java index 9140ea238cc2a..60228368dc87f 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java @@ -7,94 +7,106 @@ import org.apache.lucene.store.Directory; import org.apache.lucene.store.FilterDirectory; -import org.elasticsearch.action.FailedNodeException; import org.elasticsearch.action.support.ActionFilters; -import org.elasticsearch.action.support.nodes.TransportNodesAction; +import org.elasticsearch.action.support.DefaultShardOperationFailedException; +import org.elasticsearch.action.support.broadcast.node.TransportBroadcastByNodeAction; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.block.ClusterBlockException; +import org.elasticsearch.cluster.block.ClusterBlockLevel; +import org.elasticsearch.cluster.metadata.IndexMetaData; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.routing.ShardRouting; +import org.elasticsearch.cluster.routing.ShardsIterator; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.index.IndexService; import org.elasticsearch.index.shard.IndexShard; import org.elasticsearch.indices.IndicesService; -import org.elasticsearch.tasks.Task; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats; -import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.CacheDirectoryStats; import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.CacheIndexInputStats; import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.Counter; import org.elasticsearch.xpack.searchablesnapshots.InMemoryNoOpCommitDirectory; -import org.elasticsearch.xpack.searchablesnapshots.action.SearchableSnapshotsStatsRequest.NodeStatsRequest; -import org.elasticsearch.xpack.searchablesnapshots.action.SearchableSnapshotsStatsResponse.NodeStatsResponse; import org.elasticsearch.xpack.searchablesnapshots.cache.CacheDirectory; import org.elasticsearch.xpack.searchablesnapshots.cache.IndexInputStats; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.stream.Collectors; import static org.elasticsearch.index.IndexModule.INDEX_STORE_TYPE_SETTING; import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshotRepository.SNAPSHOT_DIRECTORY_FACTORY_KEY; -public class TransportSearchableSnapshotsStatsAction extends TransportNodesAction { - +public class TransportSearchableSnapshotsStatsAction extends TransportBroadcastByNodeAction { private final IndicesService indicesService; @Inject - public TransportSearchableSnapshotsStatsAction(final ThreadPool threadPool, - final ClusterService clusterService, - final TransportService transportService, - final ActionFilters actionFilters, - final IndicesService indicesService) { - super(SearchableSnapshotsStatsAction.NAME, threadPool, clusterService, transportService, actionFilters, - SearchableSnapshotsStatsRequest::new, NodeStatsRequest::new, ThreadPool.Names.GENERIC, NodeStatsResponse.class); - this.indicesService = Objects.requireNonNull(indicesService); + public TransportSearchableSnapshotsStatsAction(ClusterService clusterService, TransportService transportService, + IndicesService indicesService, ActionFilters actionFilters, + IndexNameExpressionResolver indexNameExpressionResolver) { + super(SearchableSnapshotsStatsAction.NAME, clusterService, transportService, actionFilters, indexNameExpressionResolver, + SearchableSnapshotsStatsRequest::new, ThreadPool.Names.MANAGEMENT); + this.indicesService = indicesService; } @Override - protected SearchableSnapshotsStatsResponse newResponse(SearchableSnapshotsStatsRequest request, List responses, - List failures) { - return new SearchableSnapshotsStatsResponse(clusterService.getClusterName(), responses, failures); + protected ClusterBlockException checkGlobalBlock(ClusterState state, SearchableSnapshotsStatsRequest request) { + return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ); } @Override - protected NodeStatsRequest newNodeRequest(SearchableSnapshotsStatsRequest request) { - return new NodeStatsRequest(); + protected ClusterBlockException checkRequestBlock(ClusterState state, SearchableSnapshotsStatsRequest request, String[] indices) { + return state.blocks().indicesBlockedException(ClusterBlockLevel.METADATA_READ, indices); } @Override - protected NodeStatsResponse newNodeResponse(StreamInput in) throws IOException { - return new NodeStatsResponse(in); + protected SearchableSnapshotStats readShardResult(StreamInput in) throws IOException { + return new SearchableSnapshotStats(in); } @Override - protected NodeStatsResponse nodeOperation(final NodeStatsRequest request, final Task task) { - final List directoryStats = new ArrayList<>(); - if (clusterService.localNode().isDataNode()) { - for (IndexService indexService : indicesService) { - Settings indexSettings = indexService.getIndexSettings().getSettings(); + protected SearchableSnapshotsStatsResponse newResponse(SearchableSnapshotsStatsRequest request, + int totalShards, int successfulShards, int failedShards, + List searchableSnapshotStats, + List shardFailures, + ClusterState clusterState) { + return new SearchableSnapshotsStatsResponse(searchableSnapshotStats, totalShards, successfulShards, failedShards, shardFailures); + } + + @Override + protected SearchableSnapshotsStatsRequest readRequestFrom(StreamInput in) throws IOException { + return new SearchableSnapshotsStatsRequest(in); + } + + @Override + protected ShardsIterator shards(ClusterState state, SearchableSnapshotsStatsRequest request, String[] concreteIndices) { + final List searchableSnapshotIndices = new ArrayList<>(); + for (String concreteIndex : concreteIndices) { + IndexMetaData indexMetaData = state.metaData().index(concreteIndex); + if (indexMetaData != null) { + Settings indexSettings = indexMetaData.getSettings(); if (INDEX_STORE_TYPE_SETTING.get(indexSettings).equals(SNAPSHOT_DIRECTORY_FACTORY_KEY)) { - for (IndexShard indexShard : indexService) { - CacheDirectory cacheDirectory = unwrap(indexShard.store().directory()); - if (cacheDirectory != null) { - directoryStats.add(toDirectoryStats(cacheDirectory)); - } - } + searchableSnapshotIndices.add(concreteIndex); } } } - return new NodeStatsResponse(clusterService.localNode(), new SearchableSnapshotStats(directoryStats)); + return state.routingTable().allShards(searchableSnapshotIndices.toArray(new String[0])); } - private static CacheDirectoryStats toDirectoryStats(final CacheDirectory cacheDirectory) { - return new CacheDirectoryStats(cacheDirectory.getSnapshotId(), cacheDirectory.getIndexId(), cacheDirectory.getShardId(), + @Override + protected SearchableSnapshotStats shardOperation(SearchableSnapshotsStatsRequest request, ShardRouting shardRouting) { + final IndexShard indexShard = indicesService.indexServiceSafe(shardRouting.index()).getShard(shardRouting.id()); + final CacheDirectory cacheDirectory = unwrap(indexShard.store().directory()); + assert cacheDirectory != null; + assert cacheDirectory.getShardId().equals(shardRouting.shardId()); + + return new SearchableSnapshotStats(shardRouting, cacheDirectory.getSnapshotId(), cacheDirectory.getIndexId(), cacheDirectory.getStats().entrySet().stream() .map(entry -> toCacheIndexInputStats(entry.getKey(), entry.getValue())) .collect(Collectors.toList())); diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/rest/RestSearchableSnapshotsStatsAction.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/rest/RestSearchableSnapshotsStatsAction.java index 186dd7de522eb..de2052c32781a 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/rest/RestSearchableSnapshotsStatsAction.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/rest/RestSearchableSnapshotsStatsAction.java @@ -10,7 +10,7 @@ import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; -import org.elasticsearch.rest.action.RestActions; +import org.elasticsearch.rest.action.RestToXContentListener; import org.elasticsearch.xpack.searchablesnapshots.action.SearchableSnapshotsStatsAction; import org.elasticsearch.xpack.searchablesnapshots.action.SearchableSnapshotsStatsRequest; @@ -18,7 +18,7 @@ public class RestSearchableSnapshotsStatsAction extends BaseRestHandler { public RestSearchableSnapshotsStatsAction(final RestController controller) { controller.registerHandler(RestRequest.Method.GET, "/_searchable_snapshots/stats", this); - controller.registerHandler(RestRequest.Method.GET, "/_searchable_snapshots/{nodes}/stats", this); + controller.registerHandler(RestRequest.Method.GET, "/{index}/_searchable_snapshots/stats", this); } @Override @@ -28,8 +28,8 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(final RestRequest restRequest, final NodeClient client) { - String[] nodes = Strings.splitStringByCommaToArray(restRequest.param("nodes")); + String[] indices = Strings.splitStringByCommaToArray(restRequest.param("index")); return channel -> client.execute(SearchableSnapshotsStatsAction.INSTANCE, - new SearchableSnapshotsStatsRequest(nodes), new RestActions.NodesResponseRestListener<>(channel)); + new SearchableSnapshotsStatsRequest(indices), new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/searchable-snapshots/src/test/resources/rest-api-spec/api/searchable_snapshots.stats.json b/x-pack/plugin/searchable-snapshots/src/test/resources/rest-api-spec/api/searchable_snapshots.stats.json index 3c91234c5cc4c..d2f31e0f4649e 100644 --- a/x-pack/plugin/searchable-snapshots/src/test/resources/rest-api-spec/api/searchable_snapshots.stats.json +++ b/x-pack/plugin/searchable-snapshots/src/test/resources/rest-api-spec/api/searchable_snapshots.stats.json @@ -1,26 +1,26 @@ { - "searchable_snapshots.stats":{ - "documentation":{ - "url":"https://www.elastic.co/guide/en/elasticsearch/reference/current/searchable-snapshots-get-stats.html //NORELEASE" + "searchable_snapshots.stats": { + "documentation": { + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/searchable-snapshots-get-stats.html //NORELEASE" }, - "stability":"experimental", - "url":{ - "paths":[ + "stability": "experimental", + "url": { + "paths": [ { - "path":"/_searchable_snapshots/stats", - "methods":[ + "path": "/_searchable_snapshots/stats", + "methods": [ "GET" ] }, { - "path":"/_searchable_snapshots/{node_id}/stats", - "methods":[ + "path": "/{index}/_searchable_snapshots/stats", + "methods": [ "GET" ], - "parts":{ - "node_id":{ - "type":"list", - "description":"A comma-separated list of node IDs or names to limit the returned information; use `_local` to return information from the node you're connecting to, leave empty to get information from all nodes" + "parts": { + "index": { + "type": "list", + "description": "A comma-separated list of index names" } } } From fe84072c989e4698ce4a49075d899c3cf3d50463 Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Tue, 4 Feb 2020 16:13:28 +0100 Subject: [PATCH 04/12] Remove unnecessary dependency --- x-pack/plugin/searchable-snapshots/qa/rest/build.gradle | 4 ---- 1 file changed, 4 deletions(-) diff --git a/x-pack/plugin/searchable-snapshots/qa/rest/build.gradle b/x-pack/plugin/searchable-snapshots/qa/rest/build.gradle index bbc35ade30a0b..5a14efb38f466 100644 --- a/x-pack/plugin/searchable-snapshots/qa/rest/build.gradle +++ b/x-pack/plugin/searchable-snapshots/qa/rest/build.gradle @@ -2,10 +2,6 @@ apply plugin: 'elasticsearch.testclusters' apply plugin: 'elasticsearch.standalone-rest-test' apply plugin: 'elasticsearch.rest-test' -dependencies { - testCompile project(path: xpackModule('searchable-snapshots'), configuration: 'runtime') -} - testClusters.integTest { testDistribution = 'DEFAULT' setting 'xpack.license.self_generated.type', 'basic' From 1167ff77ef1db7fb89c760de236fda2d2fcae0bf Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Wed, 5 Feb 2020 10:32:08 +0100 Subject: [PATCH 05/12] Renaming --- ...java => SearchableSnapshotShardStats.java} | 9 +++++---- ...=> SearchableSnapshotShardStatsTests.java} | 14 ++++++------- .../SearchableSnapshotsStatsResponse.java | 16 +++++++-------- ...ansportSearchableSnapshotsStatsAction.java | 20 +++++++++---------- 4 files changed, 30 insertions(+), 29 deletions(-) rename x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/searchablesnapshots/{SearchableSnapshotStats.java => SearchableSnapshotShardStats.java} (97%) rename x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/{SearchableSnapshotStatsTests.java => SearchableSnapshotShardStatsTests.java} (81%) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStats.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotShardStats.java similarity index 97% rename from x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStats.java rename to x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotShardStats.java index 79ded8468b10c..ff11c3a87a183 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStats.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotShardStats.java @@ -22,21 +22,22 @@ import static java.util.Collections.unmodifiableList; import static java.util.stream.Collectors.toList; -public class SearchableSnapshotStats implements Writeable, ToXContentObject { +public class SearchableSnapshotShardStats implements Writeable, ToXContentObject { private final List inputStats; private final ShardRouting shardRouting; private final SnapshotId snapshotId; private final IndexId indexId; - public SearchableSnapshotStats(ShardRouting shardRouting, SnapshotId snapshotId, IndexId indexId, List stats) { + public SearchableSnapshotShardStats(ShardRouting shardRouting, SnapshotId snapshotId, IndexId indexId, + List stats) { this.shardRouting = Objects.requireNonNull(shardRouting); this.snapshotId = Objects.requireNonNull(snapshotId); this.indexId = Objects.requireNonNull(indexId); this.inputStats = unmodifiableList(Objects.requireNonNull(stats)); } - public SearchableSnapshotStats(StreamInput in) throws IOException { + public SearchableSnapshotShardStats(StreamInput in) throws IOException { this.shardRouting = new ShardRouting(in); this.snapshotId = new SnapshotId(in); this.indexId = new IndexId(in); @@ -104,7 +105,7 @@ public boolean equals(Object other) { if (other == null || getClass() != other.getClass()) { return false; } - SearchableSnapshotStats that = (SearchableSnapshotStats) other; + SearchableSnapshotShardStats that = (SearchableSnapshotShardStats) other; return Objects.equals(shardRouting, that.shardRouting) && Objects.equals(snapshotId, that.snapshotId) && Objects.equals(indexId, that.indexId) diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStatsTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotShardStatsTests.java similarity index 81% rename from x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStatsTests.java rename to x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotShardStatsTests.java index 5a7569cd1dc23..ad617ac707d28 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotStatsTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotShardStatsTests.java @@ -12,23 +12,23 @@ import org.elasticsearch.repositories.IndexId; import org.elasticsearch.snapshots.SnapshotId; import org.elasticsearch.test.AbstractWireSerializingTestCase; -import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.CacheIndexInputStats; -import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.Counter; +import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotShardStats.CacheIndexInputStats; +import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotShardStats.Counter; import java.util.ArrayList; import java.util.List; ; -public class SearchableSnapshotStatsTests extends AbstractWireSerializingTestCase { +public class SearchableSnapshotShardStatsTests extends AbstractWireSerializingTestCase { @Override - protected Writeable.Reader instanceReader() { - return SearchableSnapshotStats::new; + protected Writeable.Reader instanceReader() { + return SearchableSnapshotShardStats::new; } @Override - protected SearchableSnapshotStats createTestInstance() { + protected SearchableSnapshotShardStats createTestInstance() { SnapshotId snapshotId = new SnapshotId(randomAlphaOfLength(5), randomAlphaOfLength(5)); IndexId indexId = new IndexId(randomAlphaOfLength(5), randomAlphaOfLength(5)); ShardRouting shardRouting = TestShardRouting.newShardRouting(randomAlphaOfLength(5), randomInt(10), randomAlphaOfLength(5), @@ -38,7 +38,7 @@ protected SearchableSnapshotStats createTestInstance() { for (int j = 0; j < randomInt(20); j++) { inputStats.add(randomCacheIndexInputStats()); } - return new SearchableSnapshotStats(shardRouting, snapshotId, indexId, inputStats); + return new SearchableSnapshotShardStats(shardRouting, snapshotId, indexId, inputStats); } private CacheIndexInputStats randomCacheIndexInputStats() { diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsResponse.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsResponse.java index 501f7d969d0f0..a39b18f51a136 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsResponse.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/SearchableSnapshotsStatsResponse.java @@ -11,7 +11,7 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.index.Index; -import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats; +import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotShardStats; import java.io.IOException; import java.util.Comparator; @@ -23,20 +23,20 @@ public class SearchableSnapshotsStatsResponse extends BroadcastResponse { - private List stats; + private List stats; SearchableSnapshotsStatsResponse(StreamInput in) throws IOException { super(in); - this.stats = in.readList(SearchableSnapshotStats::new); + this.stats = in.readList(SearchableSnapshotShardStats::new); } - SearchableSnapshotsStatsResponse(List stats, int totalShards, int successfulShards, int failedShards, + SearchableSnapshotsStatsResponse(List stats, int totalShards, int successfulShards, int failedShards, List shardFailures) { super(totalShards, successfulShards, failedShards, shardFailures); this.stats = Objects.requireNonNull(stats); } - public List getStats() { + public List getStats() { return stats; } @@ -44,7 +44,7 @@ public List getStats() { protected void addCustomXContentFields(XContentBuilder builder, Params params) throws IOException { final List indices = getStats().stream() .filter(stats -> stats.getStats().isEmpty() == false) - .map(SearchableSnapshotStats::getShardRouting) + .map(SearchableSnapshotShardStats::getShardRouting) .map(ShardRouting::index) .sorted(Comparator.comparing(Index::getName)) .collect(toList()); @@ -55,7 +55,7 @@ protected void addCustomXContentFields(XContentBuilder builder, Params params) t { builder.startObject("shards"); { - List listOfStats = getStats().stream() + List listOfStats = getStats().stream() .filter(dirStats -> dirStats.getShardRouting().index().equals(index)) .sorted(Comparator.comparingInt(dir -> dir.getShardRouting().getId())) .collect(Collectors.toList()); @@ -65,7 +65,7 @@ protected void addCustomXContentFields(XContentBuilder builder, Params params) t for (int i = minShard; i <= maxShard; i++) { builder.startArray(Integer.toString(i)); - for (SearchableSnapshotStats stat : listOfStats) { + for (SearchableSnapshotShardStats stat : listOfStats) { if (stat.getShardRouting().getId() == i) { stat.toXContent(builder, params); } diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java index 60228368dc87f..667649f7add19 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java @@ -26,9 +26,9 @@ import org.elasticsearch.indices.IndicesService; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; -import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats; -import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.CacheIndexInputStats; -import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotStats.Counter; +import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotShardStats; +import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotShardStats.CacheIndexInputStats; +import org.elasticsearch.xpack.core.searchablesnapshots.SearchableSnapshotShardStats.Counter; import org.elasticsearch.xpack.searchablesnapshots.InMemoryNoOpCommitDirectory; import org.elasticsearch.xpack.searchablesnapshots.cache.CacheDirectory; import org.elasticsearch.xpack.searchablesnapshots.cache.IndexInputStats; @@ -43,7 +43,7 @@ public class TransportSearchableSnapshotsStatsAction extends TransportBroadcastByNodeAction { + SearchableSnapshotShardStats> { private final IndicesService indicesService; @Inject @@ -66,17 +66,17 @@ protected ClusterBlockException checkRequestBlock(ClusterState state, Searchable } @Override - protected SearchableSnapshotStats readShardResult(StreamInput in) throws IOException { - return new SearchableSnapshotStats(in); + protected SearchableSnapshotShardStats readShardResult(StreamInput in) throws IOException { + return new SearchableSnapshotShardStats(in); } @Override protected SearchableSnapshotsStatsResponse newResponse(SearchableSnapshotsStatsRequest request, int totalShards, int successfulShards, int failedShards, - List searchableSnapshotStats, + List shardsStats, List shardFailures, ClusterState clusterState) { - return new SearchableSnapshotsStatsResponse(searchableSnapshotStats, totalShards, successfulShards, failedShards, shardFailures); + return new SearchableSnapshotsStatsResponse(shardsStats, totalShards, successfulShards, failedShards, shardFailures); } @Override @@ -100,13 +100,13 @@ protected ShardsIterator shards(ClusterState state, SearchableSnapshotsStatsRequ } @Override - protected SearchableSnapshotStats shardOperation(SearchableSnapshotsStatsRequest request, ShardRouting shardRouting) { + protected SearchableSnapshotShardStats shardOperation(SearchableSnapshotsStatsRequest request, ShardRouting shardRouting) { final IndexShard indexShard = indicesService.indexServiceSafe(shardRouting.index()).getShard(shardRouting.id()); final CacheDirectory cacheDirectory = unwrap(indexShard.store().directory()); assert cacheDirectory != null; assert cacheDirectory.getShardId().equals(shardRouting.shardId()); - return new SearchableSnapshotStats(shardRouting, cacheDirectory.getSnapshotId(), cacheDirectory.getIndexId(), + return new SearchableSnapshotShardStats(shardRouting, cacheDirectory.getSnapshotId(), cacheDirectory.getIndexId(), cacheDirectory.getStats().entrySet().stream() .map(entry -> toCacheIndexInputStats(entry.getKey(), entry.getValue())) .collect(Collectors.toList())); From b1d79735f562188b5a0167b7c4400dff0f36c61e Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Wed, 5 Feb 2020 10:44:08 +0100 Subject: [PATCH 06/12] handle negative longs in tests + random seeking threshold --- .../SearchableSnapshotShardStatsTests.java | 4 +--- .../searchablesnapshots/cache/IndexInputStats.java | 11 +++++++++-- .../cache/IndexInputStatsTests.java | 7 ++++--- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotShardStatsTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotShardStatsTests.java index ad617ac707d28..67dc8876c6fee 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotShardStatsTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/searchablesnapshots/SearchableSnapshotShardStatsTests.java @@ -18,8 +18,6 @@ import java.util.ArrayList; import java.util.List; -; - public class SearchableSnapshotShardStatsTests extends AbstractWireSerializingTestCase { @Override @@ -52,6 +50,6 @@ private CacheIndexInputStats randomCacheIndexInputStats() { } private Counter randomCounter() { - return new Counter(randomNonNegativeLong(), randomNonNegativeLong(), randomNonNegativeLong(), randomNonNegativeLong()); + return new Counter(randomLong(), randomLong(), randomLong(), randomLong()); } } diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/IndexInputStats.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/IndexInputStats.java index b27d5b7c64682..9b662a95a40f5 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/IndexInputStats.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/IndexInputStats.java @@ -23,6 +23,7 @@ public class IndexInputStats { static final ByteSizeValue SEEKING_THRESHOLD = new ByteSizeValue(8, ByteSizeUnit.MB); private final long fileLength; + private final long seekingThreshold; private final LongAdder opened = new LongAdder(); private final LongAdder inner = new LongAdder(); @@ -43,7 +44,13 @@ public class IndexInputStats { private final Counter cachedBytesWritten = new Counter(); public IndexInputStats(long fileLength) { + this(fileLength, SEEKING_THRESHOLD.getBytes()); + } + + // pkg-private for testing + IndexInputStats(long fileLength, long seekingThreshold) { this.fileLength = fileLength; + this.seekingThreshold = seekingThreshold; } public void incrementOpenCount() { @@ -149,8 +156,8 @@ public Counter getCachedBytesWritten() { } @SuppressForbidden(reason = "Handles Long.MIN_VALUE before using Math.abs()") - boolean isLargeSeek(long delta) { - return delta != Long.MIN_VALUE && Math.abs(delta) > SEEKING_THRESHOLD.getBytes(); + private boolean isLargeSeek(long delta) { + return delta != Long.MIN_VALUE && Math.abs(delta) > seekingThreshold; } public static class Counter { diff --git a/x-pack/plugin/searchable-snapshots/src/test/java/org/elasticsearch/xpack/searchablesnapshots/cache/IndexInputStatsTests.java b/x-pack/plugin/searchable-snapshots/src/test/java/org/elasticsearch/xpack/searchablesnapshots/cache/IndexInputStatsTests.java index 040c2808af3ba..ceb86c04d7813 100644 --- a/x-pack/plugin/searchable-snapshots/src/test/java/org/elasticsearch/xpack/searchablesnapshots/cache/IndexInputStatsTests.java +++ b/x-pack/plugin/searchable-snapshots/src/test/java/org/elasticsearch/xpack/searchablesnapshots/cache/IndexInputStatsTests.java @@ -44,7 +44,8 @@ public void testReads() { public void testSeeks() { final long fileLength = randomLongBetween(1L, 1_000L); - final IndexInputStats inputStats = new IndexInputStats(fileLength); + final long seekingThreshold = randomBoolean() ? randomLongBetween(1L, fileLength) : SEEKING_THRESHOLD.getBytes(); + final IndexInputStats inputStats = new IndexInputStats(fileLength, seekingThreshold); assertCounter(inputStats.getForwardSmallSeeks(), 0L, 0L, 0L, 0L); assertCounter(inputStats.getForwardLargeSeeks(), 0L, 0L, 0L, 0L); @@ -63,10 +64,10 @@ public void testSeeks() { final long delta = seekToPosition - currentPosition; if (delta > 0) { - IndexInputStats.Counter forwardCounter = (delta <= SEEKING_THRESHOLD.getBytes()) ? fwSmallSeeks : fwLargeSeeks; + IndexInputStats.Counter forwardCounter = (delta <= seekingThreshold) ? fwSmallSeeks : fwLargeSeeks; forwardCounter.add(delta); } else if (delta < 0) { - IndexInputStats.Counter backwardCounter = (delta >= -1 * SEEKING_THRESHOLD.getBytes()) ? bwSmallSeeks : bwLargeSeeks; + IndexInputStats.Counter backwardCounter = (delta >= -1 * seekingThreshold) ? bwSmallSeeks : bwLargeSeeks; backwardCounter.add(delta); } } From a4f92bd70270a436a6395001dd4662fdc76efa07 Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Wed, 5 Feb 2020 10:45:46 +0100 Subject: [PATCH 07/12] unknown --- .../qa/rest/src/test/resources/rest-api-spec/test/stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml b/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml index 0b6e27adcdb12..c91ff6fea4807 100644 --- a/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml +++ b/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml @@ -57,7 +57,7 @@ setup: - do: catch: missing searchable_snapshots.stats: - index: "unkown" + index: "unknown" - do: snapshot.create_repository: From f2ea47f228c27bead4933eb04cc18ae82ca39601 Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Wed, 5 Feb 2020 11:06:28 +0100 Subject: [PATCH 08/12] replicas to 0 and rename index to docs --- .../resources/rest-api-spec/test/stats.yml | 130 +++++++++--------- 1 file changed, 67 insertions(+), 63 deletions(-) diff --git a/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml b/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml index c91ff6fea4807..a1c92262e84f9 100644 --- a/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml +++ b/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml @@ -3,22 +3,26 @@ setup: - do: indices.create: - index: index + index: docs body: settings: number_of_shards: 1 + number_of_replicas: 0 - do: bulk: body: - index: - _index: index + _index: docs + _id: 1 - field: foo - index: - _index: index + _index: docs + _id: 2 - field: bar - index: - _index: index + _index: docs + _id: 3 - field: baz - do: @@ -41,7 +45,7 @@ setup: - do: indices.delete: - index: index + index: docs --- "Tests searchable snapshots stats": @@ -83,7 +87,7 @@ setup: - do: search: rest_total_hits_as_int: true - index: index + index: docs body: query: match_all: {} @@ -97,62 +101,62 @@ setup: - do: searchable_snapshots.stats: - index: "ind*" + index: "d*" - length: { indices: 1 } - - length: { indices.index.shards: 1 } - - length: { indices.index.shards.0: 1 } - - is_true: indices.index.shards.0.0.snapshot_uuid - - is_true: indices.index.shards.0.0.index_uuid - - match: { indices.index.shards.0.0.shard.state: STARTED } - - match: { indices.index.shards.0.0.shard.primary: true } - - match: { indices.index.shards.0.0.shard.node: $node_id } - - - is_true: indices.index.shards.0.0.files.0.name - - gt: { indices.index.shards.0.0.files.0.length: 0 } - - gt: { indices.index.shards.0.0.files.0.open_count: 0 } - - gte: { indices.index.shards.0.0.files.0.inner_count: 0 } - - gt: { indices.index.shards.0.0.files.0.close_count: 0 } - - - gte: { indices.index.shards.0.0.files.0.contiguous_bytes_read.count: 0 } - - gte: { indices.index.shards.0.0.files.0.contiguous_bytes_read.sum: 0 } - - gte: { indices.index.shards.0.0.files.0.contiguous_bytes_read.min: 0 } - - gte: { indices.index.shards.0.0.files.0.contiguous_bytes_read.max: 0 } - - - gte: { indices.index.shards.0.0.files.0.non_contiguous_bytes_read.count: 0 } - - gte: { indices.index.shards.0.0.files.0.non_contiguous_bytes_read.sum: 0 } - - gte: { indices.index.shards.0.0.files.0.non_contiguous_bytes_read.min: 0 } - - gte: { indices.index.shards.0.0.files.0.non_contiguous_bytes_read.max: 0 } - - - gte: { indices.index.shards.0.0.files.0.cached_bytes_read.count: 0 } - - gte: { indices.index.shards.0.0.files.0.cached_bytes_read.sum: 0 } - - gte: { indices.index.shards.0.0.files.0.cached_bytes_read.min: 0 } - - gte: { indices.index.shards.0.0.files.0.cached_bytes_read.max: 0 } - - - gte: { indices.index.shards.0.0.files.0.cached_bytes_written.count: 0 } - - gte: { indices.index.shards.0.0.files.0.cached_bytes_written.sum: 0 } - - gte: { indices.index.shards.0.0.files.0.cached_bytes_written.min: 0 } - - gte: { indices.index.shards.0.0.files.0.cached_bytes_written.max: 0 } - - - gte: { indices.index.shards.0.0.files.0.direct_bytes_read.count: 0 } - - gte: { indices.index.shards.0.0.files.0.direct_bytes_read.sum: 0 } - - gte: { indices.index.shards.0.0.files.0.direct_bytes_read.min: 0 } - - gte: { indices.index.shards.0.0.files.0.direct_bytes_read.max: 0 } - - - gte: { indices.index.shards.0.0.files.0.forward_seeks.small.count: 0 } - - gte: { indices.index.shards.0.0.files.0.forward_seeks.small.sum: 0 } - - gte: { indices.index.shards.0.0.files.0.forward_seeks.small.min: 0 } - - gte: { indices.index.shards.0.0.files.0.forward_seeks.small.max: 0 } - - gte: { indices.index.shards.0.0.files.0.forward_seeks.large.count: 0 } - - gte: { indices.index.shards.0.0.files.0.forward_seeks.large.sum: 0 } - - gte: { indices.index.shards.0.0.files.0.forward_seeks.large.min: 0 } - - gte: { indices.index.shards.0.0.files.0.forward_seeks.large.max: 0 } - - - gte: { indices.index.shards.0.0.files.0.backward_seeks.small.count: 0 } - - gte: { indices.index.shards.0.0.files.0.backward_seeks.small.sum: 0 } - - gte: { indices.index.shards.0.0.files.0.backward_seeks.small.min: 0 } - - gte: { indices.index.shards.0.0.files.0.backward_seeks.small.max: 0 } - - gte: { indices.index.shards.0.0.files.0.backward_seeks.large.count: 0 } - - gte: { indices.index.shards.0.0.files.0.backward_seeks.large.sum: 0 } - - gte: { indices.index.shards.0.0.files.0.backward_seeks.large.min: 0 } - - gte: { indices.index.shards.0.0.files.0.backward_seeks.large.max: 0 } + - length: { indices.docs.shards: 1 } + - length: { indices.docs.shards.0: 1 } + - is_true: indices.docs.shards.0.0.snapshot_uuid + - is_true: indices.docs.shards.0.0.index_uuid + - match: { indices.docs.shards.0.0.shard.state: STARTED } + - match: { indices.docs.shards.0.0.shard.primary: true } + - match: { indices.docs.shards.0.0.shard.node: $node_id } + + - is_true: indices.docs.shards.0.0.files.0.name + - gt: { indices.docs.shards.0.0.files.0.length: 0 } + - gt: { indices.docs.shards.0.0.files.0.open_count: 0 } + - gte: { indices.docs.shards.0.0.files.0.inner_count: 0 } + - gt: { indices.docs.shards.0.0.files.0.close_count: 0 } + + - gte: { indices.docs.shards.0.0.files.0.contiguous_bytes_read.count: 0 } + - gte: { indices.docs.shards.0.0.files.0.contiguous_bytes_read.sum: 0 } + - gte: { indices.docs.shards.0.0.files.0.contiguous_bytes_read.min: 0 } + - gte: { indices.docs.shards.0.0.files.0.contiguous_bytes_read.max: 0 } + + - gte: { indices.docs.shards.0.0.files.0.non_contiguous_bytes_read.count: 0 } + - gte: { indices.docs.shards.0.0.files.0.non_contiguous_bytes_read.sum: 0 } + - gte: { indices.docs.shards.0.0.files.0.non_contiguous_bytes_read.min: 0 } + - gte: { indices.docs.shards.0.0.files.0.non_contiguous_bytes_read.max: 0 } + + - gte: { indices.docs.shards.0.0.files.0.cached_bytes_read.count: 0 } + - gte: { indices.docs.shards.0.0.files.0.cached_bytes_read.sum: 0 } + - gte: { indices.docs.shards.0.0.files.0.cached_bytes_read.min: 0 } + - gte: { indices.docs.shards.0.0.files.0.cached_bytes_read.max: 0 } + + - gte: { indices.docs.shards.0.0.files.0.cached_bytes_written.count: 0 } + - gte: { indices.docs.shards.0.0.files.0.cached_bytes_written.sum: 0 } + - gte: { indices.docs.shards.0.0.files.0.cached_bytes_written.min: 0 } + - gte: { indices.docs.shards.0.0.files.0.cached_bytes_written.max: 0 } + + - gte: { indices.docs.shards.0.0.files.0.direct_bytes_read.count: 0 } + - gte: { indices.docs.shards.0.0.files.0.direct_bytes_read.sum: 0 } + - gte: { indices.docs.shards.0.0.files.0.direct_bytes_read.min: 0 } + - gte: { indices.docs.shards.0.0.files.0.direct_bytes_read.max: 0 } + + - gte: { indices.docs.shards.0.0.files.0.forward_seeks.small.count: 0 } + - gte: { indices.docs.shards.0.0.files.0.forward_seeks.small.sum: 0 } + - gte: { indices.docs.shards.0.0.files.0.forward_seeks.small.min: 0 } + - gte: { indices.docs.shards.0.0.files.0.forward_seeks.small.max: 0 } + - gte: { indices.docs.shards.0.0.files.0.forward_seeks.large.count: 0 } + - gte: { indices.docs.shards.0.0.files.0.forward_seeks.large.sum: 0 } + - gte: { indices.docs.shards.0.0.files.0.forward_seeks.large.min: 0 } + - gte: { indices.docs.shards.0.0.files.0.forward_seeks.large.max: 0 } + + - gte: { indices.docs.shards.0.0.files.0.backward_seeks.small.count: 0 } + - gte: { indices.docs.shards.0.0.files.0.backward_seeks.small.sum: 0 } + - gte: { indices.docs.shards.0.0.files.0.backward_seeks.small.min: 0 } + - gte: { indices.docs.shards.0.0.files.0.backward_seeks.small.max: 0 } + - gte: { indices.docs.shards.0.0.files.0.backward_seeks.large.count: 0 } + - gte: { indices.docs.shards.0.0.files.0.backward_seeks.large.sum: 0 } + - gte: { indices.docs.shards.0.0.files.0.backward_seeks.large.min: 0 } + - gte: { indices.docs.shards.0.0.files.0.backward_seeks.large.max: 0 } From dda6ab7250aee4e614f516f3b718fedd3c6d8538 Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Wed, 5 Feb 2020 11:09:24 +0100 Subject: [PATCH 09/12] Collections.unmodifiableMap(stats); --- .../xpack/searchablesnapshots/cache/CacheDirectory.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/CacheDirectory.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/CacheDirectory.java index 44fd414f84765..8cfe97d85b2e0 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/CacheDirectory.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/CacheDirectory.java @@ -29,6 +29,7 @@ import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; import java.util.Map; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; @@ -77,7 +78,7 @@ public ShardId getShardId() { } public Map getStats() { - return stats; + return Collections.unmodifiableMap(stats); } // pkg private for tests From fde0a86e63f0ba22ff6aa1d5d29ddb5b5b1b49ec Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Wed, 5 Feb 2020 11:23:30 +0100 Subject: [PATCH 10/12] Document // NORELEASE --- .../resources/rest-api-spec/api/searchable_snapshots.stats.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugin/searchable-snapshots/src/test/resources/rest-api-spec/api/searchable_snapshots.stats.json b/x-pack/plugin/searchable-snapshots/src/test/resources/rest-api-spec/api/searchable_snapshots.stats.json index d2f31e0f4649e..604e30a7cac5e 100644 --- a/x-pack/plugin/searchable-snapshots/src/test/resources/rest-api-spec/api/searchable_snapshots.stats.json +++ b/x-pack/plugin/searchable-snapshots/src/test/resources/rest-api-spec/api/searchable_snapshots.stats.json @@ -1,7 +1,7 @@ { "searchable_snapshots.stats": { "documentation": { - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/searchable-snapshots-get-stats.html //NORELEASE" + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/searchable-snapshots-get-stats.html //NORELEASE This API should be documented. We expect this API to be stable at the time it is merged in master, but in case it is not its stability should be documented appropriately." }, "stability": "experimental", "url": { From c9468d104a8f341b94ba4bbba8373f68f30b508b Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Wed, 5 Feb 2020 11:58:24 +0100 Subject: [PATCH 11/12] RNFE --- .../test/resources/rest-api-spec/test/stats.yml | 15 +++++++++++++++ .../TransportSearchableSnapshotsStatsAction.java | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml b/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml index a1c92262e84f9..8abd37edcf478 100644 --- a/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml +++ b/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml @@ -55,7 +55,11 @@ setup: - do: searchable_snapshots.stats: {} + - length: { indices: 0 } + - do: + searchable_snapshots.stats: + index: _all - length: { indices: 0 } - do: @@ -63,6 +67,17 @@ setup: searchable_snapshots.stats: index: "unknown" + - do: + indices.create: + index: non_searchable_snapshot_index + + - do: + catch: missing + searchable_snapshots.stats: + index: non_* + - match: { error.root_cause.0.type: "resource_not_found_exception" } + - match: { error.root_cause.0.reason: "No searchable snapshots indices found" } + - do: snapshot.create_repository: repository: repository-searchable-snapshots diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java index 667649f7add19..ea0daab8afdbe 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java @@ -7,6 +7,7 @@ import org.apache.lucene.store.Directory; import org.apache.lucene.store.FilterDirectory; +import org.elasticsearch.ResourceNotFoundException; import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.action.support.DefaultShardOperationFailedException; import org.elasticsearch.action.support.broadcast.node.TransportBroadcastByNodeAction; @@ -96,6 +97,9 @@ protected ShardsIterator shards(ClusterState state, SearchableSnapshotsStatsRequ } } } + if (concreteIndices.length > 0 && searchableSnapshotIndices.isEmpty()) { + throw new ResourceNotFoundException("No searchable snapshots indices found"); + } return state.routingTable().allShards(searchableSnapshotIndices.toArray(new String[0])); } From d1049a35844f78f1faa595e01745efe472b5acbf Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Thu, 6 Feb 2020 09:37:20 +0100 Subject: [PATCH 12/12] RNFE bis --- .../resources/rest-api-spec/test/stats.yml | 25 +++++++++++++++---- ...ansportSearchableSnapshotsStatsAction.java | 2 +- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml b/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml index 8abd37edcf478..24e6eab79c6b8 100644 --- a/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml +++ b/x-pack/plugin/searchable-snapshots/qa/rest/src/test/resources/rest-api-spec/test/stats.yml @@ -40,12 +40,20 @@ setup: wait_for_completion: true - do: - snapshot.delete_repository: + indices.delete: + index: docs +--- +teardown: + + - do: + snapshot.delete: repository: repository-fs + snapshot: snapshot + ignore: 404 - do: - indices.delete: - index: docs + snapshot.delete_repository: + repository: repository-fs --- "Tests searchable snapshots stats": @@ -54,13 +62,19 @@ setup: reason: searchable snapshots introduced in 8.0 - do: + catch: missing searchable_snapshots.stats: {} - - length: { indices: 0 } + + - match: { error.root_cause.0.type: "resource_not_found_exception" } + - match: { error.root_cause.0.reason: "No searchable snapshots indices found" } - do: + catch: missing searchable_snapshots.stats: index: _all - - length: { indices: 0 } + + - match: { error.root_cause.0.type: "resource_not_found_exception" } + - match: { error.root_cause.0.reason: "No searchable snapshots indices found" } - do: catch: missing @@ -75,6 +89,7 @@ setup: catch: missing searchable_snapshots.stats: index: non_* + - match: { error.root_cause.0.type: "resource_not_found_exception" } - match: { error.root_cause.0.reason: "No searchable snapshots indices found" } diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java index ea0daab8afdbe..8985c0e1c1fac 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportSearchableSnapshotsStatsAction.java @@ -97,7 +97,7 @@ protected ShardsIterator shards(ClusterState state, SearchableSnapshotsStatsRequ } } } - if (concreteIndices.length > 0 && searchableSnapshotIndices.isEmpty()) { + if (searchableSnapshotIndices.isEmpty()) { throw new ResourceNotFoundException("No searchable snapshots indices found"); } return state.routingTable().allShards(searchableSnapshotIndices.toArray(new String[0]));