From f45b5fedb56b315a7daf24719b671603b91a5061 Mon Sep 17 00:00:00 2001 From: Tim Brooks Date: Wed, 23 Jan 2019 12:05:39 -0700 Subject: [PATCH] Add ability to listen to group of affix settings (#37679) Currently we have the ability to listen for setting changes to two group affix settings. However, it is possible that we might have the need to listen to more than two. This commit adds a method that allows consumer to listen to a list of affix settings for changes. --- .../settings/AbstractScopedSettings.java | 48 +++++++++++ .../common/settings/ScopedSettingsTests.java | 85 +++++++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/server/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java b/server/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java index b49f0f82250..9d3e278e889 100644 --- a/server/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java +++ b/server/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java @@ -296,6 +296,54 @@ public abstract class AbstractScopedSettings { }); } + /** + * Adds a affix settings consumer that accepts the settings for a group of settings. The consumer is only + * notified if at least one of the settings change. + *

+ * Note: Only settings registered in {@link SettingsModule} can be changed dynamically. + *

+ */ + public synchronized void addAffixGroupUpdateConsumer(List> settings, BiConsumer consumer) { + List affixUpdaters = new ArrayList<>(settings.size()); + for (Setting.AffixSetting setting : settings) { + ensureSettingIsRegistered(setting); + affixUpdaters.add(setting.newAffixUpdater((a,b)-> {}, logger, (a,b)-> {})); + } + + addSettingsUpdater(new SettingUpdater>() { + + @Override + public boolean hasChanged(Settings current, Settings previous) { + return affixUpdaters.stream().anyMatch(au -> au.hasChanged(current, previous)); + } + + @Override + public Map getValue(Settings current, Settings previous) { + Set namespaces = new HashSet<>(); + for (Setting.AffixSetting setting : settings) { + SettingUpdater affixUpdaterA = setting.newAffixUpdater((k, v) -> namespaces.add(k), logger, (a, b) ->{}); + affixUpdaterA.apply(current, previous); + } + Map namespaceToSettings = new HashMap<>(namespaces.size()); + for (String namespace : namespaces) { + Set concreteSettings = new HashSet<>(settings.size()); + for (Setting.AffixSetting setting : settings) { + concreteSettings.add(setting.getConcreteSettingForNamespace(namespace).getKey()); + } + namespaceToSettings.put(namespace, current.filter(concreteSettings::contains)); + } + return namespaceToSettings; + } + + @Override + public void apply(Map values, Settings current, Settings previous) { + for (Map.Entry entry : values.entrySet()) { + consumer.accept(entry.getKey(), entry.getValue()); + } + } + }); + } + private void ensureSettingIsRegistered(Setting.AffixSetting setting) { final Setting registeredSetting = this.complexMatchers.get(setting.getKey()); if (setting != registeredSetting) { 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 fc732fbd88e..efb46db59de 100644 --- a/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java +++ b/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java @@ -316,6 +316,91 @@ public class ScopedSettingsTests extends ESTestCase { assertEquals(0, results.size()); } + public void testAffixGroupUpdateConsumer() { + String prefix = randomAlphaOfLength(3) + "foo."; + String intSuffix = randomAlphaOfLength(3); + String listSuffix = randomAlphaOfLength(4); + Setting.AffixSetting intSetting = Setting.affixKeySetting(prefix, intSuffix, + (k) -> Setting.intSetting(k, 1, Property.Dynamic, Property.NodeScope)); + Setting.AffixSetting> listSetting = Setting.affixKeySetting(prefix, listSuffix, + (k) -> Setting.listSetting(k, Arrays.asList("1"), Integer::parseInt, Property.Dynamic, Property.NodeScope)); + AbstractScopedSettings service = new ClusterSettings(Settings.EMPTY,new HashSet<>(Arrays.asList(intSetting, listSetting))); + Map results = new HashMap<>(); + Function listBuilder = g -> (prefix + g + "." + listSuffix); + Function intBuilder = g -> (prefix + g + "." + intSuffix); + String group1 = randomAlphaOfLength(3); + String group2 = randomAlphaOfLength(4); + String group3 = randomAlphaOfLength(5); + BiConsumer listConsumer = results::put; + + service.addAffixGroupUpdateConsumer(Arrays.asList(intSetting, listSetting), listConsumer); + assertEquals(0, results.size()); + service.applySettings(Settings.builder() + .put(intBuilder.apply(group1), 2) + .put(intBuilder.apply(group2), 7) + .putList(listBuilder.apply(group1), "16", "17") + .putList(listBuilder.apply(group2), "18", "19", "20") + .build()); + Settings groupOneSettings = results.get(group1); + Settings groupTwoSettings = results.get(group2); + assertEquals(2, intSetting.getConcreteSettingForNamespace(group1).get(groupOneSettings).intValue()); + assertEquals(7, intSetting.getConcreteSettingForNamespace(group2).get(groupTwoSettings).intValue()); + assertEquals(Arrays.asList(16, 17), listSetting.getConcreteSettingForNamespace(group1).get(groupOneSettings)); + assertEquals(Arrays.asList(18, 19, 20), listSetting.getConcreteSettingForNamespace(group2).get(groupTwoSettings)); + assertEquals(2, groupOneSettings.size()); + assertEquals(2, groupTwoSettings.size()); + assertEquals(2, results.size()); + + results.clear(); + + service.applySettings(Settings.builder() + .put(intBuilder.apply(group1), 2) + .put(intBuilder.apply(group2), 7) + .putList(listBuilder.apply(group1), "16", "17") + .putNull(listBuilder.apply(group2)) // removed + .build()); + + assertNull(group1 + " wasn't changed", results.get(group1)); + groupTwoSettings = results.get(group2); + assertEquals(7, intSetting.getConcreteSettingForNamespace(group2).get(groupTwoSettings).intValue()); + assertEquals(Arrays.asList(1), listSetting.getConcreteSettingForNamespace(group2).get(groupTwoSettings)); + assertEquals(1, results.size()); + assertEquals(2, groupTwoSettings.size()); + results.clear(); + + service.applySettings(Settings.builder() + .put(intBuilder.apply(group1), 2) + .put(intBuilder.apply(group2), 7) + .putList(listBuilder.apply(group1), "16", "17") + .putList(listBuilder.apply(group3), "5", "6") // added + .build()); + assertNull(group1 + " wasn't changed", results.get(group1)); + assertNull(group2 + " wasn't changed", results.get(group2)); + + Settings groupThreeSettings = results.get(group3); + assertEquals(1, intSetting.getConcreteSettingForNamespace(group3).get(groupThreeSettings).intValue()); + assertEquals(Arrays.asList(5, 6), listSetting.getConcreteSettingForNamespace(group3).get(groupThreeSettings)); + assertEquals(1, results.size()); + assertEquals(1, groupThreeSettings.size()); + results.clear(); + + service.applySettings(Settings.builder() + .put(intBuilder.apply(group1), 4) // modified + .put(intBuilder.apply(group2), 7) + .putList(listBuilder.apply(group1), "16", "17") + .putList(listBuilder.apply(group3), "5", "6") + .build()); + assertNull(group2 + " wasn't changed", results.get(group2)); + assertNull(group3 + " wasn't changed", results.get(group3)); + + groupOneSettings = results.get(group1); + assertEquals(4, intSetting.getConcreteSettingForNamespace(group1).get(groupOneSettings).intValue()); + assertEquals(Arrays.asList(16, 17), listSetting.getConcreteSettingForNamespace(group1).get(groupOneSettings)); + assertEquals(1, results.size()); + assertEquals(2, groupOneSettings.size()); + results.clear(); + } + public void testAddConsumerAffix() { Setting.AffixSetting intSetting = Setting.affixKeySetting("foo.", "bar", (k) -> Setting.intSetting(k, 1, Property.Dynamic, Property.NodeScope));