Skip to content

Commit

Permalink
[PatchPlanning] Toposort / frontiers (#1101)
Browse files Browse the repository at this point in the history
* plan

Signed-off-by: Rebecca Metzman <rmetzman@google.com>

* add pkg

Signed-off-by: Rebecca Metzman <rmetzman@google.com>

* code

Signed-off-by: Rebecca Metzman <rmetzman@google.com>

* lint

Signed-off-by: Rebecca Metzman <rmetzman@google.com>

* lint

Signed-off-by: Rebecca Metzman <rmetzman@google.com>

* testing

Signed-off-by: Rebecca Metzman <rmetzman@google.com>

* file change

Signed-off-by: Rebecca Metzman <rmetzman@google.com>

* delete test file

Signed-off-by: Rebecca Metzman <rmetzman@google.com>

* fix concurrency

Signed-off-by: Rebecca Metzman <rmetzman@google.com>

---------

Signed-off-by: Rebecca Metzman <rmetzman@google.com>
Co-authored-by: Rebecca Metzman <rmetzman@google.com>
  • Loading branch information
rmetzman and Rebecca Metzman committed Jul 31, 2023
1 parent 7724bda commit 90cb0b7
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 17 deletions.
34 changes: 17 additions & 17 deletions pkg/guacanalytics/patchPlanning.go
Expand Up @@ -35,7 +35,7 @@ const (

type BfsNode struct {
Expanded bool // true once all node neighbors are added to queue
Parent []string
Parents []string
Depth int
Type NodeType
nodeVersions []string // for a packageName, what was the packageVersion associated with this version. For a packageVersion, what is the version.
Expand Down Expand Up @@ -90,14 +90,14 @@ func SearchDependenciesFromStartNode(ctx context.Context, gqlClient graphql.Clie
var versionsList []string
versionsList = append(versionsList, nodePkg.AllPkgTree.Namespaces[0].Names[0].Versions[0].Version)
q.nodeMap[startID] = BfsNode{
Type: PackageVersion,
Parent: []string{},
Type: PackageVersion,
Parents: []string{},
}

q.nodeMap[nodePkg.AllPkgTree.Namespaces[0].Names[0].Id] = BfsNode{
Type: PackageName,
nodeVersions: versionsList,
Parent: []string{},
Parents: []string{},
}
q.queue = append(q.queue, startID)
}
Expand Down Expand Up @@ -290,9 +290,9 @@ func exploreHasSourceAtFromPackage(ctx context.Context, gqlClient graphql.Client
node, seen := q.nodeMap[hasSourceAt.Source.Namespaces[0].Names[0].Id]
if !seen {
node = BfsNode{
Parent: []string{q.now},
Depth: q.nowNode.Depth + 1,
Type: SourceName,
Parents: []string{q.now},
Depth: q.nowNode.Depth + 1,
Type: SourceName,
}

// check if the Src has any POCs
Expand All @@ -306,7 +306,7 @@ func exploreHasSourceAtFromPackage(ctx context.Context, gqlClient graphql.Client
switch neighbor := neighbor.(type) {
case *model.NeighborsNeighborsPointOfContact:
node = BfsNode{
Parent: []string{q.now},
Parents: []string{q.now},
Depth: q.nowNode.Depth + 1,
Type: SourceName,
PointOfContact: neighbor.AllPointOfContact,
Expand All @@ -315,7 +315,7 @@ func exploreHasSourceAtFromPackage(ctx context.Context, gqlClient graphql.Client
}
} else {
node = BfsNode{
Parent: append(node.Parent, q.now),
Parents: append(node.Parents, q.now),
Depth: node.Depth,
Type: node.Type,
nodeVersions: node.nodeVersions,
Expand All @@ -331,7 +331,7 @@ func exploreHasSourceAtFromPackage(ctx context.Context, gqlClient graphql.Client

func explorePointOfContact(ctx context.Context, gqlClient graphql.Client, q *queueValues, pointOfContact model.NeighborsNeighborsPointOfContact) error {
node := BfsNode{
Parent: q.nowNode.Parent,
Parents: q.nowNode.Parents,
Depth: q.nowNode.Depth,
Type: q.nowNode.Type,
nodeVersions: q.nowNode.nodeVersions,
Expand Down Expand Up @@ -364,7 +364,7 @@ func explorePointOfContact(ctx context.Context, gqlClient graphql.Client, q *que
for _, versionEntry := range pkgResponse.Packages[0].Namespaces[0].Names[0].Versions {
if node, seen := q.nodeMap[versionEntry.Id]; seen {
node = BfsNode{
Parent: append(node.Parent, q.now),
Parents: append(node.Parents, q.now),
Depth: node.Depth,
Type: node.Type,
PointOfContact: pointOfContact.AllPointOfContact,
Expand All @@ -373,7 +373,7 @@ func explorePointOfContact(ctx context.Context, gqlClient graphql.Client, q *que
}
} else {
node = BfsNode{
Parent: append(node.Parent, q.now),
Parents: append(node.Parents, q.now),
Depth: q.nowNode.Depth + 1,
Type: PackageVersion,
PointOfContact: pointOfContact.AllPointOfContact,
Expand All @@ -393,7 +393,7 @@ func (q *queueValues) addNodesToQueueFromPackageName(ctx context.Context, gqlCli
q.queue = append(q.queue, id)
}
q.nodeMap[id] = BfsNode{
Parent: append(node.Parent, q.now),
Parents: append(node.Parents, q.now),
Depth: node.Depth,
Type: node.Type,
PointOfContact: node.PointOfContact,
Expand Down Expand Up @@ -423,7 +423,7 @@ func (q *queueValues) addNodesToQueueFromPackageName(ctx context.Context, gqlCli
q.queue = append(q.queue, versionEntry.Id)
}
q.nodeMap[versionEntry.Id] = BfsNode{
Parent: append(versionNode.Parent, q.now),
Parents: append(versionNode.Parents, q.now),
Depth: q.nowNode.Depth + 1,
Type: PackageVersion,
PointOfContact: q.nowNode.PointOfContact,
Expand All @@ -432,7 +432,7 @@ func (q *queueValues) addNodesToQueueFromPackageName(ctx context.Context, gqlCli
break
} else {
q.nodeMap[versionEntry.Id] = BfsNode{
Parent: append(versionNode.Parent, q.now),
Parents: append(versionNode.Parents, q.now),
Depth: q.nowNode.Depth + 1,
Type: PackageVersion,
PointOfContact: q.nowNode.PointOfContact,
Expand All @@ -443,7 +443,7 @@ func (q *queueValues) addNodesToQueueFromPackageName(ctx context.Context, gqlCli
}

q.nodeMap[id] = BfsNode{
Parent: []string{q.now},
Parents: []string{q.now},
Depth: q.nowNode.Depth + 1,
Type: PackageName,
nodeVersions: versionsList,
Expand All @@ -466,7 +466,7 @@ func (q *queueValues) addNodeToQueue(nodeType NodeType, versions []string, id st
}

q.nodeMap[id] = BfsNode{
Parent: append(node.Parent, q.now),
Parents: append(node.Parents, q.now),
Depth: q.nowNode.Depth + 1,
Type: nodeType,
PointOfContact: node.PointOfContact,
Expand Down
69 changes: 69 additions & 0 deletions pkg/guacanalytics/toposort.go
@@ -0,0 +1,69 @@
//
// Copyright 2023 The GUAC Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package guacanalytics

import (
"fmt"
)

// TODO: add tests
func ToposortFromBfsNodeMap(nodeMap map[string]BfsNode) (map[int][]string, error) {
frontiers := make(map[int][]string)
parentsMap := copyParents(nodeMap)
frontierLevel := 0
numNodes := 0
totalNodes := len(parentsMap)

for numNodes <= totalNodes {
foundIDs := make(map[string]bool)
for id, parentsList := range parentsMap {
if len(parentsList) == 0 {
frontiers[frontierLevel] = append(frontiers[frontierLevel], id)
foundIDs[id] = true
numNodes++
delete(parentsMap, id)
}
}

if len(foundIDs) == 0 {
return frontiers, fmt.Errorf("Error: cycle detected")
}

for id, parentsList := range parentsMap {
newParentsList := []string{}
for _, parentID := range parentsList {
if !foundIDs[parentID] {
newParentsList = append(newParentsList, parentID)
}
}

parentsMap[id] = newParentsList
}
frontierLevel++
}

return frontiers, nil
}

func copyParents(inputMap map[string]BfsNode) map[string][]string {
retMap := map[string][]string{}
for key, value := range inputMap {
if !value.NotInBlastRadius {
retMap[key] = append(retMap[key], value.Parents...)
}
}
return retMap
}

0 comments on commit 90cb0b7

Please sign in to comment.