Skip to content

Commit aa5e284

Browse files
authored
Merge branch '9.1' into 9.1-direct-io-off
2 parents 812e93e + dd3fedc commit aa5e284

File tree

66 files changed

+958
-269
lines changed

Some content is hidden

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

66 files changed

+958
-269
lines changed

benchmarks/README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,10 @@ exit
152152
Grab the async profiler from https://github.com/jvm-profiling-tools/async-profiler
153153
and run `prof async` like so:
154154
```
155-
gradlew -p benchmarks/ run --args 'LongKeyedBucketOrdsBenchmark.multiBucket -prof "async:libPath=/home/nik9000/Downloads/async-profiler-3.0-29ee888-linux-x64/lib/libasyncProfiler.so;dir=/tmp/prof;output=flamegraph"'
155+
gradlew -p benchmarks/ run --args 'LongKeyedBucketOrdsBenchmark.multiBucket -prof "async:libPath=/home/nik9000/Downloads/async-profiler-4.0-linux-x64/lib/libasyncProfiler.so;dir=/tmp/prof;output=flamegraph"'
156156
```
157157

158-
Note: As of January 2025 the latest release of async profiler doesn't work
159-
with our JDK but the nightly is fine.
158+
Note: As of July 2025 the 4.0 release of the async profiler works well.
160159

161160
If you are on Mac, this'll warn you that you downloaded the shared library from
162161
the internet. You'll need to go to settings and allow it to run.

