Skip to content

Commit

Permalink
Dedupe op rules on edge vertex
Browse files Browse the repository at this point in the history
also simplify rule hash to panic for programming errors
  • Loading branch information
gordon-klotho committed Mar 12, 2024
1 parent 19b0f60 commit 61e89c9
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 52 deletions.
15 changes: 5 additions & 10 deletions pkg/engine/operational_eval/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,15 +158,10 @@ func (eval *Evaluator) resourceVertices(
errs = errors.Join(errs, tmpl.LoopProperties(res, addProp))

for _, rule := range tmpl.AdditionalRules {
hash, err := rule.Hash()
if err != nil {
errs = errors.Join(errs, fmt.Errorf("could not hash rule for resource id %s: %w", res.ID, err))
continue
}
vertex := &resourceRuleVertex{
Resource: res.ID,
Rule: rule,
hash: hash,
hash: rule.Hash(),
}
errs = errors.Join(errs, changes.AddVertexAndDeps(eval, vertex))
}
Expand All @@ -180,10 +175,10 @@ func (eval *Evaluator) edgeVertices(
) (graphChanges, error) {
changes := newChanges()

opVertex := &edgeVertex{
Edge: construct.SimpleEdge{Source: edge.Source, Target: edge.Target},
Rules: tmpl.OperationalRules,
}
opVertex := edgeVertexWithRules(
construct.SimpleEdge{Source: edge.Source, Target: edge.Target},
tmpl.OperationalRules,
)

return changes, changes.AddVertexAndDeps(eval, opVertex)
}
Expand Down
24 changes: 15 additions & 9 deletions pkg/engine/operational_eval/vertex_edge.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,18 @@ import (
type edgeVertex struct {
Edge construct.SimpleEdge

Rules []knowledgebase.OperationalRule
Rules map[string]knowledgebase.OperationalRule
}

func edgeVertexWithRules(edge construct.SimpleEdge, rules []knowledgebase.OperationalRule) *edgeVertex {
ev := &edgeVertex{
Edge: edge,
Rules: make(map[string]knowledgebase.OperationalRule),
}
for _, rule := range rules {
ev.Rules[rule.Hash()] = rule
}
return ev
}

func (ev edgeVertex) Key() Key {
Expand Down Expand Up @@ -75,14 +86,9 @@ func (ev *edgeVertex) UpdateFrom(other Vertex) {
if ev.Edge != otherEdge.Edge {
panic(fmt.Sprintf("cannot merge edges with different refs: %s != %s", ev.Edge, otherEdge.Edge))
}
// OTHER:
// for _, rule := range otherEdge.Rules {
// for _, evRule := range ev.Rules {
// if rule.Hash() == evRule.Hash() {
// continue OTHER
// }
// }
ev.Rules = append(ev.Rules, otherEdge.Rules...)
for hash, rule := range otherEdge.Rules {
ev.Rules[hash] = rule
}
}

func (ev *edgeVertex) Evaluate(eval *Evaluator) error {
Expand Down
41 changes: 12 additions & 29 deletions pkg/knowledgebase/operational_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,40 +98,23 @@ const (
ClosestSelectionOperator SelectionOperator = ""
)

func (rule AdditionalRule) Hash() (string, error) {
// Convert the struct to a byte slice.
// Note that the struct must be able to be converted to JSON,
// so all fields must be exported (i.e., start with a capital letter).
byteSlice, err := json.Marshal(rule)
func hashStruct(s any) string {
hash := sha256.New()
err := json.NewEncoder(hash).Encode(s)
if err != nil {
return "", err
// All types that use this function should be able to be encoded to JSON.
// If this panic occurs, there's a programming error.
panic(fmt.Errorf("error hashing struct %v (%[1]T): %w", s, err))
}

// Hash the byte slice.
hash := sha256.Sum256(byteSlice)

// Convert the hash to a hexadecimal string.
hashString := hex.EncodeToString(hash[:])

return hashString, nil
return hex.EncodeToString(hash.Sum(nil))
}

func (rule OperationalRule) Hash() (string, error) {
// Convert the struct to a byte slice.
// Note that the struct must be able to be converted to JSON,
// so all fields must be exported (i.e., start with a capital letter).
byteSlice, err := json.Marshal(rule)
if err != nil {
return "", err
}

// Hash the byte slice.
hash := sha256.Sum256(byteSlice)

// Convert the hash to a hexadecimal string.
hashString := hex.EncodeToString(hash[:])
func (rule AdditionalRule) Hash() string {
return hashStruct(rule)
}

return hashString, nil
func (rule OperationalRule) Hash() string {
return hashStruct(rule)
}

func (d Direction) Edge(resource, dep construct.ResourceId) construct.SimpleEdge {
Expand Down
7 changes: 3 additions & 4 deletions pkg/knowledgebase/operational_rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func TestAdditionalRule_Hash(t *testing.T) {
},
},
},
want: "02c61dd3cd718a1cb28439705f2291018dbffe8aaa110f4e5eb72b67f0963b4f",
want: "121890af892b7324a133b58b36e4e54a03a192f5268546a56f799cd60ba3fbdb",
},
{
name: "simple rule 2",
Expand All @@ -87,14 +87,13 @@ func TestAdditionalRule_Hash(t *testing.T) {
},
},
},
want: "ec11f23efba8646d56563e96ddf8d7963d09cede7290b6242efe49bb68e91c40",
want: "a23bc24879d4b78eddef0f4c779fd7b26cc7c8c04cc65cd4b29683342b36961c",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert := assert.New(t)
got, err := tt.rule.Hash()
assert.NoError(err)
got := tt.rule.Hash()
assert.Equal(tt.want, got)
})
}
Expand Down

0 comments on commit 61e89c9

Please sign in to comment.