-
Notifications
You must be signed in to change notification settings - Fork 348
feat: add some initial optimizer functions to run atop query plans #2669
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
base: main
Are you sure you want to change the base?
Conversation
Codecov Report❌ Patch coverage is ❌ Your project check has failed because the head coverage (59.10%) is below the target coverage (75.00%). You can increase the head coverage or adjust the target coverage.
Additional details and impacted files@@ Coverage Diff @@
## main #2669 +/- ##
===========================================
- Coverage 79.46% 59.10% -20.35%
===========================================
Files 455 416 -39
Lines 47161 43848 -3313
===========================================
- Hits 37470 25911 -11559
- Misses 6945 15438 +8493
+ Partials 2746 2499 -247 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
a7608e1 to
c94ede6
Compare
c94ede6 to
d8d75fb
Compare
| {"unoptimized", false}, | ||
| {"optimized", true}, | ||
| } { | ||
| optimizationMode := optimizationMode |
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.
FYI, having to copy the variable hasn't been necessary since go 1.22 https://go.dev/wiki/LoopvarExperiment
| require.Equal(t, fixed2, result2) | ||
| }) | ||
|
|
||
| t.Run("optimizer order independence - union with all empty", func(t *testing.T) { |
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.
FYI this test is failing
optimize_test.go:467:
Error Trace: /Users/miparnisari/Documents/GitHub/spicedb/pkg/query/optimize_test.go:467
Error: Should be true
Test: TestApplyOptimizations/optimizer_order_independence_-_union_with_all_empty
| // to any iterator tree without needing runtime information or context. | ||
| var StaticOptimizations = []OptimizerFunc{ | ||
| RemoveNullIterators, | ||
| ElideSingletonUnionAndIntersection, |
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.
Had to google what "elide" meant 😅 Now that I looked at the code I would have called this "collapse". But i'm not going to die on this hill
| union := NewUnion() | ||
| fixed := newNonEmptyFixedIterator() | ||
| empty := NewEmptyFixedIterator() | ||
| union.addSubIterator(fixed) | ||
| union.addSubIterator(empty) |
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 a follow-up PR: this would be slightly easier to read if we could do
fixed := newNonEmptyFixedIterator()
empty := NewEmptyFixedIterator()
union := NewUnion(fixed, empty)| require.Equal(t, fixed2, resultUnion.subIts[1]) | ||
| }) | ||
|
|
||
| t.Run("replaces intersection with empty if it contains empty fixed", func(t *testing.T) { |
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.
| t.Run("replaces intersection with empty if it contains empty fixed", func(t *testing.T) { | |
| t.Run("replaces intersection with empty if it contains empty and fixed", func(t *testing.T) { |
| // If all subiterators were empty, return empty | ||
| if len(newSubs) == 0 { | ||
| return NewEmptyFixedIterator(), true, nil |
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 code path isn't covered with unit tests
| func TestApplyOptimizations(t *testing.T) { | ||
| t.Parallel() | ||
|
|
||
| t.Run("applies optimization to iterator", func(t *testing.T) { |
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 same test is in line 73
| // Create two different optimizers | ||
| unionOptimizer := func(it Iterator) (Iterator, bool, error) { | ||
| if u, ok := it.(*Union); ok && len(u.subIts) == 1 { | ||
| return u.subIts[0], true, nil | ||
| } | ||
| return it, false, nil | ||
| } | ||
|
|
||
| intersectionOptimizer := func(it Iterator) (Iterator, bool, error) { | ||
| if i, ok := it.(*Intersection); ok && len(i.subIts) == 1 { | ||
| return i.subIts[0], true, nil | ||
| } | ||
| return it, false, nil | ||
| } |
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.
🤔 these are the ElideSingletonUnionAndIntersection
| require.NoError(t, err) | ||
| require.True(t, changed1) | ||
|
|
||
| // Create the same structure again |
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.
why? ApplyOptimizations doesn't mutate the inputs so you can reuse it
| // has a caveat that matches the given caveat name. | ||
| func relationContainsCaveat(rel *RelationIterator, caveat *core.ContextualizedCaveat) bool { | ||
| if rel.base == nil || caveat == nil { | ||
| return false |
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 code path isn't covered with unit tests
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.
Very nice 😄
There is one test that fails both locally and in CI, and another one that fails only locally. Are we using --failfast in CI?
$ go test -race . -count=1
# github.com/authzed/spicedb/pkg/query.test
ld: warning: '/private/var/folders/5p/328y159n1334j9czdhzl2ts40000gn/T/go-link-2977391469/000013.o' has malformed LC_DYSYMTAB, expected 98 undefined symbols to start at index 1626, found 95 undefined symbols starting at index 1626
--- FAIL: TestIteratorTracing (0.00s)
--- FAIL: TestIteratorTracing/Union_tracing (0.00s)
tracing_test.go:101:
Error Trace: /Users/miparnisari/Documents/GitHub/spicedb/pkg/query/tracing_test.go:101
Error: Should be true
Test: TestIteratorTracing/Union_tracing
--- FAIL: TestAliasIterator (0.03s)
alias_test.go:47:
Error Trace: /Users/miparnisari/Documents/GitHub/spicedb/pkg/query/alias_test.go:47
Error: "[{{doc1 document} read user:alice#... <nil> <nil> [] map[]}]" should have 3 item(s), but has 1
Test: TestAliasIterator
Messages: should have 3 rewritten relations
--- FAIL: TestAliasIterator/Check_BasicRelationRewriting (0.00s)
panic: test executed panic(nil) or runtime.Goexit
goroutine 214 [running]:
testing.tRunner.func1.2({0x105a5c240, 0x1066a1b40})
/opt/homebrew/opt/go/libexec/src/testing/testing.go:1872 +0x2b4
testing.tRunner.func1()
/opt/homebrew/opt/go/libexec/src/testing/testing.go:1875 +0x460
runtime.Goexit()
/opt/homebrew/opt/go/libexec/src/runtime/panic.go:615 +0x60
testing.(*common).FailNow(0xc000102fc0)
/opt/homebrew/opt/go/libexec/src/testing/testing.go:1013 +0x70
github.com/stretchr/testify/require.Len({0x105c755e8, 0xc000102fc0}, {0x1059d5200, 0xc000948c48}, 0x3, {0xc000659e68, 0x1, 0x1})
/Users/miparnisari/go/pkg/mod/github.com/stretchr/testify@v1.11.1/require/require.go:1203 +0xe4
github.com/stretchr/testify/require.(*Assertions).Len(0xc0006cc1d0, {0x1059d5200, 0xc000948c48}, 0x3, {0xc000659e68, 0x1, 0x1})
/Users/miparnisari/go/pkg/mod/github.com/stretchr/testify@v1.11.1/require/require_forward.go:954 +0xac
github.com/authzed/spicedb/pkg/query.TestAliasIterator.func1(0xc000780e00)
/Users/miparnisari/Documents/GitHub/spicedb/pkg/query/alias_test.go:47 +0x79c
testing.tRunner(0xc000780e00, 0xc000904348)
/opt/homebrew/opt/go/libexec/src/testing/testing.go:1934 +0x168
created by testing.(*T).Run in goroutine 9
/opt/homebrew/opt/go/libexec/src/testing/testing.go:1997 +0x6e4
FAIL github.com/authzed/spicedb/pkg/query 0.626s
FAIL
[15:03:13] ~/Documents/GitHub/spicedb/pkg/query (barakmich/optimizers) $
Adds a pattern and a few basic static optimizers to
pkg/queryto rewrite query plans.Fixes a deduplication bug when we elide Unions (we might be able to further remove deduplication from unions, tbd)
Also tests both optimized and unoptimized trees for correctness in integration tests.