-
Notifications
You must be signed in to change notification settings - Fork 1.4k
v1/topdown/graphql: Cache GraphQL schema parse results (#5377) #7457
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?
v1/topdown/graphql: Cache GraphQL schema parse results (#5377) #7457
Conversation
✅ Deploy Preview for openpolicyagent ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
77cd7a2
to
c8871c7
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.
Thank you for working on this! 😃
Just a couple of questions/comments.
v1/topdown/graphql.go
Outdated
|
||
if k, keyOk := cacheKeyWithPrefix(bctx, operands, "gql_schema_ast"); keyOk { | ||
key = k | ||
if val, ok := bctx.InterQueryBuiltinValueCache.Get(ast.StringTerm(key).Value); ok { |
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.
I'd recommend using a named value cache here. The benefits are:
- Caching is isolated to the GraphQL built-in, and entries aren't "competing" with other built-ins
No need to prefix the key, for above reason(looks like we need internal differentiation, though)- Named caches can be individually configured (complete with individual default settings)
See the io.jwt.* built-ins for inspiration.
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.
@robmyersrobmyers, what's your thoughts about using a named value cache? Do you want us to help making those changes?
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.
I'm working on it now, but seem to be having trouble initializing the cache. Right now I'm looking at 3 different named value caches for the different types, but that seems a bit inelegant, so maybe I should create a single named cache and use the cache key to differentiate the different types? Let me know your preference and I'll try and get it in close shape before I get your help to take it over the finish line. :)
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.
Seems to be working; feedback welcome. Not sure people will love exposing 3 different named cache configurations.
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.
Three separate configuration options might be overkill, like you say 👍. A single named cache with differentiating cache keys for the "sub-types" sounds like a good solution to me.
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.
Sounds good - I'll resurrect the cache key stuff and consolidate to one named cache.
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.
I think it's ready - please take a look and let me know if we missed anything.
Updated bench results with a few less trivial inputs:
BenchmarkGraphQLSchemaIsValid/Trivial_Schema_-_string-10 23740 51418 ns/op
BenchmarkGraphQLSchemaIsValid/Trivial_Schema_with_cache_-_string-10 965624 1187 ns/op
BenchmarkGraphQLSchemaIsValid/Schema_w/_1000_types_-_string-10 751 1578718 ns/op
BenchmarkGraphQLSchemaIsValid/Schema_w/_1000_types_with_cache_-_string-10 33801 34915 ns/op
BenchmarkGraphQLSchemaIsValid/Trivial_Schema_-_AST_object-10 17491 67845 ns/op
BenchmarkGraphQLSchemaIsValid/Trivial_Schema_with_cache_-_AST_object-10 124808 9801 ns/op
BenchmarkGraphQLParseSchema/Trivial_Schema_-_string-10 9914 116169 ns/op
BenchmarkGraphQLParseSchema/Trivial_Schema_with_cache_-_string-10 678207 1640 ns/op
BenchmarkGraphQLParseQuery/Trivial_Query_-_string-10 26994 44328 ns/op
BenchmarkGraphQLParseQuery/Trivial_Query_with_cache_-_string-10 26922 44386 ns/op
BenchmarkGraphQLIsValid/Trivial_Schema_-_string-10 21441 55487 ns/op
BenchmarkGraphQLIsValid/Trivial_Schema_with_cache_-_string-10 152800 7384 ns/op
BenchmarkGraphQLIsValid/Schema_w/_1000_types_-_string-10 758 1568036 ns/op
BenchmarkGraphQLIsValid/Schema_w/_1000_types_with_cache_-_string-10 28108 43051 ns/op
BenchmarkGraphQLParse/Trivial_Schema_-_string-10 5119 216610 ns/op
BenchmarkGraphQLParse/Trivial_Schema_with_cache_-_string-10 24186 49551 ns/op
BenchmarkGraphQLParseAndVerify/Trivial_Schema_-_string-10 5241 217419 ns/op
BenchmarkGraphQLParseAndVerify/Trivial_Schema_with_cache_-_string-10 23911 50004 ns/op
49b0a83
to
c8871c7
Compare
13dbd37
to
32ad5f0
Compare
fad8810
to
d88bd17
Compare
…gent#5377) This commit stores parsed GraphQL schemas to the cache, which improves the performance of GraphQL operations that parse the schema more than once. Queries are not cached. BenchmarkGraphQLSchemaIsValid/Trivial_Schema_-_string-10 23740 51418 ns/op BenchmarkGraphQLSchemaIsValid/Trivial_Schema_with_cache_-_string-10 965624 1187 ns/op BenchmarkGraphQLSchemaIsValid/Schema_w/_1000_types_-_string-10 751 1578718 ns/op BenchmarkGraphQLSchemaIsValid/Schema_w/_1000_types_with_cache_-_string-10 33801 34915 ns/op BenchmarkGraphQLSchemaIsValid/Trivial_Schema_-_AST_object-10 17491 67845 ns/op BenchmarkGraphQLSchemaIsValid/Trivial_Schema_with_cache_-_AST_object-10 124808 9801 ns/op BenchmarkGraphQLParseSchema/Trivial_Schema_-_string-10 9914 116169 ns/op BenchmarkGraphQLParseSchema/Trivial_Schema_with_cache_-_string-10 678207 1640 ns/op BenchmarkGraphQLParseQuery/Trivial_Query_-_string-10 26994 44328 ns/op BenchmarkGraphQLParseQuery/Trivial_Query_with_cache_-_string-10 26922 44386 ns/op BenchmarkGraphQLIsValid/Trivial_Schema_-_string-10 21441 55487 ns/op BenchmarkGraphQLIsValid/Trivial_Schema_with_cache_-_string-10 152800 7384 ns/op BenchmarkGraphQLIsValid/Schema_w/_1000_types_-_string-10 758 1568036 ns/op BenchmarkGraphQLIsValid/Schema_w/_1000_types_with_cache_-_string-10 28108 43051 ns/op BenchmarkGraphQLParse/Trivial_Schema_-_string-10 5119 216610 ns/op BenchmarkGraphQLParse/Trivial_Schema_with_cache_-_string-10 24186 49551 ns/op BenchmarkGraphQLParseAndVerify/Trivial_Schema_-_string-10 5241 217419 ns/op BenchmarkGraphQLParseAndVerify/Trivial_Schema_with_cache_-_string-10 23911 50004 ns/op Resolves: open-policy-agent#5377 Signed-off-by: Rob Myers <[email protected]>
d88bd17
to
f9a0b8f
Compare
This commit stores parsed GraphQL schemas to the cache, which improves the performance of GraphQL operations that parse the schema more than once.
Queries are not cached.
Resolves: #5377
Why the changes in this PR are needed?
GraphQL schema parsing can be an expensive operation, so caching can help speed things up.
What are the changes in this PR?
This PR leverages the InterQueryBuiltinValueCache to store parsed GraphQL schema data.
Notes to assist PR review:
The performance improvements are more dramatic on more complex schemas, but the complex schemas were omitted from the included test cases because they are quite large. Those numbers are captured in the issue thread.
Further comments:
The GraphQL builtin code has some repeated patterns which could probably be cleaned up, but I felt that was out of scope for adding a caching layer.