Skip to content

Commit 11b5248

Browse files
authored
Merge branch 'main' into changelogs-08-04
2 parents f6cf204 + 34ca620 commit 11b5248

120 files changed

Lines changed: 1465 additions & 396 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

benchmarks/src/main/java/org/elasticsearch/benchmark/routing/allocation/ShardsAvailabilityHealthIndicatorBenchmark.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ public void setUp() throws Exception {
144144
true,
145145
RecoverySource.ExistingStoreRecoverySource.INSTANCE,
146146
decidersNoUnassignedInfo,
147-
ShardRouting.Role.DEFAULT
147+
ShardRouting.Role.DEFAULT,
148+
ShardRouting.RecoveryPriority.UNASSIGNED_UNEXPECTED
148149
);
149150
shardBuilder.addShard(shardRouting);
150151
if (shardIdNumber < numReplicas) {
@@ -154,7 +155,8 @@ public void setUp() throws Exception {
154155
false,
155156
RecoverySource.EmptyStoreRecoverySource.INSTANCE,
156157
decidersNoUnassignedInfo,
157-
ShardRouting.Role.DEFAULT
158+
ShardRouting.Role.DEFAULT,
159+
ShardRouting.RecoveryPriority.UNASSIGNED_UNEXPECTED
158160
)
159161
);
160162
}

docs/changelog/155186.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
area: ES|QL
2+
issues:
3+
- 138019
4+
pr: 155186
5+
summary: Load numeric values from stored fields
6+
type: bug

docs/changelog/155375.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
area: ES|QL
2+
issues: []
3+
pr: 155375
4+
summary: "Log circuit breaker trips at WARN, not ERROR"
5+
type: bug

modules/data-streams/src/internalClusterTest/java/org/elasticsearch/datastreams/DataStreamAutoshardingIT.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,8 @@ private static ShardStats getShardStats(IndexMetadata indexMeta, int shardIndex,
520520
true,
521521
RecoverySource.EmptyStoreRecoverySource.INSTANCE,
522522
new UnassignedInfo(UnassignedInfo.Reason.INDEX_CREATED, null),
523-
ShardRouting.Role.DEFAULT
523+
ShardRouting.Role.DEFAULT,
524+
ShardRouting.RecoveryPriority.UNASSIGNED_NEW_PRIMARY
524525
);
525526
shardRouting = shardRouting.initialize(assignedShardNodeId, null, ShardRouting.UNAVAILABLE_EXPECTED_SHARD_SIZE);
526527
shardRouting = shardRouting.moveToStarted(ShardRouting.UNAVAILABLE_EXPECTED_SHARD_SIZE);

modules/ip-location/src/test/java/org/elasticsearch/ingest/geoip/DatabaseNodeServiceTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1017,7 +1017,8 @@ private static ClusterState createClusterState(
10171017
true,
10181018
RecoverySource.ExistingStoreRecoverySource.INSTANCE,
10191019
new UnassignedInfo(UnassignedInfo.Reason.INDEX_CREATED, ""),
1020-
ShardRouting.Role.DEFAULT
1020+
ShardRouting.Role.DEFAULT,
1021+
ShardRouting.RecoveryPriority.UNASSIGNED_EXPECTED
10211022
);
10221023
String nodeId = ESTestCase.randomAlphaOfLength(8);
10231024
shardRouting = shardRouting.initialize(nodeId, null, shardRouting.getExpectedShardSize());

qa/packaging/src/test/java/org/elasticsearch/packaging/test/NativeLibraryTests.java

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,15 @@
1111

1212
import org.apache.http.client.fluent.Request;
1313
import org.apache.http.entity.ContentType;
14+
import org.elasticsearch.packaging.util.FileUtils;
15+
import org.elasticsearch.packaging.util.Platforms;
1416
import org.elasticsearch.packaging.util.ServerUtils;
17+
import org.elasticsearch.packaging.util.docker.Docker;
1518
import org.elasticsearch.packaging.util.docker.DockerRun;
1619

1720
import java.util.Map;
21+
import java.util.regex.Matcher;
22+
import java.util.regex.Pattern;
1823

