Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
130 commits
Select commit Hold shift + click to select a range
9d9b6af
unmute tests
drempapis Jan 3, 2025
02ddf82
revert
drempapis Jan 3, 2025
bf79ef3
Merge remote-tracking branch 'upstream/main'
drempapis Jan 3, 2025
f1c91bd
Merge remote-tracking branch 'upstream/main'
drempapis Jan 7, 2025
ba67bff
Merge remote-tracking branch 'upstream/main'
drempapis Jan 7, 2025
2c3654a
Merge remote-tracking branch 'upstream/main'
drempapis Jan 8, 2025
58d4762
Merge remote-tracking branch 'upstream/main'
drempapis Jan 8, 2025
bc38090
Merge remote-tracking branch 'upstream/main'
drempapis Jan 9, 2025
ef0447b
Merge remote-tracking branch 'upstream/main'
drempapis Jan 9, 2025
fe009d7
Merge remote-tracking branch 'upstream/main'
drempapis Jan 10, 2025
a747a40
Merge remote-tracking branch 'upstream/main'
drempapis Jan 10, 2025
f3e47ae
Merge remote-tracking branch 'upstream/main'
drempapis Jan 10, 2025
2bc0107
Merge remote-tracking branch 'upstream/main'
drempapis Jan 13, 2025
f3b3d00
Merge remote-tracking branch 'upstream/main'
drempapis Jan 13, 2025
f52789e
Merge remote-tracking branch 'upstream/main'
drempapis Jan 14, 2025
ec243b7
Merge remote-tracking branch 'upstream/main'
drempapis Jan 14, 2025
f93eb9b
Merge remote-tracking branch 'upstream/main'
drempapis Jan 16, 2025
2777916
Merge remote-tracking branch 'upstream/main'
drempapis Jan 16, 2025
623bd7b
Merge remote-tracking branch 'upstream/main'
drempapis Jan 16, 2025
3fee6af
Merge remote-tracking branch 'upstream/main'
drempapis Jan 16, 2025
af3fff9
Merge remote-tracking branch 'upstream/main'
drempapis Jan 17, 2025
a41bbad
Merge remote-tracking branch 'upstream/main'
drempapis Jan 17, 2025
8115a61
Merge remote-tracking branch 'upstream/main'
drempapis Jan 20, 2025
6b2361e
Merge remote-tracking branch 'upstream/main'
drempapis Jan 20, 2025
41dcc1c
Merge remote-tracking branch 'upstream/main'
drempapis Jan 21, 2025
2df7f62
Merge remote-tracking branch 'upstream/main'
drempapis Jan 21, 2025
6b95b0c
Merge remote-tracking branch 'upstream/main'
drempapis Jan 22, 2025
eadf8cf
Merge remote-tracking branch 'upstream/main'
drempapis Jan 23, 2025
41dc557
Merge remote-tracking branch 'upstream/main'
drempapis Jan 24, 2025
e0e1740
Merge remote-tracking branch 'upstream/main'
drempapis Jan 24, 2025
1ba2eaa
Merge remote-tracking branch 'upstream/main'
drempapis Jan 24, 2025
6820c35
Merge remote-tracking branch 'upstream/main'
drempapis Jan 24, 2025
8280559
Merge remote-tracking branch 'upstream/main'
drempapis Jan 24, 2025
e82375e
Merge remote-tracking branch 'upstream/main'
drempapis Jan 27, 2025
ce4c1c9
Merge remote-tracking branch 'upstream/main'
drempapis Jan 27, 2025
ff92f92
Merge remote-tracking branch 'upstream/main'
drempapis Jan 28, 2025
c0f4d18
Merge remote-tracking branch 'upstream/main'
drempapis Jan 28, 2025
02ac377
Merge remote-tracking branch 'upstream/main'
drempapis Jan 29, 2025
42aa647
Merge remote-tracking branch 'upstream/main'
drempapis Jan 30, 2025
bd258ab
Merge remote-tracking branch 'upstream/main'
drempapis Jan 30, 2025
0d5b0d3
Merge remote-tracking branch 'upstream/main'
drempapis Jan 31, 2025
a6f543a
Merge remote-tracking branch 'upstream/main'
drempapis Jan 31, 2025
89a6aca
Merge remote-tracking branch 'upstream/main'
drempapis Jan 31, 2025
19b0900
Merge remote-tracking branch 'upstream/main'
drempapis Jan 31, 2025
9f1af25
Merge remote-tracking branch 'upstream/main'
drempapis Feb 3, 2025
9cedf78
Merge remote-tracking branch 'upstream/main'
drempapis Feb 7, 2025
a23541b
Merge remote-tracking branch 'upstream/main'
drempapis Feb 11, 2025
406af11
Merge remote-tracking branch 'upstream/main'
drempapis Feb 14, 2025
d324d5f
Merge remote-tracking branch 'upstream/main'
drempapis Feb 14, 2025
fc2b041
Merge remote-tracking branch 'upstream/main'
drempapis Feb 14, 2025
206454b
Merge remote-tracking branch 'upstream/main'
drempapis Feb 14, 2025
f36ed2a
Merge remote-tracking branch 'upstream/main'
drempapis Feb 17, 2025
acc28b5
Merge remote-tracking branch 'upstream/main'
drempapis Feb 17, 2025
f8d3ce0
Merge remote-tracking branch 'upstream/main'
drempapis Feb 17, 2025
c34cc87
Merge remote-tracking branch 'upstream/main'
drempapis Feb 17, 2025
e2c36f8
Merge remote-tracking branch 'upstream/main'
drempapis Feb 17, 2025
8398854
Merge remote-tracking branch 'upstream/main'
drempapis Feb 18, 2025
037eedd
Merge remote-tracking branch 'upstream/main'
drempapis Feb 18, 2025
2a8a7d3
Merge remote-tracking branch 'upstream/main'
drempapis Feb 19, 2025
83b8fab
Merge remote-tracking branch 'upstream/main'
drempapis Feb 19, 2025
b6a0df7
Merge remote-tracking branch 'upstream/main'
drempapis Feb 19, 2025
c33891e
Merge remote-tracking branch 'upstream/main'
drempapis Feb 21, 2025
0c64b54
Merge remote-tracking branch 'upstream/main'
drempapis Feb 21, 2025
e7ba6ee
Merge remote-tracking branch 'upstream/main'
drempapis Feb 21, 2025
66453b4
Merge remote-tracking branch 'upstream/main'
drempapis Feb 24, 2025
a345f39
Merge remote-tracking branch 'upstream/main'
drempapis Feb 25, 2025
e9dac7a
Merge remote-tracking branch 'upstream/main'
drempapis Mar 4, 2025
2cb1681
Merge remote-tracking branch 'upstream/main'
drempapis Mar 5, 2025
d90c490
Merge remote-tracking branch 'upstream/main'
drempapis Mar 6, 2025
0a9a91d
Merge branch 'main' of github.com:drempapis/elasticsearch
drempapis Mar 27, 2025
1e23708
Merge branch 'main' of github.com:drempapis/elasticsearch
drempapis Apr 13, 2025
7639368
test
drempapis Apr 23, 2025
98fe3cf
Add Internal call for multiproject pull method
drempapis Apr 23, 2025
93a7ee7
Merge branch 'main' into multiproject/lightweight_stats_action_rrc
drempapis Apr 24, 2025
75a5398
update
drempapis Apr 24, 2025
db45d45
update
drempapis Apr 24, 2025
c5a249d
update the base code
drempapis Apr 28, 2025
cce3194
update code
drempapis Apr 28, 2025
01d1aa9
Add javadoc
drempapis Apr 28, 2025
dfed174
update naming
drempapis Apr 28, 2025
6d4928d
Update code
drempapis Apr 29, 2025
5210c25
Merge branch 'main' into multiproject/lightweight_stats_action_rrc
drempapis Apr 29, 2025
44aced7
revert code
drempapis Apr 29, 2025
6efbdba
update code
drempapis Apr 29, 2025
7a60718
Add tests for certain classes:
drempapis Apr 29, 2025
9839c83
Update naming
drempapis Apr 29, 2025
2891849
update code
drempapis Apr 29, 2025
fa837fa
Merge branch 'main' into multiproject/lightweight_stats_action_rrc
drempapis Apr 29, 2025
c395c50
update after review
drempapis Apr 29, 2025
da312f2
Add javadoc
drempapis Apr 29, 2025
cdbe6ff
udpate javadoc:
drempapis Apr 29, 2025
3b692ae
spi implementation
drempapis Apr 29, 2025
6ccf982
update
drempapis Apr 29, 2025
2eadc7f
update
drempapis Apr 29, 2025
9023b18
update
drempapis Apr 29, 2025
7dccbe7
update code
drempapis Apr 30, 2025
1e797fc
update code
drempapis Apr 30, 2025
c4353ae
update
drempapis Apr 30, 2025
36a861d
update
drempapis Apr 30, 2025
c786d43
Create spi to load serverless classes
drempapis Apr 30, 2025
5fea235
update after local review
drempapis Apr 30, 2025
88635ca
Spi implementation for search load
drempapis Apr 30, 2025
a8b99c1
Move test to serverless
drempapis Apr 30, 2025
a3a050b
Move new Transport Action code to serverless repo
drempapis Apr 30, 2025
7fa6707
Fix compilation errors
drempapis Apr 30, 2025
da34d84
Remove file
drempapis Apr 30, 2025
f072f3b
Merge branch 'main' into multiproject/lightweight_stats_action_rrc
drempapis May 5, 2025
c1b8b13
move code to stateless
drempapis May 5, 2025
1a5005c
Merge branch 'main' into multiproject/lightweight_stats_action_rrc
drempapis May 6, 2025
62c4349
Merge branch 'main' into multiproject/lightweight_stats_action_rrc
drempapis May 6, 2025
1f9d90e
Mock method for tests
drempapis May 6, 2025
341d44d
[CI] Auto commit changes from spotless
May 6, 2025
2a8a7eb
Merge branch 'main' into multiproject/lightweight_stats_action_rrc
drempapis May 6, 2025
984063f
Merge branch 'main' into multiproject/lightweight_stats_action_rrc
drempapis May 6, 2025
04558d5
Minimize the scope of retuned dto on a per shard basis
drempapis May 6, 2025
6e70bd6
Merge branch 'main' into multiproject/lightweight_stats_action_rrc
drempapis May 6, 2025
f03a83b
Merge branch 'main' into multiproject/lightweight_stats_action_rrc
drempapis May 7, 2025
d12c34d
Merge branch 'main' of github.com:drempapis/elasticsearch
drempapis May 18, 2025
046faba
Merge branch 'elastic:main' into main
drempapis May 18, 2025
6015323
Merge remote-tracking branch 'upstream/main'
drempapis May 19, 2025
043cb6a
Merge remote-tracking branch 'upstream/main'
drempapis May 21, 2025
a488d9f
Merge branch 'main' into multiproject/lightweight_stats_action_rrc
drempapis May 21, 2025
30e138b
Merge remote-tracking branch 'upstream/main'
drempapis May 21, 2025
80e62e8
Merge branch 'main' into multiproject/lightweight_stats_action_rrc
drempapis May 21, 2025
5545cfc
Merge branch 'main' into multiproject/lightweight_stats_action_rrc
drempapis May 21, 2025
36e19da
Merge branch 'main' into multiproject/lightweight_stats_action_rrc
drempapis May 21, 2025
e60add0
Merge branch 'main' into multiproject/lightweight_stats_action_rrc
drempapis May 22, 2025
e551894
Merge branch 'main' into multiproject/lightweight_stats_action_rrc
drempapis May 30, 2025
2f3017c
update after review
drempapis May 30, 2025
c55a725
[CI] Auto commit changes from spotless
May 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
import org.elasticsearch.index.flush.FlushStats;
import org.elasticsearch.index.mapper.MapperMetrics;
import org.elasticsearch.index.mapper.SourceToParse;
import org.elasticsearch.index.search.stats.SearchStatsSettings;
import org.elasticsearch.index.search.stats.ShardSearchLoadRateProvider;
import org.elasticsearch.index.seqno.RetentionLeaseSyncer;
import org.elasticsearch.index.seqno.SequenceNumbers;
import org.elasticsearch.index.translog.TestTranslog;
Expand Down Expand Up @@ -638,7 +640,9 @@ public static final IndexShard newIndexShard(
System::nanoTime,
null,
MapperMetrics.NOOP,
new IndexingStatsSettings(ClusterSettings.createBuiltInClusterSettings())
new IndexingStatsSettings(ClusterSettings.createBuiltInClusterSettings()),
new SearchStatsSettings(ClusterSettings.createBuiltInClusterSettings()),
ShardSearchLoadRateProvider.DEFAULT
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
import org.elasticsearch.index.IndexingPressure;
import org.elasticsearch.index.MergePolicyConfig;
import org.elasticsearch.index.engine.ThreadPoolMergeScheduler;
import org.elasticsearch.index.search.stats.SearchStatsSettings;
import org.elasticsearch.index.shard.IndexingStatsSettings;
import org.elasticsearch.indices.IndexingMemoryController;
import org.elasticsearch.indices.IndicesQueryCache;
Expand Down Expand Up @@ -636,6 +637,7 @@ public void apply(Settings value, Settings current, Settings previous) {
ShardsAvailabilityHealthIndicatorService.REPLICA_UNASSIGNED_BUFFER_TIME,
DataStreamFailureStoreSettings.DATA_STREAM_FAILURE_STORED_ENABLED_SETTING,
IndexingStatsSettings.RECENT_WRITE_LOAD_HALF_LIFE_SETTING,
SearchStatsSettings.RECENT_READ_LOAD_HALF_LIFE_SETTING,
TransportGetAllocationStatsAction.CACHE_TTL_SETTING
);
}
9 changes: 7 additions & 2 deletions server/src/main/java/org/elasticsearch/index/IndexModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.elasticsearch.index.mapper.MapperMetrics;
import org.elasticsearch.index.mapper.MapperRegistry;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.search.stats.SearchStatsSettings;
import org.elasticsearch.index.shard.IndexEventListener;
import org.elasticsearch.index.shard.IndexingOperationListener;
import org.elasticsearch.index.shard.IndexingStatsSettings;
Expand Down Expand Up @@ -179,6 +180,7 @@ public interface DirectoryWrapper {
private final SetOnce<Engine.IndexCommitListener> indexCommitListener = new SetOnce<>();
private final MapperMetrics mapperMetrics;
private final IndexingStatsSettings indexingStatsSettings;
private final SearchStatsSettings searchStatsSettings;

/**
* Construct the index module for the index with the specified index settings. The index module contains extension points for plugins
Expand All @@ -200,7 +202,8 @@ public IndexModule(
final SlowLogFieldProvider slowLogFieldProvider,
final MapperMetrics mapperMetrics,
final List<SearchOperationListener> searchOperationListeners,
final IndexingStatsSettings indexingStatsSettings
final IndexingStatsSettings indexingStatsSettings,
final SearchStatsSettings searchStatsSettings
) {
this.indexSettings = indexSettings;
this.analysisRegistry = analysisRegistry;
Expand All @@ -216,6 +219,7 @@ public IndexModule(
this.recoveryStateFactories = recoveryStateFactories;
this.mapperMetrics = mapperMetrics;
this.indexingStatsSettings = indexingStatsSettings;
this.searchStatsSettings = searchStatsSettings;
}

/**
Expand Down Expand Up @@ -552,7 +556,8 @@ public IndexService newIndexService(
indexCommitListener.get(),
mapperMetrics,
queryRewriteInterceptor,
indexingStatsSettings
indexingStatsSettings,
searchStatsSettings
);
success = true;
return indexService;
Expand Down
14 changes: 11 additions & 3 deletions server/src/main/java/org/elasticsearch/index/IndexService.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
import org.elasticsearch.index.query.QueryRewriteContext;
import org.elasticsearch.index.query.SearchExecutionContext;
import org.elasticsearch.index.query.SearchIndexNameMatcher;
import org.elasticsearch.index.search.stats.SearchStatsSettings;
import org.elasticsearch.index.search.stats.ShardSearchLoadRateProvider;
import org.elasticsearch.index.seqno.RetentionLeaseSyncer;
import org.elasticsearch.index.shard.GlobalCheckpointSyncer;
import org.elasticsearch.index.shard.IndexEventListener;
Expand Down Expand Up @@ -170,6 +172,7 @@ public class IndexService extends AbstractIndexComponent implements IndicesClust
private final MapperMetrics mapperMetrics;
private final QueryRewriteInterceptor queryRewriteInterceptor;
private final IndexingStatsSettings indexingStatsSettings;
private final SearchStatsSettings searchStatsSettings;

@SuppressWarnings("this-escape")
public IndexService(
Expand Down Expand Up @@ -207,7 +210,8 @@ public IndexService(
Engine.IndexCommitListener indexCommitListener,
MapperMetrics mapperMetrics,
QueryRewriteInterceptor queryRewriteInterceptor,
IndexingStatsSettings indexingStatsSettings
IndexingStatsSettings indexingStatsSettings,
SearchStatsSettings searchStatsSettings
) {
super(indexSettings);
assert indexCreationContext != IndexCreationContext.RELOAD_ANALYZERS
Expand Down Expand Up @@ -293,6 +297,7 @@ public IndexService(
this.retentionLeaseSyncTask = new AsyncRetentionLeaseSyncTask(this);
}
this.indexingStatsSettings = indexingStatsSettings;
this.searchStatsSettings = searchStatsSettings;
updateFsyncTaskIfNecessary();
}

Expand Down Expand Up @@ -462,7 +467,8 @@ private long getAvgShardSizeInBytes() throws IOException {
public synchronized IndexShard createShard(
final ShardRouting routing,
final GlobalCheckpointSyncer globalCheckpointSyncer,
final RetentionLeaseSyncer retentionLeaseSyncer
final RetentionLeaseSyncer retentionLeaseSyncer,
final ShardSearchLoadRateProvider shardSearchLoadRateProvider
) throws IOException {
Objects.requireNonNull(retentionLeaseSyncer);
/*
Expand Down Expand Up @@ -583,7 +589,9 @@ public synchronized IndexShard createShard(
System::nanoTime,
indexCommitListener,
mapperMetrics,
indexingStatsSettings
indexingStatsSettings,
searchStatsSettings,
shardSearchLoadRateProvider
);
eventListener.indexShardStateChanged(indexShard, null, indexShard.state(), "shard created");
eventListener.afterIndexShardCreated(indexShard);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.index.search.stats;

import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.core.TimeValue;

/**
* Container for cluster settings
*/
public class SearchStatsSettings {

public static final TimeValue RECENT_READ_LOAD_HALF_LIFE_DEFAULT = TimeValue.timeValueMinutes(5);
static final TimeValue RECENT_READ_LOAD_HALF_LIFE_MIN = TimeValue.timeValueSeconds(1); // A sub-second half-life makes no sense
static final TimeValue RECENT_READ_LOAD_HALF_LIFE_MAX = TimeValue.timeValueDays(100_000); // Long.MAX_VALUE nanos, rounded down

/**
* A cluster setting giving the half-life, in seconds, to use for the Exponentially Weighted Moving Rate calculation used for the
* recency-weighted read load
*
* <p>This is dynamic, but changes only apply to newly-opened shards.
*/
public static final Setting<TimeValue> RECENT_READ_LOAD_HALF_LIFE_SETTING = Setting.timeSetting(
"indices.stats.recent_read_load.half_life",
RECENT_READ_LOAD_HALF_LIFE_DEFAULT,
RECENT_READ_LOAD_HALF_LIFE_MIN,
RECENT_READ_LOAD_HALF_LIFE_MAX,
Setting.Property.Dynamic,
Setting.Property.NodeScope
);

private TimeValue recentReadLoadHalfLifeForNewShards = RECENT_READ_LOAD_HALF_LIFE_SETTING.getDefault(Settings.EMPTY);

public SearchStatsSettings(ClusterSettings clusterSettings) {
clusterSettings.initializeAndWatch(RECENT_READ_LOAD_HALF_LIFE_SETTING, value -> recentReadLoadHalfLifeForNewShards = value);
}

public TimeValue getRecentReadLoadHalfLifeForNewShards() {
return recentReadLoadHalfLifeForNewShards;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.index.search.stats;

import java.util.function.Supplier;

/**
* A factory interface for creating instances of {@link ShardSearchLoadRateService} using configurable settings
* and a time source.
* <p>
* This abstraction allows for flexible instantiation of load rate tracking services, potentially with
* different strategies based on provided settings or runtime context.
*/
public interface ShardSearchLoadRateProvider {

/**
* The default no-op implementation of the provider, which always returns {@link ShardSearchLoadRateService#NOOP}.
* <p>
* Useful as a fallback or when search load rate tracking is disabled or not required.
*/
ShardSearchLoadRateProvider DEFAULT = (settings, timeProvider) -> ShardSearchLoadRateService.NOOP;

/**
* Creates a new instance of {@link ShardSearchLoadRateService} using the given settings and time provider.
*
* @param settings the search statistics configuration settings that may influence the service behavior
* @param timeProvider a supplier of the current time, typically in milliseconds or nanoseconds
* @return a {@code ShardSearchLoadRateService} instance configured with the provided context
*/
ShardSearchLoadRateService create(SearchStatsSettings settings, Supplier<Long> timeProvider);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.index.search.stats;

/**
* Service interface for estimating the search load rate of a shard using provided search statistics.
* <p>
* Implementations may apply various heuristics or models, such as exponentially weighted moving rate,
* to track and estimate the current load on a shard based on its search activity.
*/
public interface ShardSearchLoadRateService {

/**
* A no-op implementation of {@code ShardSearchLoadRateService} that always returns {@code 0.0}
* This can be used as a fallback or default when no actual load tracking is required.
*/
ShardSearchLoadRateService NOOP = (stats) -> 0.0;

/**
* Computes the search load rate based on the provided shard-level search statistics.
*
* @param stats the search statistics for the shard, typically including metrics like query count, latency, etc.
* @return the {@code double} representing the calculated EWMR on the shard
*/
double getSearchLoadRate(SearchStats.Stats stats);
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,10 @@
import org.elasticsearch.index.refresh.RefreshStats;
import org.elasticsearch.index.search.stats.FieldUsageStats;
import org.elasticsearch.index.search.stats.SearchStats;
import org.elasticsearch.index.search.stats.SearchStatsSettings;
import org.elasticsearch.index.search.stats.ShardFieldUsageTracker;
import org.elasticsearch.index.search.stats.ShardSearchLoadRateProvider;
import org.elasticsearch.index.search.stats.ShardSearchLoadRateService;
import org.elasticsearch.index.search.stats.ShardSearchStats;
import org.elasticsearch.index.seqno.ReplicationTracker;
import org.elasticsearch.index.seqno.RetentionLease;
Expand Down Expand Up @@ -204,6 +207,7 @@ public class IndexShard extends AbstractIndexShardComponent implements IndicesCl
private final Store store;
private final InternalIndexingStats internalIndexingStats;
private final ShardSearchStats searchStats = new ShardSearchStats();
private final ShardSearchLoadRateService shardSearchLoadRateService;
private final ShardFieldUsageTracker fieldUsageTracker;
private final String shardUuid = UUIDs.randomBase64UUID();
private final long shardCreationTime;
Expand Down Expand Up @@ -341,7 +345,9 @@ public IndexShard(
final LongSupplier relativeTimeInNanosSupplier,
final Engine.IndexCommitListener indexCommitListener,
final MapperMetrics mapperMetrics,
final IndexingStatsSettings indexingStatsSettings
final IndexingStatsSettings indexingStatsSettings,
final SearchStatsSettings searchStatsSettings,
final ShardSearchLoadRateProvider shardSearchLoadRateProvider
) throws IOException {
super(shardRouting.shardId(), indexSettings);
assert shardRouting.initializing();
Expand All @@ -366,6 +372,7 @@ public IndexShard(
CollectionUtils.appendToCopyNoNullElements(listeners, internalIndexingStats, indexingFailuresDebugListener),
logger
);
this.shardSearchLoadRateService = shardSearchLoadRateProvider.create(searchStatsSettings, System::currentTimeMillis);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why we're injecting a service here. Could the index shard calculate the ewmr directly?
What's the reason for the SPI?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good question. The main reason for injecting the service via SPI rather than calculating the EWMR directly in IndexShard is to avoid unnecessary memory overhead when the functionality isn't needed. While lazy initialization behind a proxy is an option on the stateful side, it would add unnecessary complexity to the core codebase.

Additionally, this design helps separate concerns: the implementation is specific to the multi-project setup and doesn't belong in the core logic of IndexShard. Placing it behind an SPI keeps the core codebase clean and aligns the implementation more closely with the project that owns the logic, improving maintainability and modularity. So, keeping it behind an SPI ensures it's only enabled where applicable.

this.bulkOperationListener = new ShardBulkStats();
this.globalCheckpointSyncer = globalCheckpointSyncer;
this.retentionLeaseSyncer = Objects.requireNonNull(retentionLeaseSyncer);
Expand Down Expand Up @@ -1414,6 +1421,13 @@ public SearchStats searchStats(String... groups) {
return searchStats.stats(groups);
}

/**
* Returns the search load rate stats for this shard.
*/
public double getSearchLoadRate() {
return shardSearchLoadRateService.getSearchLoadRate(searchStats.stats().getTotal());
}

public FieldUsageStats fieldUsageStats(String... fields) {
return fieldUsageTracker.stats(fields);
}
Expand Down
23 changes: 20 additions & 3 deletions server/src/main/java/org/elasticsearch/indices/IndicesService.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@
import org.elasticsearch.index.recovery.RecoveryStats;
import org.elasticsearch.index.refresh.RefreshStats;
import org.elasticsearch.index.search.stats.SearchStats;
import org.elasticsearch.index.search.stats.SearchStatsSettings;
import org.elasticsearch.index.search.stats.ShardSearchLoadRateProvider;
import org.elasticsearch.index.seqno.RetentionLeaseStats;
import org.elasticsearch.index.seqno.RetentionLeaseSyncer;
import org.elasticsearch.index.seqno.SeqNoStats;
Expand Down Expand Up @@ -281,6 +283,7 @@ public class IndicesService extends AbstractLifecycleComponent
private final QueryRewriteInterceptor queryRewriteInterceptor;
final SlowLogFieldProvider slowLogFieldProvider; // pkg-private for testingå
private final IndexingStatsSettings indexStatsSettings;
private final SearchStatsSettings searchStatsSettings;

@Override
protected void doStart() {
Expand Down Expand Up @@ -406,6 +409,7 @@ public void onRemoval(ShardId shardId, String fieldName, boolean wasEvicted, lon
this.searchOperationListeners = builder.searchOperationListener;
this.slowLogFieldProvider = builder.slowLogFieldProvider;
this.indexStatsSettings = new IndexingStatsSettings(clusterService.getClusterSettings());
this.searchStatsSettings = new SearchStatsSettings(clusterService.getClusterSettings());
}

private static final String DANGLING_INDICES_UPDATE_THREAD_NAME = "DanglingIndices#updateTask";
Expand Down Expand Up @@ -795,7 +799,8 @@ private synchronized IndexService createIndexService(
slowLogFieldProvider,
mapperMetrics,
searchOperationListeners,
indexStatsSettings
indexStatsSettings,
searchStatsSettings
);
for (IndexingOperationListener operationListener : indexingOperationListeners) {
indexModule.addIndexOperationListener(operationListener);
Expand Down Expand Up @@ -893,7 +898,8 @@ public synchronized MapperService createIndexMapperServiceForValidation(IndexMet
slowLogFieldProvider,
mapperMetrics,
searchOperationListeners,
indexStatsSettings
indexStatsSettings,
searchStatsSettings
);
pluginsService.forEach(p -> p.onIndexModule(indexModule));
return indexModule.newIndexMapperService(clusterService, parserConfig, mapperRegistry, scriptService);
Expand Down Expand Up @@ -954,7 +960,18 @@ public void createShard(
IndexService indexService = indexService(shardRouting.index());
assert indexService != null;
RecoveryState recoveryState = indexService.createRecoveryState(shardRouting, targetNode, sourceNode);
IndexShard indexShard = indexService.createShard(shardRouting, globalCheckpointSyncer, retentionLeaseSyncer);

ShardSearchLoadRateProvider shardSearchLoadRateProvider = pluginsService.loadSingletonServiceProvider(
ShardSearchLoadRateProvider.class,
() -> ShardSearchLoadRateProvider.DEFAULT
);

IndexShard indexShard = indexService.createShard(
shardRouting,
globalCheckpointSyncer,
retentionLeaseSyncer,
shardSearchLoadRateProvider
);
indexShard.addShardFailureCallback(onShardFailure);
indexShard.startRecovery(
recoveryState,
Expand Down
Loading