scheduler: always edge merge in one direction

When we perform a vertex merge, we should explicitly track the vertex
that it was merged into. This way, we can avoid the case where we merge
an index 0 edge from A->B and, later an index 1 edge from B->A.

With this patch, this scenario instead flips the direction of the merge
to merge from A->B for index 1.

Signed-off-by: Justin Chadwell <me@jedevc.com>
This commit is contained in:
Justin Chadwell
2024-01-16 12:29:26 +00:00
parent 7aee2929ee
commit 4e59c55b84
2 changed files with 52 additions and 3 deletions

View File

@@ -280,6 +280,49 @@ func NewSolver(opts SolverOpt) *Solver {
return jl
}
// hasOwner returns true if the provided target edge (or any of it's sibling
// edges) has the provided owner.
func (jl *Solver) hasOwner(target Edge, owner Edge) bool {
jl.mu.RLock()
defer jl.mu.RUnlock()
st, ok := jl.actives[target.Vertex.Digest()]
if !ok {
return false
}
var owners []Edge
for _, e := range st.edges {
if e.owner != nil {
owners = append(owners, e.owner.edge)
}
}
for len(owners) > 0 {
var owners2 []Edge
for _, e := range owners {
st, ok = jl.actives[e.Vertex.Digest()]
if !ok {
continue
}
if st.vtx.Digest() == owner.Vertex.Digest() {
return true
}
for _, e := range st.edges {
if e.owner != nil {
owners2 = append(owners2, e.owner.edge)
}
}
}
// repeat recursively, this time with the linked owners owners
owners = owners2
}
return false
}
func (jl *Solver) setEdge(e Edge, targetEdge *edge) {
jl.mu.RLock()
defer jl.mu.RUnlock()

View File

@@ -186,9 +186,14 @@ func (s *scheduler) dispatch(e *edge) {
if e.isDep(origEdge) || origEdge.isDep(e) {
bklog.G(context.TODO()).Debugf("skip merge due to dependency")
} else {
bklog.G(context.TODO()).Debugf("merging edge %s[%d] to %s[%d]\n", e.edge.Vertex.Name(), e.edge.Index, origEdge.edge.Vertex.Name(), origEdge.edge.Index)
if s.mergeTo(origEdge, e) {
s.ef.setEdge(e.edge, origEdge)
dest, src := origEdge, e
if s.ef.hasOwner(origEdge.edge, e.edge) {
dest, src = src, dest
}
bklog.G(context.TODO()).Debugf("merging edge %s[%d] to %s[%d]\n", src.edge.Vertex.Name(), src.edge.Index, dest.edge.Vertex.Name(), dest.edge.Index)
if s.mergeTo(dest, src) {
s.ef.setEdge(src.edge, dest)
}
}
}
@@ -351,6 +356,7 @@ func (s *scheduler) mergeTo(target, src *edge) bool {
type edgeFactory interface {
getEdge(Edge) *edge
setEdge(Edge, *edge)
hasOwner(Edge, Edge) bool
}
type pipeFactory struct {