-
Notifications
You must be signed in to change notification settings - Fork 25.8k
Add INDEX_REFRESH_BLOCK #117543
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add INDEX_REFRESH_BLOCK #117543
Changes from all commits
f9e5264
3a592e1
d447c47
37b3123
0f980e6
40a3a18
063e904
5b23da3
9f943dc
789ed95
d838465
ccee9d1
7525d2d
7030f80
beed63c
00d3dce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,7 +15,8 @@ public enum ClusterBlockLevel { | |
| READ, | ||
| WRITE, | ||
| METADATA_READ, | ||
| METADATA_WRITE; | ||
| METADATA_WRITE, | ||
| REFRESH; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did not check, but wonder if there are any greater than, less than comparisons against the "level", since the wording signals some order. Perhaps you can take a look (if you have not already)?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I checked and saw no comparisons based on the ordinal (and did not expect to saw one either) |
||
|
|
||
| public static final EnumSet<ClusterBlockLevel> ALL = EnumSet.allOf(ClusterBlockLevel.class); | ||
| public static final EnumSet<ClusterBlockLevel> READ_WRITE = EnumSet.of(READ, WRITE); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -140,6 +140,15 @@ public class IndexMetadata implements Diffable<IndexMetadata>, ToXContentFragmen | |
| RestStatus.TOO_MANY_REQUESTS, | ||
| EnumSet.of(ClusterBlockLevel.WRITE) | ||
| ); | ||
| public static final ClusterBlock INDEX_REFRESH_BLOCK = new ClusterBlock( | ||
| 14, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is with the hole here, just avoiding the unfortunate 13 or leaving room for one to go in between?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I was thinking of declaring all ids in the same constant class (all blocks are defined in |
||
| "index refresh blocked, waiting for shard(s) to be started", | ||
| true, | ||
| false, | ||
| false, | ||
| RestStatus.REQUEST_TIMEOUT, | ||
| EnumSet.of(ClusterBlockLevel.REFRESH) | ||
| ); | ||
|
|
||
| // 'event.ingested' (part of Elastic Common Schema) range is tracked in cluster state, along with @timestamp | ||
| public static final String EVENT_INGESTED_FIELD_NAME = "event.ingested"; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,6 +28,7 @@ | |
| import org.elasticsearch.cluster.ClusterStateUpdateTask; | ||
| import org.elasticsearch.cluster.block.ClusterBlockLevel; | ||
| import org.elasticsearch.cluster.block.ClusterBlocks; | ||
| import org.elasticsearch.cluster.node.DiscoveryNode; | ||
| import org.elasticsearch.cluster.node.DiscoveryNodes; | ||
| import org.elasticsearch.cluster.routing.IndexRoutingTable; | ||
| import org.elasticsearch.cluster.routing.RoutingTable; | ||
|
|
@@ -127,6 +128,16 @@ public class MetadataCreateIndexService { | |
|
|
||
| public static final int MAX_INDEX_NAME_BYTES = 255; | ||
|
|
||
| /** | ||
| * Name of the setting used to allow blocking refreshes on newly created indices. | ||
| */ | ||
| public static final String USE_INDEX_REFRESH_BLOCK_SETTING_NAME = "stateless.indices.use_refresh_block_upon_index_creation"; | ||
|
|
||
| @FunctionalInterface | ||
| interface ClusterBlocksTransformer { | ||
| void apply(ClusterBlocks.Builder clusterBlocks, IndexMetadata indexMetadata, TransportVersion minClusterTransportVersion); | ||
| } | ||
|
|
||
| private final Settings settings; | ||
| private final ClusterService clusterService; | ||
| private final IndicesService indicesService; | ||
|
|
@@ -139,6 +150,7 @@ public class MetadataCreateIndexService { | |
| private final boolean forbidPrivateIndexSettings; | ||
| private final Set<IndexSettingProvider> indexSettingProviders; | ||
| private final ThreadPool threadPool; | ||
| private final ClusterBlocksTransformer blocksTransformerUponIndexCreation; | ||
|
|
||
| public MetadataCreateIndexService( | ||
| final Settings settings, | ||
|
|
@@ -166,6 +178,7 @@ public MetadataCreateIndexService( | |
| this.shardLimitValidator = shardLimitValidator; | ||
| this.indexSettingProviders = indexSettingProviders.getIndexSettingProviders(); | ||
| this.threadPool = threadPool; | ||
| this.blocksTransformerUponIndexCreation = createClusterBlocksTransformerForIndexCreation(settings); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -540,8 +553,10 @@ private ClusterState applyCreateIndexWithTemporaryService( | |
| currentState, | ||
| indexMetadata, | ||
| metadataTransformer, | ||
| blocksTransformerUponIndexCreation, | ||
| allocationService.getShardRoutingRoleStrategy() | ||
| ); | ||
| assert assertHasRefreshBlock(indexMetadata, updated, updated.getMinTransportVersion()); | ||
| if (request.performReroute()) { | ||
| updated = allocationService.reroute(updated, "index [" + indexMetadata.getIndex().getName() + "] created", rerouteListener); | ||
| } | ||
|
|
@@ -1294,6 +1309,7 @@ static ClusterState clusterStateCreateIndex( | |
| ClusterState currentState, | ||
| IndexMetadata indexMetadata, | ||
| BiConsumer<Metadata.Builder, IndexMetadata> metadataTransformer, | ||
| ClusterBlocksTransformer blocksTransformer, | ||
| ShardRoutingRoleStrategy shardRoutingRoleStrategy | ||
| ) { | ||
| final Metadata newMetadata; | ||
|
|
@@ -1307,6 +1323,9 @@ static ClusterState clusterStateCreateIndex( | |
|
|
||
| var blocksBuilder = ClusterBlocks.builder().blocks(currentState.blocks()); | ||
| blocksBuilder.updateBlocks(indexMetadata); | ||
| if (blocksTransformer != null) { | ||
| blocksTransformer.apply(blocksBuilder, indexMetadata, currentState.getMinTransportVersion()); | ||
| } | ||
|
|
||
| var routingTableBuilder = RoutingTable.builder(shardRoutingRoleStrategy, currentState.routingTable()) | ||
| .addAsNew(newMetadata.index(indexMetadata.getIndex().getName())); | ||
|
|
@@ -1745,4 +1764,39 @@ public static void validateStoreTypeSetting(Settings indexSettings) { | |
| ); | ||
| } | ||
| } | ||
|
|
||
| private static boolean useRefreshBlock(Settings settings) { | ||
| return DiscoveryNode.isStateless(settings) && settings.getAsBoolean(USE_INDEX_REFRESH_BLOCK_SETTING_NAME, false); | ||
| } | ||
|
|
||
| static ClusterBlocksTransformer createClusterBlocksTransformerForIndexCreation(Settings settings) { | ||
| if (useRefreshBlock(settings) == false) { | ||
| return (clusterBlocks, indexMetadata, minClusterTransportVersion) -> {}; | ||
| } | ||
| logger.debug("applying refresh block on index creation"); | ||
| return (clusterBlocks, indexMetadata, minClusterTransportVersion) -> { | ||
| if (applyRefreshBlock(indexMetadata, minClusterTransportVersion)) { | ||
| // Applies the INDEX_REFRESH_BLOCK to the index. This block will remain in cluster state until an unpromotable shard is | ||
| // started or a configurable delay is elapsed. | ||
| clusterBlocks.addIndexBlock(indexMetadata.getIndex().getName(), IndexMetadata.INDEX_REFRESH_BLOCK); | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| private static boolean applyRefreshBlock(IndexMetadata indexMetadata, TransportVersion minClusterTransportVersion) { | ||
kingherc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return 0 < indexMetadata.getNumberOfReplicas() // index has replicas | ||
| && indexMetadata.getResizeSourceIndex() == null // index is not a split/shrink index | ||
| && indexMetadata.getInSyncAllocationIds().values().stream().allMatch(Set::isEmpty) // index is a new index | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this ever be not true? Fine to keep ofc.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I expect this to be always true, but decided to copy the conditions from org.elasticsearch.cluster.routing.IndexRoutingTable.Builder#initializeEmpty for extra safety. |
||
| && minClusterTransportVersion.onOrAfter(TransportVersions.NEW_REFRESH_CLUSTER_BLOCK); | ||
| } | ||
|
|
||
| private boolean assertHasRefreshBlock(IndexMetadata indexMetadata, ClusterState clusterState, TransportVersion minTransportVersion) { | ||
| var hasRefreshBlock = clusterState.blocks().hasIndexBlock(indexMetadata.getIndex().getName(), IndexMetadata.INDEX_REFRESH_BLOCK); | ||
| if (useRefreshBlock(settings) == false || applyRefreshBlock(indexMetadata, minTransportVersion) == false) { | ||
| assert hasRefreshBlock == false : indexMetadata.getIndex(); | ||
| } else { | ||
| assert hasRefreshBlock : indexMetadata.getIndex(); | ||
| } | ||
| return true; | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.