benchmarks/src/main/java/org/elasticsearch/benchmark/_nightly/esql/ValuesSourceReaderBenchmark.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@
2424
import org.apache.lucene.util.BytesRef;
2525
import org.apache.lucene.util.NumericUtils;
2626
import org.elasticsearch.common.breaker.NoopCircuitBreaker;
27+
import org.elasticsearch.common.logging.LogConfigurator;
2728
import org.elasticsearch.common.lucene.Lucene;
2829
import org.elasticsearch.common.settings.Settings;
30+
import org.elasticsearch.common.unit.ByteSizeValue;
2931
import org.elasticsearch.common.util.BigArrays;
3032
import org.elasticsearch.compute.data.BlockFactory;
3133
import org.elasticsearch.compute.data.BytesRefBlock;
@@ -85,6 +87,10 @@
8587
@State(Scope.Thread)
8688
@Fork(1)
8789
public class ValuesSourceReaderBenchmark {
90+
static {
91+
LogConfigurator.configureESLogging();
92+
}
93+
8894
private static final String[] SUPPORTED_LAYOUTS = new String[] { "in_order", "shuffled", "shuffled_singles" };
8995
private static final String[] SUPPORTED_NAMES = new String[] {
9096
"long",
@@ -344,6 +350,7 @@ public FieldNamesFieldMapper.FieldNamesFieldType fieldNames() {
344350
public void benchmark() {
345351
ValuesSourceReaderOperator op = new ValuesSourceReaderOperator(
346352
blockFactory,
353+
ByteSizeValue.ofMb(1).getBytes(),
347354
fields(name),
348355
List.of(new ValuesSourceReaderOperator.ShardContext(reader, () -> {
349356
throw new UnsupportedOperationException("can't load _source here");

docs/changelog/131053.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 131053
2+
summary: Split large pages on load sometimes
3+
area: ES|QL
4+
type: bug
5+
issues: []

docs/changelog/131945.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 131945
2+
summary: Restrict remote ENRICH after FORK
3+
area: ES|QL
4+
type: bug
5+
issues:
6+
- 131445

docs/changelog/131990.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 131990
2+
summary: Prevent the trained model deployment memory estimation from double-counting
3+
allocations
4+
area: Machine Learning
5+
type: bug
6+
issues: []

docs/changelog/132018.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 132018
2+
summary: Fix decoding of non-ascii field names in ignored source
3+
area: Mapping
4+
type: bug
5+
issues: []

muted-tests.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,9 @@ tests:
453453
- class: org.elasticsearch.xpack.stack.StackYamlIT
454454
method: test {yaml=stack/10_basic/Test wrong data_stream type - logs from 9.2.0}
455455
issue: https://github.com/elastic/elasticsearch/issues/131803
456+
- class: org.elasticsearch.index.engine.MergeWithLowDiskSpaceIT
457+
method: testRelocationWhileForceMerging
458+
issue: https://github.com/elastic/elasticsearch/issues/131789
456459

457460
# Examples:
458461
#

server/src/internalClusterTest/java/org/elasticsearch/index/engine/MergeWithLowDiskSpaceIT.java

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,23 @@
1010
package org.elasticsearch.index.engine;
1111

1212
import org.elasticsearch.action.ActionFuture;
13+
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
1314
import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
1415
import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
16+
import org.elasticsearch.action.admin.cluster.reroute.ClusterRerouteUtils;
17+
import org.elasticsearch.action.admin.indices.segments.IndicesSegmentResponse;
1518
import org.elasticsearch.action.admin.indices.segments.ShardSegments;
1619
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
1720
import org.elasticsearch.action.support.broadcast.BroadcastResponse;
1821
import org.elasticsearch.cluster.DiskUsageIntegTestCase;
1922
import org.elasticsearch.cluster.metadata.IndexMetadata;
23+
import org.elasticsearch.cluster.metadata.Metadata;
2024
import org.elasticsearch.cluster.routing.allocation.DiskThresholdSettings;
25+
import org.elasticsearch.cluster.routing.allocation.command.MoveAllocationCommand;
26+
import org.elasticsearch.common.Priority;
2127
import org.elasticsearch.common.settings.Settings;
2228
import org.elasticsearch.common.util.concurrent.EsExecutors;
29+
import org.elasticsearch.core.TimeValue;
2330
import org.elasticsearch.index.IndexNotFoundException;
2431
import org.elasticsearch.indices.IndicesService;
2532
import org.elasticsearch.plugins.Plugin;
@@ -33,16 +40,20 @@
3340
import java.util.Collection;
3441
import java.util.List;
3542
import java.util.Locale;
43+
import java.util.concurrent.TimeUnit;
3644
import java.util.stream.IntStream;
3745

3846
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
3947
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
4048
import static org.hamcrest.Matchers.equalTo;
4149
import static org.hamcrest.Matchers.greaterThan;
50+
import static org.hamcrest.Matchers.iterableWithSize;
4251
import static org.hamcrest.Matchers.lessThan;
52+
import static org.hamcrest.Matchers.not;
4353

4454
@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0)
4555
public class MergeWithLowDiskSpaceIT extends DiskUsageIntegTestCase {
56+
private final TimeValue ACCEPTABLE_RELOCATION_TIME = new TimeValue(5, TimeUnit.MINUTES);
4657
protected static long MERGE_DISK_HIGH_WATERMARK_BYTES;
4758

4859
@BeforeClass
@@ -266,6 +277,118 @@ public void testForceMergeIsBlockedThenUnblocked() throws Exception {
266277
assertAcked(indicesAdmin().prepareDelete(indexName).get());
267278
}
268279

280+
public void testRelocationWhileForceMerging() throws Exception {
281+
final String node1 = internalCluster().startNode();
282+
ensureStableCluster(1);
283+
setTotalSpace(node1, Long.MAX_VALUE);
284+
String indexName = randomAlphaOfLength(10).toLowerCase(Locale.ROOT);
285+
createIndex(
286+
indexName,
287+
Settings.builder().put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0).put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1).build()
288+
);
289+
// get current disk space usage (for all indices on the node)
290+
IndicesStatsResponse stats = indicesAdmin().prepareStats().clear().setStore(true).get();
291+
long usedDiskSpaceAfterIndexing = stats.getTotal().getStore().sizeInBytes();
292+
// restrict the total disk space such that the next merge does not have sufficient disk space
293+
long insufficientTotalDiskSpace = usedDiskSpaceAfterIndexing + MERGE_DISK_HIGH_WATERMARK_BYTES - randomLongBetween(1L, 10L);
294+
setTotalSpace(node1, insufficientTotalDiskSpace);
295+
// node stats' FS stats should report that there is insufficient disk space available
296+
assertBusy(() -> {
297+
NodesStatsResponse nodesStatsResponse = client().admin().cluster().prepareNodesStats().setFs(true).get();
298+
assertThat(nodesStatsResponse.getNodes().size(), equalTo(1));
299+
NodeStats nodeStats = nodesStatsResponse.getNodes().get(0);
300+
assertThat(nodeStats.getFs().getTotal().getTotal().getBytes(), equalTo(insufficientTotalDiskSpace));
301+
assertThat(nodeStats.getFs().getTotal().getAvailable().getBytes(), lessThan(MERGE_DISK_HIGH_WATERMARK_BYTES));
302+
});
303+
int indexingRounds = randomIntBetween(5, 10);
304+
while (indexingRounds-- > 0) {
305+
indexRandom(
306+
true,
307+
true,
308+
true,
309+
false,
310+
IntStream.range(1, randomIntBetween(5, 10))
311+
.mapToObj(i -> prepareIndex(indexName).setSource("field", randomAlphaOfLength(50)))
312+
.toList()
313+
);
314+
}
315+
// the max segments argument makes it a blocking call
316+
ActionFuture<BroadcastResponse> forceMergeBeforeRelocationFuture = indicesAdmin().prepareForceMerge(indexName)
317+
.setMaxNumSegments(1)
318+
.execute();
319+
ThreadPoolMergeExecutorService threadPoolMergeExecutorService = internalCluster().getInstance(IndicesService.class, node1)
320+
.getThreadPoolMergeExecutorService();
321+
TestTelemetryPlugin testTelemetryPlugin = getTelemetryPlugin(node1);
322+
assertBusy(() -> {
323+
// merge executor says merging is blocked due to insufficient disk space while there is a single merge task enqueued
324+
assertThat(threadPoolMergeExecutorService.getMergeTasksQueueLength(), equalTo(1));
325+
assertTrue(threadPoolMergeExecutorService.isMergingBlockedDueToInsufficientDiskSpace());
326+
// telemetry says that there are indeed some segments enqueued to be merged
327+
testTelemetryPlugin.collect();
328+
assertThat(
329+
testTelemetryPlugin.getLongGaugeMeasurement(MergeMetrics.MERGE_SEGMENTS_QUEUED_USAGE).getLast().getLong(),
330+
greaterThan(0L)
331+
);
332+
// but still no merges are currently running
333+
assertThat(
334+
testTelemetryPlugin.getLongGaugeMeasurement(MergeMetrics.MERGE_SEGMENTS_RUNNING_USAGE).getLast().getLong(),
335+
equalTo(0L)
336+
);
337+
// indices stats also says that no merge is currently running (blocked merges are NOT considered as "running")
338+
IndicesStatsResponse indicesStatsResponse = client().admin().indices().prepareStats(indexName).setMerge(true).get();
339+
long currentMergeCount = indicesStatsResponse.getIndices().get(indexName).getPrimaries().merge.getCurrent();
340+
assertThat(currentMergeCount, equalTo(0L));
341+
});
342+
// the force merge call is still blocked
343+
assertFalse(forceMergeBeforeRelocationFuture.isCancelled());
344+
assertFalse(forceMergeBeforeRelocationFuture.isDone());
345+
// merge executor still confirms merging is blocked due to insufficient disk space
346+
assertTrue(threadPoolMergeExecutorService.isMergingBlockedDueToInsufficientDiskSpace());
347+
IndicesSegmentResponse indicesSegmentResponseBeforeRelocation = indicesAdmin().prepareSegments(indexName).get();
348+
// the index should have more than 1 segments at this stage
349+
assertThat(
350+
indicesSegmentResponseBeforeRelocation.getIndices().get(indexName).iterator().next().shards()[0].getSegments(),
351+
iterableWithSize(greaterThan(1))
352+
);
353+
// start another node
354+
final String node2 = internalCluster().startNode();
355+
ensureStableCluster(2);
356+
setTotalSpace(node2, Long.MAX_VALUE);
357+
// relocate the shard from node1 to node2
358+
ClusterRerouteUtils.reroute(client(), new MoveAllocationCommand(indexName, 0, node1, node2, Metadata.DEFAULT_PROJECT_ID));
359+
ClusterHealthResponse clusterHealthResponse = clusterAdmin().prepareHealth(TEST_REQUEST_TIMEOUT)
360+
.setWaitForEvents(Priority.LANGUID)
361+
.setWaitForNoRelocatingShards(true)
362+
.setTimeout(ACCEPTABLE_RELOCATION_TIME)
363+
.get();
364+
assertThat(clusterHealthResponse.isTimedOut(), equalTo(false));
365+
// the force merge call is now unblocked
366+
assertBusy(() -> {
367+
assertTrue(forceMergeBeforeRelocationFuture.isDone());
368+
assertFalse(forceMergeBeforeRelocationFuture.isCancelled());
369+
});
370+
// there is some merging going on in the {@code PostRecoveryMerger} after recovery, but that's not guaranteeing us a single segment,
371+
// so let's trigger a force merge to 1 segment again (this one should succeed promptly)
372+
indicesAdmin().prepareForceMerge(indexName).setMaxNumSegments(1).get();
373+
IndicesSegmentResponse indicesSegmentResponseAfterRelocation = indicesAdmin().prepareSegments(indexName).get();
374+
// assert there's only one segment now
375+
assertThat(
376+
indicesSegmentResponseAfterRelocation.getIndices().get(indexName).iterator().next().shards()[0].getSegments(),
377+
iterableWithSize(1)
378+
);
379+
// also assert that the shard was indeed moved to a different node
380+
assertThat(
381+
indicesSegmentResponseAfterRelocation.getIndices().get(indexName).iterator().next().shards()[0].getShardRouting()
382+
.currentNodeId(),
383+
not(
384+
equalTo(
385+
indicesSegmentResponseBeforeRelocation.getIndices().get(indexName).iterator().next().shards()[0].getShardRouting()
386+
.currentNodeId()
387+
)
388+
)
389+
);
390+
}
391+
269392
public void setTotalSpace(String dataNodeName, long totalSpace) {
270393
getTestFileStore(dataNodeName).setTotalSpace(totalSpace);
271394
refreshClusterInfo();

server/src/main/java/org/elasticsearch/index/mapper/AbstractShapeGeometryFieldMapper.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,11 @@ protected void writeExtent(BlockLoader.IntBuilder builder, Extent extent) {
9898
public BlockLoader.AllReader reader(LeafReaderContext context) throws IOException {
9999
return new BlockLoader.AllReader() {
100100
@Override
101-
public BlockLoader.Block read(BlockLoader.BlockFactory factory, BlockLoader.Docs docs) throws IOException {
101+
public BlockLoader.Block read(BlockLoader.BlockFactory factory, BlockLoader.Docs docs, int offset) throws IOException {
102102
var binaryDocValues = context.reader().getBinaryDocValues(fieldName);
103103
var reader = new GeometryDocValueReader();
104-
try (var builder = factory.ints(docs.count())) {
105-
for (int i = 0; i < docs.count(); i++) {
104+
try (var builder = factory.ints(docs.count() - offset)) {
105+
for (int i = offset; i < docs.count(); i++) {
106106
read(binaryDocValues, docs.get(i), reader, builder);
107107
}
108108
return builder.build();

0 commit comments

Comments
 (0)