From 1a9c84fc5c7a40515ba89dd16bc1c3a772dc28af Mon Sep 17 00:00:00 2001 From: opensearch-ci <83309141+opensearch-ci-bot@users.noreply.github.com> Date: Fri, 24 Jul 2026 15:34:00 -0400 Subject: [PATCH 01/11] Bound regexp determinize work limit and simple_query_string nesting depth (#22557) (#22559) Two low-privilege search-request DoS vectors: - CVE-2026-63136 (regexp/query_string determinization OOM): max_determinized_states was read unbounded and passed to Lucene's RegexpQuery, so a request could set it to Integer.MAX_VALUE and disable Lucene's TooComplexToDeterminizeException safeguard. A pattern like .*a.{30} then determinizes toward ~2^30 states and exhausts the heap. - CVE-2026-63144 (simple_query_string nested-paren StackOverflow): Lucene's SimpleQueryParser recurses one frame per '(' with no depth cap, so deeply nested parentheses overflow the JVM stack. Both now fail fast with a 4xx instead of crashing the node. Adds regression tests including the reported PoC payloads. (cherry picked from commit f9cfc837b9578f5bd9c55b8612c6e46862a749c4) Signed-off-by: Darshit Chanpura Signed-off-by: opensearch-ci-bot Co-authored-by: Darshit Chanpura --- .../index/query/QueryStringQueryBuilder.java | 21 +++++- .../index/query/RegexpQueryBuilder.java | 22 ++++++- .../search/SimpleQueryStringQueryParser.java | 65 +++++++++++++++++++ .../index/query/RegexpQueryBuilderTests.java | 64 ++++++++++++++++++ .../query/SimpleQueryStringBuilderTests.java | 22 +++++++ 5 files changed, 192 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/org/opensearch/index/query/QueryStringQueryBuilder.java b/server/src/main/java/org/opensearch/index/query/QueryStringQueryBuilder.java index bf84740ca4003..92a46881d6b29 100644 --- a/server/src/main/java/org/opensearch/index/query/QueryStringQueryBuilder.java +++ b/server/src/main/java/org/opensearch/index/query/QueryStringQueryBuilder.java @@ -209,7 +209,10 @@ public QueryStringQueryBuilder(StreamInput in) throws IOException { lenient = in.readOptionalBoolean(); timeZone = in.readOptionalZoneId(); escape = in.readBoolean(); - maxDeterminizedStates = in.readVInt(); + // Route through the setter so the CVE-2026-63136 bound is enforced on the transport + // deserialization path too, not just REST/XContent. Protects a patched data node from an + // unbounded value sent by an unpatched coordinating node in a mixed-version cluster. + maxDeterminizedStates(in.readVInt()); autoGenerateSynonymsPhraseQuery = in.readBoolean(); fuzzyTranspositions = in.readBoolean(); } @@ -377,6 +380,22 @@ public QueryStringQueryBuilder quoteAnalyzer(String quoteAnalyzer) { * Protects against too-difficult regular expression queries. */ public QueryStringQueryBuilder maxDeterminizedStates(int maxDeterminizedStates) { + if (maxDeterminizedStates < 0) { + throw new IllegalArgumentException( + "[" + NAME + "] max_determinized_states cannot be negative but was [" + maxDeterminizedStates + "]" + ); + } + if (maxDeterminizedStates > RegexpQueryBuilder.MAX_DETERMINIZE_WORK_LIMIT) { + throw new IllegalArgumentException( + "[" + + NAME + + "] max_determinized_states cannot exceed [" + + RegexpQueryBuilder.MAX_DETERMINIZE_WORK_LIMIT + + "] but was [" + + maxDeterminizedStates + + "]" + ); + } this.maxDeterminizedStates = maxDeterminizedStates; return this; } diff --git a/server/src/main/java/org/opensearch/index/query/RegexpQueryBuilder.java b/server/src/main/java/org/opensearch/index/query/RegexpQueryBuilder.java index 692ce355d003e..1ee83584d5678 100644 --- a/server/src/main/java/org/opensearch/index/query/RegexpQueryBuilder.java +++ b/server/src/main/java/org/opensearch/index/query/RegexpQueryBuilder.java @@ -68,6 +68,15 @@ public class RegexpQueryBuilder extends AbstractQueryBuilder public static final int DEFAULT_FLAGS_VALUE = RegexpFlag.ALL.value(); public static final int DEFAULT_DETERMINIZE_WORK_LIMIT = Operations.DEFAULT_DETERMINIZE_WORK_LIMIT; + /** + * Upper bound for {@code max_determinized_states}. The determinize work limit exists to cap the + * amount of work Lucene performs while determinizing a regexp automaton; allowing an arbitrarily + * large value (e.g. {@link Integer#MAX_VALUE}) effectively disables that safeguard and lets a + * crafted pattern exhaust the heap before Lucene ever throws {@code TooComplexToDeterminizeException}. + * This ceiling (100x the default) still permits legitimately complex expressions while keeping the + * safeguard effective. See CVE-2026-63136. + */ + public static final int MAX_DETERMINIZE_WORK_LIMIT = 1_000_000; public static final boolean DEFAULT_CASE_INSENSITIVITY = false; private static final ParseField FLAGS_VALUE_FIELD = new ParseField("flags_value"); @@ -113,7 +122,10 @@ public RegexpQueryBuilder(StreamInput in) throws IOException { fieldName = in.readString(); value = in.readString(); syntaxFlagsValue = in.readVInt(); - maxDeterminizedStates = in.readVInt(); + // Route through the setter so the CVE-2026-63136 bound is enforced on the transport + // deserialization path too, not just REST/XContent. Protects a patched data node from an + // unbounded value sent by an unpatched coordinating node in a mixed-version cluster. + maxDeterminizedStates(in.readVInt()); rewrite = in.readOptionalString(); caseInsensitive = in.readBoolean(); } @@ -180,6 +192,14 @@ public boolean caseInsensitive() { * Sets the regexp maxDeterminizedStates. */ public RegexpQueryBuilder maxDeterminizedStates(int value) { + if (value < 0) { + throw new IllegalArgumentException("[" + NAME + "] max_determinized_states cannot be negative but was [" + value + "]"); + } + if (value > MAX_DETERMINIZE_WORK_LIMIT) { + throw new IllegalArgumentException( + "[" + NAME + "] max_determinized_states cannot exceed [" + MAX_DETERMINIZE_WORK_LIMIT + "] but was [" + value + "]" + ); + } this.maxDeterminizedStates = value; return this; } diff --git a/server/src/main/java/org/opensearch/index/search/SimpleQueryStringQueryParser.java b/server/src/main/java/org/opensearch/index/search/SimpleQueryStringQueryParser.java index 11ec237153c01..7321cbb6fa667 100644 --- a/server/src/main/java/org/opensearch/index/search/SimpleQueryStringQueryParser.java +++ b/server/src/main/java/org/opensearch/index/search/SimpleQueryStringQueryParser.java @@ -71,6 +71,19 @@ */ public class SimpleQueryStringQueryParser extends SimpleQueryParser { + /** + * Maximum nesting depth of parenthesized (precedence) groups that will be parsed. Lucene's + * {@link SimpleQueryParser} parses precedence groups recursively, so a query string containing + * deeply nested unescaped parentheses drives one JVM stack frame per level and overflows the + * stack ({@code StackOverflowError}) before any query is built. Capping the depth and failing + * with a catchable exception keeps the recursion bounded. See CVE-2026-63144. + *

+ * Configurable via the {@code opensearch.query.simple_query_string.max_depth} system property + * (default 1000, aligned with the recursion depth limits in {@code StreamInput} / + * {@code XContentConstraints}) so operators can tune it for unusual workloads without a code change. + */ + static final int MAX_NESTING_DEPTH = Integer.parseInt(System.getProperty("opensearch.query.simple_query_string.max_depth", "1000")); + private final Settings settings; private QueryShardContext context; private final MultiMatchQuery queryBuilder; @@ -100,6 +113,58 @@ public SimpleQueryStringQueryParser( } } + @Override + public Query parse(String queryText) { + checkNestingDepth(queryText); + return super.parse(queryText); + } + + /** + * Rejects query strings whose parenthesized (precedence) groups nest deeper than + * {@link #MAX_NESTING_DEPTH}. This mirrors how Lucene's {@link SimpleQueryParser} tokenizes the + * input so the guard trips before the recursive parse can overflow the JVM stack: a parenthesis + * only opens/closes a group when the precedence flag is enabled and the character is neither + * escaped nor inside a quoted phrase. Fails with an {@link IllegalArgumentException} (translated + * to an HTTP 400) instead of an unrecoverable {@code StackOverflowError}. See CVE-2026-63144. + */ + private void checkNestingDepth(String queryText) { + if (queryText == null || (flags & SimpleQueryParser.PRECEDENCE_OPERATORS) == 0) { + return; + } + final boolean escapeEnabled = (flags & SimpleQueryParser.ESCAPE_OPERATOR) != 0; + final boolean phraseEnabled = (flags & SimpleQueryParser.PHRASE_OPERATOR) != 0; + int depth = 0; + boolean inPhrase = false; + for (int i = 0; i < queryText.length(); i++) { + char c = queryText.charAt(i); + if (escapeEnabled && c == '\\') { + i++; // skip the escaped character + continue; + } + if (phraseEnabled && c == '"') { + inPhrase = !inPhrase; + continue; + } + if (inPhrase) { + continue; + } + if (c == '(') { + depth++; + if (depth > MAX_NESTING_DEPTH) { + throw new IllegalArgumentException( + "[" + + SimpleQueryStringBuilder.NAME + + "] query text nests parentheses deeper than the limit of [" + + MAX_NESTING_DEPTH + + "]" + ); + } + } else if (c == ')' && depth > 0) { + depth--; + } + } + } + private Analyzer getAnalyzer(MappedFieldType ft) { if (getAnalyzer() != null) { return analyzer; diff --git a/server/src/test/java/org/opensearch/index/query/RegexpQueryBuilderTests.java b/server/src/test/java/org/opensearch/index/query/RegexpQueryBuilderTests.java index 98613a6b3cdbb..edb5314ff5d30 100644 --- a/server/src/test/java/org/opensearch/index/query/RegexpQueryBuilderTests.java +++ b/server/src/test/java/org/opensearch/index/query/RegexpQueryBuilderTests.java @@ -34,7 +34,9 @@ import org.apache.lucene.search.Query; import org.apache.lucene.search.RegexpQuery; +import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.ParsingException; +import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.test.AbstractQueryTestCase; import java.io.IOException; @@ -44,6 +46,7 @@ import java.util.Locale; import java.util.Map; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; @@ -120,6 +123,67 @@ public void testIllegalArguments() { assertEquals("value cannot be null", e.getMessage()); } + public void testMaxDeterminizedStatesIsBounded() { + // Guards against CVE-2026-63136: an unbounded max_determinized_states disables Lucene's + // determinization safeguard and lets a crafted pattern exhaust the heap. + RegexpQueryBuilder query = new RegexpQueryBuilder("field", ".*a.{30}"); + + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> query.maxDeterminizedStates(Integer.MAX_VALUE)); + assertThat(e.getMessage(), containsString("max_determinized_states cannot exceed")); + + e = expectThrows( + IllegalArgumentException.class, + () -> query.maxDeterminizedStates(RegexpQueryBuilder.MAX_DETERMINIZE_WORK_LIMIT + 1) + ); + assertThat(e.getMessage(), containsString("max_determinized_states cannot exceed")); + + e = expectThrows(IllegalArgumentException.class, () -> query.maxDeterminizedStates(-1)); + assertThat(e.getMessage(), containsString("cannot be negative")); + + // The ceiling itself and typical values remain accepted. + assertEquals( + RegexpQueryBuilder.MAX_DETERMINIZE_WORK_LIMIT, + query.maxDeterminizedStates(RegexpQueryBuilder.MAX_DETERMINIZE_WORK_LIMIT).maxDeterminizedStates() + ); + assertEquals(20000, query.maxDeterminizedStates(20000).maxDeterminizedStates()); + } + + public void testMaxDeterminizedStatesFromJsonIsBounded() { + // The bound must also apply when the value arrives via the REST/XContent parse path. + String json = String.format(Locale.ROOT, """ + { + "regexp" : { + "field" : { + "value" : ".*a.{30}", + "max_determinized_states" : 2147483647 + } + } + }"""); + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> parseQuery(json)); + assertThat(e.getMessage(), containsString("max_determinized_states cannot exceed")); + } + + public void testMaxDeterminizedStatesFromStreamIsBounded() throws IOException { + // Guards against CVE-2026-63136 on the transport deserialization path: a patched data node + // must reject an out-of-bounds value serialized by an (unpatched) coordinating node instead + // of feeding it to Lucene. The setter bound cannot be reached by serializing a real builder + // (the setter itself blocks it), so we hand-craft the wire bytes with an oversized value. + BytesStreamOutput out = new BytesStreamOutput(); + out.writeFloat(AbstractQueryBuilder.DEFAULT_BOOST); // boost + out.writeOptionalString(null); // queryName + out.writeString("field"); // fieldName + out.writeString(".*a.{30}"); // value + out.writeVInt(RegexpQueryBuilder.DEFAULT_FLAGS_VALUE); + out.writeVInt(Integer.MAX_VALUE); // maxDeterminizedStates (malicious) + out.writeOptionalString(null); // rewrite + out.writeBoolean(false); // caseInsensitive + + try (StreamInput in = out.bytes().streamInput()) { + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> new RegexpQueryBuilder(in)); + assertThat(e.getMessage(), containsString("max_determinized_states cannot exceed")); + } + } + public void testFromJson() throws IOException { String json = """ { diff --git a/server/src/test/java/org/opensearch/index/query/SimpleQueryStringBuilderTests.java b/server/src/test/java/org/opensearch/index/query/SimpleQueryStringBuilderTests.java index a3731e9dcc60d..e90864ccf65ff 100644 --- a/server/src/test/java/org/opensearch/index/query/SimpleQueryStringBuilderTests.java +++ b/server/src/test/java/org/opensearch/index/query/SimpleQueryStringBuilderTests.java @@ -479,6 +479,28 @@ public void testExpandedTerms() throws Exception { assertEquals(expected, query); } + public void testDeeplyNestedParensAreRejected() throws IOException { + // Guards against CVE-2026-63144: deeply nested parentheses drive one recursion frame per + // level in Lucene's SimpleQueryParser and overflow the JVM stack. The query must instead + // fail with a catchable IllegalArgumentException (surfaced to clients as HTTP 400). + int depth = 200_000; + String nested = "(".repeat(depth) + "a" + ")".repeat(depth); + SimpleQueryStringBuilder qb = new SimpleQueryStringBuilder(nested).field(TEXT_FIELD_NAME); + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> qb.toQuery(createShardContext())); + assertThat(e.getMessage(), containsString("nests parentheses deeper than the limit")); + + // Escaped parentheses and parentheses inside a quoted phrase do not count toward nesting + // depth, mirroring how Lucene tokenizes the input, so they must still parse successfully. + String escaped = "\\(".repeat(depth) + "a"; + Query query = new SimpleQueryStringBuilder(escaped).field(TEXT_FIELD_NAME).toQuery(createShardContext()); + assertNotNull(query); + + // A modestly nested (well under the limit) query remains valid. + String shallow = "(".repeat(50) + "a" + ")".repeat(50); + query = new SimpleQueryStringBuilder(shallow).field(TEXT_FIELD_NAME).toQuery(createShardContext()); + assertNotNull(query); + } + public void testAnalyzeWildcard() throws IOException { SimpleQueryStringQueryParser.Settings settings = new SimpleQueryStringQueryParser.Settings(); settings.analyzeWildcard(true); From 8aff7d863799a65993fdcc8dc16b74aa849cb010 Mon Sep 17 00:00:00 2001 From: opensearch-ci <83309141+opensearch-ci-bot@users.noreply.github.com> Date: Tue, 28 Jul 2026 17:27:22 -0400 Subject: [PATCH 02/11] Align repository-gcs OpenTelemetry dependencies (#22579) (#22585) (cherry picked from commit f767a7a95a820da04973023f3968a302f6527f69) Signed-off-by: Craig Perkins Signed-off-by: opensearch-ci-bot Co-authored-by: Craig Perkins --- plugins/repository-gcs/build.gradle | 6 ++++-- .../licenses/opentelemetry-api-1.47.0.jar.sha1 | 1 - .../licenses/opentelemetry-api-1.63.0.jar.sha1 | 1 + .../licenses/opentelemetry-common-1.63.0.jar.sha1 | 1 + .../licenses/opentelemetry-context-1.47.0.jar.sha1 | 1 - .../licenses/opentelemetry-context-1.63.0.jar.sha1 | 1 + 6 files changed, 7 insertions(+), 4 deletions(-) delete mode 100644 plugins/repository-gcs/licenses/opentelemetry-api-1.47.0.jar.sha1 create mode 100644 plugins/repository-gcs/licenses/opentelemetry-api-1.63.0.jar.sha1 create mode 100644 plugins/repository-gcs/licenses/opentelemetry-common-1.63.0.jar.sha1 delete mode 100644 plugins/repository-gcs/licenses/opentelemetry-context-1.47.0.jar.sha1 create mode 100644 plugins/repository-gcs/licenses/opentelemetry-context-1.63.0.jar.sha1 diff --git a/plugins/repository-gcs/build.gradle b/plugins/repository-gcs/build.gradle index aefc9ed2a7829..1552852532c3a 100644 --- a/plugins/repository-gcs/build.gradle +++ b/plugins/repository-gcs/build.gradle @@ -90,8 +90,9 @@ dependencies { implementation "org.checkerframework:checker-qual:3.52.1" - runtimeOnly "io.opentelemetry:opentelemetry-api:1.47.0" - runtimeOnly "io.opentelemetry:opentelemetry-context:1.47.0" + runtimeOnly libs.opentelemetry.api + runtimeOnly libs.opentelemetry.common + runtimeOnly libs.opentelemetry.context runtimeOnly "com.google.api.grpc:proto-google-cloud-storage-v2:2.60.0" runtimeOnly "io.grpc:grpc-api:1.71.0" @@ -137,6 +138,7 @@ tasks.named("dependencyLicenses").configure { mapping from: /google-auth-.*/, to: 'google-auth' mapping from: /google-http-.*/, to: 'google-http' mapping from: /opencensus.*/, to: 'opencensus' + mapping from: /opentelemetry-common.*/, to: 'opentelemetry-api' mapping from: /protobuf.*/, to: 'protobuf' mapping from: /proto-google.*/, to: 'proto-google' } diff --git a/plugins/repository-gcs/licenses/opentelemetry-api-1.47.0.jar.sha1 b/plugins/repository-gcs/licenses/opentelemetry-api-1.47.0.jar.sha1 deleted file mode 100644 index 1806d8e42714a..0000000000000 --- a/plugins/repository-gcs/licenses/opentelemetry-api-1.47.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -9de168f2c648c33b86136f51a4584bde9a705ff1 \ No newline at end of file diff --git a/plugins/repository-gcs/licenses/opentelemetry-api-1.63.0.jar.sha1 b/plugins/repository-gcs/licenses/opentelemetry-api-1.63.0.jar.sha1 new file mode 100644 index 0000000000000..0f145e077247a --- /dev/null +++ b/plugins/repository-gcs/licenses/opentelemetry-api-1.63.0.jar.sha1 @@ -0,0 +1 @@ +39c923c0f236417ec8c4e2091f9e3032b4b6fb91 \ No newline at end of file diff --git a/plugins/repository-gcs/licenses/opentelemetry-common-1.63.0.jar.sha1 b/plugins/repository-gcs/licenses/opentelemetry-common-1.63.0.jar.sha1 new file mode 100644 index 0000000000000..5c57ec9f8ba92 --- /dev/null +++ b/plugins/repository-gcs/licenses/opentelemetry-common-1.63.0.jar.sha1 @@ -0,0 +1 @@ +450f8d552f33d51b19457d1336d8f7bdaec35e01 \ No newline at end of file diff --git a/plugins/repository-gcs/licenses/opentelemetry-context-1.47.0.jar.sha1 b/plugins/repository-gcs/licenses/opentelemetry-context-1.47.0.jar.sha1 deleted file mode 100644 index af4d69f26d333..0000000000000 --- a/plugins/repository-gcs/licenses/opentelemetry-context-1.47.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -86e49fe98ce06c279f7b9f028af8658cb7bc972a \ No newline at end of file diff --git a/plugins/repository-gcs/licenses/opentelemetry-context-1.63.0.jar.sha1 b/plugins/repository-gcs/licenses/opentelemetry-context-1.63.0.jar.sha1 new file mode 100644 index 0000000000000..0b6d3c50f42e3 --- /dev/null +++ b/plugins/repository-gcs/licenses/opentelemetry-context-1.63.0.jar.sha1 @@ -0,0 +1 @@ +4af6d513cedbf78dafe104f82f8dce7c7a205f07 \ No newline at end of file From a7f917927df00946b03ca762c609b11e08632aa5 Mon Sep 17 00:00:00 2001 From: opensearch-ci <83309141+opensearch-ci-bot@users.noreply.github.com> Date: Tue, 28 Jul 2026 20:12:35 -0400 Subject: [PATCH 03/11] Update OpenTelemetry to 1.64.0 and OpenTelemetry SemConv to 1.43.0 (#22591) (#22593) (cherry picked from commit 6056533e637cb043daeb54a29cb473ffbf488385) Signed-off-by: Andriy Redko Signed-off-by: opensearch-ci-bot Co-authored-by: Andriy Redko --- gradle/libs.versions.toml | 4 ++-- .../repository-gcs/licenses/opentelemetry-api-1.63.0.jar.sha1 | 1 - .../repository-gcs/licenses/opentelemetry-api-1.64.0.jar.sha1 | 1 + .../licenses/opentelemetry-common-1.63.0.jar.sha1 | 1 - .../licenses/opentelemetry-common-1.64.0.jar.sha1 | 1 + .../licenses/opentelemetry-context-1.63.0.jar.sha1 | 1 - .../licenses/opentelemetry-context-1.64.0.jar.sha1 | 1 + .../telemetry-otel/licenses/opentelemetry-api-1.63.0.jar.sha1 | 1 - .../telemetry-otel/licenses/opentelemetry-api-1.64.0.jar.sha1 | 1 + .../opentelemetry-api-incubator-1.63.0-alpha.jar.sha1 | 1 - .../opentelemetry-api-incubator-1.64.0-alpha.jar.sha1 | 1 + .../licenses/opentelemetry-common-1.63.0.jar.sha1 | 1 - .../licenses/opentelemetry-common-1.64.0.jar.sha1 | 1 + .../licenses/opentelemetry-context-1.63.0.jar.sha1 | 1 - .../licenses/opentelemetry-context-1.64.0.jar.sha1 | 1 + .../licenses/opentelemetry-exporter-common-1.63.0.jar.sha1 | 1 - .../licenses/opentelemetry-exporter-common-1.64.0.jar.sha1 | 1 + .../licenses/opentelemetry-exporter-logging-1.63.0.jar.sha1 | 1 - .../licenses/opentelemetry-exporter-logging-1.64.0.jar.sha1 | 1 + .../licenses/opentelemetry-exporter-otlp-1.63.0.jar.sha1 | 1 - .../licenses/opentelemetry-exporter-otlp-1.64.0.jar.sha1 | 1 + .../opentelemetry-exporter-otlp-common-1.63.0.jar.sha1 | 1 - .../opentelemetry-exporter-otlp-common-1.64.0.jar.sha1 | 1 + .../opentelemetry-exporter-sender-okhttp-1.63.0.jar.sha1 | 1 - .../opentelemetry-exporter-sender-okhttp-1.64.0.jar.sha1 | 1 + .../telemetry-otel/licenses/opentelemetry-sdk-1.63.0.jar.sha1 | 1 - .../telemetry-otel/licenses/opentelemetry-sdk-1.64.0.jar.sha1 | 1 + .../licenses/opentelemetry-sdk-common-1.63.0.jar.sha1 | 1 - .../licenses/opentelemetry-sdk-common-1.64.0.jar.sha1 | 1 + .../licenses/opentelemetry-sdk-logs-1.63.0.jar.sha1 | 1 - .../licenses/opentelemetry-sdk-logs-1.64.0.jar.sha1 | 1 + .../licenses/opentelemetry-sdk-metrics-1.63.0.jar.sha1 | 1 - .../licenses/opentelemetry-sdk-metrics-1.64.0.jar.sha1 | 1 + .../licenses/opentelemetry-sdk-trace-1.63.0.jar.sha1 | 1 - .../licenses/opentelemetry-sdk-trace-1.64.0.jar.sha1 | 1 + .../licenses/opentelemetry-semconv-1.41.0.jar.sha1 | 1 - .../licenses/opentelemetry-semconv-1.43.0.jar.sha1 | 1 + 37 files changed, 20 insertions(+), 20 deletions(-) delete mode 100644 plugins/repository-gcs/licenses/opentelemetry-api-1.63.0.jar.sha1 create mode 100644 plugins/repository-gcs/licenses/opentelemetry-api-1.64.0.jar.sha1 delete mode 100644 plugins/repository-gcs/licenses/opentelemetry-common-1.63.0.jar.sha1 create mode 100644 plugins/repository-gcs/licenses/opentelemetry-common-1.64.0.jar.sha1 delete mode 100644 plugins/repository-gcs/licenses/opentelemetry-context-1.63.0.jar.sha1 create mode 100644 plugins/repository-gcs/licenses/opentelemetry-context-1.64.0.jar.sha1 delete mode 100644 plugins/telemetry-otel/licenses/opentelemetry-api-1.63.0.jar.sha1 create mode 100644 plugins/telemetry-otel/licenses/opentelemetry-api-1.64.0.jar.sha1 delete mode 100644 plugins/telemetry-otel/licenses/opentelemetry-api-incubator-1.63.0-alpha.jar.sha1 create mode 100644 plugins/telemetry-otel/licenses/opentelemetry-api-incubator-1.64.0-alpha.jar.sha1 delete mode 100644 plugins/telemetry-otel/licenses/opentelemetry-common-1.63.0.jar.sha1 create mode 100644 plugins/telemetry-otel/licenses/opentelemetry-common-1.64.0.jar.sha1 delete mode 100644 plugins/telemetry-otel/licenses/opentelemetry-context-1.63.0.jar.sha1 create mode 100644 plugins/telemetry-otel/licenses/opentelemetry-context-1.64.0.jar.sha1 delete mode 100644 plugins/telemetry-otel/licenses/opentelemetry-exporter-common-1.63.0.jar.sha1 create mode 100644 plugins/telemetry-otel/licenses/opentelemetry-exporter-common-1.64.0.jar.sha1 delete mode 100644 plugins/telemetry-otel/licenses/opentelemetry-exporter-logging-1.63.0.jar.sha1 create mode 100644 plugins/telemetry-otel/licenses/opentelemetry-exporter-logging-1.64.0.jar.sha1 delete mode 100644 plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-1.63.0.jar.sha1 create mode 100644 plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-1.64.0.jar.sha1 delete mode 100644 plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-common-1.63.0.jar.sha1 create mode 100644 plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-common-1.64.0.jar.sha1 delete mode 100644 plugins/telemetry-otel/licenses/opentelemetry-exporter-sender-okhttp-1.63.0.jar.sha1 create mode 100644 plugins/telemetry-otel/licenses/opentelemetry-exporter-sender-okhttp-1.64.0.jar.sha1 delete mode 100644 plugins/telemetry-otel/licenses/opentelemetry-sdk-1.63.0.jar.sha1 create mode 100644 plugins/telemetry-otel/licenses/opentelemetry-sdk-1.64.0.jar.sha1 delete mode 100644 plugins/telemetry-otel/licenses/opentelemetry-sdk-common-1.63.0.jar.sha1 create mode 100644 plugins/telemetry-otel/licenses/opentelemetry-sdk-common-1.64.0.jar.sha1 delete mode 100644 plugins/telemetry-otel/licenses/opentelemetry-sdk-logs-1.63.0.jar.sha1 create mode 100644 plugins/telemetry-otel/licenses/opentelemetry-sdk-logs-1.64.0.jar.sha1 delete mode 100644 plugins/telemetry-otel/licenses/opentelemetry-sdk-metrics-1.63.0.jar.sha1 create mode 100644 plugins/telemetry-otel/licenses/opentelemetry-sdk-metrics-1.64.0.jar.sha1 delete mode 100644 plugins/telemetry-otel/licenses/opentelemetry-sdk-trace-1.63.0.jar.sha1 create mode 100644 plugins/telemetry-otel/licenses/opentelemetry-sdk-trace-1.64.0.jar.sha1 delete mode 100644 plugins/telemetry-otel/licenses/opentelemetry-semconv-1.41.0.jar.sha1 create mode 100644 plugins/telemetry-otel/licenses/opentelemetry-semconv-1.43.0.jar.sha1 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f769a478000f5..f31edcdc28e68 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -97,8 +97,8 @@ jzlib = "1.1.3" resteasy = "6.2.4.Final" # opentelemetry dependencies -opentelemetry = "1.63.0" -opentelemetrysemconv = "1.41.0" +opentelemetry = "1.64.0" +opentelemetrysemconv = "1.43.0" # arrow dependencies arrow = "18.1.0" diff --git a/plugins/repository-gcs/licenses/opentelemetry-api-1.63.0.jar.sha1 b/plugins/repository-gcs/licenses/opentelemetry-api-1.63.0.jar.sha1 deleted file mode 100644 index 0f145e077247a..0000000000000 --- a/plugins/repository-gcs/licenses/opentelemetry-api-1.63.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -39c923c0f236417ec8c4e2091f9e3032b4b6fb91 \ No newline at end of file diff --git a/plugins/repository-gcs/licenses/opentelemetry-api-1.64.0.jar.sha1 b/plugins/repository-gcs/licenses/opentelemetry-api-1.64.0.jar.sha1 new file mode 100644 index 0000000000000..a8786d2d4116c --- /dev/null +++ b/plugins/repository-gcs/licenses/opentelemetry-api-1.64.0.jar.sha1 @@ -0,0 +1 @@ +35d317f2526758575613f4b148b8c70241f7f175 \ No newline at end of file diff --git a/plugins/repository-gcs/licenses/opentelemetry-common-1.63.0.jar.sha1 b/plugins/repository-gcs/licenses/opentelemetry-common-1.63.0.jar.sha1 deleted file mode 100644 index 5c57ec9f8ba92..0000000000000 --- a/plugins/repository-gcs/licenses/opentelemetry-common-1.63.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -450f8d552f33d51b19457d1336d8f7bdaec35e01 \ No newline at end of file diff --git a/plugins/repository-gcs/licenses/opentelemetry-common-1.64.0.jar.sha1 b/plugins/repository-gcs/licenses/opentelemetry-common-1.64.0.jar.sha1 new file mode 100644 index 0000000000000..957db4d1e3d02 --- /dev/null +++ b/plugins/repository-gcs/licenses/opentelemetry-common-1.64.0.jar.sha1 @@ -0,0 +1 @@ +baae45914b5c233d8da972fc9d4a3ad811322ed8 \ No newline at end of file diff --git a/plugins/repository-gcs/licenses/opentelemetry-context-1.63.0.jar.sha1 b/plugins/repository-gcs/licenses/opentelemetry-context-1.63.0.jar.sha1 deleted file mode 100644 index 0b6d3c50f42e3..0000000000000 --- a/plugins/repository-gcs/licenses/opentelemetry-context-1.63.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -4af6d513cedbf78dafe104f82f8dce7c7a205f07 \ No newline at end of file diff --git a/plugins/repository-gcs/licenses/opentelemetry-context-1.64.0.jar.sha1 b/plugins/repository-gcs/licenses/opentelemetry-context-1.64.0.jar.sha1 new file mode 100644 index 0000000000000..e93080c81974d --- /dev/null +++ b/plugins/repository-gcs/licenses/opentelemetry-context-1.64.0.jar.sha1 @@ -0,0 +1 @@ +04f60a721d458642983d4df7bd7d179287919dd0 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-api-1.63.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-api-1.63.0.jar.sha1 deleted file mode 100644 index 0f145e077247a..0000000000000 --- a/plugins/telemetry-otel/licenses/opentelemetry-api-1.63.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -39c923c0f236417ec8c4e2091f9e3032b4b6fb91 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-api-1.64.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-api-1.64.0.jar.sha1 new file mode 100644 index 0000000000000..a8786d2d4116c --- /dev/null +++ b/plugins/telemetry-otel/licenses/opentelemetry-api-1.64.0.jar.sha1 @@ -0,0 +1 @@ +35d317f2526758575613f4b148b8c70241f7f175 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-api-incubator-1.63.0-alpha.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-api-incubator-1.63.0-alpha.jar.sha1 deleted file mode 100644 index aa0966ff936aa..0000000000000 --- a/plugins/telemetry-otel/licenses/opentelemetry-api-incubator-1.63.0-alpha.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -2a88356ec37eb66666dc6798e4221b26af74e24d \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-api-incubator-1.64.0-alpha.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-api-incubator-1.64.0-alpha.jar.sha1 new file mode 100644 index 0000000000000..8b397e5e0a787 --- /dev/null +++ b/plugins/telemetry-otel/licenses/opentelemetry-api-incubator-1.64.0-alpha.jar.sha1 @@ -0,0 +1 @@ +79cbdcb115c92d8c29c757659abf680419350590 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-common-1.63.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-common-1.63.0.jar.sha1 deleted file mode 100644 index 5c57ec9f8ba92..0000000000000 --- a/plugins/telemetry-otel/licenses/opentelemetry-common-1.63.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -450f8d552f33d51b19457d1336d8f7bdaec35e01 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-common-1.64.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-common-1.64.0.jar.sha1 new file mode 100644 index 0000000000000..957db4d1e3d02 --- /dev/null +++ b/plugins/telemetry-otel/licenses/opentelemetry-common-1.64.0.jar.sha1 @@ -0,0 +1 @@ +baae45914b5c233d8da972fc9d4a3ad811322ed8 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-context-1.63.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-context-1.63.0.jar.sha1 deleted file mode 100644 index 0b6d3c50f42e3..0000000000000 --- a/plugins/telemetry-otel/licenses/opentelemetry-context-1.63.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -4af6d513cedbf78dafe104f82f8dce7c7a205f07 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-context-1.64.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-context-1.64.0.jar.sha1 new file mode 100644 index 0000000000000..e93080c81974d --- /dev/null +++ b/plugins/telemetry-otel/licenses/opentelemetry-context-1.64.0.jar.sha1 @@ -0,0 +1 @@ +04f60a721d458642983d4df7bd7d179287919dd0 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-common-1.63.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-common-1.63.0.jar.sha1 deleted file mode 100644 index 20fd2fafeff60..0000000000000 --- a/plugins/telemetry-otel/licenses/opentelemetry-exporter-common-1.63.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -75e2658228eb885770b894f71e8d145d46095fdf \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-common-1.64.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-common-1.64.0.jar.sha1 new file mode 100644 index 0000000000000..36fc1ce0c3e3d --- /dev/null +++ b/plugins/telemetry-otel/licenses/opentelemetry-exporter-common-1.64.0.jar.sha1 @@ -0,0 +1 @@ +ee714eb3ac9ed82d3370bc8fd2f44216f19268dd \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-logging-1.63.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-logging-1.63.0.jar.sha1 deleted file mode 100644 index aaaef68da4186..0000000000000 --- a/plugins/telemetry-otel/licenses/opentelemetry-exporter-logging-1.63.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -0a5f203ebd35f1ff54171a01335d1a47c3600523 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-logging-1.64.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-logging-1.64.0.jar.sha1 new file mode 100644 index 0000000000000..b4a712b8698f3 --- /dev/null +++ b/plugins/telemetry-otel/licenses/opentelemetry-exporter-logging-1.64.0.jar.sha1 @@ -0,0 +1 @@ +596108744459e001f71346e948f8c97dfec38f30 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-1.63.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-1.63.0.jar.sha1 deleted file mode 100644 index 6b5d64d4dfe72..0000000000000 --- a/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-1.63.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -7f02be0f4f2c44476e957bce9d7f7d3e0a1a7ae4 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-1.64.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-1.64.0.jar.sha1 new file mode 100644 index 0000000000000..79de020e73491 --- /dev/null +++ b/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-1.64.0.jar.sha1 @@ -0,0 +1 @@ +84faa1ae0b301e7edce18aabd49a50034f5d2b02 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-common-1.63.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-common-1.63.0.jar.sha1 deleted file mode 100644 index e1adbf694257b..0000000000000 --- a/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-common-1.63.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -d6a9a75d3e4b9f69a67c3a333162a3b0783178c0 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-common-1.64.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-common-1.64.0.jar.sha1 new file mode 100644 index 0000000000000..9a2e24dcc917f --- /dev/null +++ b/plugins/telemetry-otel/licenses/opentelemetry-exporter-otlp-common-1.64.0.jar.sha1 @@ -0,0 +1 @@ +acb771790bdfe839188bf00cf2316987f57f8f5c \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-sender-okhttp-1.63.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-sender-okhttp-1.63.0.jar.sha1 deleted file mode 100644 index 71c90cfe4405d..0000000000000 --- a/plugins/telemetry-otel/licenses/opentelemetry-exporter-sender-okhttp-1.63.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -2045d90ed21954e0f61e900d168034e17711c7e9 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-exporter-sender-okhttp-1.64.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-exporter-sender-okhttp-1.64.0.jar.sha1 new file mode 100644 index 0000000000000..e40628415499e --- /dev/null +++ b/plugins/telemetry-otel/licenses/opentelemetry-exporter-sender-okhttp-1.64.0.jar.sha1 @@ -0,0 +1 @@ +8223a30d3c26e6a89e7429ba297a4a91ced3e12d \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-1.63.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-1.63.0.jar.sha1 deleted file mode 100644 index 5cc2625880df0..0000000000000 --- a/plugins/telemetry-otel/licenses/opentelemetry-sdk-1.63.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -1d522dcf3fb4903c7f95835c3f6f631cf1c3824b \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-1.64.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-1.64.0.jar.sha1 new file mode 100644 index 0000000000000..272ef8d92f62b --- /dev/null +++ b/plugins/telemetry-otel/licenses/opentelemetry-sdk-1.64.0.jar.sha1 @@ -0,0 +1 @@ +99a22fc6efb8e15c6ad489d7f018e425624118b3 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-common-1.63.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-common-1.63.0.jar.sha1 deleted file mode 100644 index c4a8a431030c5..0000000000000 --- a/plugins/telemetry-otel/licenses/opentelemetry-sdk-common-1.63.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -db2ec1f09c307adcf015bb8a87dd687eefa32e77 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-common-1.64.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-common-1.64.0.jar.sha1 new file mode 100644 index 0000000000000..0c88aa3677ece --- /dev/null +++ b/plugins/telemetry-otel/licenses/opentelemetry-sdk-common-1.64.0.jar.sha1 @@ -0,0 +1 @@ +0d8dee45c2ae69ca69a93f3d0649f014b6316d9b \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-logs-1.63.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-logs-1.63.0.jar.sha1 deleted file mode 100644 index dfdc2f6853b85..0000000000000 --- a/plugins/telemetry-otel/licenses/opentelemetry-sdk-logs-1.63.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -ef1e93dc6e05d2b9191d7fb9449fea8965086acb \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-logs-1.64.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-logs-1.64.0.jar.sha1 new file mode 100644 index 0000000000000..9a6b4f24abec0 --- /dev/null +++ b/plugins/telemetry-otel/licenses/opentelemetry-sdk-logs-1.64.0.jar.sha1 @@ -0,0 +1 @@ +547b4b277c2f56dc02f7b84bbb066ba03691cf74 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-metrics-1.63.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-metrics-1.63.0.jar.sha1 deleted file mode 100644 index 2db28d76c8a47..0000000000000 --- a/plugins/telemetry-otel/licenses/opentelemetry-sdk-metrics-1.63.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -decbaf0de6dbe8156aa426ddc85b5b38354a236b \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-metrics-1.64.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-metrics-1.64.0.jar.sha1 new file mode 100644 index 0000000000000..64e87e8620f3c --- /dev/null +++ b/plugins/telemetry-otel/licenses/opentelemetry-sdk-metrics-1.64.0.jar.sha1 @@ -0,0 +1 @@ +2ddb240acc63a50666002d3e3ea62e44cd71c68a \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-trace-1.63.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-trace-1.63.0.jar.sha1 deleted file mode 100644 index 0ee645084e84b..0000000000000 --- a/plugins/telemetry-otel/licenses/opentelemetry-sdk-trace-1.63.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -5c948707623a0dbd79105eb29461f42bfe0db11b \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-sdk-trace-1.64.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-sdk-trace-1.64.0.jar.sha1 new file mode 100644 index 0000000000000..ab6d47101f6f9 --- /dev/null +++ b/plugins/telemetry-otel/licenses/opentelemetry-sdk-trace-1.64.0.jar.sha1 @@ -0,0 +1 @@ +560505af9ea6aad3b29bb2de2f8912cea18d670a \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-semconv-1.41.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-semconv-1.41.0.jar.sha1 deleted file mode 100644 index 1d54e026636d9..0000000000000 --- a/plugins/telemetry-otel/licenses/opentelemetry-semconv-1.41.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -bb726d13dbdf41d18560a82f2266a2f07f6114e2 \ No newline at end of file diff --git a/plugins/telemetry-otel/licenses/opentelemetry-semconv-1.43.0.jar.sha1 b/plugins/telemetry-otel/licenses/opentelemetry-semconv-1.43.0.jar.sha1 new file mode 100644 index 0000000000000..52969673d9bd2 --- /dev/null +++ b/plugins/telemetry-otel/licenses/opentelemetry-semconv-1.43.0.jar.sha1 @@ -0,0 +1 @@ +a452c4166bda1a51a9792fbd0f459556143c2ae4 \ No newline at end of file From ef4d890de0fc6c5a3035a74a8e0fb1b6a6b91d2a Mon Sep 17 00:00:00 2001 From: opensearch-ci <83309141+opensearch-ci-bot@users.noreply.github.com> Date: Wed, 29 Jul 2026 11:50:10 -0400 Subject: [PATCH 04/11] Update bundled JDK to 25.0.4+7 (#22574) (#22600) (cherry picked from commit 564ce01bf8054682de6b467340ebed568fc24754) Signed-off-by: Andriy Redko Signed-off-by: opensearch-ci-bot Co-authored-by: Andriy Redko --- .../java/org/opensearch/gradle/test/DistroTestPlugin.java | 4 ++-- gradle/libs.versions.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/buildSrc/src/main/java/org/opensearch/gradle/test/DistroTestPlugin.java b/buildSrc/src/main/java/org/opensearch/gradle/test/DistroTestPlugin.java index d2ed84147ae72..a3f24845fc222 100644 --- a/buildSrc/src/main/java/org/opensearch/gradle/test/DistroTestPlugin.java +++ b/buildSrc/src/main/java/org/opensearch/gradle/test/DistroTestPlugin.java @@ -77,9 +77,9 @@ import java.util.stream.Stream; public class DistroTestPlugin implements Plugin { - private static final String SYSTEM_JDK_VERSION = "25.0.3+9"; + private static final String SYSTEM_JDK_VERSION = "25.0.4+7"; private static final String SYSTEM_JDK_VENDOR = "adoptium"; - private static final String GRADLE_JDK_VERSION = "25.0.3+9"; + private static final String GRADLE_JDK_VERSION = "25.0.4+7"; private static final String GRADLE_JDK_VENDOR = "adoptium"; // all distributions used by distro tests. this is temporary until tests are per distribution diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f31edcdc28e68..3bf10a02cedfb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ opensearch = "3.8.0" lucene = "10.5.0" bundled_jdk_vendor = "adoptium" -bundled_jdk = "25.0.3+9" +bundled_jdk = "25.0.4+7" # optional dependencies spatial4j = "0.7" From 52bcd297962e6e01950a456e4d84a0e0cc7667bc Mon Sep 17 00:00:00 2001 From: opensearch-ci <83309141+opensearch-ci-bot@users.noreply.github.com> Date: Wed, 29 Jul 2026 16:08:18 -0400 Subject: [PATCH 05/11] [AUTO] Add release notes for 3.8.0 (#22540) (#22606) (cherry picked from commit 46871ff38d61c09c9efa00536a0061536636e3c8) Signed-off-by: opensearch-ci-bot --- .../opensearch.release-notes-3.8.0.md | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 release-notes/opensearch.release-notes-3.8.0.md diff --git a/release-notes/opensearch.release-notes-3.8.0.md b/release-notes/opensearch.release-notes-3.8.0.md new file mode 100644 index 0000000000000..1277afe4f76d6 --- /dev/null +++ b/release-notes/opensearch.release-notes-3.8.0.md @@ -0,0 +1,75 @@ +## Version 3.8.0 Release Notes + +Compatible with OpenSearch and OpenSearch Dashboards version 3.8.0 + +### Features + +* Add API to modify a data stream's backing indices (`POST /_data_stream/_modify`) ([#22487](https://github.com/opensearch-project/OpenSearch/pull/22487)) +* Add `multivalue_doc_count` aggregation that returns the number of documents with two or more values ([#20472](https://github.com/opensearch-project/OpenSearch/pull/20472)) +* Add pull-based ingestion from Hive tables via new `ingestion-hive` plugin ([#21700](https://github.com/opensearch-project/OpenSearch/pull/21700)) +* Add support for HTTP/3 on the client side via JDK HttpClient ([#21718](https://github.com/opensearch-project/OpenSearch/pull/21718)) +* Add gRPC support for Point-in-Time (PIT) create and delete operations ([#22105](https://github.com/opensearch-project/OpenSearch/pull/22105)) +* Add gRPC API support for `extra_field_values` in bulk requests ([#21907](https://github.com/opensearch-project/OpenSearch/pull/21907)) +* Add cross-cluster streaming support to the remote cluster client via Arrow Flight ([#22359](https://github.com/opensearch-project/OpenSearch/pull/22359)) +* Add coordinator-side index-level field domain pruning before `can_match` for faster time-range queries ([#21865](https://github.com/opensearch-project/OpenSearch/pull/21865)) +* Add bulkscorer script processing interface in ScriptScore query for bulk scoring optimizations ([#22423](https://github.com/opensearch-project/OpenSearch/pull/22423)) +* Add process-wide ObjectInputFilter to reject Java deserialization by default, gated behind `bootstrap.serial_filter` setting ([#22073](https://github.com/opensearch-project/OpenSearch/pull/22073)) +* Add cluster-level default setting for delayed shard allocation timeout (`cluster.routing.allocation.unassigned.node_left.delayed_timeout`) ([#22379](https://github.com/opensearch-project/OpenSearch/pull/22379)) + +### Enhancements + +* Add HTTP request body decompression (gzip/deflate) to reactor-netty4 transport ([#22382](https://github.com/opensearch-project/OpenSearch/pull/22382)) +* Add cross-setting validator to prevent cluster-manager crash loop when both balance factors are set to zero ([#22391](https://github.com/opensearch-project/OpenSearch/pull/22391)) +* Add support for double, int, and long types in ExtraFieldValue for gRPC bulk indexing ([#22058](https://github.com/opensearch-project/OpenSearch/pull/22058)) +* Add timing logs for repository create, update, and delete operations ([#22489](https://github.com/opensearch-project/OpenSearch/pull/22489)) +* Add parent action name to `ProcessorGenerationContext` for conditional system-generated processor logic ([#22195](https://github.com/opensearch-project/OpenSearch/pull/22195)) +* Add getter for remote translog transfer tracker to enable plugin access to tracking metrics ([#22453](https://github.com/opensearch-project/OpenSearch/pull/22453)) +* Deprecate `RestClient` in favor of the internal HTTP client ([#22116](https://github.com/opensearch-project/OpenSearch/pull/22116)) +* Disable Mustache partial template resolution in search templates ([#22438](https://github.com/opensearch-project/OpenSearch/pull/22438)) +* Use binary serialization for resource usage headers to reduce CPU overhead on the search path ([#21230](https://github.com/opensearch-project/OpenSearch/pull/21230)) +* Preserve resolved search pipeline id and inline pipeline source through query rewrite ([#22501](https://github.com/opensearch-project/OpenSearch/pull/22501)) +* Fork `GET _aliases` serialization to MANAGEMENT thread pool to avoid blocking transport threads ([#21954](https://github.com/opensearch-project/OpenSearch/pull/21954)) +* Strengthen `scroll_id` validation to prevent OOM from crafted scroll IDs ([#22396](https://github.com/opensearch-project/OpenSearch/pull/22396)) +* Add depth tracking to recursive deserialization to prevent StackOverflowError ([#22404](https://github.com/opensearch-project/OpenSearch/pull/22404)) +* Validate `base_path` in FsRepository to prevent path traversal outside `path.repo` ([#22328](https://github.com/opensearch-project/OpenSearch/pull/22328)) +* Add path boundary validation in `resolveAnalyzerPath` to prevent directory traversal ([#22094](https://github.com/opensearch-project/OpenSearch/pull/22094)) +* Register snapshot resilience settings (`snapshot.repository.io_timeout`, `max_outstanding_ops`, `cleanup_stale_blobs`) ([#22516](https://github.com/opensearch-project/OpenSearch/pull/22516)) +* Wire `request_timeout` into S3 sync client to prevent indefinite hangs on degraded stores ([#22479](https://github.com/opensearch-project/OpenSearch/pull/22479)) +* Separate internal ignore settings from user ignore settings during snapshot restore ([#20494](https://github.com/opensearch-project/OpenSearch/pull/20494)) +* Validate `total_primary_shards_per_node` on index templates against the cluster instead of index-local flag ([#22203](https://github.com/opensearch-project/OpenSearch/pull/22203)) +* Rollover `checkBlock` now scoped to write index only, skipping non-write alias members ([#21838](https://github.com/opensearch-project/OpenSearch/pull/21838)) + +### Bug Fixes + +* Fix `OpenSearchTimeoutException` to return HTTP 504 instead of 500 ([#22064](https://github.com/opensearch-project/OpenSearch/pull/22064)) +* Fix `ClassCastException` on malformed mappings in create index to return 400 instead of 500 ([#22371](https://github.com/opensearch-project/OpenSearch/pull/22371)) +* Fix NPE for search-only indices without primaries in cluster allocation explain and bulk shard selection ([#22097](https://github.com/opensearch-project/OpenSearch/pull/22097)) +* Fix NPE in S3 multipart upload when `provideStream()` throws, and fix shared segment array corruption ([#22309](https://github.com/opensearch-project/OpenSearch/pull/22309)) +* Fix `ReplicationCheckpoint.compareTo` to return 0 for equal checkpoints, preventing TimSort crash during shard allocation ([#22376](https://github.com/opensearch-project/OpenSearch/pull/22376)) +* Fix negative `os.cpu.percent` on cgroup v2 containers by granting read access to `/sys/fs/cgroup/cpu.stat` ([#22408](https://github.com/opensearch-project/OpenSearch/pull/22408)) +* Fix snapshot listing failing on repositories containing legacy Elasticsearch snapshots ([#22193](https://github.com/opensearch-project/OpenSearch/pull/22193)) +* Fix default SSE type to send `AES256` header, preventing silent snapshot failures on buckets requiring encryption ([#22144](https://github.com/opensearch-project/OpenSearch/pull/22144)) +* Fix default replica count resolution from node settings (`opensearch.yml`) ([#22334](https://github.com/opensearch-project/OpenSearch/pull/22334)) +* Fix `filter` rewrite crash with sub-aggregations in `date_histogram` when segment contains out-of-range documents ([#22390](https://github.com/opensearch-project/OpenSearch/pull/22390)) +* Fix V1 template merge regression that broke dynamic object inheritance for dotted field paths ([#22515](https://github.com/opensearch-project/OpenSearch/pull/22515)) +* Fix `disable_objects` array parsing to preserve dotted field names ([#22127](https://github.com/opensearch-project/OpenSearch/pull/22127)) +* Fix field resolution for dotted fields under `disable_objects` ([#21929](https://github.com/opensearch-project/OpenSearch/pull/21929)) +* Fix `NestedQueryBuilder.visit()` to recursively visit child query tree ([#22196](https://github.com/opensearch-project/OpenSearch/pull/22196)) +* Fix `InputStream` leak when loading hyphenation patterns in analysis-common ([#22508](https://github.com/opensearch-project/OpenSearch/pull/22508)) +* Fix `_cat/nodes` API showing negative values in cpu stats when perf counters are unavailable ([#22074](https://github.com/opensearch-project/OpenSearch/pull/22074)) +* Fix global ordinals to properly trip fielddata circuit breaker ([#22129](https://github.com/opensearch-project/OpenSearch/pull/22129)) +* Restore default max nesting depth to 1000 and decouple stream depth limit from XContent limit ([#22486](https://github.com/opensearch-project/OpenSearch/pull/22486)) +* Fix unbounded recursion in deserialization that can cause StackOverflowError ([#22404](https://github.com/opensearch-project/OpenSearch/pull/22404)) + +### Maintenance + +* Bump `bc-fips` to 2.1.3 to fix CVE-2026-8149 ([#22537](https://github.com/opensearch-project/OpenSearch/pull/22537)) +* Upgrade Jackson 2 to 2.22.1 to resolve CVE-2026-54515 ([#22476](https://github.com/opensearch-project/OpenSearch/pull/22476)) +* Bump Hadoop from 3.4.2 to 3.5.0 to resolve CVE-2026-2332 ([#22362](https://github.com/opensearch-project/OpenSearch/pull/22362)) +* Update Jackson to 3.2.1 ([#22497](https://github.com/opensearch-project/OpenSearch/pull/22497)) +* Update Netty to 4.2.16.Final ([#22403](https://github.com/opensearch-project/OpenSearch/pull/22403)) +* Update OpenTelemetry to 1.63.0 ([#22111](https://github.com/opensearch-project/OpenSearch/pull/22111)) +* Update Project Reactor to 3.8.6 and Reactor Netty to 1.3.6 ([#22059](https://github.com/opensearch-project/OpenSearch/pull/22059)) +* Upgrade Lucene to 10.5.0 ([#22322](https://github.com/opensearch-project/OpenSearch/pull/22322)) +* Accommodate JDK-26 related changes with respect to HttpClient behavior ([#22386](https://github.com/opensearch-project/OpenSearch/pull/22386)) +* Remove `OpenSearchYamlFactory` / `OpenSearchYamlParser` after Jackson 3.2.0 update ([#22147](https://github.com/opensearch-project/OpenSearch/pull/22147)) From e5a3c5691be87af6c12dbe3e158c59c04ee72973 Mon Sep 17 00:00:00 2001 From: opensearch-ci <83309141+opensearch-ci-bot@users.noreply.github.com> Date: Fri, 31 Jul 2026 16:46:07 -0400 Subject: [PATCH 06/11] Add ci.opensearch.org/m2/ mirror for plugin resolution (#22612) (#22621) (cherry picked from commit 20ba4aa8c89b5077c23a76394be3c682174d7460) Signed-off-by: Peter Zhu Signed-off-by: opensearch-ci-bot Co-authored-by: Peter Zhu --- buildSrc/build.gradle | 6 ++++++ .../java/org/opensearch/gradle/RepositoriesSetupPlugin.java | 5 +++++ gradle/code-coverage.gradle | 6 ++++++ gradle/ide.gradle | 3 +++ settings.gradle | 6 ++++++ 5 files changed, 26 insertions(+) diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 82d374fbca5b6..d1cb9276e60b9 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -100,6 +100,12 @@ repositories { excludeGroupByRegex "adoptium.*|adoptopenjdk.*|openjdk.*" } } + maven { + url = uri("https://ci.opensearch.org/m2/") + content { + excludeGroupByRegex "adoptium.*|adoptopenjdk.*|openjdk.*" + } + } mavenCentral { content { excludeGroupByRegex "adoptium.*|adoptopenjdk.*|openjdk.*" diff --git a/buildSrc/src/main/java/org/opensearch/gradle/RepositoriesSetupPlugin.java b/buildSrc/src/main/java/org/opensearch/gradle/RepositoriesSetupPlugin.java index e2a57969bc299..c41a9774d132a 100644 --- a/buildSrc/src/main/java/org/opensearch/gradle/RepositoriesSetupPlugin.java +++ b/buildSrc/src/main/java/org/opensearch/gradle/RepositoriesSetupPlugin.java @@ -87,6 +87,11 @@ public static void configureRepositories(Project project) { repo.setUrl("https://ci.opensearch.org/maven2/"); repo.content(descriptor -> descriptor.excludeGroupByRegex("adoptium.*|adoptopenjdk.*|openjdk.*")); }); + repos.maven(repo -> { + repo.setName("Plugin Mirror"); + repo.setUrl("https://ci.opensearch.org/m2/"); + repo.content(descriptor -> descriptor.excludeGroupByRegex("adoptium.*|adoptopenjdk.*|openjdk.*")); + }); repos.mavenCentral(repo -> { repo.content(descriptor -> descriptor.excludeGroupByRegex("adoptium.*|adoptopenjdk.*|openjdk.*")); }); String luceneVersion = VersionProperties.getLucene(); diff --git a/gradle/code-coverage.gradle b/gradle/code-coverage.gradle index 1851b1c4eb68f..24e43630894f0 100644 --- a/gradle/code-coverage.gradle +++ b/gradle/code-coverage.gradle @@ -15,6 +15,12 @@ repositories { excludeGroupByRegex "adoptium.*|adoptopenjdk.*|openjdk.*" } } + maven { + url = uri("https://ci.opensearch.org/m2/") + content { + excludeGroupByRegex "adoptium.*|adoptopenjdk.*|openjdk.*" + } + } mavenCentral { content { excludeGroupByRegex "adoptium.*|adoptopenjdk.*|openjdk.*" diff --git a/gradle/ide.gradle b/gradle/ide.gradle index 01b4f4d02af98..acd666ef58700 100644 --- a/gradle/ide.gradle +++ b/gradle/ide.gradle @@ -20,6 +20,9 @@ buildscript { maven { url = "https://ci.opensearch.org/maven2/" } + maven { + url = "https://ci.opensearch.org/m2/" + } maven { url = "https://plugins.gradle.org/m2/" } diff --git a/settings.gradle b/settings.gradle index 2d4b3d4db6755..31ad457f5ff43 100644 --- a/settings.gradle +++ b/settings.gradle @@ -17,6 +17,12 @@ pluginManagement { excludeGroupByRegex "adoptium.*|adoptopenjdk.*|openjdk.*" } } + maven { + url = uri("https://ci.opensearch.org/m2/") + content { + excludeGroupByRegex "adoptium.*|adoptopenjdk.*|openjdk.*" + } + } gradlePluginPortal { content { excludeGroupByRegex "adoptium.*|adoptopenjdk.*|openjdk.*" From bc8c743a6d0dc77ede653cf4779d29556a8f4963 Mon Sep 17 00:00:00 2001 From: Peter Ossian Date: Fri, 14 Aug 2026 15:08:24 -0700 Subject: [PATCH 07/11] fix search replica routing --- .../vsco-publish-opensearch-image.yaml | 136 ++++++++++++++++++ .../routing/IndexShardRoutingTable.java | 28 +++- .../routing/IndexShardRoutingTableTests.java | 80 +++++++++++ 3 files changed, 237 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/vsco-publish-opensearch-image.yaml diff --git a/.github/workflows/vsco-publish-opensearch-image.yaml b/.github/workflows/vsco-publish-opensearch-image.yaml new file mode 100644 index 0000000000000..6b8293d903337 --- /dev/null +++ b/.github/workflows/vsco-publish-opensearch-image.yaml @@ -0,0 +1,136 @@ +# ============================================================================= +# VSCO FORK ONLY — REMOVE BEFORE OPENING A PR TO opensearch-project/OpenSearch +# +# Builds the core OpenSearch Docker image from this fork and pushes ONLY to: +# ghcr.io/vsco/opensearch: +# +# Tag convention matches official OpenSearch releases with a VSCO suffix, e.g.: +# 3.8.0-vsco1 +# (same pattern as ome: 0.1.5-vsco7) +# +# Usage: +# Actions → "VSCO (fork) publish OpenSearch image to ghcr.io/vsco" → Run workflow +# Default image_tag: 3.8.0-vsco1 +# +# Auth: GITHUB_TOKEN usually works for packages:write in the vsco org. +# If pushes fail with 403, add repo secret VSCO_GHCR_TOKEN (PAT with +# write:packages). +# +# Note: this builds the in-repo core/min image via Gradle +# (:distribution:docker:buildDockerImage), not the full Hub distro from +# opensearch-build. Point the OpenSearch operator / Helm values at +# ghcr.io/vsco/opensearch:3.8.0-vsco1 after publishing. +# ============================================================================= + +name: VSCO (fork) publish OpenSearch image to ghcr.io/vsco + +on: + workflow_dispatch: + inputs: + image_tag: + description: 'Tag for ghcr.io/vsco/opensearch (e.g. 3.8.0-vsco1)' + required: true + default: '3.8.0-vsco1' + java_version: + description: 'JDK major version for the Gradle build' + required: true + default: '21' + +permissions: + contents: read + packages: write + +env: + REGISTRY: ghcr.io + IMAGE_ORG: vsco + IMAGE_NAME: opensearch + +jobs: + build-push-opensearch: + runs-on: self-hosted + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Install protoc + run: | + set -euo pipefail + if [ "$(uname -m)" = "x86_64" ]; then + curl -fsSL -X GET "https://github.com/protocolbuffers/protobuf/releases/download/v33.0/protoc-33.0-linux-x86_64.zip" -o protoc.zip + else + curl -fsSL -X GET "https://github.com/protocolbuffers/protobuf/releases/download/v33.0/protoc-33.0-linux-aarch_64.zip" -o protoc.zip + fi + sudo unzip -o protoc.zip -d /usr/local && rm -f protoc.zip + protoc --version + + - name: Set up JDK + uses: actions/setup-java@v5 + with: + java-version: ${{ inputs.java_version }} + distribution: temurin + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to ghcr.io (org vsco packages) + uses: docker/login-action@v4 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.VSCO_GHCR_TOKEN || secrets.GITHUB_TOKEN }} + + - name: Resolve upstream OpenSearch version + id: version + run: | + set -euo pipefail + # buildSrc/version.properties: opensearch = 3.8.0 + OS_VERSION="$(awk -F= '/^opensearch[[:space:]]*=/ { gsub(/[[:space:]]/, "", $2); print $2; exit }' buildSrc/version.properties)" + if [[ -z "${OS_VERSION}" ]]; then + echo "Could not read opensearch version from buildSrc/version.properties" >&2 + exit 1 + fi + echo "opensearch_version=${OS_VERSION}" >> "$GITHUB_OUTPUT" + echo "Building OpenSearch ${OS_VERSION}; publishing as ${{ inputs.image_tag }}" + + - name: Validate image tag matches base release + run: | + set -euo pipefail + TAG="${{ inputs.image_tag }}" + BASE="${{ steps.version.outputs.opensearch_version }}" + case "${TAG}" in + "${BASE}-vsco"*) ;; + *) + echo "image_tag '${TAG}' must start with '${BASE}-vsco' (e.g. ${BASE}-vsco1)" >&2 + exit 1 + ;; + esac + + - name: Build OpenSearch Docker image (Gradle) + run: | + set -euo pipefail + ./gradlew :distribution:docker:buildDockerImage --parallel --no-build-cache -PDISABLE_BUILD_CACHE + + - name: Retag and push to ghcr.io/vsco + run: | + set -euo pipefail + SRC="docker.opensearch.org/opensearch:${{ steps.version.outputs.opensearch_version }}" + DST="${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/${{ env.IMAGE_NAME }}:${{ inputs.image_tag }}" + if ! docker image inspect "${SRC}" >/dev/null 2>&1; then + # Fallback used by some Gradle builds + SRC="opensearch:test" + fi + docker tag "${SRC}" "${DST}" + docker push "${DST}" + echo "Pushed ${DST}" + + - name: Summary + run: | + { + echo "## VSCO OpenSearch image" + echo "" + echo "Upstream version (buildSrc): \`${{ steps.version.outputs.opensearch_version }}\`" + echo "Pushed: \`${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/${{ env.IMAGE_NAME }}:${{ inputs.image_tag }}\`" + echo "" + echo "Point the OpenSearch Helm/operator image to that tag." + echo "Remove \`.github/workflows/vsco-publish-opensearch-image.yaml\` before submitting a PR upstream." + } >> "$GITHUB_STEP_SUMMARY" diff --git a/server/src/main/java/org/opensearch/cluster/routing/IndexShardRoutingTable.java b/server/src/main/java/org/opensearch/cluster/routing/IndexShardRoutingTable.java index 2c5b8919f1c6a..39fd0c05811d4 100644 --- a/server/src/main/java/org/opensearch/cluster/routing/IndexShardRoutingTable.java +++ b/server/src/main/java/org/opensearch/cluster/routing/IndexShardRoutingTable.java @@ -702,15 +702,29 @@ public ShardIterator replicaFirstActiveInitializingShardsIt() { return new PlainShardIterator(shardId, ordered); } + /** + * Builds an ordered iterator over replicas matching {@code filter}. + *

+ * Eligible replicas are collected first, then rotated. Rotating the full + * replica list (including copies that fail the filter) before filtering + * biases which matching replica is preferred — for example with + * {@link #searchReplicaActiveInitializingShardIt()} when writable data + * replicas are present. Filtering first keeps selection fair among the + * eligible set only. + */ private ShardIterator filterAndOrderShards(Predicate filter) { - LinkedList ordered = new LinkedList<>(); - for (ShardRouting replica : shuffler.shuffle(replicas)) { + List matching = new ArrayList<>(); + for (ShardRouting replica : replicas) { if (filter.test(replica)) { - if (replica.active()) { - ordered.addFirst(replica); - } else if (replica.initializing()) { - ordered.addLast(replica); - } + matching.add(replica); + } + } + LinkedList ordered = new LinkedList<>(); + for (ShardRouting replica : shuffler.shuffle(matching)) { + if (replica.active()) { + ordered.addFirst(replica); + } else if (replica.initializing()) { + ordered.addLast(replica); } } return new PlainShardIterator(shardId, ordered); diff --git a/server/src/test/java/org/opensearch/cluster/routing/IndexShardRoutingTableTests.java b/server/src/test/java/org/opensearch/cluster/routing/IndexShardRoutingTableTests.java index 5f8dabdcd4e45..ce1f27ab57331 100644 --- a/server/src/test/java/org/opensearch/cluster/routing/IndexShardRoutingTableTests.java +++ b/server/src/test/java/org/opensearch/cluster/routing/IndexShardRoutingTableTests.java @@ -142,4 +142,84 @@ public void testShardsMatchingPredicate() { table.shardsMatchingPredicate(shardRouting -> !shardRouting.primary() && shardRouting.relocating()) ); } + + /** + * With writable data replicas present, search-replica preference must still + * pick fairly among search-only copies. Rotating the full replica list + * before filtering used to pin ~75% of first picks on one search copy. + */ + public void testSearchReplicaRoutingIsFairWhenWriterReplicasPresent() { + ShardId shardId = new ShardId(new Index("test", UUID.randomUUID().toString()), 0); + ShardRouting primary = TestShardRouting.newShardRouting(shardId, "data-0", true, ShardRoutingState.STARTED); + ShardRouting writer0 = TestShardRouting.newShardRouting(shardId, "data-1", false, ShardRoutingState.STARTED); + ShardRouting writer1 = TestShardRouting.newShardRouting(shardId, "data-2", false, ShardRoutingState.STARTED); + ShardRouting search0 = TestShardRouting.newShardRouting( + shardId, + "search-0", + null, + false, + true, + ShardRoutingState.STARTED, + null + ); + ShardRouting search1 = TestShardRouting.newShardRouting( + shardId, + "search-1", + null, + false, + true, + ShardRoutingState.STARTED, + null + ); + + IndexShardRoutingTable table = new IndexShardRoutingTable( + shardId, + Arrays.asList(primary, writer0, writer1, search0, search1) + ); + + int search0First = 0; + int search1First = 0; + final int iterations = 400; + for (int i = 0; i < iterations; i++) { + ShardRouting first = table.searchReplicaActiveInitializingShardIt().nextOrNull(); + assertNotNull(first); + assertTrue("expected a search replica, got " + first, first.isSearchOnly()); + if ("search-0".equals(first.currentNodeId())) { + search0First++; + } else if ("search-1".equals(first.currentNodeId())) { + search1First++; + } else { + fail("unexpected node " + first.currentNodeId()); + } + } + + assertEquals("only search replicas should be selected", iterations, search0First + search1First); + assertEquals("search-0 and search-1 must split first-picks evenly", search0First, search1First); + assertEquals(iterations / 2, search0First); + } + + public void testSearchReplicaRoutingIgnoresWriterReplicas() { + ShardId shardId = new ShardId(new Index("test", UUID.randomUUID().toString()), 0); + ShardRouting primary = TestShardRouting.newShardRouting(shardId, "data-0", true, ShardRoutingState.STARTED); + ShardRouting writer = TestShardRouting.newShardRouting(shardId, "data-1", false, ShardRoutingState.STARTED); + ShardRouting search = TestShardRouting.newShardRouting( + shardId, + "search-0", + null, + false, + true, + ShardRoutingState.STARTED, + null + ); + IndexShardRoutingTable table = new IndexShardRoutingTable(shardId, Arrays.asList(primary, writer, search)); + + for (int i = 0; i < 20; i++) { + ShardIterator it = table.searchReplicaActiveInitializingShardIt(); + assertEquals(1, it.size()); + ShardRouting first = it.nextOrNull(); + assertNotNull(first); + assertTrue(first.isSearchOnly()); + assertEquals("search-0", first.currentNodeId()); + } + } } From 95e7a48152b117357f730c8e086128ff2860cfba Mon Sep 17 00:00:00 2001 From: Peter Ossian Date: Fri, 14 Aug 2026 15:59:23 -0700 Subject: [PATCH 08/11] pull official java binaries from upstream as to not have to recompile them --- .../vsco-publish-opensearch-image.yaml | 132 ++++++++++++++---- 1 file changed, 108 insertions(+), 24 deletions(-) diff --git a/.github/workflows/vsco-publish-opensearch-image.yaml b/.github/workflows/vsco-publish-opensearch-image.yaml index 6b8293d903337..5db333fe3d614 100644 --- a/.github/workflows/vsco-publish-opensearch-image.yaml +++ b/.github/workflows/vsco-publish-opensearch-image.yaml @@ -1,25 +1,34 @@ # ============================================================================= # VSCO FORK ONLY — REMOVE BEFORE OPENING A PR TO opensearch-project/OpenSearch # -# Builds the core OpenSearch Docker image from this fork and pushes ONLY to: -# ghcr.io/vsco/opensearch: +# Publishes a patched OpenSearch image to: +# ghcr.io/vsco/opensearch: e.g. 3.8.0-vsco1 +# (same tag pattern as ome: 0.1.5-vsco7) # -# Tag convention matches official OpenSearch releases with a VSCO suffix, e.g.: -# 3.8.0-vsco1 -# (same pattern as ome: 0.1.5-vsco7) +# Approach: derive from the official opensearchproject/opensearch: +# image and replace only the core jar (lib/opensearch-.jar) built from +# this fork. +# +# Why not :distribution:docker:buildDockerImage — that Gradle task produces the +# *min* distribution: /usr/share/opensearch/plugins is empty, so there is no +# opensearch-security (the operator's HTTPS + basic-auth probes never pass) and +# no opensearch-knn. The Docker Hub image is assembled separately by +# opensearch-build and bundles ~26 plugins. It is also single-arch, built for +# whatever the runner happens to be. +# +# distribution/build.gradle puts `libs project(':server')` into lib/, so +# swapping opensearch-.jar is equivalent to rebuilding the +# distribution with this fork's patch — provided this fork stays at the +# tag plus core-only changes. The jar is pure bytecode, so one build +# serves every platform and buildx emits a real multi-arch manifest list off +# the official multi-arch base (no QEMU needed: the Dockerfile only COPYs). # # Usage: # Actions → "VSCO (fork) publish OpenSearch image to ghcr.io/vsco" → Run workflow -# Default image_tag: 3.8.0-vsco1 # # Auth: GITHUB_TOKEN usually works for packages:write in the vsco org. # If pushes fail with 403, add repo secret VSCO_GHCR_TOKEN (PAT with # write:packages). -# -# Note: this builds the in-repo core/min image via Gradle -# (:distribution:docker:buildDockerImage), not the full Hub distro from -# opensearch-build. Point the OpenSearch operator / Helm values at -# ghcr.io/vsco/opensearch:3.8.0-vsco1 after publishing. # ============================================================================= name: VSCO (fork) publish OpenSearch image to ghcr.io/vsco @@ -28,9 +37,9 @@ on: workflow_dispatch: inputs: image_tag: - description: 'Tag for ghcr.io/vsco/opensearch (e.g. 3.8.0-vsco1)' + description: 'Tag for ghcr.io/vsco/opensearch (e.g. 3.8.0-vsco2)' required: true - default: '3.8.0-vsco1' + default: '3.8.0-vsco2' java_version: description: 'JDK major version for the Gradle build' required: true @@ -44,6 +53,8 @@ env: REGISTRY: ghcr.io IMAGE_ORG: vsco IMAGE_NAME: opensearch + BASE_REPO: opensearchproject/opensearch + PLATFORMS: linux/amd64,linux/arm64 jobs: build-push-opensearch: @@ -105,30 +116,103 @@ jobs: ;; esac - - name: Build OpenSearch Docker image (Gradle) + - name: Verify fork is tag plus core-only changes run: | set -euo pipefail - ./gradlew :distribution:docker:buildDockerImage --parallel --no-build-cache -PDISABLE_BUILD_CACHE + BASE="${{ steps.version.outputs.opensearch_version }}" + git fetch --no-tags --depth=1 origin "refs/tags/${BASE}:refs/tags/${BASE}" + # Swapping only lib/opensearch-.jar is safe only while every + # change since the tag lands in :server (or is fork-only tooling). + CHANGED="$(git diff --name-only "refs/tags/${BASE}..HEAD" \ + | grep -v -E '^(server/|\.github/workflows/vsco-)' || true)" + if [[ -n "${CHANGED}" ]]; then + echo "Changes outside server/ since tag ${BASE}; a core-jar swap would silently drop them:" >&2 + echo "${CHANGED}" >&2 + exit 1 + fi + git diff --stat "refs/tags/${BASE}..HEAD" - - name: Retag and push to ghcr.io/vsco + - name: Build patched core jar (Gradle) run: | set -euo pipefail - SRC="docker.opensearch.org/opensearch:${{ steps.version.outputs.opensearch_version }}" - DST="${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/${{ env.IMAGE_NAME }}:${{ inputs.image_tag }}" - if ! docker image inspect "${SRC}" >/dev/null 2>&1; then - # Fallback used by some Gradle builds - SRC="opensearch:test" + ./gradlew :server:jar --parallel + + - name: Stage build context + id: stage + run: | + set -euo pipefail + OS_VERSION="${{ steps.version.outputs.opensearch_version }}" + JAR="server/build/libs/opensearch-${OS_VERSION}.jar" + if [[ ! -f "${JAR}" ]]; then + echo "Expected core jar at ${JAR}; found:" >&2 + ls -la server/build/libs/ >&2 || true + exit 1 fi - docker tag "${SRC}" "${DST}" - docker push "${DST}" + + rm -rf vsco-image && mkdir -p vsco-image + cp "${JAR}" vsco-image/opensearch-core.jar + + cat > vsco-image/Dockerfile <<'DOCKERFILE' + ARG BASE_IMAGE + FROM ${BASE_IMAGE} + ARG OS_VERSION + # Official image owns /usr/share/opensearch as opensearch(1000):root(0). + COPY --chown=1000:0 opensearch-core.jar /usr/share/opensearch/lib/opensearch-${OS_VERSION}.jar + DOCKERFILE + + ls -la vsco-image/ + + - name: Verify base image layout + run: | + set -euo pipefail + OS_VERSION="${{ steps.version.outputs.opensearch_version }}" + BASE_IMAGE="${{ env.BASE_REPO }}:${OS_VERSION}" + docker pull "${BASE_IMAGE}" + # Confirm the jar we are about to overwrite actually exists, and that + # the plugins we depend on are bundled. + docker run --rm -e "OS_VERSION=${OS_VERSION}" --entrypoint /bin/bash "${BASE_IMAGE}" -c ' + set -euo pipefail + test -f "/usr/share/opensearch/lib/opensearch-${OS_VERSION}.jar" + ls -d /usr/share/opensearch/plugins/opensearch-security + ls -d /usr/share/opensearch/plugins/opensearch-knn + echo "base image layout OK" + ' + + - name: Build and push multi-arch image + run: | + set -euo pipefail + OS_VERSION="${{ steps.version.outputs.opensearch_version }}" + DST="${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/${{ env.IMAGE_NAME }}:${{ inputs.image_tag }}" + docker buildx build \ + --platform "${{ env.PLATFORMS }}" \ + --build-arg "BASE_IMAGE=${{ env.BASE_REPO }}:${OS_VERSION}" \ + --build-arg "OS_VERSION=${OS_VERSION}" \ + --provenance=false \ + --tag "${DST}" \ + --push \ + vsco-image echo "Pushed ${DST}" + - name: Verify pushed manifest covers every platform + run: | + set -euo pipefail + DST="${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/${{ env.IMAGE_NAME }}:${{ inputs.image_tag }}" + docker buildx imagetools inspect "${DST}" + for platform in $(echo "${{ env.PLATFORMS }}" | tr ',' ' '); do + if ! docker buildx imagetools inspect "${DST}" | grep -q "${platform}"; then + echo "Pushed manifest is missing ${platform}" >&2 + exit 1 + fi + done + - name: Summary run: | { echo "## VSCO OpenSearch image" echo "" - echo "Upstream version (buildSrc): \`${{ steps.version.outputs.opensearch_version }}\`" + echo "Base: \`${{ env.BASE_REPO }}:${{ steps.version.outputs.opensearch_version }}\`" + echo "Patched: \`lib/opensearch-${{ steps.version.outputs.opensearch_version }}.jar\` (built from this fork)" + echo "Platforms: \`${{ env.PLATFORMS }}\`" echo "Pushed: \`${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/${{ env.IMAGE_NAME }}:${{ inputs.image_tag }}\`" echo "" echo "Point the OpenSearch Helm/operator image to that tag." From 369dbf086192d49a1d5882f1af9af7b1453494f7 Mon Sep 17 00:00:00 2001 From: Peter Ossian Date: Fri, 14 Aug 2026 16:04:29 -0700 Subject: [PATCH 09/11] add upstream 3.8.0 ref --- .../workflows/vsco-publish-opensearch-image.yaml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/vsco-publish-opensearch-image.yaml b/.github/workflows/vsco-publish-opensearch-image.yaml index 5db333fe3d614..e123fec3ef377 100644 --- a/.github/workflows/vsco-publish-opensearch-image.yaml +++ b/.github/workflows/vsco-publish-opensearch-image.yaml @@ -54,6 +54,7 @@ env: IMAGE_ORG: vsco IMAGE_NAME: opensearch BASE_REPO: opensearchproject/opensearch + UPSTREAM_REPO: opensearch-project/OpenSearch PLATFORMS: linux/amd64,linux/arm64 jobs: @@ -120,17 +121,21 @@ jobs: run: | set -euo pipefail BASE="${{ steps.version.outputs.opensearch_version }}" - git fetch --no-tags --depth=1 origin "refs/tags/${BASE}:refs/tags/${BASE}" + # Anchor on upstream's tag, not the fork's: the base image was built from + # upstream ${BASE}, and a fork made with "copy the default branch only" + # carries no release tags (3.8.0 lives on the 3.8 branch, not main). + git fetch --no-tags --depth=1 "https://github.com/${{ env.UPSTREAM_REPO }}.git" \ + "refs/tags/${BASE}:refs/tags/upstream-${BASE}" # Swapping only lib/opensearch-.jar is safe only while every # change since the tag lands in :server (or is fork-only tooling). - CHANGED="$(git diff --name-only "refs/tags/${BASE}..HEAD" \ + CHANGED="$(git diff --name-only "refs/tags/upstream-${BASE}..HEAD" \ | grep -v -E '^(server/|\.github/workflows/vsco-)' || true)" if [[ -n "${CHANGED}" ]]; then - echo "Changes outside server/ since tag ${BASE}; a core-jar swap would silently drop them:" >&2 + echo "Changes outside server/ since upstream tag ${BASE}; a core-jar swap would silently drop them:" >&2 echo "${CHANGED}" >&2 exit 1 fi - git diff --stat "refs/tags/${BASE}..HEAD" + git diff --stat "refs/tags/upstream-${BASE}..HEAD" - name: Build patched core jar (Gradle) run: | From 1a1e7209fabda3e6debfee4219a2b9a52d3e6bff Mon Sep 17 00:00:00 2001 From: Peter Ossian Date: Fri, 14 Aug 2026 16:21:01 -0700 Subject: [PATCH 10/11] add command to locate necessary jar --- .../vsco-publish-opensearch-image.yaml | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/.github/workflows/vsco-publish-opensearch-image.yaml b/.github/workflows/vsco-publish-opensearch-image.yaml index e123fec3ef377..9ead07a025b47 100644 --- a/.github/workflows/vsco-publish-opensearch-image.yaml +++ b/.github/workflows/vsco-publish-opensearch-image.yaml @@ -140,17 +140,38 @@ jobs: - name: Build patched core jar (Gradle) run: | set -euo pipefail - ./gradlew :server:jar --parallel + # -Dbuild.snapshot=false is how opensearch-build produces a release: without + # it the artifact is opensearch--SNAPSHOT.jar and its manifest + # advertises a snapshot, which would not match the release plugins bundled + # in the base image. + ./gradlew :server:jar --parallel -Dbuild.snapshot=false - name: Stage build context id: stage run: | set -euo pipefail OS_VERSION="${{ steps.version.outputs.opensearch_version }}" - JAR="server/build/libs/opensearch-${OS_VERSION}.jar" - if [[ ! -f "${JAR}" ]]; then - echo "Expected core jar at ${JAR}; found:" >&2 - ls -la server/build/libs/ >&2 || true + + # Locate the jar rather than assume server/build/libs: Gradle's layout has + # moved before, and a silently-wrong path here is what a bad image looks like. + JARS=() + mapfile -t JARS < <(find . -type f -name "opensearch-${OS_VERSION}.jar" \ + -not -path './.git/*' | sort) + if [[ ${#JARS[@]} -ne 1 ]]; then + echo "Expected exactly one opensearch-${OS_VERSION}.jar, found ${#JARS[@]}." >&2 + echo "--- every opensearch-*.jar in the workspace ---" >&2 + find . -type f -name 'opensearch-*.jar' -not -path './.git/*' >&2 || true + echo "--- directories under server/ (depth 3) ---" >&2 + find server -maxdepth 3 -type d >&2 || true + exit 1 + fi + JAR="${JARS[0]}" + echo "Core jar: ${JAR}" + unzip -p "${JAR}" META-INF/MANIFEST.MF | grep -i 'version' || true + + # Guard against grabbing some other artifact that happens to match the name. + if ! unzip -l "${JAR}" | grep -q 'org/opensearch/cluster/routing/IndexShardRoutingTable.class'; then + echo "${JAR} does not contain the patched class; wrong artifact." >&2 exit 1 fi From d4a95e83157428d97b5a7ece85791d52a22afea2 Mon Sep 17 00:00:00 2001 From: Peter Ossian Date: Thu, 20 Aug 2026 04:05:35 -0700 Subject: [PATCH 11/11] fix ARS-ranked search-replica routing --- .../vsco-publish-opensearch-image.yaml | 4 +- .../routing/IndexShardRoutingTable.java | 32 +++++++++++-- .../cluster/routing/OperationRouting.java | 5 +- .../routing/IndexShardRoutingTableTests.java | 35 ++------------ .../routing/OperationRoutingTests.java | 47 +++++++++++++++++++ 5 files changed, 84 insertions(+), 39 deletions(-) diff --git a/.github/workflows/vsco-publish-opensearch-image.yaml b/.github/workflows/vsco-publish-opensearch-image.yaml index 9ead07a025b47..df1046082b4f3 100644 --- a/.github/workflows/vsco-publish-opensearch-image.yaml +++ b/.github/workflows/vsco-publish-opensearch-image.yaml @@ -37,9 +37,9 @@ on: workflow_dispatch: inputs: image_tag: - description: 'Tag for ghcr.io/vsco/opensearch (e.g. 3.8.0-vsco2)' + description: 'Tag for ghcr.io/vsco/opensearch (e.g. 3.8.0-vsco3)' required: true - default: '3.8.0-vsco2' + default: '3.8.0-vsco3' java_version: description: 'JDK major version for the Gradle build' required: true diff --git a/server/src/main/java/org/opensearch/cluster/routing/IndexShardRoutingTable.java b/server/src/main/java/org/opensearch/cluster/routing/IndexShardRoutingTable.java index 39fd0c05811d4..2207bced18ed9 100644 --- a/server/src/main/java/org/opensearch/cluster/routing/IndexShardRoutingTable.java +++ b/server/src/main/java/org/opensearch/cluster/routing/IndexShardRoutingTable.java @@ -57,7 +57,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; @@ -671,7 +670,18 @@ public ShardIterator replicaActiveInitializingShardIt() { } public ShardIterator searchReplicaActiveInitializingShardIt() { - return filterAndOrderShards(ShardRouting::isSearchOnly); + return searchReplicaActiveInitializingShardIt(null, null); + } + + /** + * Returns search-only replicas, ordered by adaptive replica selection when + * response statistics are available. + */ + public ShardIterator searchReplicaActiveInitializingShardIt( + @Nullable ResponseCollectorService collector, + @Nullable Map nodeSearchCounts + ) { + return filterAndOrderShards(ShardRouting::isSearchOnly, collector, nodeSearchCounts); } /** @@ -713,20 +723,32 @@ public ShardIterator replicaFirstActiveInitializingShardsIt() { * eligible set only. */ private ShardIterator filterAndOrderShards(Predicate filter) { + return filterAndOrderShards(filter, null, null); + } + + private ShardIterator filterAndOrderShards( + Predicate filter, + @Nullable ResponseCollectorService collector, + @Nullable Map nodeSearchCounts + ) { List matching = new ArrayList<>(); for (ShardRouting replica : replicas) { if (filter.test(replica)) { matching.add(replica); } } - LinkedList ordered = new LinkedList<>(); + List active = new ArrayList<>(); + List initializing = new ArrayList<>(); for (ShardRouting replica : shuffler.shuffle(matching)) { if (replica.active()) { - ordered.addFirst(replica); + active.add(replica); } else if (replica.initializing()) { - ordered.addLast(replica); + initializing.add(replica); } } + List ordered = new ArrayList<>(active.size() + initializing.size()); + ordered.addAll(rankShardsAndUpdateStats(active, collector, nodeSearchCounts)); + ordered.addAll(initializing); return new PlainShardIterator(shardId, ordered); } diff --git a/server/src/main/java/org/opensearch/cluster/routing/OperationRouting.java b/server/src/main/java/org/opensearch/cluster/routing/OperationRouting.java index 210e9828876df..3644d85fad3bb 100644 --- a/server/src/main/java/org/opensearch/cluster/routing/OperationRouting.java +++ b/server/src/main/java/org/opensearch/cluster/routing/OperationRouting.java @@ -416,7 +416,10 @@ private ShardIterator preferenceActiveShardIterator( case REPLICA_FIRST: return indexShard.replicaFirstActiveInitializingShardsIt(); case SEARCH_REPLICA: - return indexShard.searchReplicaActiveInitializingShardIt(); + return indexShard.searchReplicaActiveInitializingShardIt( + useAdaptiveReplicaSelection ? collectorService : null, + useAdaptiveReplicaSelection ? nodeCounts : null + ); case ONLY_LOCAL: return indexShard.onlyNodeActiveInitializingShardsIt(localNodeId); case ONLY_NODES: diff --git a/server/src/test/java/org/opensearch/cluster/routing/IndexShardRoutingTableTests.java b/server/src/test/java/org/opensearch/cluster/routing/IndexShardRoutingTableTests.java index ce1f27ab57331..a2ee5f9577d49 100644 --- a/server/src/test/java/org/opensearch/cluster/routing/IndexShardRoutingTableTests.java +++ b/server/src/test/java/org/opensearch/cluster/routing/IndexShardRoutingTableTests.java @@ -153,29 +153,10 @@ public void testSearchReplicaRoutingIsFairWhenWriterReplicasPresent() { ShardRouting primary = TestShardRouting.newShardRouting(shardId, "data-0", true, ShardRoutingState.STARTED); ShardRouting writer0 = TestShardRouting.newShardRouting(shardId, "data-1", false, ShardRoutingState.STARTED); ShardRouting writer1 = TestShardRouting.newShardRouting(shardId, "data-2", false, ShardRoutingState.STARTED); - ShardRouting search0 = TestShardRouting.newShardRouting( - shardId, - "search-0", - null, - false, - true, - ShardRoutingState.STARTED, - null - ); - ShardRouting search1 = TestShardRouting.newShardRouting( - shardId, - "search-1", - null, - false, - true, - ShardRoutingState.STARTED, - null - ); + ShardRouting search0 = TestShardRouting.newShardRouting(shardId, "search-0", null, false, true, ShardRoutingState.STARTED, null); + ShardRouting search1 = TestShardRouting.newShardRouting(shardId, "search-1", null, false, true, ShardRoutingState.STARTED, null); - IndexShardRoutingTable table = new IndexShardRoutingTable( - shardId, - Arrays.asList(primary, writer0, writer1, search0, search1) - ); + IndexShardRoutingTable table = new IndexShardRoutingTable(shardId, Arrays.asList(primary, writer0, writer1, search0, search1)); int search0First = 0; int search1First = 0; @@ -202,15 +183,7 @@ public void testSearchReplicaRoutingIgnoresWriterReplicas() { ShardId shardId = new ShardId(new Index("test", UUID.randomUUID().toString()), 0); ShardRouting primary = TestShardRouting.newShardRouting(shardId, "data-0", true, ShardRoutingState.STARTED); ShardRouting writer = TestShardRouting.newShardRouting(shardId, "data-1", false, ShardRoutingState.STARTED); - ShardRouting search = TestShardRouting.newShardRouting( - shardId, - "search-0", - null, - false, - true, - ShardRoutingState.STARTED, - null - ); + ShardRouting search = TestShardRouting.newShardRouting(shardId, "search-0", null, false, true, ShardRoutingState.STARTED, null); IndexShardRoutingTable table = new IndexShardRoutingTable(shardId, Arrays.asList(primary, writer, search)); for (int i = 0; i < 20; i++) { diff --git a/server/src/test/java/org/opensearch/cluster/routing/OperationRoutingTests.java b/server/src/test/java/org/opensearch/cluster/routing/OperationRoutingTests.java index 1254c1a84e573..670fb784badbc 100644 --- a/server/src/test/java/org/opensearch/cluster/routing/OperationRoutingTests.java +++ b/server/src/test/java/org/opensearch/cluster/routing/OperationRoutingTests.java @@ -1195,6 +1195,53 @@ public void testSearchReplicaDefaultRouting() throws Exception { } } + public void testSearchReplicaDefaultRoutingUsesAdaptiveReplicaSelection() throws Exception { + final String indexName = "test"; + final String[] indexNames = new String[] { indexName }; + ClusterState state = ClusterStateCreationUtils.stateWithAssignedPrimariesAndReplicas(indexNames, 1, 2, 2); + List searchReplicas = state.routingTable().index(indexName).shard(0).searchOnlyReplicas(); + assertEquals(2, searchReplicas.size()); + + String fastNode = searchReplicas.get(0).currentNodeId(); + String slowNode = searchReplicas.get(1).currentNodeId(); + TestThreadPool threadPool = new TestThreadPool("testSearchReplicaDefaultRoutingUsesAdaptiveReplicaSelection"); + ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool); + + try { + OperationRouting opRouting = new OperationRouting( + Settings.EMPTY, + new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS) + ); + opRouting.setUseAdaptiveReplicaSelection(true); + + ResponseCollectorService collector = new ResponseCollectorService(clusterService); + collector.addNodeStatistics(fastNode, 0, TimeValue.timeValueMillis(10).nanos(), TimeValue.timeValueMillis(10).nanos()); + collector.addNodeStatistics(slowNode, 10, TimeValue.timeValueMillis(500).nanos(), TimeValue.timeValueMillis(500).nanos()); + Map outstandingRequests = new HashMap<>(); + outstandingRequests.put(fastNode, 1L); + outstandingRequests.put(slowNode, 1L); + + ShardIterator iterator = opRouting.searchShards(state, indexNames, null, null, collector, outstandingRequests, null).get(0); + + assertEquals(2, iterator.size()); + ShardRouting first = iterator.nextOrNull(); + ShardRouting second = iterator.nextOrNull(); + assertNotNull(first); + assertNotNull(second); + assertTrue(first.isSearchOnly()); + assertTrue(second.isSearchOnly()); + assertEquals( + "adaptive replica selection must preserve the lowest-ranked search replica first", + fastNode, + first.currentNodeId() + ); + assertEquals(slowNode, second.currentNodeId()); + } finally { + IOUtils.close(clusterService); + terminate(threadPool); + } + } + public void testSearchReplicaRoutingWhenSearchOnlyStrictSettingIsFalse() throws Exception { final int numShards = 1; final int numReplicas = 2;