mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-20 18:31:15 +00:00
Initialize a base CEL env and share it to avoid repeated function declaration validation
This commit is contained in:
parent
4c90653d19
commit
6c6d76c69e
@ -19,6 +19,7 @@ package cel
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/cel-go/cel"
|
||||
@ -66,6 +67,27 @@ type CompilationResult struct {
|
||||
MaxCost uint64
|
||||
}
|
||||
|
||||
var (
|
||||
initEnvOnce sync.Once
|
||||
initEnv *cel.Env
|
||||
initEnvErr error
|
||||
)
|
||||
|
||||
func getBaseEnv() (*cel.Env, error) {
|
||||
initEnvOnce.Do(func() {
|
||||
var opts []cel.EnvOption
|
||||
opts = append(opts, cel.HomogeneousAggregateLiterals())
|
||||
// Validate function declarations once during base env initialization,
|
||||
// so they don't need to be evaluated each time a CEL rule is compiled.
|
||||
// This is a relatively expensive operation.
|
||||
opts = append(opts, cel.EagerlyValidateDeclarations(true))
|
||||
opts = append(opts, library.ExtensionLibs...)
|
||||
|
||||
initEnv, initEnvErr = cel.NewEnv(opts...)
|
||||
})
|
||||
return initEnv, initEnvErr
|
||||
}
|
||||
|
||||
// Compile compiles all the XValidations rules (without recursing into the schema) and returns a slice containing a
|
||||
// CompilationResult for each ValidationRule, or an error.
|
||||
// Each CompilationResult may contain:
|
||||
@ -82,13 +104,11 @@ func Compile(s *schema.Structural, isResourceRoot bool, perCallLimit uint64) ([]
|
||||
var propDecls []*expr.Decl
|
||||
var root *celmodel.DeclType
|
||||
var ok bool
|
||||
env, err := cel.NewEnv(
|
||||
cel.HomogeneousAggregateLiterals(),
|
||||
)
|
||||
baseEnv, err := getBaseEnv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reg := celmodel.NewRegistry(env)
|
||||
reg := celmodel.NewRegistry(baseEnv)
|
||||
scopedTypeName := generateUniqueSelfTypeName()
|
||||
rt, err := celmodel.NewRuleTypes(scopedTypeName, s, isResourceRoot, reg)
|
||||
if err != nil {
|
||||
@ -97,7 +117,7 @@ func Compile(s *schema.Structural, isResourceRoot bool, perCallLimit uint64) ([]
|
||||
if rt == nil {
|
||||
return nil, nil
|
||||
}
|
||||
opts, err := rt.EnvOptions(env.TypeProvider())
|
||||
opts, err := rt.EnvOptions(baseEnv.TypeProvider())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -111,9 +131,8 @@ func Compile(s *schema.Structural, isResourceRoot bool, perCallLimit uint64) ([]
|
||||
}
|
||||
propDecls = append(propDecls, decls.NewVar(ScopedVarName, root.ExprType()))
|
||||
propDecls = append(propDecls, decls.NewVar(OldScopedVarName, root.ExprType()))
|
||||
opts = append(opts, cel.Declarations(propDecls...), cel.HomogeneousAggregateLiterals())
|
||||
opts = append(opts, library.ExtensionLibs...)
|
||||
env, err = env.Extend(opts...)
|
||||
opts = append(opts, cel.Declarations(propDecls...))
|
||||
env, err := baseEnv.Extend(opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1605,3 +1605,19 @@ func TestCostEstimation(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCompile(b *testing.B) {
|
||||
_, err := getBaseEnv() // prime the baseEnv
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
s := genArrayWithRule("number", "true")(nil)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := Compile(s, false, uint64(math.MaxInt64))
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user