-
Notifications
You must be signed in to change notification settings - Fork 24.9k
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
Fix setting notification for complex setting (affixMap settings) that could cause transient settings to be ignored #28317
Conversation
Previously if an affixMap setting was registered, and then a completely different setting was applied, the affixMap update consumer would be notified with an empty map. This caused settings that were previously set to be unset in local state in a consumer that assumed it would only be called when the affixMap setting was changed. This commit changes the behavior so if a prefix `foo.` is registered, any setting under the prefix will have the update consumer notified if there are changes starting with `foo.`. Resolves elastic#28316
There might be a better way to solve this, which is why I am marking this as "discuss" |
@dakrone it's unclear to me what you are fixing here. is it possible to have a simple unittest that fails previously and passes now? |
I'm planning on adding a unit test for this, I wanted to get it up for
discussion in case I missed something in the implementation. Hopefully a
test will make it clearer
…On Jan 20, 2018 9:23 AM, "Simon Willnauer" ***@***.***> wrote:
@dakrone <https://github.com/dakrone> it's unclear to me what you are
fixing here. is it possible to have a simple unittest that fails previously
and passes now?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#28317 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AABKdBQSN5aknqJzb6p_zqK3yncUNp-bks5tMhLzgaJpZM4RlL-m>
.
|
++ @dakrone |
This should be backported to 6.2, it's confusing to have a fix in the 6.1 and 6.3 series but not 6.2? |
absolutely this should go into 6.2 |
@dakrone I looked at it to make sure I understand what's going on. I suggest this patch based on your changes: diff --git a/server/src/main/java/org/elasticsearch/common/settings/Setting.java b/server/src/main/java/org/elasticsearch/common/settings/Setting.java
index 4ecb8b1442..fd91a8a760 100644
--- a/server/src/main/java/org/elasticsearch/common/settings/Setting.java
+++ b/server/src/main/java/org/elasticsearch/common/settings/Setting.java
@@ -597,21 +597,7 @@ public class Setting<T> implements ToXContentObject {
@Override
public boolean hasChanged(Settings current, Settings previous) {
- return Stream.concat(matchStream(current), matchStream(previous)).distinct().anyMatch(aKey -> {
- String namespace = key.getNamespace(aKey);
- Setting<T> concreteSetting = getConcreteSetting(aKey);
- AbstractScopedSettings.SettingUpdater<T> updater =
- concreteSetting.newUpdater((v) -> {}, logger, (v) -> validator.accept(namespace, v));
- T value = updater.getValue(current, previous);
- if (updater.hasChanged(current, previous)) {
- // only the ones that have changed otherwise we might get too many updates
- // the hasChanged above checks only if there are any changes
- if ((omitDefaults && value.equals(concreteSetting.getDefault(current))) == false) {
- return true;
- }
- }
- return false;
- });
+ return current.filter(k -> match(k)).equals(previous.filter(k -> match(k))) == false;
}
@Override
@@ -623,8 +609,14 @@ public class Setting<T> implements ToXContentObject {
Setting<T> concreteSetting = getConcreteSetting(aKey);
AbstractScopedSettings.SettingUpdater<T> updater =
concreteSetting.newUpdater((v) -> {}, logger, (v) -> validator.accept(namespace, v));
- T value = updater.getValue(current, previous);
- result.put(namespace, value);
+ if (updater.hasChanged(current, 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);
+ }
+ }
});
return result;
}
diff --git a/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java b/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java
index 298a82a138..fba760bc60 100644
--- a/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java
+++ b/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java
@@ -226,6 +226,27 @@ public class ScopedSettingsTests extends ESTestCase {
assertEquals(1, intResults.size());
}
+ public void testPrefixKeySetting() {
+ Setting.AffixSetting<String> setting = Setting.prefixKeySetting("foo.",
+ (k) -> Setting.simpleString(k, Property.Dynamic, Property.NodeScope));
+ Setting<String> stringSetting = Setting.simpleString("test.bar", Property.Dynamic, Property.NodeScope);
+ AbstractScopedSettings service = new ClusterSettings(Settings.EMPTY,new HashSet<>(Arrays.asList(setting, stringSetting)));
+ Map<String, String> consumerMap = new HashMap<>();
+ service.addAffixMapUpdateConsumer(setting, (m) -> {
+ consumerMap.clear();
+ consumerMap.putAll(m);
+ }, (s, k) -> {}, false);
+ service.applySettings(Settings.builder().put("foo.bar", "1").put("foo.baz", "2").build());
+ assertEquals(2, consumerMap.size());
+ assertEquals("1", consumerMap.get("bar"));
+ assertEquals("2", consumerMap.get("baz"));
+ service.applySettings(Settings.builder().put("foo.bar", "1").put("foo.baz", "2").put("test.bar", "foo").build());
+
+ assertEquals(2, consumerMap.size());
+ assertEquals("1", consumerMap.get("bar"));
+ assertEquals("2", consumerMap.get("baz"));
+ }
+
public void testAddConsumerAffixMap() {
Setting.AffixSetting<Integer> intSetting = Setting.affixKeySetting("foo.", "bar",
(k) -> Setting.intSetting(k, 1, Property.Dynamic, Property.NodeScope));
@@ -261,6 +282,21 @@ public class ScopedSettingsTests extends ESTestCase {
assertEquals(2, listResults.size());
assertEquals(2, intResults.size());
+ service.applySettings(Settings.builder()
+ .put("foo.test.bar", 2)
+ .put("foo.test_1.bar", 7)
+ .putList("foo.test_list.list", "16", "17")
+ .putList("foo.test_list_1.list", "18", "19", "20")
+ .build());
+
+ assertEquals(2, intResults.get("test").intValue());
+ assertEquals(7, intResults.get("test_1").intValue());
+ assertEquals(Arrays.asList(16, 17), listResults.get("test_list"));
+ assertEquals(Arrays.asList(18, 19, 20), listResults.get("test_list_1"));
+ assertEquals(2, listResults.size());
+ assertEquals(2, intResults.size());
+
+
listResults.clear();
intResults.clear();
@@ -270,19 +306,18 @@ public class ScopedSettingsTests extends ESTestCase {
.putList("foo.test_list.list", "16", "17")
.putNull("foo.test_list_1.list")
.build());
- // TODO: should this assertion be kept?
- // assertNull("test wasn't changed", intResults.get("test"));
+ 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"));
+ 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(2, intResults.size());
+ assertEquals(1, intResults.size());
} else {
assertEquals(Arrays.asList(1), listResults.get("test_list_1")); // reset to default
- assertEquals(2, listResults.size());
- assertEquals(2, intResults.size());
+ assertEquals(1, listResults.size());
+ assertEquals(1, intResults.size());
}
} |
@s1monw whoops I didn't see that before I started working on mine, I added a unit test that demonstrates this |
I will apply your comments, thanks Simon |
@s1monw thanks for the suggested patch, can you take another look please? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@@ -156,5 +161,58 @@ public void testInvalidIPFilterClusterSettings() { | |||
.execute().actionGet()); | |||
assertEquals("invalid IP address [192.168.1.1.] for [" + filterSetting.getKey() + ipKey + "]", e.getMessage()); | |||
} | |||
|
|||
public void testTransientSettingsStillApplied() throws Exception { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think we should test the patch for persistent settings as well, or a mix of the two? We observed that issue effects persistent and transient settings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jhalterman the unit test for this is outside the scope of persistent or transient (the fix is to the settings themselves, it actually doesn't matter whether the settings are transient or persistent), so I don't think a test for that is necessary.
…#28317) * Notify affixMap settings when any under the registered prefix matches Previously if an affixMap setting was registered, and then a completely different setting was applied, the affixMap update consumer would be notified with an empty map. This caused settings that were previously set to be unset in local state in a consumer that assumed it would only be called when the affixMap setting was changed. This commit changes the behavior so if a prefix `foo.` is registered, any setting under the prefix will have the update consumer notified if there are changes starting with `foo.`. Resolves #28316 * Add unit test * Address feedback
…#28317) * Notify affixMap settings when any under the registered prefix matches Previously if an affixMap setting was registered, and then a completely different setting was applied, the affixMap update consumer would be notified with an empty map. This caused settings that were previously set to be unset in local state in a consumer that assumed it would only be called when the affixMap setting was changed. This commit changes the behavior so if a prefix `foo.` is registered, any setting under the prefix will have the update consumer notified if there are changes starting with `foo.`. Resolves #28316 * Add unit test * Address feedback
…#28317) * Notify affixMap settings when any under the registered prefix matches Previously if an affixMap setting was registered, and then a completely different setting was applied, the affixMap update consumer would be notified with an empty map. This caused settings that were previously set to be unset in local state in a consumer that assumed it would only be called when the affixMap setting was changed. This commit changes the behavior so if a prefix `foo.` is registered, any setting under the prefix will have the update consumer notified if there are changes starting with `foo.`. Resolves #28316 * Add unit test * Address feedback
* es/master: Remove redundant argument for buildConfiguration of s3 plugin (#28281) Completely remove Painless Type from AnalyzerCaster in favor of Java Class. (#28329) Fix spelling error Reindex: Wait for deletion in test Reindex: log more on rare test failure Ensure we protect Collections obtained from scripts from self-referencing (#28335) [Docs] Fix asciidoc style in composite agg docs Adds the ability to specify a format on composite date_histogram source (#28310) Provide a better error message for the case when all shards failed (#28333) [Test] Re-Add integer_range and date_range field types for query builder tests (#28171) Added Put Mapping API to high-level Rest client (#27869) Revert change that does not return all indices if a specific alias is requested via get alias api. (#28294) Painless: Replace Painless Type with Java Class during Casts (#27847) Notify affixMap settings when any under the registered prefix matches (#28317)
* es/6.x: Remove redundant argument for buildConfiguration of s3 plugin (#28281) Completely remove Painless Type from AnalyzerCaster in favor of Java Class. (#28329) Fix spelling error Reindex: Wait for deletion in test Reindex: log more on rare test failure Ensure we protect Collections obtained from scripts from self-referencing (#28335) Provide a better error message for the case when all shards failed (#28333) REST high-level client: add support for update_all_types option to put mapping API Added Put Mapping API to high-level Rest client (#27869) [Test] Re-Add integer_range and date_range field types for query builder tests (#28171) Revert change that does not return all indices if a specific alias is requested via get alias api. (#28294) Painless: Replace Painless Type with Java Class during Casts (#27847) Notify affixMap settings when any under the registered prefix matches (#28317)
* master: (94 commits) Completely remove Painless Type from AnalyzerCaster in favor of Java Class. (elastic#28329) Fix spelling error Reindex: Wait for deletion in test Reindex: log more on rare test failure Ensure we protect Collections obtained from scripts from self-referencing (elastic#28335) [Docs] Fix asciidoc style in composite agg docs Adds the ability to specify a format on composite date_histogram source (elastic#28310) Provide a better error message for the case when all shards failed (elastic#28333) [Test] Re-Add integer_range and date_range field types for query builder tests (elastic#28171) Added Put Mapping API to high-level Rest client (elastic#27869) Revert change that does not return all indices if a specific alias is requested via get alias api. (elastic#28294) Painless: Replace Painless Type with Java Class during Casts (elastic#27847) Notify affixMap settings when any under the registered prefix matches (elastic#28317) Trim down usages of `ShardOperationFailedException` interface (elastic#28312) Do not return all indices if a specific alias is requested via get aliases api. [Test] Lower bwc version for rank-eval rest tests CountedBitSet doesn't need to extend BitSet. (elastic#28239) Calculate sum in Kahan summation algorithm in aggregations (elastic#27807) (elastic#27848) Remove the `update_all_types` option. (elastic#28288) Add information when master node left to DiscoveryNodes' shortSummary() (elastic#28197) ...
We don't need this custom fix anymore, since it is fixed in ES v6.8+ and ES v7.0+. See elastic/elasticsearch#28317.
We don't need this custom fix anymore, since it is fixed in ES v6.8+ and ES v7.0+. See elastic/elasticsearch#28317.
Previously if an affixMap setting was registered, and then a completely
different setting was applied, the affixMap update consumer would be notified
with an empty map. This caused settings that were previously set to be unset in
local state in a consumer that assumed it would only be called when the affixMap
setting was changed.
This commit changes the behavior so if a prefix
foo.
is registered, anysetting under the prefix will have the update consumer notified if there are
changes starting with
foo.
.Resolves #28316