Skip to content

Commit

Permalink
Implement a new, experimental variant of LookupResources as LookupRes…
Browse files Browse the repository at this point in the history
…ources2

This implementation should be much faster for intersections, exclusions and caveats due to early tree shearing and check hints
  • Loading branch information
josephschorr committed May 23, 2024
1 parent c51f10a commit ea58074
Show file tree
Hide file tree
Showing 49 changed files with 7,352 additions and 1,031 deletions.
236 changes: 174 additions & 62 deletions internal/caveats/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,26 @@ type ExpressionResult interface {
}

type syntheticResult struct {
value bool
contextValues map[string]any
exprString string
value bool
contextValues map[string]any
exprString string
missingContextParams []string
}

func (sr syntheticResult) Value() bool {
return sr.value
}

func (sr syntheticResult) IsPartial() bool {
return false
return len(sr.missingContextParams) > 0
}

func (sr syntheticResult) MissingVarNames() ([]string, error) {
return nil, fmt.Errorf("not a partial value")
if len(sr.missingContextParams) == 0 {
return nil, fmt.Errorf("not a partial value")
}

return sr.missingContextParams, nil
}

func (sr syntheticResult) ContextValues() map[string]any {
Expand Down Expand Up @@ -156,6 +161,14 @@ func (lc loadedCaveats) Get(caveatDefName string) (*core.CaveatDefinition, *cave
return caveat, justDeserialized, nil
}

func isFalseResult(resuilt ExpressionResult) bool {
return !resuilt.Value() && !resuilt.IsPartial()
}

func isTrueResult(resuilt ExpressionResult) bool {
return resuilt.Value() && !resuilt.IsPartial()
}

func runExpressionWithCaveats(
ctx context.Context,
env *caveats.Environment,
Expand Down Expand Up @@ -203,15 +216,30 @@ func runExpressionWithCaveats(
}

cop := expr.GetOperation()
boolResult := false
if cop.Op == core.CaveatOperation_AND {
boolResult = true
}

var contextValues map[string]any
var exprStringPieces []string

var currentResult ExpressionResult = syntheticResult{
value: false,
contextValues: map[string]any{},
exprString: "",
missingContextParams: []string{},
}
if cop.Op == core.CaveatOperation_AND {
currentResult = syntheticResult{
value: true,
contextValues: map[string]any{},
exprString: "",
missingContextParams: []string{},
}
}

buildExprString := func() (string, error) {
if debugOption != RunCaveatExpressionWithDebugInformation {
return "", nil
}

switch cop.Op {
case core.CaveatOperation_AND:
return strings.Join(exprStringPieces, " && "), nil
Expand All @@ -227,90 +255,174 @@ func runExpressionWithCaveats(
}
}

for _, child := range cop.Children {
childResult, err := runExpressionWithCaveats(ctx, env, child, context, loadedCaveats, debugOption)
if err != nil {
addDebugInfo := func(found ExpressionResult) error {
if debugOption == RunCaveatExpressionWithDebugInformation {
contextValues = combineMaps(contextValues, found.ContextValues())
exprString, err := found.ExpressionString()
if err != nil {
return err
}

exprStringPieces = append(exprStringPieces, exprString)
}

return nil
}

and := func(existing ExpressionResult, found ExpressionResult) (ExpressionResult, error) {
if err := addDebugInfo(found); err != nil {
return nil, err
}

if childResult.IsPartial() {
return childResult, nil
var missingContextParams []string
if existing.IsPartial() {
params, err := existing.MissingVarNames()
if err != nil {
return nil, err
}

missingContextParams = params
} else if !existing.Value() {
return existing, nil
}

switch cop.Op {
case core.CaveatOperation_AND:
boolResult = boolResult && childResult.Value()
if found.IsPartial() {
params, err := found.MissingVarNames()
if err != nil {
return nil, err
}

if debugOption == RunCaveatExpressionWithDebugInformation {
contextValues = combineMaps(contextValues, childResult.ContextValues())
exprString, err := childResult.ExpressionString()
if err != nil {
return nil, err
}
missingContextParams = append(missingContextParams, params...)
} else if !found.Value() {
return found, nil
}

exprString, err := buildExprString()
if err != nil {
return nil, err
}

exprStringPieces = append(exprStringPieces, exprString)
return syntheticResult{
value: existing.Value() && found.Value(),
contextValues: contextValues,
exprString: exprString,
missingContextParams: missingContextParams,
}, nil
}

or := func(existing ExpressionResult, found ExpressionResult) (ExpressionResult, error) {
if err := addDebugInfo(found); err != nil {
return nil, err
}

var missingContextParams []string
if existing.IsPartial() {
params, err := existing.MissingVarNames()
if err != nil {
return nil, err
}

if !boolResult {
built, err := buildExprString()
if err != nil {
return nil, err
}
missingContextParams = params
} else if existing.Value() {
return found, nil
}

return syntheticResult{false, contextValues, built}, nil
if found.IsPartial() {
params, err := found.MissingVarNames()
if err != nil {
return nil, err
}

case core.CaveatOperation_OR:
boolResult = boolResult || childResult.Value()
missingContextParams = append(missingContextParams, params...)
} else if found.Value() {
return found, nil
}

if debugOption == RunCaveatExpressionWithDebugInformation {
contextValues = combineMaps(contextValues, childResult.ContextValues())
exprString, err := childResult.ExpressionString()
if err != nil {
return nil, err
}
exprString, err := buildExprString()
if err != nil {
return nil, err
}

return syntheticResult{
value: existing.Value() || found.Value(),
contextValues: contextValues,
exprString: exprString,
missingContextParams: missingContextParams,
}, nil
}

exprStringPieces = append(exprStringPieces, exprString)
invert := func(existing ExpressionResult) (ExpressionResult, error) {
if debugOption == RunCaveatExpressionWithDebugInformation {
contextValues = combineMaps(contextValues, existing.ContextValues())
exprString, err := existing.ExpressionString()
if err != nil {
return nil, err
}

if boolResult {
built, err := buildExprString()
if err != nil {
return nil, err
}
exprStringPieces = append(exprStringPieces, "!("+exprString+")")
}

value := !existing.Value()

var missingContextParams []string
if existing.IsPartial() {
value = false // partials always have a value of false.
missingContextParams, _ = existing.MissingVarNames()
}

exprString, err := buildExprString()
if err != nil {
return nil, err
}

return syntheticResult{
value: value,
contextValues: contextValues,
exprString: exprString,
missingContextParams: missingContextParams,
}, nil
}

return syntheticResult{true, contextValues, built}, nil
for _, child := range cop.Children {
childResult, err := runExpressionWithCaveats(ctx, env, child, context, loadedCaveats, debugOption)
if err != nil {
return nil, err
}

switch cop.Op {
case core.CaveatOperation_AND:
cr, err := and(currentResult, childResult)
if err != nil {
return nil, err
}

case core.CaveatOperation_NOT:
if debugOption == RunCaveatExpressionWithDebugInformation {
contextValues = combineMaps(contextValues, childResult.ContextValues())
exprString, err := childResult.ExpressionString()
if err != nil {
return nil, err
}

exprStringPieces = append(exprStringPieces, "!("+exprString+")")
currentResult = cr

if isFalseResult(currentResult) {
return currentResult, nil
}

built, err := buildExprString()
case core.CaveatOperation_OR:
cr, err := or(currentResult, childResult)
if err != nil {
return nil, err
}

return syntheticResult{!childResult.Value(), contextValues, built}, nil
currentResult = cr

if isTrueResult(currentResult) {
return currentResult, nil
}

case core.CaveatOperation_NOT:
return invert(childResult)

default:
return nil, spiceerrors.MustBugf("unknown caveat operation: %v", cop.Op)
}
}

built, err := buildExprString()
if err != nil {
return nil, err
}

return syntheticResult{boolResult, contextValues, built}, nil
return currentResult, nil
}

func combineMaps(first map[string]any, second map[string]any) map[string]any {
Expand Down
Loading

0 comments on commit ea58074

Please sign in to comment.