diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8936210de707c..644fb05900ceb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -43,6 +43,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Bump JNA version from 5.5 to 5.13 ([#9963](https://github.com/opensearch-project/OpenSearch/pull/9963))
- Bumps jetty version to 9.4.52.v20230823 to fix GMS-2023-1857 ([#9822](https://github.com/opensearch-project/OpenSearch/pull/9822))
- Bump `org.eclipse.jgit` from 6.5.0 to 6.7.0 ([#10147](https://github.com/opensearch-project/OpenSearch/pull/10147))
+- Bump OpenTelemetry from 1.30.1 to 1.31.0 ([#10617](https://github.com/opensearch-project/OpenSearch/pull/10617))
### Changed
- [CCR] Add getHistoryOperationsFromTranslog method to fetch the history snapshot from translogs ([#3948](https://github.com/opensearch-project/OpenSearch/pull/3948))
@@ -82,6 +83,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
## [Unreleased 2.x]
### Added
+- Per request phase latency ([#10351](https://github.com/opensearch-project/OpenSearch/issues/10351))
### Dependencies
- Bump `com.google.api.grpc:proto-google-common-protos` from 2.10.0 to 2.25.1 ([#10208](https://github.com/opensearch-project/OpenSearch/pull/10208), [#10298](https://github.com/opensearch-project/OpenSearch/pull/10298))
@@ -96,6 +98,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Mute the query profile IT with concurrent execution ([#9840](https://github.com/opensearch-project/OpenSearch/pull/9840))
- Force merge with `only_expunge_deletes` honors max segment size ([#10036](https://github.com/opensearch-project/OpenSearch/pull/10036))
- Add the means to extract the contextual properties from HttpChannel, TcpCChannel and TrasportChannel without excessive typecasting ([#10562](https://github.com/opensearch-project/OpenSearch/pull/10562))
+- [Remote Store] Add Remote Store backpressure rejection stats to `_nodes/stats` ([#10524](https://github.com/opensearch-project/OpenSearch/pull/10524))
### Deprecated
diff --git a/buildSrc/version.properties b/buildSrc/version.properties
index 64f9f9a8828ad..a5171aa582a86 100644
--- a/buildSrc/version.properties
+++ b/buildSrc/version.properties
@@ -68,4 +68,5 @@ jzlib = 1.1.3
resteasy = 6.2.4.Final
# opentelemetry dependencies
-opentelemetry = 1.30.1
+opentelemetry = 1.31.0
+opentelemetrysemconv = 1.21.0-alpha
diff --git a/plugins/telemetry-otel/build.gradle b/plugins/telemetry-otel/build.gradle
index 04fff20947b4f..f5c367cb7643b 100644
--- a/plugins/telemetry-otel/build.gradle
+++ b/plugins/telemetry-otel/build.gradle
@@ -28,7 +28,7 @@ dependencies {
api "io.opentelemetry:opentelemetry-sdk-trace:${versions.opentelemetry}"
api "io.opentelemetry:opentelemetry-sdk-metrics:${versions.opentelemetry}"
api "io.opentelemetry:opentelemetry-exporter-logging:${versions.opentelemetry}"
- api "io.opentelemetry:opentelemetry-semconv:${versions.opentelemetry}-alpha"
+ api "io.opentelemetry.semconv:opentelemetry-semconv:${versions.opentelemetrysemconv}"
api "io.opentelemetry:opentelemetry-sdk-logs:${versions.opentelemetry}"
api "io.opentelemetry:opentelemetry-exporter-otlp:${versions.opentelemetry}"
api "io.opentelemetry:opentelemetry-exporter-common:${versions.opentelemetry}"
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-api-1.30.1.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-api-1.30.1.jar.sha1
deleted file mode 100644
index b0ce00e191830..0000000000000
--- a/plugins/telemetry-otel/licenses/opentelemetry-api-1.30.1.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-a32dfbd7f01de6711fd0e970f8d4b4c0405056d6
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-api-1.31.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-api-1.31.0.jar.sha1
new file mode 100644
index 0000000000000..eae141a8d1a23
--- /dev/null
+++ b/plugins/telemetry-otel/licenses/opentelemetry-api-1.31.0.jar.sha1
@@ -0,0 +1 @@
+bb24a44d73484c681c236aed84fe6c28d17f30e2
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-context-1.30.1.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-context-1.30.1.jar.sha1
deleted file mode 100644
index 84cb60a2f7acb..0000000000000
--- a/plugins/telemetry-otel/licenses/opentelemetry-context-1.30.1.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-58f665ff01ce6b964cdf0b8cb5cd1c196dfe94ce
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-context-1.31.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-context-1.31.0.jar.sha1
new file mode 100644
index 0000000000000..6e42973adc581
--- /dev/null
+++ b/plugins/telemetry-otel/licenses/opentelemetry-context-1.31.0.jar.sha1
@@ -0,0 +1 @@
+b8004737f7a970124e36ac71fde8eb88423e8cee
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-common-1.30.1.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-common-1.30.1.jar.sha1
deleted file mode 100644
index eccb15f7b7c8e..0000000000000
--- a/plugins/telemetry-otel/licenses/opentelemetry-exporter-common-1.30.1.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-f299d336dba1039478497f37b273dfa764c6faef
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-common-1.31.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-common-1.31.0.jar.sha1
new file mode 100644
index 0000000000000..b119468e7f88b
--- /dev/null
+++ b/plugins/telemetry-otel/licenses/opentelemetry-exporter-common-1.31.0.jar.sha1
@@ -0,0 +1 @@
+b7b4baf5f9af72d5eb8a231dfb114ae31c57150d
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-logging-1.30.1.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-logging-1.30.1.jar.sha1
deleted file mode 100644
index 40537a399ab14..0000000000000
--- a/plugins/telemetry-otel/licenses/opentelemetry-exporter-logging-1.30.1.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-58f1a09e89955e6145babf8bcdf80c95174eb817
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-logging-1.31.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-logging-1.31.0.jar.sha1
new file mode 100644
index 0000000000000..8f653922d6418
--- /dev/null
+++ b/plugins/telemetry-otel/licenses/opentelemetry-exporter-logging-1.31.0.jar.sha1
@@ -0,0 +1 @@
+260e5363dad83a0ae65c16ad6a3dd2914e0db201
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-1.30.1.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-1.30.1.jar.sha1
deleted file mode 100644
index e88b7514ee54d..0000000000000
--- a/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-1.30.1.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-15692246539571c41180aff2b55abe527b939a7b
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-1.31.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-1.31.0.jar.sha1
new file mode 100644
index 0000000000000..103da4720de96
--- /dev/null
+++ b/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-1.31.0.jar.sha1
@@ -0,0 +1 @@
+b6454464425dfd81519070caeca3824558a2f1ae
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-common-1.30.1.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-common-1.30.1.jar.sha1
deleted file mode 100644
index 86937743208c6..0000000000000
--- a/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-common-1.30.1.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-947cf43a6411c4a323e14594431040a476ad43e8
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-common-1.31.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-common-1.31.0.jar.sha1
new file mode 100644
index 0000000000000..3db07532ceea9
--- /dev/null
+++ b/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-common-1.31.0.jar.sha1
@@ -0,0 +1 @@
+d8c22b6851bbc3dbf5d2387b9bde158ed5416ba4
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-sender-okhttp-1.30.1.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-sender-okhttp-1.30.1.jar.sha1
deleted file mode 100644
index 068926277253c..0000000000000
--- a/plugins/telemetry-otel/licenses/opentelemetry-exporter-sender-okhttp-1.30.1.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-9f3a14515500e4df260ce7b10a668237a95ac791
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-sender-okhttp-1.31.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-sender-okhttp-1.31.0.jar.sha1
new file mode 100644
index 0000000000000..10d9b7cdfe3e3
--- /dev/null
+++ b/plugins/telemetry-otel/licenses/opentelemetry-exporter-sender-okhttp-1.31.0.jar.sha1
@@ -0,0 +1 @@
+dd209381d58cfe81a989e29c9ca26d97c8dabd7a
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-extension-incubator-1.30.1-alpha.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-extension-incubator-1.30.1-alpha.jar.sha1
deleted file mode 100644
index bde43937e82e4..0000000000000
--- a/plugins/telemetry-otel/licenses/opentelemetry-extension-incubator-1.30.1-alpha.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-bfcea9bd71f97dd4e8a4f92c15ba5659fb07ff05
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-extension-incubator-1.31.0-alpha.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-extension-incubator-1.31.0-alpha.jar.sha1
new file mode 100644
index 0000000000000..162890965a6eb
--- /dev/null
+++ b/plugins/telemetry-otel/licenses/opentelemetry-extension-incubator-1.31.0-alpha.jar.sha1
@@ -0,0 +1 @@
+6c9f5c063309d92b6dd28bff0667f54b63afd36f
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-1.30.1.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-1.30.1.jar.sha1
deleted file mode 100644
index d425ed61cc4cd..0000000000000
--- a/plugins/telemetry-otel/licenses/opentelemetry-sdk-1.30.1.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-4d15a9ea26e8e6ea93287a9f4ee02d91e5a74392
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-1.31.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-1.31.0.jar.sha1
new file mode 100644
index 0000000000000..d6ce31a31cc6f
--- /dev/null
+++ b/plugins/telemetry-otel/licenses/opentelemetry-sdk-1.31.0.jar.sha1
@@ -0,0 +1 @@
+2b2093be08a09ac536292bf6cecf8129cc7fb191
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-common-1.30.1.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-common-1.30.1.jar.sha1
deleted file mode 100644
index 6b32d98b0f7c7..0000000000000
--- a/plugins/telemetry-otel/licenses/opentelemetry-sdk-common-1.30.1.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-8e437ba87004bb63069d04fb06beae65b98dd13a
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-common-1.31.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-common-1.31.0.jar.sha1
new file mode 100644
index 0000000000000..8a6a9705d836d
--- /dev/null
+++ b/plugins/telemetry-otel/licenses/opentelemetry-sdk-common-1.31.0.jar.sha1
@@ -0,0 +1 @@
+f492528288236e097e12fc1c45963dd82c70d33c
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-logs-1.30.1.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-logs-1.30.1.jar.sha1
deleted file mode 100644
index 13ef6de11e82d..0000000000000
--- a/plugins/telemetry-otel/licenses/opentelemetry-sdk-logs-1.30.1.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-5985d0950746ad12b49cc42c063f26ddfbcaaacb
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-logs-1.31.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-logs-1.31.0.jar.sha1
new file mode 100644
index 0000000000000..37d79f5c573f7
--- /dev/null
+++ b/plugins/telemetry-otel/licenses/opentelemetry-sdk-logs-1.31.0.jar.sha1
@@ -0,0 +1 @@
+a63a203d3dc6f8875f8c26b9e3b522dc9a3f6280
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-metrics-1.30.1.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-metrics-1.30.1.jar.sha1
deleted file mode 100644
index fc5aad9c9011e..0000000000000
--- a/plugins/telemetry-otel/licenses/opentelemetry-sdk-metrics-1.30.1.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-b12825541c5dae52a0fb35045c1b36df3ca8f632
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-metrics-1.31.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-metrics-1.31.0.jar.sha1
new file mode 100644
index 0000000000000..80179e4808f50
--- /dev/null
+++ b/plugins/telemetry-otel/licenses/opentelemetry-sdk-metrics-1.31.0.jar.sha1
@@ -0,0 +1 @@
+47cc23762fae728d68e4fda1dfb71986ae0b8b3e
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-trace-1.30.1.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-trace-1.30.1.jar.sha1
deleted file mode 100644
index ac522b765da05..0000000000000
--- a/plugins/telemetry-otel/licenses/opentelemetry-sdk-trace-1.30.1.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-4c5531fbc44178a7bcfeb7021ae80e70a7c43458
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-trace-1.31.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-trace-1.31.0.jar.sha1
new file mode 100644
index 0000000000000..fd917a58ba77c
--- /dev/null
+++ b/plugins/telemetry-otel/licenses/opentelemetry-sdk-trace-1.31.0.jar.sha1
@@ -0,0 +1 @@
+a3941197cfb8ae9eb9e482073480c0c3918b746c
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-semconv-1.21.0-alpha.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-semconv-1.21.0-alpha.jar.sha1
new file mode 100644
index 0000000000000..77b12c99464f6
--- /dev/null
+++ b/plugins/telemetry-otel/licenses/opentelemetry-semconv-1.21.0-alpha.jar.sha1
@@ -0,0 +1 @@
+207660e74d1e155272e9559fd4d27854b92fc6ac
\ No newline at end of file
diff --git a/plugins/telemetry-otel/licenses/opentelemetry-semconv-1.30.1-alpha.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-semconv-1.30.1-alpha.jar.sha1
deleted file mode 100644
index 089a2484dd1d5..0000000000000
--- a/plugins/telemetry-otel/licenses/opentelemetry-semconv-1.30.1-alpha.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-8e8f7a97a4896a81846553275b9d61885be7ef50
\ No newline at end of file
diff --git a/plugins/telemetry-otel/src/main/java/org/opensearch/telemetry/tracing/OTelResourceProvider.java b/plugins/telemetry-otel/src/main/java/org/opensearch/telemetry/tracing/OTelResourceProvider.java
index a6a1f12aab8a9..14a19f122c17b 100644
--- a/plugins/telemetry-otel/src/main/java/org/opensearch/telemetry/tracing/OTelResourceProvider.java
+++ b/plugins/telemetry-otel/src/main/java/org/opensearch/telemetry/tracing/OTelResourceProvider.java
@@ -30,7 +30,7 @@
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import io.opentelemetry.sdk.trace.samplers.Sampler;
-import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
+import io.opentelemetry.semconv.ResourceAttributes;
import static org.opensearch.telemetry.OTelTelemetrySettings.TRACER_EXPORTER_BATCH_SIZE_SETTING;
import static org.opensearch.telemetry.OTelTelemetrySettings.TRACER_EXPORTER_DELAY_SETTING;
diff --git a/server/src/main/java/org/opensearch/action/search/AbstractSearchAsyncAction.java b/server/src/main/java/org/opensearch/action/search/AbstractSearchAsyncAction.java
index 1c0a1280ad550..14f57218ae1dc 100644
--- a/server/src/main/java/org/opensearch/action/search/AbstractSearchAsyncAction.java
+++ b/server/src/main/java/org/opensearch/action/search/AbstractSearchAsyncAction.java
@@ -215,6 +215,7 @@ public final void start() {
0,
0,
buildTookInMillis(),
+ timeProvider.getPhaseTook(),
ShardSearchFailure.EMPTY_ARRAY,
clusters,
null
@@ -662,6 +663,7 @@ protected final SearchResponse buildSearchResponse(
successfulOps.get(),
skippedOps.get(),
buildTookInMillis(),
+ timeProvider.getPhaseTook(),
failures,
clusters,
searchContextId
diff --git a/server/src/main/java/org/opensearch/action/search/MultiSearchRequest.java b/server/src/main/java/org/opensearch/action/search/MultiSearchRequest.java
index da8f8f144eaf2..00e0345062d1c 100644
--- a/server/src/main/java/org/opensearch/action/search/MultiSearchRequest.java
+++ b/server/src/main/java/org/opensearch/action/search/MultiSearchRequest.java
@@ -277,6 +277,8 @@ public static void readMultiLineFormat(
} else if ("cancel_after_time_interval".equals(entry.getKey())
|| "cancelAfterTimeInterval".equals(entry.getKey())) {
searchRequest.setCancelAfterTimeInterval(nodeTimeValue(value, null));
+ } else if ("phase_took".equals(entry.getKey())) {
+ searchRequest.setPhaseTook(nodeBooleanValue(value));
} else {
throw new IllegalArgumentException("key [" + entry.getKey() + "] is not supported in the metadata section");
}
@@ -374,6 +376,9 @@ public static void writeSearchRequestParams(SearchRequest request, XContentBuild
if (request.getCancelAfterTimeInterval() != null) {
xContentBuilder.field("cancel_after_time_interval", request.getCancelAfterTimeInterval().getStringRep());
}
+ if (request.isPhaseTook() != null) {
+ xContentBuilder.field("phase_took", request.isPhaseTook());
+ }
xContentBuilder.endObject();
}
diff --git a/server/src/main/java/org/opensearch/action/search/SearchRequest.java b/server/src/main/java/org/opensearch/action/search/SearchRequest.java
index 21cf0ed97b9da..9e50213eab5f9 100644
--- a/server/src/main/java/org/opensearch/action/search/SearchRequest.java
+++ b/server/src/main/java/org/opensearch/action/search/SearchRequest.java
@@ -117,6 +117,8 @@ public class SearchRequest extends ActionRequest implements IndicesRequest.Repla
private String pipeline;
+ private Boolean phaseTook = null;
+
public SearchRequest() {
this.localClusterAlias = null;
this.absoluteStartMillis = DEFAULT_ABSOLUTE_START_MILLIS;
@@ -209,6 +211,7 @@ private SearchRequest(
this.absoluteStartMillis = absoluteStartMillis;
this.finalReduce = finalReduce;
this.cancelAfterTimeInterval = searchRequest.cancelAfterTimeInterval;
+ this.phaseTook = searchRequest.phaseTook;
}
/**
@@ -253,6 +256,9 @@ public SearchRequest(StreamInput in) throws IOException {
if (in.getVersion().onOrAfter(Version.V_2_7_0)) {
pipeline = in.readOptionalString();
}
+ if (in.getVersion().onOrAfter(Version.V_3_0_0)) {
+ phaseTook = in.readOptionalBoolean();
+ }
}
@Override
@@ -284,6 +290,9 @@ public void writeTo(StreamOutput out) throws IOException {
if (out.getVersion().onOrAfter(Version.V_2_7_0)) {
out.writeOptionalString(pipeline);
}
+ if (out.getVersion().onOrAfter(Version.V_3_0_0)) {
+ out.writeOptionalBoolean(phaseTook);
+ }
}
@Override
@@ -615,6 +624,20 @@ public void setPreFilterShardSize(int preFilterShardSize) {
this.preFilterShardSize = preFilterShardSize;
}
+ /**
+ * Returns value of user-provided phase_took query parameter for this search request.
+ */
+ public Boolean isPhaseTook() {
+ return phaseTook;
+ }
+
+ /**
+ * Sets value of phase_took query param if provided by user. Defaults to null
.
+ */
+ public void setPhaseTook(Boolean phaseTook) {
+ this.phaseTook = phaseTook;
+ }
+
/**
* Returns a threshold that enforces a pre-filter roundtrip to pre-filter search shards based on query rewriting if the number of shards
* the search request expands to exceeds the threshold, or null
if the threshold is unspecified.
@@ -719,7 +742,8 @@ public boolean equals(Object o) {
&& absoluteStartMillis == that.absoluteStartMillis
&& ccsMinimizeRoundtrips == that.ccsMinimizeRoundtrips
&& Objects.equals(cancelAfterTimeInterval, that.cancelAfterTimeInterval)
- && Objects.equals(pipeline, that.pipeline);
+ && Objects.equals(pipeline, that.pipeline)
+ && Objects.equals(phaseTook, that.phaseTook);
}
@Override
@@ -740,7 +764,8 @@ public int hashCode() {
localClusterAlias,
absoluteStartMillis,
ccsMinimizeRoundtrips,
- cancelAfterTimeInterval
+ cancelAfterTimeInterval,
+ phaseTook
);
}
@@ -783,6 +808,8 @@ public String toString() {
+ cancelAfterTimeInterval
+ ", pipeline="
+ pipeline
+ + ", phaseTook="
+ + phaseTook
+ "}";
}
}
diff --git a/server/src/main/java/org/opensearch/action/search/SearchResponse.java b/server/src/main/java/org/opensearch/action/search/SearchResponse.java
index a546311a1f668..91f0dc0737637 100644
--- a/server/src/main/java/org/opensearch/action/search/SearchResponse.java
+++ b/server/src/main/java/org/opensearch/action/search/SearchResponse.java
@@ -33,6 +33,7 @@
package org.opensearch.action.search;
import org.apache.lucene.search.TotalHits;
+import org.opensearch.Version;
import org.opensearch.common.Nullable;
import org.opensearch.common.unit.TimeValue;
import org.opensearch.common.xcontent.StatusToXContentObject;
@@ -63,7 +64,9 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
@@ -94,6 +97,7 @@ public class SearchResponse extends ActionResponse implements StatusToXContentOb
private final ShardSearchFailure[] shardFailures;
private final Clusters clusters;
private final long tookInMillis;
+ private final PhaseTook phaseTook;
public SearchResponse(StreamInput in) throws IOException {
super(in);
@@ -112,6 +116,11 @@ public SearchResponse(StreamInput in) throws IOException {
clusters = new Clusters(in);
scrollId = in.readOptionalString();
tookInMillis = in.readVLong();
+ if (in.getVersion().onOrAfter(Version.V_3_0_0)) {
+ phaseTook = in.readOptionalWriteable(PhaseTook::new);
+ } else {
+ phaseTook = null;
+ }
skippedShards = in.readVInt();
pointInTimeId = in.readOptionalString();
}
@@ -126,7 +135,32 @@ public SearchResponse(
ShardSearchFailure[] shardFailures,
Clusters clusters
) {
- this(internalResponse, scrollId, totalShards, successfulShards, skippedShards, tookInMillis, shardFailures, clusters, null);
+ this(internalResponse, scrollId, totalShards, successfulShards, skippedShards, tookInMillis, null, shardFailures, clusters, null);
+ }
+
+ public SearchResponse(
+ SearchResponseSections internalResponse,
+ String scrollId,
+ int totalShards,
+ int successfulShards,
+ int skippedShards,
+ long tookInMillis,
+ ShardSearchFailure[] shardFailures,
+ Clusters clusters,
+ String pointInTimeId
+ ) {
+ this(
+ internalResponse,
+ scrollId,
+ totalShards,
+ successfulShards,
+ skippedShards,
+ tookInMillis,
+ null,
+ shardFailures,
+ clusters,
+ pointInTimeId
+ );
}
public SearchResponse(
@@ -136,6 +170,7 @@ public SearchResponse(
int successfulShards,
int skippedShards,
long tookInMillis,
+ PhaseTook phaseTook,
ShardSearchFailure[] shardFailures,
Clusters clusters,
String pointInTimeId
@@ -148,6 +183,7 @@ public SearchResponse(
this.successfulShards = successfulShards;
this.skippedShards = skippedShards;
this.tookInMillis = tookInMillis;
+ this.phaseTook = phaseTook;
this.shardFailures = shardFailures;
assert skippedShards <= totalShards : "skipped: " + skippedShards + " total: " + totalShards;
assert scrollId == null || pointInTimeId == null : "SearchResponse can't have both scrollId ["
@@ -210,6 +246,13 @@ public TimeValue getTook() {
return new TimeValue(tookInMillis);
}
+ /**
+ * How long the request took in each search phase.
+ */
+ public PhaseTook getPhaseTook() {
+ return phaseTook;
+ }
+
/**
* The total number of shards the search was executed on.
*/
@@ -298,6 +341,9 @@ public XContentBuilder innerToXContent(XContentBuilder builder, Params params) t
builder.field(POINT_IN_TIME_ID.getPreferredName(), pointInTimeId);
}
builder.field(TOOK.getPreferredName(), tookInMillis);
+ if (phaseTook != null) {
+ phaseTook.toXContent(builder, params);
+ }
builder.field(TIMED_OUT.getPreferredName(), isTimedOut());
if (isTerminatedEarly() != null) {
builder.field(TERMINATED_EARLY.getPreferredName(), isTerminatedEarly());
@@ -337,6 +383,7 @@ public static SearchResponse innerFromXContent(XContentParser parser) throws IOE
Boolean terminatedEarly = null;
int numReducePhases = 1;
long tookInMillis = -1;
+ PhaseTook phaseTook = null;
int successfulShards = -1;
int totalShards = -1;
int skippedShards = 0; // 0 for BWC
@@ -401,6 +448,24 @@ public static SearchResponse innerFromXContent(XContentParser parser) throws IOE
parser.skipChildren();
}
}
+ } else if (PhaseTook.PHASE_TOOK.match(currentFieldName, parser.getDeprecationHandler())) {
+ Map phaseTookMap = new HashMap<>();
+
+ while ((token = parser.nextToken()) != Token.END_OBJECT) {
+ if (token == Token.FIELD_NAME) {
+ currentFieldName = parser.currentName();
+ } else if (token.isValue()) {
+ try {
+ SearchPhaseName.valueOf(currentFieldName.toUpperCase(Locale.ROOT));
+ phaseTookMap.put(currentFieldName, parser.longValue());
+ } catch (final IllegalArgumentException ex) {
+ parser.skipChildren();
+ }
+ } else {
+ parser.skipChildren();
+ }
+ }
+ phaseTook = new PhaseTook(phaseTookMap);
} else if (Clusters._CLUSTERS_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
int successful = -1;
int total = -1;
@@ -472,6 +537,7 @@ public static SearchResponse innerFromXContent(XContentParser parser) throws IOE
successfulShards,
skippedShards,
tookInMillis,
+ phaseTook,
failures.toArray(ShardSearchFailure.EMPTY_ARRAY),
clusters,
searchContextId
@@ -491,6 +557,9 @@ public void writeTo(StreamOutput out) throws IOException {
clusters.writeTo(out);
out.writeOptionalString(scrollId);
out.writeVLong(tookInMillis);
+ if (out.getVersion().onOrAfter(Version.V_3_0_0)) {
+ out.writeOptionalWriteable(phaseTook);
+ }
out.writeVInt(skippedShards);
out.writeOptionalString(pointInTimeId);
}
@@ -604,6 +673,67 @@ public String toString() {
}
}
+ /**
+ * Holds info about the clusters that the search was executed on: how many in total, how many of them were successful
+ * and how many of them were skipped.
+ *
+ * @opensearch.internal
+ */
+ public static class PhaseTook implements ToXContentFragment, Writeable {
+ static final ParseField PHASE_TOOK = new ParseField("phase_took");
+ private final Map phaseTookMap;
+
+ public PhaseTook(Map phaseTookMap) {
+ this.phaseTookMap = phaseTookMap;
+ }
+
+ private PhaseTook(StreamInput in) throws IOException {
+ this(in.readMap(StreamInput::readString, StreamInput::readLong));
+ }
+
+ @Override
+ public void writeTo(StreamOutput out) throws IOException {
+ out.writeMap(phaseTookMap, StreamOutput::writeString, StreamOutput::writeLong);
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.startObject(PHASE_TOOK.getPreferredName());
+
+ for (SearchPhaseName searchPhaseName : SearchPhaseName.values()) {
+ if (phaseTookMap.containsKey(searchPhaseName.getName())) {
+ builder.field(searchPhaseName.getName(), phaseTookMap.get(searchPhaseName.getName()));
+ } else {
+ builder.field(searchPhaseName.getName(), 0);
+ }
+ }
+ builder.endObject();
+ return builder;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ PhaseTook phaseTook = (PhaseTook) o;
+
+ if (phaseTook.phaseTookMap.equals(phaseTookMap)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(phaseTookMap);
+ }
+ }
+
static SearchResponse empty(Supplier tookInMillisSupplier, Clusters clusters) {
SearchHits searchHits = new SearchHits(new SearchHit[0], new TotalHits(0L, TotalHits.Relation.EQUAL_TO), Float.NaN);
InternalSearchResponse internalSearchResponse = new InternalSearchResponse(
diff --git a/server/src/main/java/org/opensearch/action/search/SearchResponseMerger.java b/server/src/main/java/org/opensearch/action/search/SearchResponseMerger.java
index f90e98106f93f..054bd578cc56c 100644
--- a/server/src/main/java/org/opensearch/action/search/SearchResponseMerger.java
+++ b/server/src/main/java/org/opensearch/action/search/SearchResponseMerger.java
@@ -236,6 +236,7 @@ SearchResponse getMergedResponse(SearchResponse.Clusters clusters) {
successfulShards,
skippedShards,
tookInMillis,
+ searchTimeProvider.getPhaseTook(),
shardFailures,
clusters,
null
diff --git a/server/src/main/java/org/opensearch/action/search/TransportSearchAction.java b/server/src/main/java/org/opensearch/action/search/TransportSearchAction.java
index cff1005beff27..284f71bd9da62 100644
--- a/server/src/main/java/org/opensearch/action/search/TransportSearchAction.java
+++ b/server/src/main/java/org/opensearch/action/search/TransportSearchAction.java
@@ -98,6 +98,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -154,6 +155,14 @@ public class TransportSearchAction extends HandledTransportAction SEARCH_PHASE_TOOK_ENABLED = Setting.boolSetting(
+ SEARCH_PHASE_TOOK_ENABLED_KEY,
+ false,
+ Property.Dynamic,
+ Property.NodeScope
+ );
+
private final NodeClient client;
private final ThreadPool threadPool;
private final ClusterService clusterService;
@@ -252,6 +261,8 @@ private Map resolveIndexBoosts(SearchRequest searchRequest, Clust
}
/**
+ * Listener to track request-level tookTime and phase tookTimes from the coordinator.
+ *
* Search operations need two clocks. One clock is to fulfill real clock needs (e.g., resolving
* "now" to an index name). Another clock is needed for measuring how long a search operation
* took. These two uses are at odds with each other. There are many issues with using a real
@@ -261,11 +272,12 @@ private Map resolveIndexBoosts(SearchRequest searchRequest, Clust
*
* @opensearch.internal
*/
- static final class SearchTimeProvider {
+ static final class SearchTimeProvider implements SearchRequestOperationsListener {
private final long absoluteStartMillis;
private final long relativeStartNanos;
private final LongSupplier relativeCurrentNanosProvider;
+ private boolean phaseTook = false;
/**
* Instantiates a new search time provider. The absolute start time is the real clock time
@@ -291,6 +303,47 @@ long getAbsoluteStartMillis() {
long buildTookInMillis() {
return TimeUnit.NANOSECONDS.toMillis(relativeCurrentNanosProvider.getAsLong() - relativeStartNanos);
}
+
+ public void setPhaseTook(boolean phaseTook) {
+ this.phaseTook = phaseTook;
+ }
+
+ public boolean isPhaseTook() {
+ return phaseTook;
+ }
+
+ SearchResponse.PhaseTook getPhaseTook() {
+ if (phaseTook) {
+ Map phaseTookMap = new HashMap<>();
+ // Convert Map to Map for SearchResponse()
+ for (SearchPhaseName searchPhaseName : phaseStatsMap.keySet()) {
+ phaseTookMap.put(searchPhaseName.getName(), phaseStatsMap.get(searchPhaseName));
+ }
+ return new SearchResponse.PhaseTook(phaseTookMap);
+ } else {
+ return null;
+ }
+ }
+
+ Map phaseStatsMap = new EnumMap<>(SearchPhaseName.class);
+
+ @Override
+ public void onPhaseStart(SearchPhaseContext context) {}
+
+ @Override
+ public void onPhaseEnd(SearchPhaseContext context) {
+ phaseStatsMap.put(
+ context.getCurrentPhase().getSearchPhaseName(),
+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - context.getCurrentPhase().getStartTimeInNanos())
+ );
+ }
+
+ @Override
+ public void onPhaseFailure(SearchPhaseContext context) {}
+
+ public Long getPhaseTookTime(SearchPhaseName searchPhaseName) {
+ return phaseStatsMap.get(searchPhaseName);
+ }
}
@Override
@@ -332,13 +385,6 @@ public void executeRequest(
SinglePhaseSearchAction phaseSearchAction,
ActionListener listener
) {
- final List searchListenersList = createSearchListenerList();
- final SearchRequestOperationsListener searchRequestOperationsListener;
- if (!CollectionUtils.isEmpty(searchListenersList)) {
- searchRequestOperationsListener = new SearchRequestOperationsListener.CompositeListener(searchListenersList, logger);
- } else {
- searchRequestOperationsListener = null;
- }
executeRequest(task, searchRequest, new SearchAsyncActionProvider() {
@Override
public AbstractSearchAsyncAction extends SearchPhaseResult> asyncSearchAction(
@@ -355,7 +401,8 @@ public AbstractSearchAsyncAction extends SearchPhaseResult> asyncSearchAction(
ActionListener listener,
boolean preFilter,
ThreadPool threadPool,
- SearchResponse.Clusters clusters
+ SearchResponse.Clusters clusters,
+ SearchRequestOperationsListener searchRequestOperationsListener
) {
return new AbstractSearchAsyncAction(
actionName,
@@ -419,6 +466,16 @@ private void executeRequest(
relativeStartNanos,
System::nanoTime
);
+
+ final List searchListenersList = createSearchListenerList(originalSearchRequest, timeProvider);
+
+ final SearchRequestOperationsListener searchRequestOperationsListener;
+ if (!CollectionUtils.isEmpty(searchListenersList)) {
+ searchRequestOperationsListener = new SearchRequestOperationsListener.CompositeListener(searchListenersList, logger);
+ } else {
+ searchRequestOperationsListener = null;
+ }
+
PipelinedRequest searchRequest;
ActionListener listener;
try {
@@ -462,7 +519,8 @@ private void executeRequest(
clusterState,
listener,
searchContext,
- searchAsyncActionProvider
+ searchAsyncActionProvider,
+ searchRequestOperationsListener
);
} else {
if (shouldMinimizeRoundtrips(searchRequest)) {
@@ -483,7 +541,8 @@ private void executeRequest(
clusterState,
l,
searchContext,
- searchAsyncActionProvider
+ searchAsyncActionProvider,
+ searchRequestOperationsListener
)
);
} else {
@@ -533,7 +592,8 @@ private void executeRequest(
listener,
new SearchResponse.Clusters(totalClusters, successfulClusters, skippedClusters.get()),
searchContext,
- searchAsyncActionProvider
+ searchAsyncActionProvider,
+ searchRequestOperationsListener
);
}, listener::onFailure)
);
@@ -622,6 +682,7 @@ public void onResponse(SearchResponse searchResponse) {
searchResponse.getSuccessfulShards(),
searchResponse.getSkippedShards(),
timeProvider.buildTookInMillis(),
+ timeProvider.getPhaseTook(),
searchResponse.getShardFailures(),
new SearchResponse.Clusters(1, 1, 0),
searchResponse.pointInTimeId()
@@ -811,7 +872,8 @@ private void executeLocalSearch(
ClusterState clusterState,
ActionListener listener,
SearchContextId searchContext,
- SearchAsyncActionProvider searchAsyncActionProvider
+ SearchAsyncActionProvider searchAsyncActionProvider,
+ SearchRequestOperationsListener searchRequestOperationsListener
) {
executeSearch(
(SearchTask) task,
@@ -825,7 +887,8 @@ private void executeLocalSearch(
listener,
SearchResponse.Clusters.EMPTY,
searchContext,
- searchAsyncActionProvider
+ searchAsyncActionProvider,
+ searchRequestOperationsListener
);
}
@@ -943,7 +1006,8 @@ private void executeSearch(
ActionListener listener,
SearchResponse.Clusters clusters,
@Nullable SearchContextId searchContext,
- SearchAsyncActionProvider searchAsyncActionProvider
+ SearchAsyncActionProvider searchAsyncActionProvider,
+ SearchRequestOperationsListener searchRequestOperationsListener
) {
clusterState.blocks().globalBlockedRaiseException(ClusterBlockLevel.READ);
// TODO: I think startTime() should become part of ActionRequest and that should be used both for index name
@@ -1044,7 +1108,8 @@ private void executeSearch(
listener,
preFilterSearchShards,
threadPool,
- clusters
+ clusters,
+ searchRequestOperationsListener
).start();
}
@@ -1127,15 +1192,30 @@ AbstractSearchAsyncAction extends SearchPhaseResult> asyncSearchAction(
ActionListener listener,
boolean preFilter,
ThreadPool threadPool,
- SearchResponse.Clusters clusters
+ SearchResponse.Clusters clusters,
+ SearchRequestOperationsListener searchRequestOperationsListener
);
}
- private List createSearchListenerList() {
+ private List createSearchListenerList(SearchRequest searchRequest, SearchTimeProvider timeProvider) {
final List searchListenersList = new ArrayList<>();
+
if (isRequestStatsEnabled) {
searchListenersList.add(searchRequestStats);
}
+
+ // phase_took is enabled with request param and/or cluster setting
+ Boolean phaseTookRequestParam = searchRequest.isPhaseTook();
+ if (phaseTookRequestParam == null) { // check cluster setting only when request param is undefined
+ if (clusterService.getClusterSettings().get(TransportSearchAction.SEARCH_PHASE_TOOK_ENABLED)) {
+ timeProvider.setPhaseTook(true);
+ searchListenersList.add(timeProvider);
+ }
+ } else if (phaseTookRequestParam == true) {
+ timeProvider.setPhaseTook(true);
+ searchListenersList.add(timeProvider);
+ }
+
return searchListenersList;
}
@@ -1153,15 +1233,9 @@ private AbstractSearchAsyncAction extends SearchPhaseResult> searchAsyncAction
ActionListener listener,
boolean preFilter,
ThreadPool threadPool,
- SearchResponse.Clusters clusters
+ SearchResponse.Clusters clusters,
+ SearchRequestOperationsListener searchRequestOperationsListener
) {
- final List searchListenersList = createSearchListenerList();
- final SearchRequestOperationsListener searchRequestOperationsListener;
- if (!CollectionUtils.isEmpty(searchListenersList)) {
- searchRequestOperationsListener = new SearchRequestOperationsListener.CompositeListener(searchListenersList, logger);
- } else {
- searchRequestOperationsListener = null;
- }
if (preFilter) {
return new CanMatchPreFilterSearchPhase(
logger,
@@ -1192,7 +1266,8 @@ private AbstractSearchAsyncAction extends SearchPhaseResult> searchAsyncAction
listener,
false,
threadPool,
- clusters
+ clusters,
+ searchRequestOperationsListener
);
return new SearchPhase(action.getName()) {
@Override
diff --git a/server/src/main/java/org/opensearch/common/settings/ClusterSettings.java b/server/src/main/java/org/opensearch/common/settings/ClusterSettings.java
index 4cd3490cffb4c..ad2b89aa3948d 100644
--- a/server/src/main/java/org/opensearch/common/settings/ClusterSettings.java
+++ b/server/src/main/java/org/opensearch/common/settings/ClusterSettings.java
@@ -375,6 +375,7 @@ public void apply(Settings value, Settings current, Settings previous) {
TransportSearchAction.SHARD_COUNT_LIMIT_SETTING,
TransportSearchAction.SEARCH_CANCEL_AFTER_TIME_INTERVAL_SETTING,
TransportSearchAction.SEARCH_REQUEST_STATS_ENABLED,
+ TransportSearchAction.SEARCH_PHASE_TOOK_ENABLED,
RemoteClusterService.REMOTE_CLUSTER_SKIP_UNAVAILABLE,
SniffConnectionStrategy.REMOTE_CONNECTIONS_PER_CLUSTER,
RemoteClusterService.REMOTE_INITIAL_CONNECTION_TIMEOUT_SETTING,
diff --git a/server/src/main/java/org/opensearch/index/remote/RemoteSegmentStats.java b/server/src/main/java/org/opensearch/index/remote/RemoteSegmentStats.java
index c7863536adf20..5992923a4157b 100644
--- a/server/src/main/java/org/opensearch/index/remote/RemoteSegmentStats.java
+++ b/server/src/main/java/org/opensearch/index/remote/RemoteSegmentStats.java
@@ -8,6 +8,7 @@
package org.opensearch.index.remote;
+import org.opensearch.Version;
import org.opensearch.action.admin.cluster.remotestore.stats.RemoteStoreStats;
import org.opensearch.common.unit.TimeValue;
import org.opensearch.core.common.io.stream.StreamInput;
@@ -75,6 +76,10 @@ public class RemoteSegmentStats implements Writeable, ToXContentFragment {
* Total time spent in downloading segments from remote store
*/
private long totalDownloadTime;
+ /**
+ * Total rejections due to remote store upload backpressure
+ */
+ private long totalRejections;
public RemoteSegmentStats() {}
@@ -90,6 +95,10 @@ public RemoteSegmentStats(StreamInput in) throws IOException {
totalRefreshBytesLag = in.readLong();
totalUploadTime = in.readLong();
totalDownloadTime = in.readLong();
+ // TODO: change to V_2_12_0 on main after backport to 2.x
+ if (in.getVersion().onOrAfter(Version.V_3_0_0)) {
+ totalRejections = in.readVLong();
+ }
}
/**
@@ -115,6 +124,7 @@ public RemoteSegmentStats(RemoteSegmentTransferTracker.Stats trackerStats) {
this.totalRefreshBytesLag = trackerStats.bytesLag;
this.totalUploadTime = trackerStats.totalUploadTimeInMs;
this.totalDownloadTime = trackerStats.directoryFileTransferTrackerStats.totalTransferTimeInMs;
+ this.totalRejections = trackerStats.rejectionCount;
}
// Getter and setters. All are visible for testing
@@ -207,6 +217,14 @@ public void addTotalDownloadTime(long totalDownloadTime) {
this.totalDownloadTime += totalDownloadTime;
}
+ public long getTotalRejections() {
+ return totalRejections;
+ }
+
+ public void addTotalRejections(long totalRejections) {
+ this.totalRejections += totalRejections;
+ }
+
/**
* Adds existing stats. Used for stats roll-ups at index or node level
*
@@ -225,6 +243,7 @@ public void add(RemoteSegmentStats existingStats) {
this.totalRefreshBytesLag += existingStats.getTotalRefreshBytesLag();
this.totalUploadTime += existingStats.getTotalUploadTime();
this.totalDownloadTime += existingStats.getTotalDownloadTime();
+ this.totalRejections += existingStats.totalRejections;
}
}
@@ -241,18 +260,26 @@ public void writeTo(StreamOutput out) throws IOException {
out.writeLong(totalRefreshBytesLag);
out.writeLong(totalUploadTime);
out.writeLong(totalDownloadTime);
+ // TODO: change to V_2_12_0 on main after backport to 2.x
+ if (out.getVersion().onOrAfter(Version.V_3_0_0)) {
+ out.writeVLong(totalRejections);
+ }
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(Fields.REMOTE_STORE);
+
builder.startObject(Fields.UPLOAD);
buildUploadStats(builder);
- builder.endObject();
+ builder.endObject(); // UPLOAD
+
builder.startObject(Fields.DOWNLOAD);
buildDownloadStats(builder);
- builder.endObject();
- builder.endObject();
+ builder.endObject(); // DOWNLOAD
+
+ builder.endObject(); // REMOTE_STORE
+
return builder;
}
@@ -261,13 +288,19 @@ private void buildUploadStats(XContentBuilder builder) throws IOException {
builder.humanReadableField(Fields.STARTED_BYTES, Fields.STARTED, new ByteSizeValue(uploadBytesStarted));
builder.humanReadableField(Fields.SUCCEEDED_BYTES, Fields.SUCCEEDED, new ByteSizeValue(uploadBytesSucceeded));
builder.humanReadableField(Fields.FAILED_BYTES, Fields.FAILED, new ByteSizeValue(uploadBytesFailed));
- builder.endObject();
+ builder.endObject(); // TOTAL_UPLOAD_SIZE
+
builder.startObject(Fields.REFRESH_SIZE_LAG);
builder.humanReadableField(Fields.TOTAL_BYTES, Fields.TOTAL, new ByteSizeValue(totalRefreshBytesLag));
builder.humanReadableField(Fields.MAX_BYTES, Fields.MAX, new ByteSizeValue(maxRefreshBytesLag));
- builder.endObject();
+ builder.endObject(); // REFRESH_SIZE_LAG
+
builder.humanReadableField(Fields.MAX_REFRESH_TIME_LAG_IN_MILLIS, Fields.MAX_REFRESH_TIME_LAG, new TimeValue(maxRefreshTimeLag));
builder.humanReadableField(Fields.TOTAL_TIME_SPENT_IN_MILLIS, Fields.TOTAL_TIME_SPENT, new TimeValue(totalUploadTime));
+
+ builder.startObject(Fields.PRESSURE);
+ builder.field(Fields.TOTAL_REJECTIONS, totalRejections);
+ builder.endObject(); // PRESSURE
}
private void buildDownloadStats(XContentBuilder builder) throws IOException {
@@ -300,6 +333,8 @@ static final class Fields {
static final String MAX_BYTES = "max_bytes";
static final String TOTAL_TIME_SPENT = "total_time_spent";
static final String TOTAL_TIME_SPENT_IN_MILLIS = "total_time_spent_in_millis";
+ static final String PRESSURE = "pressure";
+ static final String TOTAL_REJECTIONS = "total_rejections";
}
@Override
@@ -318,7 +353,8 @@ public boolean equals(Object o) {
&& maxRefreshBytesLag == that.maxRefreshBytesLag
&& totalRefreshBytesLag == that.totalRefreshBytesLag
&& totalUploadTime == that.totalUploadTime
- && totalDownloadTime == that.totalDownloadTime;
+ && totalDownloadTime == that.totalDownloadTime
+ && totalRejections == that.totalRejections;
}
@Override
@@ -334,7 +370,8 @@ public int hashCode() {
maxRefreshBytesLag,
totalRefreshBytesLag,
totalUploadTime,
- totalDownloadTime
+ totalDownloadTime,
+ totalRejections
);
}
}
diff --git a/server/src/main/java/org/opensearch/index/remote/RemoteSegmentTransferTracker.java b/server/src/main/java/org/opensearch/index/remote/RemoteSegmentTransferTracker.java
index 05081180bb179..2a703f17aa953 100644
--- a/server/src/main/java/org/opensearch/index/remote/RemoteSegmentTransferTracker.java
+++ b/server/src/main/java/org/opensearch/index/remote/RemoteSegmentTransferTracker.java
@@ -267,7 +267,8 @@ public long getRejectionCount() {
return rejectionCount.get();
}
- void incrementRejectionCount() {
+ /** public only for testing **/
+ public void incrementRejectionCount() {
rejectionCount.incrementAndGet();
}
diff --git a/server/src/main/java/org/opensearch/rest/action/search/RestSearchAction.java b/server/src/main/java/org/opensearch/rest/action/search/RestSearchAction.java
index ebfd082d974fd..080366e536da1 100644
--- a/server/src/main/java/org/opensearch/rest/action/search/RestSearchAction.java
+++ b/server/src/main/java/org/opensearch/rest/action/search/RestSearchAction.java
@@ -180,6 +180,12 @@ public static void parseSearchRequest(
searchRequest.allowPartialSearchResults(request.paramAsBoolean("allow_partial_search_results", null));
}
+ if (request.hasParam("phase_took")) {
+ // only set if we have the parameter passed to override the cluster-level default
+ // else phaseTook = null
+ searchRequest.setPhaseTook(request.paramAsBoolean("phase_took", true));
+ }
+
// do not allow 'query_and_fetch' or 'dfs_query_and_fetch' search types
// from the REST layer. these modes are an internal optimization and should
// not be specified explicitly by the user.
diff --git a/server/src/test/java/org/opensearch/action/admin/cluster/node/stats/NodeStatsTests.java b/server/src/test/java/org/opensearch/action/admin/cluster/node/stats/NodeStatsTests.java
index e3f16463a5328..e0b35c69cc3c0 100644
--- a/server/src/test/java/org/opensearch/action/admin/cluster/node/stats/NodeStatsTests.java
+++ b/server/src/test/java/org/opensearch/action/admin/cluster/node/stats/NodeStatsTests.java
@@ -815,6 +815,7 @@ private static NodeIndicesStats getNodeIndicesStats(boolean remoteStoreStats) {
remoteSegmentStats.setMaxRefreshTimeLag(2L);
remoteSegmentStats.addTotalUploadTime(20L);
remoteSegmentStats.addTotalDownloadTime(20L);
+ remoteSegmentStats.addTotalRejections(5L);
RemoteTranslogStats remoteTranslogStats = indicesStats.getTranslog().getRemoteTranslogStats();
RemoteTranslogStats otherRemoteTranslogStats = new RemoteTranslogStats(getRandomRemoteTranslogTransferTrackerStats());
diff --git a/server/src/test/java/org/opensearch/action/search/AbstractSearchAsyncActionTests.java b/server/src/test/java/org/opensearch/action/search/AbstractSearchAsyncActionTests.java
index f628bb3201452..edac50813e191 100644
--- a/server/src/test/java/org/opensearch/action/search/AbstractSearchAsyncActionTests.java
+++ b/server/src/test/java/org/opensearch/action/search/AbstractSearchAsyncActionTests.java
@@ -688,7 +688,11 @@ private SearchDfsQueryThenFetchAsyncAction createSearchDfsQueryThenFetchAsyncAct
);
AtomicReference exception = new AtomicReference<>();
ActionListener listener = ActionListener.wrap(response -> fail("onResponse should not be called"), exception::set);
-
+ TransportSearchAction.SearchTimeProvider timeProvider = new TransportSearchAction.SearchTimeProvider(
+ 0,
+ System.nanoTime(),
+ System::nanoTime
+ );
return new SearchDfsQueryThenFetchAsyncAction(
logger,
null,
@@ -702,7 +706,7 @@ private SearchDfsQueryThenFetchAsyncAction createSearchDfsQueryThenFetchAsyncAct
searchRequest,
listener,
shardsIter,
- null,
+ timeProvider,
null,
task,
SearchResponse.Clusters.EMPTY,
@@ -734,6 +738,11 @@ private SearchQueryThenFetchAsyncAction createSearchQueryThenFetchAsyncAction(
);
AtomicReference exception = new AtomicReference<>();
ActionListener listener = ActionListener.wrap(response -> fail("onResponse should not be called"), exception::set);
+ TransportSearchAction.SearchTimeProvider timeProvider = new TransportSearchAction.SearchTimeProvider(
+ 0,
+ System.nanoTime(),
+ System::nanoTime
+ );
return new SearchQueryThenFetchAsyncAction(
logger,
null,
@@ -747,7 +756,7 @@ private SearchQueryThenFetchAsyncAction createSearchQueryThenFetchAsyncAction(
searchRequest,
listener,
shardsIter,
- null,
+ timeProvider,
null,
task,
SearchResponse.Clusters.EMPTY,
diff --git a/server/src/test/java/org/opensearch/action/search/SearchRequestTests.java b/server/src/test/java/org/opensearch/action/search/SearchRequestTests.java
index 25d8c5551880f..cdd0ea863ce37 100644
--- a/server/src/test/java/org/opensearch/action/search/SearchRequestTests.java
+++ b/server/src/test/java/org/opensearch/action/search/SearchRequestTests.java
@@ -244,6 +244,7 @@ private SearchRequest mutate(SearchRequest searchRequest) {
);
mutators.add(() -> mutation.source(randomValueOtherThan(searchRequest.source(), this::createSearchSourceBuilder)));
mutators.add(() -> mutation.setCcsMinimizeRoundtrips(searchRequest.isCcsMinimizeRoundtrips() == false));
+ mutators.add(() -> mutation.setPhaseTook(searchRequest.isPhaseTook() == false));
mutators.add(
() -> mutation.setCancelAfterTimeInterval(
searchRequest.getCancelAfterTimeInterval() != null
diff --git a/server/src/test/java/org/opensearch/action/search/SearchResponseTests.java b/server/src/test/java/org/opensearch/action/search/SearchResponseTests.java
index 097e922147698..c9e59ab4ea04d 100644
--- a/server/src/test/java/org/opensearch/action/search/SearchResponseTests.java
+++ b/server/src/test/java/org/opensearch/action/search/SearchResponseTests.java
@@ -74,7 +74,9 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
import static java.util.Collections.singletonMap;
@@ -152,6 +154,11 @@ public SearchResponse createTestItem(
Boolean terminatedEarly = randomBoolean() ? null : randomBoolean();
int numReducePhases = randomIntBetween(1, 10);
long tookInMillis = randomNonNegativeLong();
+ Map phaseTookMap = new HashMap<>();
+ for (SearchPhaseName searchPhaseName : SearchPhaseName.values()) {
+ phaseTookMap.put(searchPhaseName.getName(), randomNonNegativeLong());
+ }
+ SearchResponse.PhaseTook phaseTook = new SearchResponse.PhaseTook(phaseTookMap);
int totalShards = randomIntBetween(1, Integer.MAX_VALUE);
int successfulShards = randomIntBetween(0, totalShards);
int skippedShards = randomIntBetween(0, totalShards);
@@ -182,6 +189,7 @@ public SearchResponse createTestItem(
successfulShards,
skippedShards,
tookInMillis,
+ phaseTook,
shardSearchFailures,
randomBoolean() ? randomClusters() : SearchResponse.Clusters.EMPTY,
null
@@ -353,6 +361,14 @@ public void testToXContent() {
assertEquals(1, searchExtBuilders.size());
}
{
+ Map phaseTookMap = new HashMap<>();
+ for (SearchPhaseName searchPhaseName : SearchPhaseName.values()) {
+ phaseTookMap.put(searchPhaseName.getName(), 0L);
+ }
+ phaseTookMap.put(SearchPhaseName.QUERY.getName(), 50L);
+ phaseTookMap.put(SearchPhaseName.FETCH.getName(), 25L);
+ phaseTookMap.put(SearchPhaseName.EXPAND.getName(), 30L);
+ SearchResponse.PhaseTook phaseTook = new SearchResponse.PhaseTook(phaseTookMap);
SearchResponse response = new SearchResponse(
new InternalSearchResponse(
new SearchHits(hits, new TotalHits(100, TotalHits.Relation.EQUAL_TO), 1.5f),
@@ -368,13 +384,24 @@ public void testToXContent() {
0,
0,
0,
+ phaseTook,
ShardSearchFailure.EMPTY_ARRAY,
- new SearchResponse.Clusters(5, 3, 2)
+ new SearchResponse.Clusters(5, 3, 2),
+ null
);
StringBuilder expectedString = new StringBuilder();
expectedString.append("{");
{
expectedString.append("\"took\":0,");
+ expectedString.append("\"phase_took\":");
+ {
+ expectedString.append("{\"dfs_pre_query\":0,");
+ expectedString.append("\"query\":50,");
+ expectedString.append("\"fetch\":25,");
+ expectedString.append("\"dfs_query\":0,");
+ expectedString.append("\"expand\":30,");
+ expectedString.append("\"can_match\":0},");
+ }
expectedString.append("\"timed_out\":false,");
expectedString.append("\"_shards\":");
{
@@ -477,6 +504,24 @@ public void testToXContentEmptyClusters() throws IOException {
assertEquals(0, builder.toString().length());
}
+ public void testSearchResponsePhaseTookEquals() throws IOException {
+ SearchResponse.PhaseTook phaseTookA = new SearchResponse.PhaseTook(Map.of("foo", 0L, "bar", 1L));
+ SearchResponse.PhaseTook phaseTookB = new SearchResponse.PhaseTook(Map.of("foo", 1L, "bar", 1L));
+ SearchResponse.PhaseTook phaseTookC = new SearchResponse.PhaseTook(Map.of("foo", 0L));
+ SearchResponse.PhaseTook phaseTookD = new SearchResponse.PhaseTook(Map.of());
+
+ assertNotEquals(phaseTookA, phaseTookB);
+ assertNotEquals(phaseTookB, phaseTookA);
+ assertNotEquals(phaseTookA, phaseTookC);
+ assertNotEquals(phaseTookC, phaseTookA);
+ assertNotEquals(phaseTookA, phaseTookD);
+ assertNotEquals(phaseTookD, phaseTookA);
+ assertEquals(phaseTookA, phaseTookA);
+ assertEquals(phaseTookB, phaseTookB);
+ assertEquals(phaseTookC, phaseTookC);
+ assertEquals(phaseTookD, phaseTookD);
+ }
+
static class DummySearchExtBuilder extends SearchExtBuilder {
static ParseField DUMMY_FIELD = new ParseField("dummy");
diff --git a/server/src/test/java/org/opensearch/action/search/SearchTimeProviderTests.java b/server/src/test/java/org/opensearch/action/search/SearchTimeProviderTests.java
new file mode 100644
index 0000000000000..f0f1a43e6c21e
--- /dev/null
+++ b/server/src/test/java/org/opensearch/action/search/SearchTimeProviderTests.java
@@ -0,0 +1,54 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.action.search;
+
+import org.opensearch.test.OpenSearchTestCase;
+
+import java.util.concurrent.TimeUnit;
+
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class SearchTimeProviderTests extends OpenSearchTestCase {
+
+ public void testSearchTimeProviderPhaseFailure() {
+ TransportSearchAction.SearchTimeProvider testTimeProvider = new TransportSearchAction.SearchTimeProvider(0, 0, () -> 0);
+ SearchPhaseContext ctx = mock(SearchPhaseContext.class);
+ SearchPhase mockSearchPhase = mock(SearchPhase.class);
+ when(ctx.getCurrentPhase()).thenReturn(mockSearchPhase);
+
+ for (SearchPhaseName searchPhaseName : SearchPhaseName.values()) {
+ when(mockSearchPhase.getSearchPhaseName()).thenReturn(searchPhaseName);
+ testTimeProvider.onPhaseStart(ctx);
+ assertNull(testTimeProvider.getPhaseTookTime(searchPhaseName));
+ testTimeProvider.onPhaseFailure(ctx);
+ assertNull(testTimeProvider.getPhaseTookTime(searchPhaseName));
+ }
+ }
+
+ public void testSearchTimeProviderPhaseEnd() {
+ TransportSearchAction.SearchTimeProvider testTimeProvider = new TransportSearchAction.SearchTimeProvider(0, 0, () -> 0);
+
+ SearchPhaseContext ctx = mock(SearchPhaseContext.class);
+ SearchPhase mockSearchPhase = mock(SearchPhase.class);
+ when(ctx.getCurrentPhase()).thenReturn(mockSearchPhase);
+
+ for (SearchPhaseName searchPhaseName : SearchPhaseName.values()) {
+ when(mockSearchPhase.getSearchPhaseName()).thenReturn(searchPhaseName);
+ long tookTimeInMillis = randomIntBetween(1, 100);
+ testTimeProvider.onPhaseStart(ctx);
+ long startTime = System.nanoTime() - TimeUnit.MILLISECONDS.toNanos(tookTimeInMillis);
+ when(mockSearchPhase.getStartTimeInNanos()).thenReturn(startTime);
+ assertNull(testTimeProvider.getPhaseTookTime(searchPhaseName));
+ testTimeProvider.onPhaseEnd(ctx);
+ assertThat(testTimeProvider.getPhaseTookTime(searchPhaseName), greaterThanOrEqualTo(tookTimeInMillis));
+ }
+ }
+}
diff --git a/server/src/test/java/org/opensearch/index/engine/NRTReplicationEngineTests.java b/server/src/test/java/org/opensearch/index/engine/NRTReplicationEngineTests.java
index ee25d3789fb13..09484cd1b5840 100644
--- a/server/src/test/java/org/opensearch/index/engine/NRTReplicationEngineTests.java
+++ b/server/src/test/java/org/opensearch/index/engine/NRTReplicationEngineTests.java
@@ -35,6 +35,7 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicLong;
@@ -591,7 +592,9 @@ public void testCommitOnCloseThrowsException_decRefStore() throws Exception {
indexOperations(nrtEngine, operations);
// wipe the nrt directory initially so we can sync with primary.
cleanAndCopySegmentsFromPrimary(nrtEngine);
- nrtEngineStore.directory().deleteFile("_0.si");
+ final Optional toDelete = Set.of(nrtEngineStore.directory().listAll()).stream().filter(f -> f.endsWith(".si")).findAny();
+ assertTrue(toDelete.isPresent());
+ nrtEngineStore.directory().deleteFile(toDelete.get());
assertEquals(2, nrtEngineStore.refCount());
nrtEngine.close();
assertEquals(1, nrtEngineStore.refCount());
diff --git a/server/src/test/java/org/opensearch/index/shard/IndexShardTests.java b/server/src/test/java/org/opensearch/index/shard/IndexShardTests.java
index b2eb41828a4df..9ef9bec01cb38 100644
--- a/server/src/test/java/org/opensearch/index/shard/IndexShardTests.java
+++ b/server/src/test/java/org/opensearch/index/shard/IndexShardTests.java
@@ -4910,6 +4910,8 @@ private void populateSampleRemoteSegmentStats(RemoteSegmentTransferTracker track
tracker.addUploadBytesStarted(30L);
tracker.addUploadBytesSucceeded(10L);
tracker.addUploadBytesFailed(10L);
+ tracker.incrementRejectionCount();
+ tracker.incrementRejectionCount();
}
private void populateSampleRemoteTranslogStats(RemoteTranslogTransferTracker tracker) {
@@ -4943,5 +4945,7 @@ private static void assertRemoteSegmentStats(
assertEquals(remoteSegmentTransferTracker.getUploadBytesStarted(), remoteSegmentStats.getUploadBytesStarted());
assertEquals(remoteSegmentTransferTracker.getUploadBytesSucceeded(), remoteSegmentStats.getUploadBytesSucceeded());
assertEquals(remoteSegmentTransferTracker.getUploadBytesFailed(), remoteSegmentStats.getUploadBytesFailed());
+ assertTrue(remoteSegmentStats.getTotalRejections() > 0);
+ assertEquals(remoteSegmentTransferTracker.getRejectionCount(), remoteSegmentStats.getTotalRejections());
}
}
diff --git a/test/framework/src/main/java/org/opensearch/search/RandomSearchRequestGenerator.java b/test/framework/src/main/java/org/opensearch/search/RandomSearchRequestGenerator.java
index b942136e1f1e2..74de1e6d96d93 100644
--- a/test/framework/src/main/java/org/opensearch/search/RandomSearchRequestGenerator.java
+++ b/test/framework/src/main/java/org/opensearch/search/RandomSearchRequestGenerator.java
@@ -131,6 +131,9 @@ public static SearchRequest randomSearchRequest(Supplier ra
if (randomBoolean()) {
searchRequest.setCancelAfterTimeInterval(TimeValue.parseTimeValue(randomTimeValue(), null, "cancel_after_time_interval"));
}
+ if (randomBoolean()) {
+ searchRequest.setPhaseTook(randomBoolean());
+ }
return searchRequest;
}