1924
import static org.elasticsearch.packaging.util.docker.Docker.runContainer;
2025
import static org.elasticsearch.packaging.util.docker.DockerRun.builder;
@@ -79,6 +84,99 @@ public void test20ZstdCompression() throws Exception {
7984
}
8085
}
8186

87+
/**
88+
* Verifies that the native simdvec library (libvec.so/libvec.dylib) loads and can perform vector similarity
89+
* scoring.
90+
* <p>
91+
* A {@code dense_vector} field with HNSW indexing uses the native vector scorer from {@code libvec}
92+
* for computing vector distances during kNN search. If the native library cannot be loaded (e.g. due to
93+
* a glibc version incompatibility), the search will fall back to the Java implementation or fail entirely.
94+
* This test indexes vectors and performs a kNN search to exercise the native scoring path.
95+
* <p>
96+
* On Linux and macOS (where native simdvec is supported), this test additionally asserts that the native
97+
* library was loaded successfully by checking for the {@code vec_caps=N} log line (where N > 0) emitted
98+
* by the simdvec library during startup.
99+
*/
100+
public void test30SimdVecKnnSearch() throws Exception {
101+
configureAndStart(SECURITY_DISABLED_SETTINGS);
102+
103+
try {
104+
// Create an index with a dense_vector field using plain HNSW (no quantization).
105+
// Explicitly setting "type": "hnsw" avoids the default int8_hnsw quantization,
106+
// ensuring the native float32 vector scorer in libvec is used for distance computation.
107+
ServerUtils.makeRequest(Request.Put("http://localhost:9200/simdvec_test").bodyString("""
108+
{
109+
"settings": {"number_of_replicas": 0, "number_of_shards": 1},
110+
"mappings": {
111+
"properties": {
112+
"vector": {
113+
"type": "dense_vector",
114+
"dims": 3,
115+
"index": true,
116+
"similarity": "l2_norm",
117+
"index_options": {"type": "hnsw"}
118+
},
119+
"name": {"type": "keyword"}
120+
}
121+
}
122+
}""", ContentType.APPLICATION_JSON));
123+
124+
// Index documents with vectors
125+
ServerUtils.makeRequest(
126+
Request.Post("http://localhost:9200/simdvec_test/_doc/1")
127+
.bodyString("{\"vector\": [1.0, 2.0, 3.0], \"name\": \"first\"}", ContentType.APPLICATION_JSON)
128+
);
129+
ServerUtils.makeRequest(
130+
Request.Post("http://localhost:9200/simdvec_test/_doc/2")
131+
.bodyString("{\"vector\": [4.0, 5.0, 6.0], \"name\": \"second\"}", ContentType.APPLICATION_JSON)
132+
);
133+
ServerUtils.makeRequest(
134+
Request.Post("http://localhost:9200/simdvec_test/_doc/3?refresh=true")
135+
.bodyString("{\"vector\": [7.0, 8.0, 9.0], \"name\": \"third\"}", ContentType.APPLICATION_JSON)
136+
);
137+
138+
// Force merge to a single segment to ensure the HNSW graph is built and the native scorer is used
139+
ServerUtils.makeRequest(Request.Post("http://localhost:9200/simdvec_test/_forcemerge?max_num_segments=1"));
140+
141+
// Perform a kNN search — this exercises native vector distance scoring via libvec
142+
String response = ServerUtils.makeRequest(Request.Post("http://localhost:9200/simdvec_test/_search").bodyString("""
143+
{
144+
"knn": {
145+
"field": "vector",
146+
"query_vector": [1.0, 2.0, 3.0],
147+
"k": 1,
148+
"num_candidates": 3
149+
}
150+
}""", ContentType.APPLICATION_JSON));
151+
152+
// The nearest neighbor to [1,2,3] should be the document with vector [1,2,3]
153+
assertThat(response, containsString("\"_id\":\"1\""));
154+
assertThat(response, containsString("\"first\""));
155+
156+
// On Linux and macOS (where native simdvec is supported), verify that libvec loaded and vec_caps > 0.
157+
// The vec_caps log line is emitted during NativeAccess initialization at node startup.
158+
if (Platforms.LINUX || Platforms.DARWIN) {
159+
String logs = getElasticsearchLogs();
160+
Matcher matcher = Pattern.compile("vec_caps=(\\d+)").matcher(logs);
161+
assertTrue("Expected vec_caps=N log line indicating simdvec library loaded, but not found in logs", matcher.find());
162+
int vecCaps = Integer.parseInt(matcher.group(1));
163+
assertTrue("Expected vec_caps > 0, indicating native simdvec is operational, but got: " + vecCaps, vecCaps > 0);
164+
}
165+
} finally {
166+
stopElasticsearch();
167+
}
168+
}
169+
170+
/**
171+
* Returns the Elasticsearch startup logs, handling both Docker and non-Docker distributions.
172+
*/
173+
private String getElasticsearchLogs() {
174+
if (distribution().isDocker()) {
175+
return Docker.getContainerLogs().stdout();
176+
}
177+
return FileUtils.slurpAllLogs(installation.logs, "elasticsearch.log", "*.log.gz");
178+
}
179+
82180
private void configureAndStart(Map<String, String> settings) throws Exception {
83181
if (distribution().isDocker()) {
84182
DockerRun dockerRun = builder();

server/src/internalClusterTest/java/org/elasticsearch/cluster/routing/allocation/decider/WriteLoadConstraintDeciderIT.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -927,7 +927,8 @@ private static ShardStats createShardStats(
927927
true,
928928
RecoverySource.EmptyStoreRecoverySource.INSTANCE,
929929
new UnassignedInfo(UnassignedInfo.Reason.INDEX_CREATED, null),
930-
ShardRouting.Role.DEFAULT
930+
ShardRouting.Role.DEFAULT,
931+
ShardRouting.RecoveryPriority.UNASSIGNED_NEW_PRIMARY
931932
);
932933
shardRouting = shardRouting.initialize(assignedShardNodeId, null, ShardRouting.UNAVAILABLE_EXPECTED_SHARD_SIZE);
933934
shardRouting = shardRouting.moveToStarted(ShardRouting.UNAVAILABLE_EXPECTED_SHARD_SIZE);

server/src/main/java/org/elasticsearch/action/search/SearchQueryThenFetchAsyncAction.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.elasticsearch.client.internal.Client;
2525
import org.elasticsearch.cluster.ClusterState;
2626
import org.elasticsearch.cluster.routing.SplitShardCountSummary;
27+
import org.elasticsearch.common.breaker.CircuitBreakingException;
2728
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
2829
import org.elasticsearch.common.io.stream.RecyclerBytesStreamOutput;
2930
import org.elasticsearch.common.io.stream.StreamInput;
@@ -714,7 +715,13 @@ static void registerNodeSearchAction(
714715
cancellableTask::isCancelled,
715716
SearchProgressListener.NOOP,
716717
shardCount,
717-
e -> logger.error("failed to merge on data node", e)
718+
e -> {
719+
if (ExceptionsHelper.unwrapCause(e) instanceof CircuitBreakingException) {
720+
logger.debug("failed to merge on data node", e);
721+
} else {
722+
logger.error("failed to merge on data node", e);
723+
}
724+
}
718725
),
719726
request,
720727
cancellableTask,

server/src/main/java/org/elasticsearch/cluster/ClusterInfoSimulator.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,18 @@ public void simulateAlreadyStartedShard(ShardRouting startedShard, @Nullable Str
172172
);
173173
}
174174
final long expectedShardSize = startedShard.getExpectedShardSize();
175+
// Use the unknown recovery priority here: it does not make any difference to the calculation, and this routing will not be added to
176+
// the cluster state:
177+
ShardRouting.RecoveryPriority recoveryPriority = ShardRouting.RecoveryPriority.UNKNOWN;
175178
if (sourceNodeId != null) {
176-
final var relocatingShard = startedShard.moveToUnassigned(new UnassignedInfo(REINITIALIZED, "simulation"))
179+
final var relocatingShard = startedShard.moveToUnassigned(new UnassignedInfo(REINITIALIZED, "simulation"), recoveryPriority)
177180
.initialize(sourceNodeId, null, expectedShardSize)
178181
.moveToStarted(expectedShardSize)
179-
.relocate(startedShard.currentNodeId(), expectedShardSize)
182+
.relocate(startedShard.currentNodeId(), expectedShardSize, recoveryPriority)
180183
.getTargetRelocatingShard();
181184
simulateShardStarted(relocatingShard, false);
182185
} else {
183-
final var initializingShard = startedShard.moveToUnassigned(new UnassignedInfo(REINITIALIZED, "simulation"))
186+
final var initializingShard = startedShard.moveToUnassigned(new UnassignedInfo(REINITIALIZED, "simulation"), recoveryPriority)
184187
.initialize(startedShard.currentNodeId(), null, expectedShardSize);
185188
simulateShardStarted(initializingShard, false);
186189
}

server/src/main/java/org/elasticsearch/cluster/ClusterState.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.elasticsearch.cluster.routing.IndexRoutingTable;
3030
import org.elasticsearch.cluster.routing.RoutingNodes;
3131
import org.elasticsearch.cluster.routing.RoutingTable;
32+
import org.elasticsearch.cluster.routing.ShardRouting;
3233
import org.elasticsearch.cluster.service.ClusterApplierService;
3334
import org.elasticsearch.cluster.service.ClusterService;
3435
import org.elasticsearch.cluster.service.MasterService;
@@ -63,13 +64,16 @@
6364
import java.util.EnumSet;
6465
import java.util.HashMap;
6566
import java.util.Iterator;
67+
import java.util.List;
6668
import java.util.Map;
6769
import java.util.Objects;
6870
import java.util.Set;
6971
import java.util.TreeSet;
7072
import java.util.concurrent.Executor;
7173
import java.util.function.Consumer;
7274
import java.util.function.Function;
75+
import java.util.stream.Stream;
76+
import java.util.stream.StreamSupport;
7377

7478
import static org.elasticsearch.gateway.GatewayService.STATE_NOT_RECOVERED_BLOCK;
7579

@@ -230,6 +234,7 @@ public ClusterState(
230234
this.stateUUID = stateUUID;
231235
this.clusterName = clusterName;
232236
this.metadata = metadata;
237+
assert assertNoUnknownRecoveryPrioritiesInRoutingTable(routingTable);
233238
this.routingTable = routingTable;
234239
this.nodes = nodes;
235240
this.compatibilityVersions = Map.copyOf(compatibilityVersions);
@@ -245,6 +250,20 @@ public ClusterState(
245250
: CompatibilityVersions.minimumVersions(compatibilityVersions.values());
246251
}
247252

253+
private boolean assertNoUnknownRecoveryPrioritiesInRoutingTable(GlobalRoutingTable routingTable) {
254+
List<ShardRouting> shardRoutingsWithUnknownRecoveryPriority = StreamSupport.stream(routingTable.spliterator(), false)
255+
.flatMap(project -> StreamSupport.stream(project.spliterator(), false))
256+
.flatMap(IndexRoutingTable::allShards)
257+
// Get all shards from the IndexShardRoutingTable, including relocation targets which are included in getAllInitializingShards()
258+
// but not in allShards(), deduping because getAllInitializingShards() also includes some shards that _are_ in allShards():
259+
.flatMap(shard -> Stream.concat(shard.allShards(), shard.getAllInitializingShards().stream()).distinct())
260+
.filter(shard -> shard.recoveryPriority() == ShardRouting.RecoveryPriority.UNKNOWN)
261+
.toList();
262+
assert shardRoutingsWithUnknownRecoveryPriority.isEmpty()
263+
: "Cluster state contained shard routings with UNKNOWN recovery priority [" + shardRoutingsWithUnknownRecoveryPriority + "]";
264+
return true;
265+
}
266+
248267
private static boolean assertConsistentRoutingNodes(
249268
GlobalRoutingTable routingTable,
250269
DiscoveryNodes nodes,

0 commit comments

Comments
 (0)