Skip to content

Commit 9602d79

Browse files
cbismuthDaveCTurner
authored andcommitted
Separate out validation of groups of settings (#34184)
Today, a setting can declare that its validity depends on the values of other related settings. However, the validity of a setting is not always checked against the correct values of its dependent settings because those settings' correct values may not be available when the validator runs. This commit separates the validation of a settings updates into two phases, with separate methods on the `Setting.Validator` interface. In the first phase the setting's validity is checked in isolation, and in the second phase it is checked again against the values of its related settings. Most settings only use the first phase, and only the few settings with dependencies make use of the second phase.
1 parent 9d0e0eb commit 9602d79

File tree

15 files changed

+266
-168
lines changed

15 files changed

+266
-168
lines changed

plugins/examples/custom-settings/src/main/java/org/elasticsearch/example/customsettings/ExampleCustomSettingsConfig.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public class ExampleCustomSettingsConfig {
4949
/**
5050
* A string setting that can be dynamically updated and that is validated by some logic
5151
*/
52-
static final Setting<String> VALIDATED_SETTING = Setting.simpleString("custom.validated", (value, settings) -> {
52+
static final Setting<String> VALIDATED_SETTING = Setting.simpleString("custom.validated", value -> {
5353
if (value != null && value.contains("forbidden")) {
5454
throw new IllegalArgumentException("Setting must not contain [forbidden]");
5555
}

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,10 @@ static Setting<Integer> buildNumberOfShardsSetting() {
157157
public static final Setting<Integer> INDEX_NUMBER_OF_ROUTING_SHARDS_SETTING =
158158
Setting.intSetting("index.number_of_routing_shards", INDEX_NUMBER_OF_SHARDS_SETTING,
159159
1, new Setting.Validator<Integer>() {
160+
@Override
161+
public void validate(Integer value) {
162+
}
163+
160164
@Override
161165
public void validate(Integer numRoutingShards, Map<Setting<Integer>, Integer> settings) {
162166
Integer numShards = settings.get(INDEX_NUMBER_OF_SHARDS_SETTING);
@@ -223,14 +227,14 @@ public Iterator<Setting<Integer>> settings() {
223227
public static final String INDEX_ROUTING_INCLUDE_GROUP_PREFIX = "index.routing.allocation.include";
224228
public static final String INDEX_ROUTING_EXCLUDE_GROUP_PREFIX = "index.routing.allocation.exclude";
225229
public static final Setting.AffixSetting<String> INDEX_ROUTING_REQUIRE_GROUP_SETTING =
226-
Setting.prefixKeySetting(INDEX_ROUTING_REQUIRE_GROUP_PREFIX + ".", (key) ->
227-
Setting.simpleString(key, (value, map) -> IP_VALIDATOR.accept(key, value), Property.Dynamic, Property.IndexScope));
230+
Setting.prefixKeySetting(INDEX_ROUTING_REQUIRE_GROUP_PREFIX + ".", key ->
231+
Setting.simpleString(key, value -> IP_VALIDATOR.accept(key, value), Property.Dynamic, Property.IndexScope));
228232
public static final Setting.AffixSetting<String> INDEX_ROUTING_INCLUDE_GROUP_SETTING =
229-
Setting.prefixKeySetting(INDEX_ROUTING_INCLUDE_GROUP_PREFIX + ".", (key) ->
230-
Setting.simpleString(key, (value, map) -> IP_VALIDATOR.accept(key, value), Property.Dynamic, Property.IndexScope));
233+
Setting.prefixKeySetting(INDEX_ROUTING_INCLUDE_GROUP_PREFIX + ".", key ->
234+
Setting.simpleString(key, value -> IP_VALIDATOR.accept(key, value), Property.Dynamic, Property.IndexScope));
231235
public static final Setting.AffixSetting<String> INDEX_ROUTING_EXCLUDE_GROUP_SETTING =
232-
Setting.prefixKeySetting(INDEX_ROUTING_EXCLUDE_GROUP_PREFIX + ".", (key) ->
233-
Setting.simpleString(key, (value, map) -> IP_VALIDATOR.accept(key, value), Property.Dynamic, Property.IndexScope));
236+
Setting.prefixKeySetting(INDEX_ROUTING_EXCLUDE_GROUP_PREFIX + ".", key ->
237+
Setting.simpleString(key, value -> IP_VALIDATOR.accept(key, value), Property.Dynamic, Property.IndexScope));
234238
public static final Setting.AffixSetting<String> INDEX_ROUTING_INITIAL_RECOVERY_GROUP_SETTING =
235239
Setting.prefixKeySetting("index.routing.allocation.initial_recovery.", key -> Setting.simpleString(key));
236240
// this is only setable internally not a registered setting!!

server/src/main/java/org/elasticsearch/cluster/routing/allocation/DiskThresholdSettings.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ public DiskThresholdSettings(Settings settings, ClusterSettings clusterSettings)
9393

9494
static final class LowDiskWatermarkValidator implements Setting.Validator<String> {
9595

96+
@Override
97+
public void validate(String value) {
98+
}
99+
96100
@Override
97101
public void validate(String value, Map<Setting<String>, String> settings) {
98102
final String highWatermarkRaw = settings.get(CLUSTER_ROUTING_ALLOCATION_HIGH_DISK_WATERMARK_SETTING);
@@ -112,6 +116,10 @@ public Iterator<Setting<String>> settings() {
112116

113117
static final class HighDiskWatermarkValidator implements Setting.Validator<String> {
114118

119+
@Override
120+
public void validate(String value) {
121+
}
122+
115123
@Override
116124
public void validate(String value, Map<Setting<String>, String> settings) {
117125
final String lowWatermarkRaw = settings.get(CLUSTER_ROUTING_ALLOCATION_LOW_DISK_WATERMARK_SETTING);
@@ -131,6 +139,10 @@ public Iterator<Setting<String>> settings() {
131139

132140
static final class FloodStageValidator implements Setting.Validator<String> {
133141

142+
@Override
143+
public void validate(String value) {
144+
}
145+
134146
@Override
135147
public void validate(String value, Map<Setting<String>, String> settings) {
136148
final String lowWatermarkRaw = settings.get(CLUSTER_ROUTING_ALLOCATION_LOW_DISK_WATERMARK_SETTING);

server/src/main/java/org/elasticsearch/cluster/routing/allocation/decider/FilterAllocationDecider.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,14 @@ public class FilterAllocationDecider extends AllocationDecider {
7272
private static final String CLUSTER_ROUTING_INCLUDE_GROUP_PREFIX = "cluster.routing.allocation.include";
7373
private static final String CLUSTER_ROUTING_EXCLUDE_GROUP_PREFIX = "cluster.routing.allocation.exclude";
7474
public static final Setting.AffixSetting<String> CLUSTER_ROUTING_REQUIRE_GROUP_SETTING =
75-
Setting.prefixKeySetting(CLUSTER_ROUTING_REQUIRE_GROUP_PREFIX + ".", (key) ->
76-
Setting.simpleString(key, (value, map) -> IP_VALIDATOR.accept(key, value), Property.Dynamic, Property.NodeScope));
75+
Setting.prefixKeySetting(CLUSTER_ROUTING_REQUIRE_GROUP_PREFIX + ".", key ->
76+
Setting.simpleString(key, value -> IP_VALIDATOR.accept(key, value), Property.Dynamic, Property.NodeScope));
7777
public static final Setting.AffixSetting<String> CLUSTER_ROUTING_INCLUDE_GROUP_SETTING =
78-
Setting.prefixKeySetting(CLUSTER_ROUTING_INCLUDE_GROUP_PREFIX + ".", (key) ->
79-
Setting.simpleString(key, (value, map) -> IP_VALIDATOR.accept(key, value), Property.Dynamic, Property.NodeScope));
78+
Setting.prefixKeySetting(CLUSTER_ROUTING_INCLUDE_GROUP_PREFIX + ".", key ->
79+
Setting.simpleString(key, value -> IP_VALIDATOR.accept(key, value), Property.Dynamic, Property.NodeScope));
8080
public static final Setting.AffixSetting<String>CLUSTER_ROUTING_EXCLUDE_GROUP_SETTING =
81-
Setting.prefixKeySetting(CLUSTER_ROUTING_EXCLUDE_GROUP_PREFIX + ".", (key) ->
82-
Setting.simpleString(key, (value, map) -> IP_VALIDATOR.accept(key, value), Property.Dynamic, Property.NodeScope));
81+
Setting.prefixKeySetting(CLUSTER_ROUTING_EXCLUDE_GROUP_PREFIX + ".", key ->
82+
Setting.simpleString(key, value -> IP_VALIDATOR.accept(key, value), Property.Dynamic, Property.NodeScope));
8383

8484
/**
8585
* The set of {@link RecoverySource.Type} values for which the

server/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ private boolean updateSettings(Settings toApply, Settings.Builder target, Settin
723723
} else if (get(key) == null) {
724724
throw new IllegalArgumentException(type + " setting [" + key + "], not recognized");
725725
} else if (isDelete == false && canUpdate.test(key)) {
726-
validate(key, toApply, false); // we might not have a full picture here do to a dependency validation
726+
get(key).validateWithoutDependencies(toApply); // we might not have a full picture here do to a dependency validation
727727
settingsBuilder.copy(key, toApply);
728728
updates.copy(key, toApply);
729729
changed |= toApply.get(key).equals(target.get(key)) == false;

server/src/main/java/org/elasticsearch/common/settings/Setting.java

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ private void checkPropertyRequiresIndexScope(final EnumSet<Property> properties,
186186
* @param properties properties for this setting like scope, filtering...
187187
*/
188188
public Setting(Key key, Function<Settings, String> defaultValue, Function<String, T> parser, Property... properties) {
189-
this(key, defaultValue, parser, (v, s) -> {}, properties);
189+
this(key, defaultValue, parser, v -> {}, properties);
190190
}
191191

192192
/**
@@ -246,7 +246,7 @@ public Setting(String key, Function<Settings, String> defaultValue, Function<Str
246246
* @param properties properties for this setting like scope, filtering...
247247
*/
248248
public Setting(Key key, Setting<T> fallbackSetting, Function<String, T> parser, Property... properties) {
249-
this(key, fallbackSetting, fallbackSetting::getRaw, parser, (v, m) -> {}, properties);
249+
this(key, fallbackSetting, fallbackSetting::getRaw, parser, v -> {}, properties);
250250
}
251251

252252
/**
@@ -354,6 +354,14 @@ boolean hasComplexMatcher() {
354354
return isGroupSetting();
355355
}
356356

357+
/**
358+
* Validate the current setting value only without dependencies with {@link Setting.Validator#validate(Object)}.
359+
* @param settings a settings object for settings that has a default value depending on another setting if available
360+
*/
361+
void validateWithoutDependencies(Settings settings) {
362+
validator.validate(get(settings, false));
363+
}
364+
357365
/**
358366
* Returns the default value string representation for this setting.
359367
* @param settings a settings object for settings that has a default value depending on another setting if available
@@ -414,6 +422,7 @@ private T get(Settings settings, boolean validate) {
414422
} else {
415423
map = Collections.emptyMap();
416424
}
425+
validator.validate(parsed);
417426
validator.validate(parsed, map);
418427
}
419428
return parsed;
@@ -805,26 +814,39 @@ public Map<String, T> getAsMap(Settings settings) {
805814
}
806815

807816
/**
808-
* Represents a validator for a setting. The {@link #validate(Object, Map)} method is invoked with the value of this setting and a map
809-
* from the settings specified by {@link #settings()}} to their values. All these values come from the same {@link Settings} instance.
817+
* Represents a validator for a setting. The {@link #validate(Object)} method is invoked early in the update setting process with the
818+
* value of this setting for a fail-fast validation. Later on, the {@link #validate(Object, Map)} method is invoked with the value of
819+
* this setting and a map from the settings specified by {@link #settings()}} to their values. All these values come from the same
820+
* {@link Settings} instance.
810821
*
811822
* @param <T> the type of the {@link Setting}
812823
*/
813824
@FunctionalInterface
814825
public interface Validator<T> {
815826

816827
/**
817-
* The validation routine for this validator.
828+
* Validate this setting's value in isolation.
829+
*
830+
* @param value the value of this setting
831+
*/
832+
void validate(T value);
833+
834+
/**
835+
* Validate this setting against its dependencies, specified by {@link #settings()}. The default implementation does nothing,
836+
* accepting any value as valid as long as it passes the validation in {@link #validate(Object)}.
818837
*
819838
* @param value the value of this setting
820839
* @param settings a map from the settings specified by {@link #settings()}} to their values
821840
*/
822-
void validate(T value, Map<Setting<T>, T> settings);
841+
default void validate(T value, Map<Setting<T>, T> settings) {
842+
}
823843

824844
/**
825-
* The settings needed by this validator.
845+
* The settings on which the validity of this setting depends. The values of the specified settings are passed to
846+
* {@link #validate(Object, Map)}. By default this returns an empty iterator, indicating that this setting does not depend on any
847+
* other settings.
826848
*
827-
* @return the settings needed to validate; these can be used for cross-settings validation
849+
* @return the settings on which the validity of this setting depends.
828850
*/
829851
default Iterator<Setting<T>> settings() {
830852
return Collections.emptyIterator();
@@ -1021,8 +1043,8 @@ public static Setting<String> simpleString(String key, Property... properties) {
10211043
return new Setting<>(key, s -> "", Function.identity(), properties);
10221044
}
10231045

1024-
public static Setting<String> simpleString(String key, Function<String, String> parser, Property... properties) {
1025-
return new Setting<>(key, s -> "", parser, properties);
1046+
public static Setting<String> simpleString(String key, Validator<String> validator, Property... properties) {
1047+
return new Setting<>(new SimpleKey(key), null, s -> "", Function.identity(), validator, properties);
10261048
}
10271049

10281050
public static Setting<String> simpleString(String key, Setting<String> fallback, Property... properties) {
@@ -1037,10 +1059,6 @@ public static Setting<String> simpleString(
10371059
return new Setting<>(key, fallback, parser, properties);
10381060
}
10391061

1040-
public static Setting<String> simpleString(String key, Validator<String> validator, Property... properties) {
1041-
return new Setting<>(new SimpleKey(key), null, s -> "", Function.identity(), validator, properties);
1042-
}
1043-
10441062
/**
10451063
* Creates a new Setting instance with a String value
10461064
*
@@ -1279,9 +1297,9 @@ private ListSetting(
12791297
super(
12801298
new ListKey(key),
12811299
fallbackSetting,
1282-
(s) -> Setting.arrayToParsableString(defaultStringValue.apply(s)),
1300+
s -> Setting.arrayToParsableString(defaultStringValue.apply(s)),
12831301
parser,
1284-
(v,s) -> {},
1302+
v -> {},
12851303
properties);
12861304
this.defaultStringValue = defaultStringValue;
12871305
}
@@ -1339,7 +1357,7 @@ public static Setting<TimeValue> timeSetting(
13391357
fallbackSetting,
13401358
fallbackSetting::getRaw,
13411359
minTimeValueParser(key, minValue),
1342-
(v, s) -> {},
1360+
v -> {},
13431361
properties);
13441362
}
13451363

server/src/main/java/org/elasticsearch/threadpool/AutoQueueAdjustingExecutorBuilder.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,12 @@ public final class AutoQueueAdjustingExecutorBuilder extends ExecutorBuilder<Aut
7575
this.minQueueSizeSetting = new Setting<>(
7676
minSizeKey,
7777
Integer.toString(minQueueSize),
78-
(s) -> Setting.parseInt(s, 0, minSizeKey),
78+
s -> Setting.parseInt(s, 0, minSizeKey),
7979
new Setting.Validator<Integer>() {
80+
@Override
81+
public void validate(Integer value) {
82+
}
83+
8084
@Override
8185
public void validate(Integer value, Map<Setting<Integer>, Integer> settings) {
8286
if (value > settings.get(tempMaxQueueSizeSetting)) {
@@ -94,8 +98,12 @@ public Iterator<Setting<Integer>> settings() {
9498
this.maxQueueSizeSetting = new Setting<>(
9599
maxSizeKey,
96100
Integer.toString(maxQueueSize),
97-
(s) -> Setting.parseInt(s, 0, maxSizeKey),
101+
s -> Setting.parseInt(s, 0, maxSizeKey),
98102
new Setting.Validator<Integer>() {
103+
@Override
104+
public void validate(Integer value) {
105+
}
106+
99107
@Override
100108
public void validate(Integer value, Map<Setting<Integer>, Integer> settings) {
101109
if (value < settings.get(tempMinQueueSizeSetting)) {

server/src/main/java/org/elasticsearch/transport/RemoteClusterAware.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,6 @@ public String getKey(final String key) {
121121
if (Strings.hasLength(s)) {
122122
parsePort(s);
123123
}
124-
return s;
125124
},
126125
Setting.Property.Deprecated,
127126
Setting.Property.Dynamic,

0 commit comments

Comments
 (0)