Skip to content

Commit 13d89a7

Browse files
committed
Check shard limit after applying index templates (#44619)
Today when creating an index and checking cluster shard limits, we check the number of shards before applying index templates. At this point, we do not know the actual number of shards that will be used to create the index. In a case when the defaults are used and a template would override, we could be grossly underestimating the number of shards that would be created, and thus incorrectly applying the limits. This commit addresses this by checking the shard limits after applying index templates.
1 parent 9de868d commit 13d89a7

File tree

4 files changed

+41
-15
lines changed

4 files changed

+41
-15
lines changed

server/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
package org.elasticsearch.cluster.metadata;
2121

2222
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
23-
import org.apache.logging.log4j.Logger;
2423
import org.apache.logging.log4j.LogManager;
24+
import org.apache.logging.log4j.Logger;
2525
import org.apache.logging.log4j.message.ParameterizedMessage;
2626
import org.elasticsearch.ElasticsearchException;
2727
import org.elasticsearch.ResourceAlreadyExistsException;
@@ -435,6 +435,13 @@ public ClusterState execute(ClusterState currentState) throws Exception {
435435
indexScopedSettings);
436436
}
437437
final Settings actualIndexSettings = indexSettingsBuilder.build();
438+
439+
/*
440+
* We can not check the shard limit until we have applied templates, otherwise we do not know the actual number of shards
441+
* that will be used to create this index.
442+
*/
443+
checkShardLimit(actualIndexSettings, currentState);
444+
438445
tmpImdBuilder.settings(actualIndexSettings);
439446

440447
if (recoverFromIndex != null) {
@@ -583,6 +590,10 @@ public ClusterState execute(ClusterState currentState) throws Exception {
583590
}
584591
}
585592

593+
protected void checkShardLimit(final Settings settings, final ClusterState clusterState) {
594+
MetaDataCreateIndexService.checkShardLimit(settings, clusterState, deprecationLogger);
595+
}
596+
586597
@Override
587598
public void onFailure(String source, Exception e) {
588599
if (e instanceof ResourceAlreadyExistsException) {
@@ -603,9 +614,6 @@ public void validateIndexSettings(String indexName, final Settings settings, fin
603614
final boolean forbidPrivateIndexSettings) throws IndexCreationException {
604615
List<String> validationErrors = getIndexSettingsValidationErrors(settings, forbidPrivateIndexSettings);
605616

606-
Optional<String> shardAllocation = checkShardLimit(settings, clusterState, deprecationLogger);
607-
shardAllocation.ifPresent(validationErrors::add);
608-
609617
if (validationErrors.isEmpty() == false) {
610618
ValidationException validationException = new ValidationException();
611619
validationException.addValidationErrors(validationErrors);
@@ -616,16 +624,22 @@ public void validateIndexSettings(String indexName, final Settings settings, fin
616624
/**
617625
* Checks whether an index can be created without going over the cluster shard limit.
618626
*
619-
* @param settings The settings of the index to be created.
620-
* @param clusterState The current cluster state.
621-
* @param deprecationLogger The logger to use to emit a deprecation warning, if appropriate.
622-
* @return If present, an error message to be used to reject index creation. If empty, a signal that this operation may be carried out.
627+
* @param settings the settings of the index to be created
628+
* @param clusterState the current cluster state
629+
* @param deprecationLogger the logger to use to emit a deprecation warning, if appropriate
630+
* @throws ValidationException if creating this index would put the cluster over the cluster shard limit
623631
*/
624-
static Optional<String> checkShardLimit(Settings settings, ClusterState clusterState, DeprecationLogger deprecationLogger) {
625-
int shardsToCreate = IndexMetaData.INDEX_NUMBER_OF_SHARDS_SETTING.get(settings)
626-
* (1 + IndexMetaData.INDEX_NUMBER_OF_REPLICAS_SETTING.get(settings));
627-
628-
return IndicesService.checkShardLimit(shardsToCreate, clusterState, deprecationLogger);
632+
public static void checkShardLimit(Settings settings, ClusterState clusterState, DeprecationLogger deprecationLogger) {
633+
final int numberOfShards = IndexMetaData.INDEX_NUMBER_OF_SHARDS_SETTING.get(settings);
634+
final int numberOfReplicas = IndexMetaData.INDEX_NUMBER_OF_REPLICAS_SETTING.get(settings);
635+
final int shardsToCreate = numberOfShards * (1 + numberOfReplicas);
636+
637+
final Optional<String> shardLimit = IndicesService.checkShardLimit(shardsToCreate, clusterState, deprecationLogger);
638+
if (shardLimit.isPresent()) {
639+
final ValidationException e = new ValidationException();
640+
e.addValidationError(shardLimit.get());
641+
throw e;
642+
}
629643
}
630644

631645
List<String> getIndexSettingsValidationErrors(final Settings settings, final boolean forbidPrivateIndexSettings) {

server/src/main/java/org/elasticsearch/snapshots/RestoreService.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import org.elasticsearch.common.UUIDs;
5959
import org.elasticsearch.common.collect.ImmutableOpenMap;
6060
import org.elasticsearch.common.inject.Inject;
61+
import org.elasticsearch.common.logging.DeprecationLogger;
6162
import org.elasticsearch.common.lucene.Lucene;
6263
import org.elasticsearch.common.regex.Regex;
6364
import org.elasticsearch.common.settings.ClusterSettings;
@@ -117,6 +118,7 @@
117118
public class RestoreService implements ClusterStateApplier {
118119

119120
private static final Logger logger = LogManager.getLogger(RestoreService.class);
121+
private static final DeprecationLogger deprecationLogger = new DeprecationLogger(logger);
120122

121123
private static final Set<String> UNMODIFIABLE_SETTINGS = unmodifiableSet(newHashSet(
122124
SETTING_NUMBER_OF_SHARDS,
@@ -288,6 +290,10 @@ public ClusterState execute(ClusterState currentState) {
288290
indexMdBuilder.settings(Settings.builder()
289291
.put(snapshotIndexMetaData.getSettings())
290292
.put(IndexMetaData.SETTING_INDEX_UUID, UUIDs.randomBase64UUID()));
293+
MetaDataCreateIndexService.checkShardLimit(
294+
snapshotIndexMetaData.getSettings(),
295+
currentState,
296+
deprecationLogger);
291297
if (!request.includeAliases() && !snapshotIndexMetaData.getAliases().isEmpty()) {
292298
// Remove all aliases - they shouldn't be restored
293299
indexMdBuilder.removeAllAliases();

server/src/test/java/org/elasticsearch/cluster/metadata/IndexCreationTaskTests.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,14 @@ private ClusterState executeTask() throws Exception {
471471
setupRequest();
472472
final MetaDataCreateIndexService.IndexCreationTask task = new MetaDataCreateIndexService.IndexCreationTask(
473473
logger, allocationService, request, listener, indicesService, aliasValidator, xContentRegistry, clusterStateSettings.build(),
474-
validator, IndexScopedSettings.DEFAULT_SCOPED_SETTINGS);
474+
validator, IndexScopedSettings.DEFAULT_SCOPED_SETTINGS) {
475+
476+
@Override
477+
protected void checkShardLimit(final Settings settings, final ClusterState clusterState) {
478+
// we have to make this a no-op since we are not mocking enough for this method to be able to execute
479+
}
480+
481+
};
475482
return task.execute(state);
476483
}
477484

server/src/test/java/org/elasticsearch/cluster/shards/ClusterShardLimitIT.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
* under the License.
1818
*/
1919

20-
2120
package org.elasticsearch.cluster.shards;
2221

2322
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;

0 commit comments

Comments
 (0)