Files
Anders Eknert 61d3b7b64d perf: cost of indexing greatly reduced (#7370)
And many smaller performance improvements. The indexer recycling results
is one of the most impactful performance improvements as of yet, and alone
saves more than 2 million allocations in the Regal lint benchmark. The indexer
is also more efficient, as `values` are no longer stored on the struct. Thanks
@tsandall for that code!

Also included a bunch of small improvements from my perf branches.

**Before**
```
1209043041 ns/op	3255157224 B/op	64026192 allocs/op
```

**After**
```
1197131792 ns/op	3194124864 B/op	61876276 allocs/op
```

Signed-off-by: Anders Eknert <anders@styra.com>
2025-02-19 11:09:27 +01:00

96 lines
2.3 KiB
Go

// Copyright 2023 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
package compiler
import (
"errors"
"sync"
"github.com/open-policy-agent/opa/v1/ast"
"github.com/open-policy-agent/opa/v1/schemas"
"github.com/open-policy-agent/opa/v1/util"
)
type SchemaFile string
const (
AuthorizationPolicySchema SchemaFile = "authorizationPolicy.json"
)
var schemaDefinitions = map[SchemaFile]any{}
var loadOnce = sync.OnceValue(func() error {
cont, err := schemas.FS.ReadFile(string(AuthorizationPolicySchema))
if err != nil {
return err
}
if len(cont) == 0 {
return errors.New("expected authorization policy schema file to be present")
}
var schema any
if err := util.Unmarshal(cont, &schema); err != nil {
return err
}
schemaDefinitions[AuthorizationPolicySchema] = schema
return nil
})
// VerifyAuthorizationPolicySchema performs type checking on rules against the schema for the Authorization Policy
// Input document.
// NOTE: The provided compiler should have already run the compilation process on the input modules
func VerifyAuthorizationPolicySchema(compiler *ast.Compiler, ref ast.Ref) error {
if err := loadOnce(); err != nil {
panic(err)
}
rules := getRulesWithDependencies(compiler, ref)
if len(rules) == 0 {
return nil
}
schemaSet := ast.NewSchemaSet()
schemaSet.Put(ast.SchemaRootRef, schemaDefinitions[AuthorizationPolicySchema])
errs := ast.NewCompiler().
WithDefaultRegoVersion(compiler.DefaultRegoVersion()).
WithSchemas(schemaSet).
PassesTypeCheckRules(rules)
if len(errs) > 0 {
return errs
}
return nil
}
// getRulesWithDependencies returns a slice of rules that are referred to by ref along with their dependencies
func getRulesWithDependencies(compiler *ast.Compiler, ref ast.Ref) []*ast.Rule {
allRules := compiler.GetRules(ref)
deps := map[*ast.Rule]struct{}{}
for _, rule := range allRules {
transitiveDependencies(compiler, rule, deps)
}
for dep := range deps {
allRules = append(allRules, dep)
}
return allRules
}
func transitiveDependencies(compiler *ast.Compiler, rule *ast.Rule, deps map[*ast.Rule]struct{}) {
for x := range compiler.Graph.Dependencies(rule) {
other := x.(*ast.Rule)
deps[other] = struct{}{}
transitiveDependencies(compiler, other, deps)
}
}