From 7077cb333b49c8ed1d8f06e12c38ce7d540af5bf Mon Sep 17 00:00:00 2001 From: Tim Brooks Date: Thu, 31 Jan 2019 18:02:35 -0700 Subject: [PATCH] Add ability to listen to group of affix settings (#37679) (#38135) 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 04dfd70f3ed06..44042e75c36f2 100644 --- a/server/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java +++ b/server/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java @@ -295,6 +295,54 @@ public void apply(Map> values, Settings current, Settings pr }); } + /** + * 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 fc732fbd88e2e..efb46db59de96 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 void testTupleAffixUpdateConsumer() { 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));