Skip to content

Commit

Permalink
Don't omit default values when updating routing exclusions (elastic#3…
Browse files Browse the repository at this point in the history
…3638)

Exclusion setting `cluster.routing.allocation.exclude._host` default value
is an empty string.

When an exclusion setting is sent with a null value the
o.e.c.s.Setting#innerGetRaw API return an empty string (probably to
avoid a NullPointerException to be raised).

The o.e.c.r.a.d.FilterAllocationDecider class is developed to omit
updates of default values for exclusion setting.

That's why a null exclusion setting value is translated to an empty
string which is equals to the exclusion default value which is
configured to be ignored.

A simple fix would be to not omit default values for exclusion setting
and keep the NullPointerException guard. This is the purpose of this
commit.

Closes elastic#32721
  • Loading branch information
cbismuth authored and s1monw committed Oct 19, 2018
1 parent aeb3cda commit 3036ab1
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ public FilterAllocationDecider(Settings settings, ClusterSettings clusterSetting
setClusterRequireFilters(CLUSTER_ROUTING_REQUIRE_GROUP_SETTING.getAsMap(settings));
setClusterExcludeFilters(CLUSTER_ROUTING_EXCLUDE_GROUP_SETTING.getAsMap(settings));
setClusterIncludeFilters(CLUSTER_ROUTING_INCLUDE_GROUP_SETTING.getAsMap(settings));
clusterSettings.addAffixMapUpdateConsumer(CLUSTER_ROUTING_REQUIRE_GROUP_SETTING, this::setClusterRequireFilters, (a,b)-> {}, true);
clusterSettings.addAffixMapUpdateConsumer(CLUSTER_ROUTING_EXCLUDE_GROUP_SETTING, this::setClusterExcludeFilters, (a,b)-> {}, true);
clusterSettings.addAffixMapUpdateConsumer(CLUSTER_ROUTING_INCLUDE_GROUP_SETTING, this::setClusterIncludeFilters, (a,b)-> {}, true);
clusterSettings.addAffixMapUpdateConsumer(CLUSTER_ROUTING_REQUIRE_GROUP_SETTING, this::setClusterRequireFilters, (a, b) -> {});
clusterSettings.addAffixMapUpdateConsumer(CLUSTER_ROUTING_EXCLUDE_GROUP_SETTING, this::setClusterExcludeFilters, (a, b) -> {});
clusterSettings.addAffixMapUpdateConsumer(CLUSTER_ROUTING_INCLUDE_GROUP_SETTING, this::setClusterIncludeFilters, (a, b) -> {});
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,13 +301,13 @@ private void ensureSettingIsRegistered(Setting.AffixSetting<?> setting) {
* consumer in order to be processed correctly. This consumer will get a namespace to value map instead of each individual namespace
* and value as in {@link #addAffixUpdateConsumer(Setting.AffixSetting, BiConsumer, BiConsumer)}
*/
public synchronized <T> void addAffixMapUpdateConsumer(Setting.AffixSetting<T> setting, Consumer<Map<String, T>> consumer,
BiConsumer<String, T> validator, boolean omitDefaults) {
public synchronized <T> void addAffixMapUpdateConsumer(Setting.AffixSetting<T> setting, Consumer<Map<String, T>> consumer,
BiConsumer<String, T> validator) {
final Setting<?> registeredSetting = this.complexMatchers.get(setting.getKey());
if (setting != registeredSetting) {
throw new IllegalArgumentException("Setting is not registered for key [" + setting.getKey() + "]");
}
addSettingsUpdater(setting.newAffixMapUpdater(consumer, logger, validator, omitDefaults));
addSettingsUpdater(setting.newAffixMapUpdater(consumer, logger, validator));
}

synchronized void addSettingsUpdater(SettingUpdater<?> updater) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,7 @@ public void apply(Map<AbstractScopedSettings.SettingUpdater<T>, T> value, Settin
}

AbstractScopedSettings.SettingUpdater<Map<String, T>> newAffixMapUpdater(Consumer<Map<String, T>> consumer, Logger logger,
BiConsumer<String, T> validator, boolean omitDefaults) {
BiConsumer<String, T> validator) {
return new AbstractScopedSettings.SettingUpdater<Map<String, T>>() {

@Override
Expand All @@ -721,9 +721,7 @@ public Map<String, T> getValue(Settings current, Settings previous) {
// only the ones that have changed otherwise we might get too many updates
// the hasChanged above checks only if there are any changes
T value = updater.getValue(current, previous);
if ((omitDefaults && value.equals(concreteSetting.getDefault(current))) == false) {
result.put(namespace, value);
}
result.put(namespace, value);
}
});
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,8 @@ public void testAddConsumerAffixMap() {
listResults.clear();
listResults.putAll(map);
};
boolean omitDefaults = randomBoolean();
service.addAffixMapUpdateConsumer(listSetting, listConsumer, (s, k) -> {}, omitDefaults);
service.addAffixMapUpdateConsumer(intSetting, intConsumer, (s, k) -> {}, omitDefaults);
service.addAffixMapUpdateConsumer(listSetting, listConsumer, (s, k) -> {});
service.addAffixMapUpdateConsumer(intSetting, intConsumer, (s, k) -> {});
assertEquals(0, listResults.size());
assertEquals(0, intResults.size());
service.applySettings(Settings.builder()
Expand Down Expand Up @@ -403,7 +402,6 @@ public void testAddConsumerAffixMap() {
assertEquals(2, listResults.size());
assertEquals(2, intResults.size());


listResults.clear();
intResults.clear();

Expand All @@ -416,17 +414,9 @@ public void testAddConsumerAffixMap() {
assertNull("test wasn't changed", intResults.get("test"));
assertEquals(8, intResults.get("test_1").intValue());
assertNull("test_list wasn't changed", listResults.get("test_list"));
if (omitDefaults) {
assertNull(listResults.get("test_list_1"));
assertFalse(listResults.containsKey("test_list_1"));
assertEquals(0, listResults.size());
assertEquals(1, intResults.size());
} else {
assertEquals(Arrays.asList(1), listResults.get("test_list_1")); // reset to default
assertEquals(1, listResults.size());
assertEquals(1, intResults.size());
}

assertEquals(Arrays.asList(1), listResults.get("test_list_1")); // reset to default
assertEquals(1, listResults.size());
assertEquals(1, intResults.size());
}

public void testAffixMapConsumerNotCalledWithNull() {
Expand All @@ -442,7 +432,7 @@ public void testAffixMapConsumerNotCalledWithNull() {
affixResults.clear();
affixResults.putAll(map);
};
service.addAffixMapUpdateConsumer(prefixSetting, consumer, (s, k) -> {}, randomBoolean());
service.addAffixMapUpdateConsumer(prefixSetting, consumer, (s, k) -> {});
assertEquals(0, affixResults.size());
service.applySettings(Settings.builder()
.put("eggplant._name", 2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.elasticsearch.common.settings;

import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.settings.AbstractScopedSettings.SettingUpdater;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.unit.ByteSizeUnit;
import org.elasticsearch.common.unit.ByteSizeValue;
Expand All @@ -33,6 +34,8 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand Down Expand Up @@ -890,4 +893,39 @@ public void testExistsWithFallback() {
}
}

public void testAffixMapUpdateWithNullSettingValue() {
// GIVEN an affix setting changed from "prefix._foo"="bar" to "prefix._foo"=null
final Settings current = Settings.builder()
.put("prefix._foo", (String) null)
.build();

final Settings previous = Settings.builder()
.put("prefix._foo", "bar")
.build();

final Setting.AffixSetting<String> affixSetting =
Setting.prefixKeySetting("prefix" + ".",
(key) -> Setting.simpleString(key, (value, map) -> {}, Property.Dynamic, Property.NodeScope));

final Consumer<Map<String, String>> consumer = (map) -> {};
final BiConsumer<String, String> validator = (s1, s2) -> {};

// WHEN creating an affix updater
final SettingUpdater<Map<String, String>> updater = affixSetting.newAffixMapUpdater(consumer, logger, validator);

// THEN affix updater is always expected to have changed (even when defaults are omitted)
assertTrue(updater.hasChanged(current, previous));

// THEN changes are expected when defaults aren't omitted
final Map<String, String> updatedSettings = updater.getValue(current, previous);
assertNotNull(updatedSettings);
assertEquals(1, updatedSettings.size());

// THEN changes are reported when defaults aren't omitted
final String key = updatedSettings.keySet().iterator().next();
final String value = updatedSettings.get(key);
assertEquals("_foo", key);
assertEquals("", value);
}

}

0 comments on commit 3036ab1

Please sign in to comment.