Skip to content

Commit 8e11323

Browse files
Merge branch 'main' into foldable
2 parents 4087f30 + feb0b8f commit 8e11323

File tree

30 files changed

+387
-96
lines changed

30 files changed

+387
-96
lines changed

docs/reference/elasticsearch/jvm-settings.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,18 @@ To override the default heap size, set the minimum and maximum heap size setting
8787

8888
The heap size should be based on the available RAM:
8989

90-
* Set `Xms` and `Xmx` to no more than 50% of your total memory. {{es}} requires memory for purposes other than the JVM heap. For example, {{es}} uses off-heap buffers for efficient network communication and relies on the operating system’s filesystem cache for efficient access to files. The JVM itself also requires some memory. It’s normal for {{es}} to use more memory than the limit configured with the `Xmx` setting.
90+
* Set `Xms` and `Xmx` to no more than 50% of the total memory available to each {{es}} node. {{es}} requires memory for purposes other than the JVM heap. For example, {{es}} uses off-heap buffers for efficient network communication and relies on the operating system’s filesystem cache for efficient access to files. The JVM itself also requires some memory. It’s normal for {{es}} to use more memory than the limit configured with the `Xmx` setting.
9191

9292
::::{note}
93-
When running in a container, such as [Docker](docs-content://deploy-manage/deploy/self-managed/install-elasticsearch-with-docker.md), total memory is defined as the amount of memory visible to the container, not the total system memory on the host.
93+
When running in a container, such as [Docker](docs-content://deploy-manage/deploy/self-managed/install-elasticsearch-with-docker.md), the total memory available to {{es}} means the amount of memory available within the container, not the total system memory on the host.
94+
95+
If you are running multiple {{es}} nodes on the same host, or in the same container, the total of all the nodes' heap sizes should not exceed 50% of the total available memory.
96+
97+
Account for the memory usage of other processes running on the same host, or in the same container, when computing the total memory available to {{es}}.
98+
99+
The 50% guideline is intended as a safe upper bound on the heap size. You may find that heap sizes smaller than this maximum offer better performance, for instance by allowing your operating system to use a larger filesystem cache.
100+
101+
If you set the heap size too large, {{es}} may perform poorly and nodes may be terminated by the operating system.
94102
::::
95103

96104
* Set `Xms` and `Xmx` to no more than the threshold for compressed ordinary object pointers (oops). The exact threshold varies but 26GB is safe on most systems and can be as large as 30GB on some systems. To verify you are under the threshold, check the {{es}} log for an entry like this:

modules/kibana/src/main/java/org/elasticsearch/kibana/KibanaPlugin.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ public class KibanaPlugin extends Plugin implements SystemIndexPlugin {
3838
.setAllowedElasticProductOrigins(KIBANA_PRODUCT_ORIGIN)
3939
.build();
4040

41+
public static final SystemIndexDescriptor ONECHAT_INDEX_DESCRIPTOR = SystemIndexDescriptor.builder()
42+
.setIndexPattern(".chat-*")
43+
.setDescription("Onechat system index")
44+
.setType(Type.EXTERNAL_UNMANAGED)
45+
.setAllowedElasticProductOrigins(KIBANA_PRODUCT_ORIGIN)
46+
.build();
47+
4148
public static final SystemIndexDescriptor APM_AGENT_CONFIG_INDEX_DESCRIPTOR = SystemIndexDescriptor.builder()
4249
.setIndexPattern(".apm-agent-configuration*")
4350
.setDescription("system index for APM agent configuration")
@@ -57,6 +64,7 @@ public Collection<SystemIndexDescriptor> getSystemIndexDescriptors(Settings sett
5764
return List.of(
5865
KIBANA_INDEX_DESCRIPTOR,
5966
REPORTING_INDEX_DESCRIPTOR,
67+
ONECHAT_INDEX_DESCRIPTOR,
6068
APM_AGENT_CONFIG_INDEX_DESCRIPTOR,
6169
APM_CUSTOM_LINK_INDEX_DESCRIPTOR
6270
);

modules/kibana/src/test/java/org/elasticsearch/kibana/KibanaPluginTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public class KibanaPluginTests extends ESTestCase {
2020
public void testKibanaIndexNames() {
2121
assertThat(
2222
new KibanaPlugin().getSystemIndexDescriptors(Settings.EMPTY).stream().map(SystemIndexDescriptor::getIndexPattern).toList(),
23-
contains(".kibana_*", ".reporting-*", ".apm-agent-configuration*", ".apm-custom-link*")
23+
contains(".kibana_*", ".reporting-*", ".chat-*", ".apm-agent-configuration*", ".apm-custom-link*")
2424
);
2525
}
2626
}

modules/repository-s3/src/main/java/org/elasticsearch/repositories/s3/S3BlobContainer.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,13 @@ void run(BytesReference expected, BytesReference updated, ActionListener<Optiona
830830

831831
.<Void>newForked(l -> ensureOtherUploadsComplete(uploadId, uploadIndex, currentUploads, l))
832832

833-
// Step 4: Read the current register value.
833+
// Step 4: Read the current register value. Note that getRegister only has read-after-write semantics but that's ok here as:
834+
// - all earlier uploads are now complete,
835+
// - our upload is not completing yet, and
836+
// - later uploads can only be completing if they have already aborted ours.
837+
// Thus if our operation ultimately succeeds then there cannot have been any concurrent writes in flight, so this read
838+
// cannot have observed a stale value, whereas if our operation ultimately fails then it doesn't matter what this read
839+
// observes.
834840

835841
.<OptionalBytesReference>andThen(l -> getRegister(purpose, rawKey, l))
836842

muted-tests.yml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -475,15 +475,24 @@ tests:
475475
- class: org.elasticsearch.xpack.search.CrossClusterAsyncSearchIT
476476
method: testCancellationViaTimeoutWithAllowPartialResultsSetToFalse
477477
issue: https://github.com/elastic/elasticsearch/issues/131248
478-
- class: org.elasticsearch.xpack.downsample.DownsampleIT
479-
method: testAggMetricInEsqlTSAfterDownsampling
480-
issue: https://github.com/elastic/elasticsearch/issues/131500
481478
- class: org.elasticsearch.xpack.esql.qa.multi_node.GenerativeIT
482479
method: test
483480
issue: https://github.com/elastic/elasticsearch/issues/131508
484481
- class: org.elasticsearch.action.admin.cluster.node.tasks.CancellableTasksIT
485482
method: testRemoveBanParentsOnDisconnect
486483
issue: https://github.com/elastic/elasticsearch/issues/131562
484+
- class: org.elasticsearch.xpack.esql.action.CrossClusterQueryWithPartialResultsIT
485+
method: testPartialResults
486+
issue: https://github.com/elastic/elasticsearch/issues/131481
487+
- class: org.elasticsearch.packaging.test.DockerTests
488+
method: test010Install
489+
issue: https://github.com/elastic/elasticsearch/issues/131376
490+
- class: org.elasticsearch.test.rest.yaml.RcsCcsCommonYamlTestSuiteIT
491+
method: test {p0=search/40_indices_boost/Indices boost with alias}
492+
issue: https://github.com/elastic/elasticsearch/issues/131598
493+
- class: org.elasticsearch.compute.lucene.read.SortedSetOrdinalsBuilderTests
494+
method: testReader
495+
issue: https://github.com/elastic/elasticsearch/issues/131573
487496

488497
# Examples:
489498
#

server/src/internalClusterTest/java/org/elasticsearch/cluster/SpecificMasterNodesIT.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,26 +60,30 @@ public void testElectOnlyBetweenMasterNodes() throws Exception {
6060

6161
logger.info("--> start master node (1)");
6262
final String masterNodeName = internalCluster().startMasterOnlyNode();
63-
awaitMasterNode(internalCluster().getNonMasterNodeName(), masterNodeName);
64-
awaitMasterNode(internalCluster().getMasterName(), masterNodeName);
63+
for (var nodeName : internalCluster().getNodeNames()) {
64+
awaitMasterNode(nodeName, masterNodeName);
65+
}
6566

6667
logger.info("--> start master node (2)");
6768
final String nextMasterEligableNodeName = internalCluster().startMasterOnlyNode();
68-
awaitMasterNode(internalCluster().getNonMasterNodeName(), masterNodeName);
69-
awaitMasterNode(internalCluster().getMasterName(), masterNodeName);
69+
for (var nodeName : internalCluster().getNodeNames()) {
70+
awaitMasterNode(nodeName, masterNodeName);
71+
}
7072

7173
logger.info("--> closing master node (1)");
7274
client().execute(
7375
TransportAddVotingConfigExclusionsAction.TYPE,
7476
new AddVotingConfigExclusionsRequest(TEST_REQUEST_TIMEOUT, masterNodeName)
7577
).get();
7678
// removing the master from the voting configuration immediately triggers the master to step down
77-
awaitMasterNode(internalCluster().getNonMasterNodeName(), nextMasterEligableNodeName);
78-
awaitMasterNode(internalCluster().getMasterName(), nextMasterEligableNodeName);
79+
for (var nodeName : internalCluster().getNodeNames()) {
80+
awaitMasterNode(nodeName, nextMasterEligableNodeName);
81+
}
7982

8083
internalCluster().stopNode(masterNodeName);
81-
awaitMasterNode(internalCluster().getNonMasterNodeName(), nextMasterEligableNodeName);
82-
awaitMasterNode(internalCluster().getMasterName(), nextMasterEligableNodeName);
84+
for (var nodeName : internalCluster().getNodeNames()) {
85+
awaitMasterNode(nodeName, nextMasterEligableNodeName);
86+
}
8387
}
8488

8589
public void testAliasFilterValidation() {

server/src/internalClusterTest/java/org/elasticsearch/index/shard/IndexShardIT.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.elasticsearch.cluster.NodeUsageStatsForThreadPools;
2828
import org.elasticsearch.cluster.NodeUsageStatsForThreadPoolsCollector;
2929
import org.elasticsearch.cluster.metadata.IndexMetadata;
30+
import org.elasticsearch.cluster.metadata.ProjectId;
3031
import org.elasticsearch.cluster.node.DiscoveryNode;
3132
import org.elasticsearch.cluster.node.DiscoveryNodeUtils;
3233
import org.elasticsearch.cluster.routing.RecoverySource;
@@ -104,6 +105,7 @@
104105
import java.util.concurrent.atomic.AtomicReference;
105106
import java.util.function.Predicate;
106107
import java.util.stream.Collectors;
108+
import java.util.stream.IntStream;
107109
import java.util.stream.Stream;
108110

109111
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomAsciiLettersOfLength;
@@ -355,6 +357,62 @@ public void testNodeWriteLoadsArePresent() {
355357
}
356358
}
357359

360+
public void testShardWriteLoadsArePresent() {
361+
// Create some indices and some write-load
362+
final int numIndices = randomIntBetween(1, 5);
363+
final String indexPrefix = randomIdentifier();
364+
IntStream.range(0, numIndices).forEach(i -> {
365+
final String indexName = indexPrefix + "_" + i;
366+
createIndex(indexName, Settings.builder().put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, randomIntBetween(1, 3)).build());
367+
IntStream.range(0, randomIntBetween(1, 500))
368+
.forEach(j -> prepareIndex(indexName).setSource("foo", randomIdentifier(), "bar", randomIdentifier()).get());
369+
});
370+
371+
final InternalClusterInfoService clusterInfoService = (InternalClusterInfoService) getInstanceFromNode(ClusterInfoService.class);
372+
373+
// Not collecting stats yet because allocation write load stats collection is disabled by default.
374+
{
375+
ClusterInfoServiceUtils.refresh(clusterInfoService);
376+
final Map<ShardId, Double> shardWriteLoads = clusterInfoService.getClusterInfo().getShardWriteLoads();
377+
assertNotNull(shardWriteLoads);
378+
assertTrue(shardWriteLoads.isEmpty());
379+
}
380+
381+
// Turn on collection of write-load stats.
382+
updateClusterSettings(
383+
Settings.builder()
384+
.put(
385+
WriteLoadConstraintSettings.WRITE_LOAD_DECIDER_ENABLED_SETTING.getKey(),
386+
WriteLoadConstraintSettings.WriteLoadDeciderStatus.ENABLED
387+
)
388+
.build()
389+
);
390+
391+
try {
392+
// Force a ClusterInfo refresh to run collection of the write-load stats.
393+
ClusterInfoServiceUtils.refresh(clusterInfoService);
394+
final Map<ShardId, Double> shardWriteLoads = clusterInfoService.getClusterInfo().getShardWriteLoads();
395+
396+
// Verify that each shard has write-load reported.
397+
final ClusterState state = getInstanceFromNode(ClusterService.class).state();
398+
assertEquals(state.projectState(ProjectId.DEFAULT).metadata().getTotalNumberOfShards(), shardWriteLoads.size());
399+
double maximumLoadRecorded = 0;
400+
for (IndexMetadata indexMetadata : state.projectState(ProjectId.DEFAULT).metadata()) {
401+
for (int i = 0; i < indexMetadata.getNumberOfShards(); i++) {
402+
final ShardId shardId = new ShardId(indexMetadata.getIndex(), i);
403+
assertTrue(shardWriteLoads.containsKey(shardId));
404+
maximumLoadRecorded = Math.max(shardWriteLoads.get(shardId), maximumLoadRecorded);
405+
}
406+
}
407+
// And that at least one is greater than zero
408+
assertThat(maximumLoadRecorded, greaterThan(0.0));
409+
} finally {
410+
updateClusterSettings(
411+
Settings.builder().putNull(WriteLoadConstraintSettings.WRITE_LOAD_DECIDER_ENABLED_SETTING.getKey()).build()
412+
);
413+
}
414+
}
415+
358416
public void testIndexCanChangeCustomDataPath() throws Exception {
359417
final String index = "test-custom-data-path";
360418
final Path sharedDataPath = getInstanceFromNode(Environment.class).sharedDataDir().resolve(randomAsciiLettersOfLength(10));

server/src/internalClusterTest/java/org/elasticsearch/search/sort/FieldSortIT.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
package org.elasticsearch.search.sort;
1111

12+
import org.apache.http.util.EntityUtils;
1213
import org.apache.lucene.tests.util.TestUtil;
1314
import org.apache.lucene.util.BytesRef;
1415
import org.apache.lucene.util.UnicodeUtil;
@@ -20,6 +21,9 @@
2021
import org.elasticsearch.action.search.SearchRequestBuilder;
2122
import org.elasticsearch.action.search.SearchResponse;
2223
import org.elasticsearch.action.search.ShardSearchFailure;
24+
import org.elasticsearch.client.Request;
25+
import org.elasticsearch.client.Response;
26+
import org.elasticsearch.client.RestClient;
2327
import org.elasticsearch.cluster.metadata.IndexMetadata;
2428
import org.elasticsearch.common.settings.Settings;
2529
import org.elasticsearch.core.Strings;
@@ -36,6 +40,7 @@
3640
import org.elasticsearch.search.SearchHits;
3741
import org.elasticsearch.test.ESIntegTestCase;
3842
import org.elasticsearch.test.InternalSettingsPlugin;
43+
import org.elasticsearch.test.junit.annotations.TestIssueLogging;
3944
import org.elasticsearch.xcontent.XContentBuilder;
4045
import org.elasticsearch.xcontent.XContentFactory;
4146
import org.elasticsearch.xcontent.XContentType;
@@ -84,6 +89,12 @@
8489
import static org.hamcrest.Matchers.not;
8590
import static org.hamcrest.Matchers.nullValue;
8691

92+
@TestIssueLogging(
93+
issueUrl = "https://github.com/elastic/elasticsearch/issues/129445",
94+
value = "org.elasticsearch.action.search.SearchQueryThenFetchAsyncAction:DEBUG,"
95+
+ "org.elasticsearch.action.search.SearchPhaseController:DEBUG,"
96+
+ "org.elasticsearch.search:TRACE"
97+
)
8798
public class FieldSortIT extends ESIntegTestCase {
8899
public static class CustomScriptPlugin extends MockScriptPlugin {
89100
@Override
@@ -112,6 +123,10 @@ protected Collection<Class<? extends Plugin>> nodePlugins() {
112123
return Arrays.asList(InternalSettingsPlugin.class, CustomScriptPlugin.class);
113124
}
114125

126+
protected boolean addMockHttpTransport() {
127+
return false;
128+
}
129+
115130
public void testIssue8226() {
116131
int numIndices = between(5, 10);
117132
final boolean useMapping = randomBoolean();
@@ -2145,7 +2160,7 @@ public void testLongSortOptimizationCorrectResults() {
21452160
);
21462161
}
21472162

2148-
public void testSortMixedFieldTypes() {
2163+
public void testSortMixedFieldTypes() throws IOException {
21492164
assertAcked(
21502165
prepareCreate("index_long").setMapping("foo", "type=long"),
21512166
prepareCreate("index_integer").setMapping("foo", "type=integer"),
@@ -2159,6 +2174,16 @@ public void testSortMixedFieldTypes() {
21592174
prepareIndex("index_keyword").setId("1").setSource("foo", "123").get();
21602175
refresh();
21612176

2177+
// for debugging, we try to see where the documents are located
2178+
try (RestClient restClient = createRestClient()) {
2179+
Request checkShardsRequest = new Request(
2180+
"GET",
2181+
"/_cat/shards/index_long,index_double,index_keyword?format=json&h=index,node,shard,prirep,state,docs,index"
2182+
);
2183+
Response response = restClient.performRequest(checkShardsRequest);
2184+
logger.info("FieldSortIT#testSortMixedFieldTypes document distribution: " + EntityUtils.toString(response.getEntity()));
2185+
}
2186+
21622187
{ // mixing long and integer types is ok, as we convert integer sort to long sort
21632188
assertNoFailures(prepareSearch("index_long", "index_integer").addSort(new FieldSortBuilder("foo")).setSize(10));
21642189
}

server/src/main/java/org/elasticsearch/TransportVersions.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,7 @@ static TransportVersion def(int id) {
344344
public static final TransportVersion ML_INFERENCE_AZURE_AI_STUDIO_RERANK_ADDED = def(9_123_0_00);
345345
public static final TransportVersion PROJECT_STATE_REGISTRY_ENTRY = def(9_124_0_00);
346346
public static final TransportVersion ML_INFERENCE_LLAMA_ADDED = def(9_125_0_00);
347+
public static final TransportVersion SHARD_WRITE_LOAD_IN_CLUSTER_INFO = def(9_126_0_00);
347348

348349
/*
349350
* STOP! READ THIS FIRST! No, really,

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

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
package org.elasticsearch.action.search;
1111

12+
import org.apache.logging.log4j.LogManager;
13+
import org.apache.logging.log4j.Logger;
1214
import org.apache.lucene.search.FieldDoc;
1315
import org.apache.lucene.search.ScoreDoc;
1416
import org.apache.lucene.search.Sort;
@@ -72,6 +74,8 @@
7274

7375
public final class SearchPhaseController {
7476

77+
private static final Logger logger = LogManager.getLogger(SearchPhaseController.class);
78+
7579
private final BiFunction<
7680
Supplier<Boolean>,
7781
AggregatorFactories.Builder,
@@ -153,17 +157,22 @@ static TopDocs mergeTopDocs(List<TopDocs> results, int topN, int from) {
153157
return topDocs;
154158
}
155159
final TopDocs mergedTopDocs;
156-
if (topDocs instanceof TopFieldGroups firstTopDocs) {
157-
final Sort sort = validateSameSortTypesAndMaybeRewrite(results, firstTopDocs.fields);
158-
TopFieldGroups[] shardTopDocs = topDocsList.toArray(new TopFieldGroups[0]);
159-
mergedTopDocs = TopFieldGroups.merge(sort, from, topN, shardTopDocs, false);
160-
} else if (topDocs instanceof TopFieldDocs firstTopDocs) {
161-
TopFieldDocs[] shardTopDocs = topDocsList.toArray(new TopFieldDocs[0]);
162-
final Sort sort = validateSameSortTypesAndMaybeRewrite(results, firstTopDocs.fields);
163-
mergedTopDocs = TopDocs.merge(sort, from, topN, shardTopDocs);
164-
} else {
165-
final TopDocs[] shardTopDocs = topDocsList.toArray(new TopDocs[0]);
166-
mergedTopDocs = TopDocs.merge(from, topN, shardTopDocs);
160+
try {
161+
if (topDocs instanceof TopFieldGroups firstTopDocs) {
162+
final Sort sort = validateSameSortTypesAndMaybeRewrite(results, firstTopDocs.fields);
163+
TopFieldGroups[] shardTopDocs = topDocsList.toArray(new TopFieldGroups[0]);
164+
mergedTopDocs = TopFieldGroups.merge(sort, from, topN, shardTopDocs, false);
165+
} else if (topDocs instanceof TopFieldDocs firstTopDocs) {
166+
TopFieldDocs[] shardTopDocs = topDocsList.toArray(new TopFieldDocs[0]);
167+
final Sort sort = validateSameSortTypesAndMaybeRewrite(results, firstTopDocs.fields);
168+
mergedTopDocs = TopDocs.merge(sort, from, topN, shardTopDocs);
169+
} else {
170+
final TopDocs[] shardTopDocs = topDocsList.toArray(new TopDocs[0]);
171+
mergedTopDocs = TopDocs.merge(from, topN, shardTopDocs);
172+
}
173+
} catch (IllegalArgumentException e) {
174+
logger.debug("Failed to merge top docs: ", e);
175+
throw e;
167176
}
168177
return mergedTopDocs;
169178
}

0 commit comments

Comments
 (0)