feat(query): add a PlanAdvisor framework in place of StatisticsSource#2928
feat(query): add a PlanAdvisor framework in place of StatisticsSource#2928
Conversation
Codecov Report❌ Patch coverage is ❌ Your project check has failed because the head coverage (31.76%) 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 #2928 +/- ##
==========================================
- Coverage 32.93% 31.76% -1.17%
==========================================
Files 423 427 +4
Lines 54315 54556 +241
==========================================
- Hits 17883 17324 -559
- Misses 34598 35467 +869
+ Partials 1834 1765 -69 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
b3dce16 to
9ff573a
Compare
pkg/query/arrow_reversal_test.go
Outdated
| resources := NewObjects("file", "file0") | ||
| subject := NewObject("user", "user42").WithEllipses() | ||
|
|
||
| reader := NewQueryDatastoreReader(datalayer.NewDataLayer(rawDS).SnapshotReader(revision)) |
There was a problem hiding this comment.
NewQueryDatastoreReader is undefined?
miparnisari
left a comment
There was a problem hiding this comment.
LGTM but please fix the compilation errors
|
|
||
| import "github.com/authzed/spicedb/pkg/spiceerrors" | ||
|
|
||
| type Hint func(it Iterator) error |
There was a problem hiding this comment.
| type Hint func(it Iterator) error | |
| // Hint can mutate the underlying Iterator | |
| type Hint func(it Iterator) error |
I asked Claude the conceptual difference between hint and outlinemutation and it gave me:
I wonder whether a better name for hint would be AfterCompilationMutation, and OutlineMutation would be a BeforeCompilationMutation
There was a problem hiding this comment.
Or maybe "provides context for iterator execution?"
I don't think it necessarily modifies the behavior of the iterator - I think that's up to the executor.
There was a problem hiding this comment.
Correct. It's a hint on how to evaluate the iterator, not the structure of the query (both branches need to happen, it's a question on what order) -- arguably, reordering the ands and ors could be a hint as well; perhaps that's preferable in the future, but tbd, cause I kinda wanted two ways of working on these trees
9ff573a to
e14ef4a
Compare
e14ef4a to
85f421e
Compare
| package query | ||
|
|
||
| // CombinePlanAdvisors creates a PlanAdvisor that combines multiple advisors | ||
| // by running through them in order and returning the first non-nil result |
There was a problem hiding this comment.
returning the first non-nil result
Does that mean that the list implies a priority, and the highest-priority hint/mutation is applied and the rest are ignored?
There was a problem hiding this comment.
Or is the idea that they won't tend to point at the same nodes?
There was a problem hiding this comment.
Yep, highest priority first. This is just a convenience I put in so that we can do something like "follow the stats. if the stats say nothing at all, or have no opinion here, fallback to pure balance" or something
| // left subtree against the IterResourcesResults of the right subtree: if the left | ||
| // fan-out is, on average, wider than the right fan-out, starting from the right is likely cheaper. | ||
| type CountAdvisor struct { | ||
| stats map[CanonicalKey]CountStats |
There was a problem hiding this comment.
Any thread safety concerns in this context?
There was a problem hiding this comment.
Not from the advisor -- this map is immutable (I could add a comment there though)
| // GetHints returns an ArrowDirectionHint for arrow nodes when observed result | ||
| // ratios suggest reversal is beneficial. For all other node types it returns nil. | ||
| func (a *CountAdvisor) GetHints(outline Outline, keySource CanonicalKeySource) ([]Hint, error) { | ||
| if outline.Type != ArrowIteratorType || len(outline.SubOutlines) != 2 { |
There was a problem hiding this comment.
Is there ever a case where you'd have an arrow type and the length of SubOutlines wouldn't be 2? Or is this belt-and-suspenders?
There was a problem hiding this comment.
Belt-and-suspenders to be sure
|
|
||
| // keySourceFromMap is a minimal CanonicalKeySource for tests, backed by an | ||
| // explicit map from OutlineNodeID to CanonicalKey. | ||
| type keySourceFromMap map[OutlineNodeID]CanonicalKey |
There was a problem hiding this comment.
Huh, defining a named type of a primitive type and then defining methods on it is something I'm sure i've seen before but never properly grokked
There was a problem hiding this comment.
Yep; that's a trick. See also CanonicalKey itself, which is just a string (that knows how to hash itself, among other tricks)
There was a problem hiding this comment.
So a "mutation" is a modification to the structure of the outline, where a "hint" is a modification to the state/execution context of a particular iterator, more or less?
| return nil, nil | ||
| } | ||
|
|
||
| // tryRotateLeft checks if rotating (A->B)->C to A->(B->C) would reduce cost. |
There was a problem hiding this comment.
Curious about "rotate" here - is there a sense in which reassociation is the same thing as rotation?
There was a problem hiding this comment.
"Rotate" in the sense of the tree -- rotating a tree takes
A
/ \
B C
\
D
If rotated right, it's C at the top (with A as left branch) and rotated left it's B at the top, so
B
/ \
D A
\
C
(These are binary trees, but the idea generalizes (and in fact, arrows are always binary))
| numOrgs = 29 // prime | ||
| numGroups = 97 // prime | ||
| numUsers = 997 // prime |
There was a problem hiding this comment.
and for steps that are other integers. can't be anything but relatively prime with a prime. If we had four orgs and step 2, then 0, 2, 0, 2 ... causing duplicate edges. With 5, (or any relative prime) you're guaranteed never to loop until you've hit everyone. (0, 2, 4, 1, 3)
| require.NoError(t, err) | ||
|
|
||
| _, err = rawDS.ReadWriteTx(ctx, func(ctx context.Context, rwt datastore.ReadWriteTransaction) error { | ||
| return rwt.LegacyWriteNamespaces(ctx, compiled.ObjectDefinitions...) |
There was a problem hiding this comment.
Is there a reason not to use the new method here?
There was a problem hiding this comment.
I suppose not. This is what happens when things are happening simultaneously. Worth a quick follow-up when I get a few more things merged; i'll plan time for that
|
|
||
| import "github.com/authzed/spicedb/pkg/spiceerrors" | ||
|
|
||
| type Hint func(it Iterator) error |
There was a problem hiding this comment.
Or maybe "provides context for iterator execution?"
I don't think it necessarily modifies the behavior of the iterator - I think that's up to the executor.
| // is not an arrow type. | ||
| func RotateArrowMutation(rotateLeft bool) OutlineMutation { | ||
| return func(outline Outline) Outline { | ||
| // Must be an arrow with exactly 2 children |
There was a problem hiding this comment.
When is "not 2 children" going to be true?
e161646 to
c333e51
Compare
c333e51 to
f1cfbb5
Compare
Description
Testing
References