Enable cross-setting validation#25560
Conversation
This commit enables multiple settings validation during dynamic updates and applies it to the disk threshold watermark settings.
|
@s1monw I'm opening this for discussion. |
|
|
||
| void validate(T value, Map<Setting<T>, T> settings); | ||
|
|
||
| default Iterator<Setting<T>> settings() { |
There was a problem hiding this comment.
Right now this carries the assumption that the settings that we validate against have the same type as the setting itself. I think this is okay for now, we can revisit later only if we need to?
|
thanks @jasontedor this is a big step. Yet, I think we need to move this kind of validation to the settings itself. We need to apply the validation to the entire |
| } else { | ||
| map = Collections.emptyMap(); | ||
| } | ||
| validator.validate(parsed, map); |
There was a problem hiding this comment.
just a drive by question - why not pass the entire settings object and let the (exceptional) validate logic look at whatever they want?
There was a problem hiding this comment.
@bleskes The reason for this is because then the validator need to pull out the settings that they want, which means parsing the settings, which means exercising the validation logic which leads to stack overflow unless we expose the skip validation override as part of the public API of Setting which I think is a bad idea.
There was a problem hiding this comment.
I hear you. There is still the alternative of let people use Setting#get for most things as I think this is just an issue with circular validation (i.e., two settings that validate each other). Where there is a circular validation, I think we typically can solve it by validating only on one of the keys (as always validate all keys). If things really get complicated people can always use Setting#getRaw and skip validation (at the price of doing parsing). Just an idea to simplify this which I wanted to hear your thoughts on. Totally up to you.
There was a problem hiding this comment.
I think that this would not quite work. Suppose that setting A is not dynamic, and setting B is. If we have validation on A between A and B but not validation on B between A and B, then an update for B will not exercise the validation leaving broken settings.
One can say: okay, only have the validation on the dynamic setting. Then I think it's odd, it relies on us remembering this fact, and it's odd to not have symmetric validation anyway.
I prefer it as is?
There was a problem hiding this comment.
I prefer it as is?
As said - totally fine. Thanks for picking this up.
* master: Refactor PathTrie and RestController to use a single trie for all methods (elastic#25459) Switch indices read-only if a node runs out of disk space (elastic#25541)
|
@s1monw This PR was getting big (due to all the tests) so I broke it into two PRs by factoring out the changes that inspired this into a separate commit (jasontedor/elasticsearch@ e346e1a5a04aab45653e27b217f523efa7ece804) which I will open as a follow-up PR to this one. |
|
retest this please |
s1monw
left a comment
There was a problem hiding this comment.
so I like the imp, I have one question. Lets say we have 2 settings A and B that are depending on each other. Now a > b all the time. Now we are updating the settings in one go setting a=5,b=4 but the current settings are a=20,b=10 if you use the updater it will still work I think since we always pass consistent views to the updater, right?
| try { | ||
| return parser.apply(value); | ||
| T parsed = parser.apply(value); | ||
| if (validate) { |
There was a problem hiding this comment.
should we check here if we have a validator at all and only check if we do?
There was a problem hiding this comment.
We always have a validator as we initialize with a trivial validator in cases one is not provided when the Setting is defined.
| map = new HashMap<>(); | ||
| while (it.hasNext()) { | ||
| final Setting<T> setting = it.next(); | ||
| map.put(setting, setting.get(settings, false)); // we have to disable validation or we will stack overflow |
There was a problem hiding this comment.
another option would be to use #get(Settings, Validator) so we can just have a simple null check instead of if (validate) and we make it nullable instead of a no-op?
There was a problem hiding this comment.
I tend to favor it as-is. The reason for this is because have the field validator in the Setting instance, and if we pass a validator into this method we have validator from the Setting instance and the passed-in validator and I think this can be confusing. Now one way around this is to make get(Settings, Validator<T>) static so that it can not see the instance Validator<T> but then this gets ugly because of generics, and because it invokes other instance methods.
That's correct. That happens because we push the new Settings instance down when doing these updates and that's where the validation happens against. |
This commit introduces a framework for settings validation and enables cross-setting validation.
Relates #25541