-
Notifications
You must be signed in to change notification settings - Fork 5k
Matcher + MatcherTree support for a keep_matching field in OnMatch #38726
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
Changes from all commits
07a8bb3
7d66365
f973da6
4ec98f3
296ce9b
322a3e7
d85941c
52b1ee1
28474f1
952187f
e63e666
4a57495
6e1e190
9639b2c
c82b721
ed4542d
258ab56
4804b2e
e7e187e
9b24cf1
7f543fb
374515b
b7a7a2a
9055263
20bdcb0
f05db5e
a99199b
5b8f246
18be96f
1a8d14b
a3e01f0
a1b9864
dc8631d
b1c09b2
acb80ac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,22 +43,20 @@ struct MaybeMatchResult { | |
|
||
// TODO(snowp): Make this a class that tracks the progress to speed up subsequent traversals. | ||
template <class DataType> | ||
static inline MaybeMatchResult evaluateMatch(MatchTree<DataType>& match_tree, | ||
const DataType& data) { | ||
const auto result = match_tree.match(data); | ||
static inline MaybeMatchResult evaluateMatch(MatchTree<DataType>& match_tree, const DataType& data, | ||
SkippedMatchCb<DataType> skipped_match_cb = nullptr) { | ||
const auto result = match_tree.match(data, skipped_match_cb); | ||
if (result.match_state_ == MatchState::UnableToMatch) { | ||
return MaybeMatchResult{nullptr, MatchState::UnableToMatch}; | ||
return {nullptr, MatchState::UnableToMatch}; | ||
} | ||
|
||
if (!result.on_match_) { | ||
return {nullptr, MatchState::MatchComplete}; | ||
} | ||
|
||
if (result.on_match_->matcher_) { | ||
return evaluateMatch(*result.on_match_->matcher_, data); | ||
} | ||
|
||
return MaybeMatchResult{result.on_match_->action_cb_, MatchState::MatchComplete}; | ||
// Note: does not handle sub-matchers or keep_matching, MatchTree::match(...) implementations are | ||
// expected to do so. | ||
return {result.on_match_->action_cb_, MatchState::MatchComplete}; | ||
} | ||
|
||
template <class DataType> using FieldMatcherFactoryCb = std::function<FieldMatcherPtr<DataType>()>; | ||
|
@@ -73,8 +71,9 @@ template <class DataType> class AnyMatcher : public MatchTree<DataType> { | |
explicit AnyMatcher(absl::optional<OnMatch<DataType>> on_no_match) | ||
: on_no_match_(std::move(on_no_match)) {} | ||
|
||
typename MatchTree<DataType>::MatchResult match(const DataType&) override { | ||
return {MatchState::MatchComplete, on_no_match_}; | ||
typename MatchTree<DataType>::MatchResult | ||
match(const DataType& data, SkippedMatchCb<DataType> skipped_match_cb = nullptr) override { | ||
return MatchTree<DataType>::handleRecursionAndSkips(on_no_match_, data, skipped_match_cb); | ||
} | ||
const absl::optional<OnMatch<DataType>> on_no_match_; | ||
}; | ||
|
@@ -153,6 +152,7 @@ class MatchTreeFactory : public OnMatchFactory<DataType> { | |
Server::Configuration::ServerFactoryContext& factory_context, | ||
MatchTreeValidationVisitor<DataType>& validation_visitor) | ||
: action_factory_context_(context), server_factory_context_(factory_context), | ||
on_match_validation_visitor_(validation_visitor), | ||
match_input_factory_(factory_context.messageValidationVisitor(), validation_visitor) {} | ||
|
||
// TODO(snowp): Remove this type parameter once we only have one Matcher proto. | ||
|
@@ -324,9 +324,15 @@ class MatchTreeFactory : public OnMatchFactory<DataType> { | |
|
||
template <class OnMatchType> | ||
absl::optional<OnMatchFactoryCb<DataType>> createOnMatchBase(const OnMatchType& on_match) { | ||
on_match_validation_visitor_.validateOnMatch(on_match); | ||
if (const std::vector<absl::Status>& errors = on_match_validation_visitor_.errors(); | ||
!errors.empty()) { | ||
return []() -> OnMatch<DataType> { return OnMatch<DataType>{}; }; | ||
} | ||
Comment on lines
+327
to
+331
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should reject this configuration if the keep_on_matching is not supported on this context? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In practice, it is rejected just by adding to the errors vector. The match tree's validator is checked by callers. There is a slight laziness in that I'm returning a lambda instead of absl::nullopt, but that's because none of the various callers to |
||
if (on_match.has_matcher()) { | ||
return [matcher_factory = std::move(create(on_match.matcher()))]() { | ||
return OnMatch<DataType>{{}, matcher_factory()}; | ||
return [matcher_factory = std::move(create(on_match.matcher())), | ||
keep_matching = on_match.keep_matching()]() { | ||
return OnMatch<DataType>{{}, matcher_factory(), keep_matching}; | ||
}; | ||
} else if (on_match.has_action()) { | ||
auto& factory = Config::Utility::getAndCheckFactory<ActionFactory<ActionFactoryContext>>( | ||
|
@@ -337,7 +343,9 @@ class MatchTreeFactory : public OnMatchFactory<DataType> { | |
|
||
auto action_factory = factory.createActionFactoryCb( | ||
*message, action_factory_context_, server_factory_context_.messageValidationVisitor()); | ||
return [action_factory] { return OnMatch<DataType>{action_factory, {}}; }; | ||
return [action_factory, keep_matching = on_match.keep_matching()] { | ||
return OnMatch<DataType>{action_factory, {}, keep_matching}; | ||
}; | ||
} | ||
|
||
return absl::nullopt; | ||
|
@@ -367,6 +375,7 @@ class MatchTreeFactory : public OnMatchFactory<DataType> { | |
const std::string stats_prefix_; | ||
ActionFactoryContext& action_factory_context_; | ||
Server::Configuration::ServerFactoryContext& server_factory_context_; | ||
MatchTreeValidationVisitor<DataType>& on_match_validation_visitor_; | ||
MatchInputFactory<DataType> match_input_factory_; | ||
}; | ||
} // namespace Matcher | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,6 +31,17 @@ template <class DataType> class MatchTreeValidationVisitor { | |
|
||
const std::vector<absl::Status>& errors() const { return errors_; } | ||
|
||
template <class OnMatchType> void validateOnMatch(const OnMatchType& on_match) { | ||
if (!support_keep_matching_ && on_match.keep_matching()) { | ||
errors_.emplace_back( | ||
absl::InvalidArgumentError("keep_matching is not supported in this context")); | ||
} | ||
} | ||
|
||
void setSupportKeepMatching(bool support_keep_matching) { | ||
support_keep_matching_ = support_keep_matching; | ||
} | ||
Comment on lines
+34
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How this works for actual production scenarios? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The intent is to reject configs that include keep_matching_ when used in a filter (or other context) that hasn't prepared to handle skipped matchers. Having a rejection during config validation, when users try the field where it's unexpected, was preferred to having matchers get silently skipped because there's no callback. |
||
|
||
protected: | ||
// Implementations would subclass this to specify the validation logic for data inputs, | ||
// returning a helpful error message if validation fails. | ||
|
@@ -39,6 +50,7 @@ template <class DataType> class MatchTreeValidationVisitor { | |
|
||
private: | ||
std::vector<absl::Status> errors_; | ||
bool support_keep_matching_ = false; | ||
}; | ||
} // namespace Matcher | ||
} // namespace Envoy |
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.
This PR implements this field only for list matchers, but there's nothing here in the API indicating that this field doesn't work for all matcher types, which may lead to confusion. I think we should either document the fact that this currently works only for list matchers and then update that as we implement it for each new matcher type, or we should just include the implementation for all matcher types in this PR so that there's no issue.
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.
Still need to address this comment.
Same thing in cncf/xds#117.
Uh oh!
There was an error while loading. Please reload this page.
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.
The keep_matching field now has an updated comment for behavior without supporting implementation.
Support has been implemented for ListMatcher and TrieMatcher (ended up needing it for 63439a3), and a TODO has been left for ravenblackx in PrefixMapMatcher.