Skip to content

Enable cross-setting validation#25560

Merged
jasontedor merged 19 commits intoelastic:masterfrom
jasontedor:multiple-settings-validation
Jul 7, 2017
Merged

Enable cross-setting validation#25560
jasontedor merged 19 commits intoelastic:masterfrom
jasontedor:multiple-settings-validation

Conversation

@jasontedor
Copy link
Copy Markdown
Member

@jasontedor jasontedor commented Jul 5, 2017

This commit introduces a framework for settings validation and enables cross-setting validation.

Relates #25541

This commit enables multiple settings validation during dynamic updates
and applies it to the disk threshold watermark settings.
@jasontedor jasontedor requested a review from s1monw July 5, 2017 19:46
@jasontedor
Copy link
Copy Markdown
Member Author

@s1monw I'm opening this for discussion.


void validate(T value, Map<Setting<T>, T> settings);

default Iterator<Setting<T>> settings() {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

@s1monw
Copy link
Copy Markdown
Contributor

s1monw commented Jul 5, 2017

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 Settings instance after the update or before the node starts. Otherwise we might fail way too late. I also wonder if the order you pass the settings matters in your solution but I haven't verified that so I might be wrong?

@jasontedor
Copy link
Copy Markdown
Member Author

@s1monw I pushed 55a3d3b; let me know what you think?

} else {
map = Collections.emptyMap();
}
validator.validate(parsed, map);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a drive by question - why not pass the entire settings object and let the (exceptional) validate logic look at whatever they want?

Copy link
Copy Markdown
Member Author

@jasontedor jasontedor Jul 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member Author

@jasontedor jasontedor Jul 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer it as is?

As said - totally fine. Thanks for picking this up.

@jasontedor
Copy link
Copy Markdown
Member Author

jasontedor commented Jul 6, 2017

@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.

@jasontedor jasontedor changed the title Enable multiple settings validation Enable cross-setting validation Jul 6, 2017
@jasontedor
Copy link
Copy Markdown
Member Author

retest this please

Copy link
Copy Markdown
Contributor

@s1monw s1monw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we check here if we have a validator at all and only check if we do?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@jasontedor
Copy link
Copy Markdown
Member Author

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?

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.

@jasontedor jasontedor merged commit 5762bce into elastic:master Jul 7, 2017
@jasontedor jasontedor deleted the multiple-settings-validation branch July 10, 2017 14:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants