-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
ast+topdown: implement early exit semantics for complete document and function rules with one (ground) value #3898
ast+topdown: implement early exit semantics for complete document and function rules with one (ground) value #3898
Conversation
c821ce9
to
d1eab2f
Compare
Currently, the failures in CI have to do with trace events not firing:
Fair enough -- P2 will be gone with this, since there's no need to evaluate the third |
Not yet dealing with sets and membership shortcuts at all btw |
bab038a
to
51e1cbc
Compare
TODO:
|
8e180c5
to
0b9c165
Compare
0b9c165
to
81c7ec7
Compare
1bc1dfa
to
bf87dd0
Compare
0d9beb9
to
5862a49
Compare
e148dc5
to
71edef8
Compare
2bd939c
to
87243a8
Compare
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.
LGTM. Feel free to merge after squashing.
b0ce662
to
5e488cf
Compare
topdown/eval.go
Outdated
@@ -2642,7 +2644,10 @@ func (e evalVirtualComplete) evalValueRule(iter unifyIterator, rule *ast.Rule, p | |||
|
|||
err := e.evalTerm(iter, term, termbindings) | |||
if err != nil { | |||
return err | |||
ok := errors.Is(err, errEarlyExit) | |||
if !ok || e.ir.EarlyExit { |
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.
For my own understanding... this ensures that topdown does not (incorrectly) early-exit on "q" when the early-exit signal from the closure of "p" is received here. In other words, the early-exit signal from "p" is caught here and dropped.
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.
Again and again I'm getting unsure about this spoiling EE for valid cases, in more involved situations... My gut feeling is that "the last" eval of q should pass the EE error along. I'll have another look into this, maybe add another trace testcase.
package test
p {
q.a
}
xs = {1, 2}
q["a"] = xs[_] ☝️ we'll next extra cases for partials, too. |
🤔 back to draft mode. I think there must be some way to approach this in a more principled way than littering eval with |
I think we'll need to rub some more of what's in the last commit over the evalVirtual cases. I'll approach the problem with more test cases next week. |
ba33207
to
96a2696
Compare
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.
One comment about use of errors.As
. Otherwise, once we get the sort-on-insert change in for sets and squash these commits, this PR looks good to me.
077a009
to
6ea4732
Compare
…tions If the following conditions hold for a set of rules returned by the indexer, it will set EarlyExit: true, and change how the complete virtual doc or function is evaluated: - all rule head values are ground - all rule head values match This implies that some cases where early exit would be possible will not be covered: p = x { x := true input.foo == "bar" } p = x { x := true input.baz == "quz" } To indicate that "early exit" is possible, the indexer result message is amended. Also, the "Exit" trace event will have a message of "early" when "early exit" actually happens in eval: $ echo '{"x":"x", "y":"y"}' | opa eval -I -fpretty --explain=full -d r.rego data.r.r query:1 Enter data.r.r = _ query:1 | Eval data.r.r = _ query:1 | Index data.r.r (matched 2 rules, early exit) r.rego:11 | Enter data.r.r r.rego:12 | | Eval input.y = "y" r.rego:11 | | Exit data.r.r query:1 | Exit data.r.r = _ query:1 Redo data.r.r = _ query:1 | Redo data.r.r = _ r.rego:11 | Redo data.r.r r.rego:12 | | Redo input.y = "y" r.rego:11 | Exit data.r.r early With `r.rego` as package r r { input.x = "x" } r = 2 { input.z = "z" } r { input.y = "y" } This is done in in a way such that early-exit will abort array/set/object iterations on data: r { data.i[_] = "one" data.j[_] = "four" } f(x, y) { data.i[_] = x data.j[_] = y } Complete rules (r) and functions (f) that iterate over sets, arrays, and objects from either data (evalTree) or a term that's returned by some other rule etc (evalTerm). The CLI and golang packages expose ways to disable 'early-exit': This is in line with how indexing can be disabled. It's supposed to be used as a debugging measure, so it's only exposed as a CLI flag to `opa eval`. Co-authored-by: Torin Sandall <[email protected]> Signed-off-by: Stephan Renatus <[email protected]>
6ea4732
to
fc0c94e
Compare
Will merge when green |
…tions (open-policy-agent#3898) If the following conditions hold for a set of rules returned by the indexer, it will set EarlyExit: true, and change how the complete virtual doc or function is evaluated: - all rule head values are ground - all rule head values match This implies that some cases where early exit would be possible will not be covered: p = x { x := true input.foo == "bar" } p = x { x := true input.baz == "quz" } To indicate that "early exit" is possible, the indexer result message is amended. Also, the "Exit" trace event will have a message of "early" when "early exit" actually happens in eval: $ echo '{"x":"x", "y":"y"}' | opa eval -I -fpretty --explain=full -d r.rego data.r.r query:1 Enter data.r.r = _ query:1 | Eval data.r.r = _ query:1 | Index data.r.r (matched 2 rules, early exit) r.rego:11 | Enter data.r.r r.rego:12 | | Eval input.y = "y" r.rego:11 | | Exit data.r.r query:1 | Exit data.r.r = _ query:1 Redo data.r.r = _ query:1 | Redo data.r.r = _ r.rego:11 | Redo data.r.r r.rego:12 | | Redo input.y = "y" r.rego:11 | Exit data.r.r early With `r.rego` as package r r { input.x = "x" } r = 2 { input.z = "z" } r { input.y = "y" } This is done in in a way such that early-exit will abort array/set/object iterations on data: r { data.i[_] = "one" data.j[_] = "four" } f(x, y) { data.i[_] = x data.j[_] = y } Complete rules (r) and functions (f) that iterate over sets, arrays, and objects from either data (evalTree) or a term that's returned by some other rule etc (evalTerm). The CLI and golang packages expose ways to disable 'early-exit': This is in line with how indexing can be disabled. It's supposed to be used as a debugging measure, so it's only exposed as a CLI flag to `opa eval`. Co-authored-by: Torin Sandall <[email protected]> Signed-off-by: Stephan Renatus <[email protected]>
If the following conditions hold for a set of rules returned by the indexer,
it will set EarlyExit: true, and change how the complete virtual doc is
evaluated:
This implies that some cases where early exit would be possible will not be
covered:
To indicate that "early exit" is possible, the indexer result message is
amended. Also, the "Exit" trace event will have a message of "early" when
"early exit" actually happens in eval:
With
r.rego
as