Rework graph & builder

Make nodes persist through runs (easier re-running).
This commit is contained in:
Tomaž Jerman
2020-11-27 11:19:15 +01:00
parent 1e2ee1bb00
commit 41d2e8cb93
3 changed files with 91 additions and 40 deletions
+3 -6
View File
@@ -64,9 +64,7 @@ func (b *graphBuilder) Build(ctx context.Context, rr ...resource.Interface) (*gr
}
}
// @todo fixme..
g.invert()
g.DryRun()
// Do any dep. related preprocessing
var state *ExecState
@@ -93,13 +91,12 @@ func (b *graphBuilder) Build(ctx context.Context, rr ...resource.Interface) (*gr
}
}()
g.Relink()
if err != nil {
return nil, err
}
// @todo fixme..
g.invert()
g.ProdRun()
g.reset()
return g, nil
}
+76 -34
View File
@@ -8,15 +8,18 @@ import (
)
type (
nodeMap map[*node]bool
graph struct {
nn nodeSet
nn nodeSet
resIndex map[resource.Interface]*node
// Config flags
inverted bool
dry bool
processed nodeSet
conflicting nodeSet
processed nodeMap
conflicting nodeMap
}
ExecState struct {
@@ -26,18 +29,27 @@ type (
DepResources []resource.Interface
ParentResources []resource.Interface
}
// Provides a filter for graph iterator
iterFilter struct {
resourceType string
}
)
func newGraph() *graph {
return &graph{
nn: make(nodeSet, 0, 100),
resIndex: make(map[resource.Interface]*node),
inverted: false,
processed: make(nodeSet, 0, 100),
conflicting: make(nodeSet, 0, 100),
processed: make(nodeMap),
conflicting: make(nodeMap),
}
}
func (g *graph) addNode(nn ...*node) {
for _, n := range nn {
g.resIndex[n.res] = n
}
g.nn = g.nn.add(nn...)
}
@@ -49,16 +61,6 @@ func (g *graph) invert() {
g.inverted = !g.inverted
}
func (g *graph) DryRun() {
g.dry = true
g.purge(true)
}
func (g *graph) ProdRun() {
g.dry = false
g.purge(true)
}
func (g *graph) childNodes(n *node) nodeSet {
if g.inverted {
return n.pp
@@ -86,12 +88,55 @@ func (g *graph) markConflicting(n *node) {
g.conflicting = g.conflicting.add(n)
}
func (g *graph) Relink() {
for res := range g.resIndex {
n := g.resIndex[res]
if n == nil {
return
}
refs := res.Refs()
cc := g.childNodes(n)
for _, ref := range refs {
// If it's already linked, skip it
if cc.findByRef(ref) != nil {
continue
}
// else find the node and link to it (if we can)
m := g.nn.findByRef(ref)
if m != nil {
g.addChild(n, m)
}
}
}
}
func (g *graph) Next(ctx context.Context) (s *ExecState, err error) {
return g.next(ctx, nil)
}
func (g *graph) NextOf(ctx context.Context, resTrype string) (s *ExecState, err error) {
return g.next(ctx, &iterFilter{resourceType: resTrype})
}
func (g *graph) next(ctx context.Context, f *iterFilter) (s *ExecState, err error) {
upNN := g.removeProcessed(g.nodes())
if f != nil {
upC := make(nodeSet, 0, len(upNN))
if f.resourceType != "" {
for _, n := range upNN {
if n.res.ResourceType() == f.resourceType {
upC = append(upC, n)
}
}
}
upNN = upC
}
// We are done here
if len(upNN) <= 0 {
g.purge(g.dry)
return nil, nil
}
@@ -112,17 +157,6 @@ func (g *graph) Next(ctx context.Context) (s *ExecState, err error) {
es := g.prepExecState(nx, false)
g.markProcessed(nx)
pp := g.parentNodes(nx)
g.removeParent(nx)
for _, p := range pp {
g.removeChild(p, nx)
if len(g.childNodes(p)) <= 0 && g.processed.has(p) {
g.removeNode(p)
g.processed = g.processed.remove(p)
g.conflicting = g.conflicting.remove(p)
}
}
return es, nil
}
@@ -148,13 +182,9 @@ func (g *graph) Next(ctx context.Context) (s *ExecState, err error) {
}
}
func (g *graph) purge(partial bool) {
g.conflicting = nil
g.processed = nil
if !partial {
g.nn = nil
}
func (g *graph) reset() {
g.conflicting = make(nodeMap)
g.processed = make(nodeMap)
}
// util
@@ -258,3 +288,15 @@ func (g *graph) prepExecState(n *node, conflicting bool) *ExecState {
Conflicting: conflicting,
}
}
func (nm nodeMap) add(n *node) nodeMap {
nm[n] = true
return nm
}
func (nm nodeMap) has(n *node) bool {
return nm[n]
}
func (nm nodeMap) remove(n *node) nodeMap {
delete(nm, n)
return nm
}
+12
View File
@@ -37,6 +37,18 @@ func (nn nodeSet) filter(f func(n *node) bool) nodeSet {
return mm
}
func (nn nodeSet) findByRef(ref *resource.Ref) *node {
for _, n := range nn {
if n.res.ResourceType() == ref.ResourceType {
if n.res.Identifiers().HasAny(ref.Identifiers.StringSlice()...) {
return n
}
}
}
return nil
}
func (nn nodeSet) has(m *node) bool {
for _, n := range nn {
if n == m {