pgraph: Clean up pgraph module to get ready for clean lib status
The graph of dependencies in golang is a DAG, and as such doesn't allow cycles. Clean up this lib so that it eventually doesn't import our resources module or anything else which might want to import it. This patch makes adjacency private, and adds a generalized key store to the graph struct.
This commit is contained in:
@@ -59,7 +59,10 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
|
|||||||
return nil, fmt.Errorf("libmgmt: MyGAPI is not initialized")
|
return nil, fmt.Errorf("libmgmt: MyGAPI is not initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
g := pgraph.NewGraph(obj.Name)
|
g, err := pgraph.NewGraph(obj.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
var vertex *pgraph.Vertex
|
var vertex *pgraph.Vertex
|
||||||
for i := uint(0); i < obj.Count; i++ {
|
for i := uint(0); i < obj.Count; i++ {
|
||||||
n := &resources.NoopRes{
|
n := &resources.NoopRes{
|
||||||
|
|||||||
@@ -56,7 +56,10 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
|
|||||||
return nil, fmt.Errorf("libmgmt: MyGAPI is not initialized")
|
return nil, fmt.Errorf("libmgmt: MyGAPI is not initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
g := pgraph.NewGraph(obj.Name)
|
g, err := pgraph.NewGraph(obj.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: these are being specified temporarily until it's the default!
|
// FIXME: these are being specified temporarily until it's the default!
|
||||||
metaparams := resources.DefaultMetaParams
|
metaparams := resources.DefaultMetaParams
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ func (g *Graph) Poke(v *Vertex) error {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func(nn *Vertex) error {
|
go func(nn *Vertex) error {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
//edge := g.Adjacency[v][nn] // lookup
|
//edge := g.adjacency[v][nn] // lookup
|
||||||
//notify := edge.Notify && edge.Refresh()
|
//notify := edge.Notify && edge.Refresh()
|
||||||
return nn.SendEvent(event.EventPoke, nil)
|
return nn.SendEvent(event.EventPoke, nil)
|
||||||
}(n)
|
}(n)
|
||||||
|
|||||||
@@ -204,11 +204,11 @@ func (g *Graph) VertexMerge(v1, v2 *Vertex, vertexMergeFn func(*Vertex, *Vertex)
|
|||||||
// methodology
|
// methodology
|
||||||
// 1) edges between v1 and v2 are removed
|
// 1) edges between v1 and v2 are removed
|
||||||
//Loop:
|
//Loop:
|
||||||
for k1 := range g.Adjacency {
|
for k1 := range g.adjacency {
|
||||||
for k2 := range g.Adjacency[k1] {
|
for k2 := range g.adjacency[k1] {
|
||||||
// v1 -> v2 || v2 -> v1
|
// v1 -> v2 || v2 -> v1
|
||||||
if (k1 == v1 && k2 == v2) || (k1 == v2 && k2 == v1) {
|
if (k1 == v1 && k2 == v2) || (k1 == v2 && k2 == v1) {
|
||||||
delete(g.Adjacency[k1], k2) // delete map & edge
|
delete(g.adjacency[k1], k2) // delete map & edge
|
||||||
// NOTE: if we assume this is a DAG, then we can
|
// NOTE: if we assume this is a DAG, then we can
|
||||||
// assume only v1 -> v2 OR v2 -> v1 exists, and
|
// assume only v1 -> v2 OR v2 -> v1 exists, and
|
||||||
// we can break out of these loops immediately!
|
// we can break out of these loops immediately!
|
||||||
@@ -220,10 +220,10 @@ func (g *Graph) VertexMerge(v1, v2 *Vertex, vertexMergeFn func(*Vertex, *Vertex)
|
|||||||
|
|
||||||
// 2) edges that point towards v2 from X now point to v1 from X (no dupes)
|
// 2) edges that point towards v2 from X now point to v1 from X (no dupes)
|
||||||
for _, x := range g.IncomingGraphVertices(v2) { // all to vertex v (??? -> v)
|
for _, x := range g.IncomingGraphVertices(v2) { // all to vertex v (??? -> v)
|
||||||
e := g.Adjacency[x][v2] // previous edge
|
e := g.adjacency[x][v2] // previous edge
|
||||||
r := g.Reachability(x, v1)
|
r := g.Reachability(x, v1)
|
||||||
// merge e with ex := g.Adjacency[x][v1] if it exists!
|
// merge e with ex := g.adjacency[x][v1] if it exists!
|
||||||
if ex, exists := g.Adjacency[x][v1]; exists && edgeMergeFn != nil && len(r) == 0 {
|
if ex, exists := g.adjacency[x][v1]; exists && edgeMergeFn != nil && len(r) == 0 {
|
||||||
e = edgeMergeFn(e, ex)
|
e = edgeMergeFn(e, ex)
|
||||||
}
|
}
|
||||||
if len(r) == 0 { // if not reachable, add it
|
if len(r) == 0 { // if not reachable, add it
|
||||||
@@ -236,21 +236,21 @@ func (g *Graph) VertexMerge(v1, v2 *Vertex, vertexMergeFn func(*Vertex, *Vertex)
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// this edge is from: prev, to: next
|
// this edge is from: prev, to: next
|
||||||
ex, _ := g.Adjacency[prev][next] // get
|
ex, _ := g.adjacency[prev][next] // get
|
||||||
ex = edgeMergeFn(ex, e)
|
ex = edgeMergeFn(ex, e)
|
||||||
g.Adjacency[prev][next] = ex // set
|
g.adjacency[prev][next] = ex // set
|
||||||
prev = next
|
prev = next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete(g.Adjacency[x], v2) // delete old edge
|
delete(g.adjacency[x], v2) // delete old edge
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) edges that point from v2 to X now point from v1 to X (no dupes)
|
// 3) edges that point from v2 to X now point from v1 to X (no dupes)
|
||||||
for _, x := range g.OutgoingGraphVertices(v2) { // all from vertex v (v -> ???)
|
for _, x := range g.OutgoingGraphVertices(v2) { // all from vertex v (v -> ???)
|
||||||
e := g.Adjacency[v2][x] // previous edge
|
e := g.adjacency[v2][x] // previous edge
|
||||||
r := g.Reachability(v1, x)
|
r := g.Reachability(v1, x)
|
||||||
// merge e with ex := g.Adjacency[v1][x] if it exists!
|
// merge e with ex := g.adjacency[v1][x] if it exists!
|
||||||
if ex, exists := g.Adjacency[v1][x]; exists && edgeMergeFn != nil && len(r) == 0 {
|
if ex, exists := g.adjacency[v1][x]; exists && edgeMergeFn != nil && len(r) == 0 {
|
||||||
e = edgeMergeFn(e, ex)
|
e = edgeMergeFn(e, ex)
|
||||||
}
|
}
|
||||||
if len(r) == 0 {
|
if len(r) == 0 {
|
||||||
@@ -263,13 +263,13 @@ func (g *Graph) VertexMerge(v1, v2 *Vertex, vertexMergeFn func(*Vertex, *Vertex)
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// this edge is from: prev, to: next
|
// this edge is from: prev, to: next
|
||||||
ex, _ := g.Adjacency[prev][next]
|
ex, _ := g.adjacency[prev][next]
|
||||||
ex = edgeMergeFn(ex, e)
|
ex = edgeMergeFn(ex, e)
|
||||||
g.Adjacency[prev][next] = ex
|
g.adjacency[prev][next] = ex
|
||||||
prev = next
|
prev = next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete(g.Adjacency[v2], x)
|
delete(g.adjacency[v2], x)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4) merge and then remove the (now merged/grouped) vertex
|
// 4) merge and then remove the (now merged/grouped) vertex
|
||||||
|
|||||||
@@ -30,19 +30,19 @@ import (
|
|||||||
|
|
||||||
// empty graph
|
// empty graph
|
||||||
func TestPgraphGrouping1(t *testing.T) {
|
func TestPgraphGrouping1(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
runGraphCmp(t, g1, g2)
|
runGraphCmp(t, g1, g2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// single vertex
|
// single vertex
|
||||||
func TestPgraphGrouping2(t *testing.T) {
|
func TestPgraphGrouping2(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{ // grouping to limit variable scope
|
{ // grouping to limit variable scope
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
g1.AddVertex(a1)
|
g1.AddVertex(a1)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
g2.AddVertex(a1)
|
g2.AddVertex(a1)
|
||||||
@@ -52,13 +52,13 @@ func TestPgraphGrouping2(t *testing.T) {
|
|||||||
|
|
||||||
// two vertices
|
// two vertices
|
||||||
func TestPgraphGrouping3(t *testing.T) {
|
func TestPgraphGrouping3(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
b1 := NewVertex(NewNoopResTest("b1"))
|
b1 := NewVertex(NewNoopResTest("b1"))
|
||||||
g1.AddVertex(a1, b1)
|
g1.AddVertex(a1, b1)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
b1 := NewVertex(NewNoopResTest("b1"))
|
b1 := NewVertex(NewNoopResTest("b1"))
|
||||||
@@ -69,13 +69,13 @@ func TestPgraphGrouping3(t *testing.T) {
|
|||||||
|
|
||||||
// two vertices merge
|
// two vertices merge
|
||||||
func TestPgraphGrouping4(t *testing.T) {
|
func TestPgraphGrouping4(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
a2 := NewVertex(NewNoopResTest("a2"))
|
a2 := NewVertex(NewNoopResTest("a2"))
|
||||||
g1.AddVertex(a1, a2)
|
g1.AddVertex(a1, a2)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a := NewVertex(NewNoopResTest("a1,a2"))
|
a := NewVertex(NewNoopResTest("a1,a2"))
|
||||||
g2.AddVertex(a)
|
g2.AddVertex(a)
|
||||||
@@ -85,14 +85,14 @@ func TestPgraphGrouping4(t *testing.T) {
|
|||||||
|
|
||||||
// three vertices merge
|
// three vertices merge
|
||||||
func TestPgraphGrouping5(t *testing.T) {
|
func TestPgraphGrouping5(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
a2 := NewVertex(NewNoopResTest("a2"))
|
a2 := NewVertex(NewNoopResTest("a2"))
|
||||||
a3 := NewVertex(NewNoopResTest("a3"))
|
a3 := NewVertex(NewNoopResTest("a3"))
|
||||||
g1.AddVertex(a1, a2, a3)
|
g1.AddVertex(a1, a2, a3)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a := NewVertex(NewNoopResTest("a1,a2,a3"))
|
a := NewVertex(NewNoopResTest("a1,a2,a3"))
|
||||||
g2.AddVertex(a)
|
g2.AddVertex(a)
|
||||||
@@ -102,14 +102,14 @@ func TestPgraphGrouping5(t *testing.T) {
|
|||||||
|
|
||||||
// three vertices, two merge
|
// three vertices, two merge
|
||||||
func TestPgraphGrouping6(t *testing.T) {
|
func TestPgraphGrouping6(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
a2 := NewVertex(NewNoopResTest("a2"))
|
a2 := NewVertex(NewNoopResTest("a2"))
|
||||||
b1 := NewVertex(NewNoopResTest("b1"))
|
b1 := NewVertex(NewNoopResTest("b1"))
|
||||||
g1.AddVertex(a1, a2, b1)
|
g1.AddVertex(a1, a2, b1)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a := NewVertex(NewNoopResTest("a1,a2"))
|
a := NewVertex(NewNoopResTest("a1,a2"))
|
||||||
b1 := NewVertex(NewNoopResTest("b1"))
|
b1 := NewVertex(NewNoopResTest("b1"))
|
||||||
@@ -120,7 +120,7 @@ func TestPgraphGrouping6(t *testing.T) {
|
|||||||
|
|
||||||
// four vertices, three merge
|
// four vertices, three merge
|
||||||
func TestPgraphGrouping7(t *testing.T) {
|
func TestPgraphGrouping7(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
a2 := NewVertex(NewNoopResTest("a2"))
|
a2 := NewVertex(NewNoopResTest("a2"))
|
||||||
@@ -128,7 +128,7 @@ func TestPgraphGrouping7(t *testing.T) {
|
|||||||
b1 := NewVertex(NewNoopResTest("b1"))
|
b1 := NewVertex(NewNoopResTest("b1"))
|
||||||
g1.AddVertex(a1, a2, a3, b1)
|
g1.AddVertex(a1, a2, a3, b1)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a := NewVertex(NewNoopResTest("a1,a2,a3"))
|
a := NewVertex(NewNoopResTest("a1,a2,a3"))
|
||||||
b1 := NewVertex(NewNoopResTest("b1"))
|
b1 := NewVertex(NewNoopResTest("b1"))
|
||||||
@@ -139,7 +139,7 @@ func TestPgraphGrouping7(t *testing.T) {
|
|||||||
|
|
||||||
// four vertices, two&two merge
|
// four vertices, two&two merge
|
||||||
func TestPgraphGrouping8(t *testing.T) {
|
func TestPgraphGrouping8(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
a2 := NewVertex(NewNoopResTest("a2"))
|
a2 := NewVertex(NewNoopResTest("a2"))
|
||||||
@@ -147,7 +147,7 @@ func TestPgraphGrouping8(t *testing.T) {
|
|||||||
b2 := NewVertex(NewNoopResTest("b2"))
|
b2 := NewVertex(NewNoopResTest("b2"))
|
||||||
g1.AddVertex(a1, a2, b1, b2)
|
g1.AddVertex(a1, a2, b1, b2)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a := NewVertex(NewNoopResTest("a1,a2"))
|
a := NewVertex(NewNoopResTest("a1,a2"))
|
||||||
b := NewVertex(NewNoopResTest("b1,b2"))
|
b := NewVertex(NewNoopResTest("b1,b2"))
|
||||||
@@ -158,7 +158,7 @@ func TestPgraphGrouping8(t *testing.T) {
|
|||||||
|
|
||||||
// five vertices, two&three merge
|
// five vertices, two&three merge
|
||||||
func TestPgraphGrouping9(t *testing.T) {
|
func TestPgraphGrouping9(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
a2 := NewVertex(NewNoopResTest("a2"))
|
a2 := NewVertex(NewNoopResTest("a2"))
|
||||||
@@ -167,7 +167,7 @@ func TestPgraphGrouping9(t *testing.T) {
|
|||||||
b3 := NewVertex(NewNoopResTest("b3"))
|
b3 := NewVertex(NewNoopResTest("b3"))
|
||||||
g1.AddVertex(a1, a2, b1, b2, b3)
|
g1.AddVertex(a1, a2, b1, b2, b3)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a := NewVertex(NewNoopResTest("a1,a2"))
|
a := NewVertex(NewNoopResTest("a1,a2"))
|
||||||
b := NewVertex(NewNoopResTest("b1,b2,b3"))
|
b := NewVertex(NewNoopResTest("b1,b2,b3"))
|
||||||
@@ -178,14 +178,14 @@ func TestPgraphGrouping9(t *testing.T) {
|
|||||||
|
|
||||||
// three unique vertices
|
// three unique vertices
|
||||||
func TestPgraphGrouping10(t *testing.T) {
|
func TestPgraphGrouping10(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
b1 := NewVertex(NewNoopResTest("b1"))
|
b1 := NewVertex(NewNoopResTest("b1"))
|
||||||
c1 := NewVertex(NewNoopResTest("c1"))
|
c1 := NewVertex(NewNoopResTest("c1"))
|
||||||
g1.AddVertex(a1, b1, c1)
|
g1.AddVertex(a1, b1, c1)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
b1 := NewVertex(NewNoopResTest("b1"))
|
b1 := NewVertex(NewNoopResTest("b1"))
|
||||||
@@ -197,7 +197,7 @@ func TestPgraphGrouping10(t *testing.T) {
|
|||||||
|
|
||||||
// three unique vertices, two merge
|
// three unique vertices, two merge
|
||||||
func TestPgraphGrouping11(t *testing.T) {
|
func TestPgraphGrouping11(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
b1 := NewVertex(NewNoopResTest("b1"))
|
b1 := NewVertex(NewNoopResTest("b1"))
|
||||||
@@ -205,7 +205,7 @@ func TestPgraphGrouping11(t *testing.T) {
|
|||||||
c1 := NewVertex(NewNoopResTest("c1"))
|
c1 := NewVertex(NewNoopResTest("c1"))
|
||||||
g1.AddVertex(a1, b1, b2, c1)
|
g1.AddVertex(a1, b1, b2, c1)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
b := NewVertex(NewNoopResTest("b1,b2"))
|
b := NewVertex(NewNoopResTest("b1,b2"))
|
||||||
@@ -220,7 +220,7 @@ func TestPgraphGrouping11(t *testing.T) {
|
|||||||
// \ / >>> | (arrows point downwards)
|
// \ / >>> | (arrows point downwards)
|
||||||
// b b
|
// b b
|
||||||
func TestPgraphGrouping12(t *testing.T) {
|
func TestPgraphGrouping12(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
a2 := NewVertex(NewNoopResTest("a2"))
|
a2 := NewVertex(NewNoopResTest("a2"))
|
||||||
@@ -230,7 +230,7 @@ func TestPgraphGrouping12(t *testing.T) {
|
|||||||
g1.AddEdge(a1, b1, e1)
|
g1.AddEdge(a1, b1, e1)
|
||||||
g1.AddEdge(a2, b1, e2)
|
g1.AddEdge(a2, b1, e2)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a := NewVertex(NewNoopResTest("a1,a2"))
|
a := NewVertex(NewNoopResTest("a1,a2"))
|
||||||
b1 := NewVertex(NewNoopResTest("b1"))
|
b1 := NewVertex(NewNoopResTest("b1"))
|
||||||
@@ -245,7 +245,7 @@ func TestPgraphGrouping12(t *testing.T) {
|
|||||||
// / \ >>> | (arrows point downwards)
|
// / \ >>> | (arrows point downwards)
|
||||||
// a1 a2 a1,a2
|
// a1 a2 a1,a2
|
||||||
func TestPgraphGrouping13(t *testing.T) {
|
func TestPgraphGrouping13(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
a2 := NewVertex(NewNoopResTest("a2"))
|
a2 := NewVertex(NewNoopResTest("a2"))
|
||||||
@@ -255,7 +255,7 @@ func TestPgraphGrouping13(t *testing.T) {
|
|||||||
g1.AddEdge(b1, a1, e1)
|
g1.AddEdge(b1, a1, e1)
|
||||||
g1.AddEdge(b1, a2, e2)
|
g1.AddEdge(b1, a2, e2)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a := NewVertex(NewNoopResTest("a1,a2"))
|
a := NewVertex(NewNoopResTest("a1,a2"))
|
||||||
b1 := NewVertex(NewNoopResTest("b1"))
|
b1 := NewVertex(NewNoopResTest("b1"))
|
||||||
@@ -270,7 +270,7 @@ func TestPgraphGrouping13(t *testing.T) {
|
|||||||
// \ | / >>> | (arrows point downwards)
|
// \ | / >>> | (arrows point downwards)
|
||||||
// b b
|
// b b
|
||||||
func TestPgraphGrouping14(t *testing.T) {
|
func TestPgraphGrouping14(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
a2 := NewVertex(NewNoopResTest("a2"))
|
a2 := NewVertex(NewNoopResTest("a2"))
|
||||||
@@ -283,7 +283,7 @@ func TestPgraphGrouping14(t *testing.T) {
|
|||||||
g1.AddEdge(a2, b1, e2)
|
g1.AddEdge(a2, b1, e2)
|
||||||
g1.AddEdge(a3, b1, e3)
|
g1.AddEdge(a3, b1, e3)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a := NewVertex(NewNoopResTest("a1,a2,a3"))
|
a := NewVertex(NewNoopResTest("a1,a2,a3"))
|
||||||
b1 := NewVertex(NewNoopResTest("b1"))
|
b1 := NewVertex(NewNoopResTest("b1"))
|
||||||
@@ -300,7 +300,7 @@ func TestPgraphGrouping14(t *testing.T) {
|
|||||||
// \ / |
|
// \ / |
|
||||||
// c1 c1
|
// c1 c1
|
||||||
func TestPgraphGrouping15(t *testing.T) {
|
func TestPgraphGrouping15(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
b1 := NewVertex(NewNoopResTest("b1"))
|
b1 := NewVertex(NewNoopResTest("b1"))
|
||||||
@@ -315,7 +315,7 @@ func TestPgraphGrouping15(t *testing.T) {
|
|||||||
g1.AddEdge(b1, c1, e3)
|
g1.AddEdge(b1, c1, e3)
|
||||||
g1.AddEdge(b2, c1, e4)
|
g1.AddEdge(b2, c1, e4)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
b := NewVertex(NewNoopResTest("b1,b2"))
|
b := NewVertex(NewNoopResTest("b1,b2"))
|
||||||
@@ -337,7 +337,7 @@ func TestPgraphGrouping15(t *testing.T) {
|
|||||||
// | / | | /
|
// | / | | /
|
||||||
// c1 c1 c1
|
// c1 c1 c1
|
||||||
func TestPgraphGrouping16(t *testing.T) {
|
func TestPgraphGrouping16(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
a2 := NewVertex(NewNoopResTest("a2"))
|
a2 := NewVertex(NewNoopResTest("a2"))
|
||||||
@@ -350,7 +350,7 @@ func TestPgraphGrouping16(t *testing.T) {
|
|||||||
g1.AddEdge(b1, c1, e2)
|
g1.AddEdge(b1, c1, e2)
|
||||||
g1.AddEdge(a2, c1, e3)
|
g1.AddEdge(a2, c1, e3)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a := NewVertex(NewNoopResTest("a1,a2"))
|
a := NewVertex(NewNoopResTest("a1,a2"))
|
||||||
b1 := NewVertex(NewNoopResTest("b1"))
|
b1 := NewVertex(NewNoopResTest("b1"))
|
||||||
@@ -370,7 +370,7 @@ func TestPgraphGrouping16(t *testing.T) {
|
|||||||
// | / |
|
// | / |
|
||||||
// c1 c1
|
// c1 c1
|
||||||
func TestPgraphGrouping17(t *testing.T) {
|
func TestPgraphGrouping17(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
b1 := NewVertex(NewNoopResTest("b1"))
|
b1 := NewVertex(NewNoopResTest("b1"))
|
||||||
@@ -383,7 +383,7 @@ func TestPgraphGrouping17(t *testing.T) {
|
|||||||
g1.AddEdge(b1, c1, e2)
|
g1.AddEdge(b1, c1, e2)
|
||||||
g1.AddEdge(b2, c1, e3)
|
g1.AddEdge(b2, c1, e3)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
b := NewVertex(NewNoopResTest("b1,b2"))
|
b := NewVertex(NewNoopResTest("b1,b2"))
|
||||||
@@ -404,7 +404,7 @@ func TestPgraphGrouping17(t *testing.T) {
|
|||||||
// \ | / |
|
// \ | / |
|
||||||
// c1 c1
|
// c1 c1
|
||||||
func TestPgraphGrouping18(t *testing.T) {
|
func TestPgraphGrouping18(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
a2 := NewVertex(NewNoopResTest("a2"))
|
a2 := NewVertex(NewNoopResTest("a2"))
|
||||||
@@ -420,7 +420,7 @@ func TestPgraphGrouping18(t *testing.T) {
|
|||||||
g1.AddEdge(a2, c1, e3)
|
g1.AddEdge(a2, c1, e3)
|
||||||
g1.AddEdge(b2, c1, e4)
|
g1.AddEdge(b2, c1, e4)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a := NewVertex(NewNoopResTest("a1,a2"))
|
a := NewVertex(NewNoopResTest("a1,a2"))
|
||||||
b := NewVertex(NewNoopResTest("b1,b2"))
|
b := NewVertex(NewNoopResTest("b1,b2"))
|
||||||
@@ -438,14 +438,14 @@ func TestPgraphGrouping18(t *testing.T) {
|
|||||||
// \ >>> \ (arrows point downwards)
|
// \ >>> \ (arrows point downwards)
|
||||||
// a2 a2
|
// a2 a2
|
||||||
func TestPgraphGroupingConnected0(t *testing.T) {
|
func TestPgraphGroupingConnected0(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
a2 := NewVertex(NewNoopResTest("a2"))
|
a2 := NewVertex(NewNoopResTest("a2"))
|
||||||
e1 := NewEdge("e1")
|
e1 := NewEdge("e1")
|
||||||
g1.AddEdge(a1, a2, e1)
|
g1.AddEdge(a1, a2, e1)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result ?
|
g2, _ := NewGraph("g2") // expected result ?
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
a2 := NewVertex(NewNoopResTest("a2"))
|
a2 := NewVertex(NewNoopResTest("a2"))
|
||||||
@@ -462,7 +462,7 @@ func TestPgraphGroupingConnected0(t *testing.T) {
|
|||||||
// \ \
|
// \ \
|
||||||
// a2 a2
|
// a2 a2
|
||||||
func TestPgraphGroupingConnected1(t *testing.T) {
|
func TestPgraphGroupingConnected1(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
b := NewVertex(NewNoopResTest("b"))
|
b := NewVertex(NewNoopResTest("b"))
|
||||||
@@ -472,7 +472,7 @@ func TestPgraphGroupingConnected1(t *testing.T) {
|
|||||||
g1.AddEdge(a1, b, e1)
|
g1.AddEdge(a1, b, e1)
|
||||||
g1.AddEdge(b, a2, e2)
|
g1.AddEdge(b, a2, e2)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result ?
|
g2, _ := NewGraph("g2") // expected result ?
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTest("a1"))
|
a1 := NewVertex(NewNoopResTest("a1"))
|
||||||
b := NewVertex(NewNoopResTest("b"))
|
b := NewVertex(NewNoopResTest("b"))
|
||||||
|
|||||||
@@ -45,10 +45,10 @@ func (g *Graph) Graphviz() (out string) {
|
|||||||
out += fmt.Sprintf("\tlabel=\"%s\";\n", g.GetName())
|
out += fmt.Sprintf("\tlabel=\"%s\";\n", g.GetName())
|
||||||
//out += "\tnode [shape=box];\n"
|
//out += "\tnode [shape=box];\n"
|
||||||
str := ""
|
str := ""
|
||||||
for i := range g.Adjacency { // reverse paths
|
for i := range g.adjacency { // reverse paths
|
||||||
out += fmt.Sprintf("\t\"%s\" [label=\"%s[%s]\"];\n", i.GetName(), i.GetKind(), i.GetName())
|
out += fmt.Sprintf("\t\"%s\" [label=\"%s[%s]\"];\n", i.GetName(), i.GetKind(), i.GetName())
|
||||||
for j := range g.Adjacency[i] {
|
for j := range g.adjacency[i] {
|
||||||
k := g.Adjacency[i][j]
|
k := g.adjacency[i][j]
|
||||||
// use str for clearer output ordering
|
// use str for clearer output ordering
|
||||||
if k.Notify {
|
if k.Notify {
|
||||||
str += fmt.Sprintf("\t\"%s\" -> \"%s\" [label=\"%s\",style=bold];\n", i.GetName(), j.GetName(), k.Name)
|
str += fmt.Sprintf("\t\"%s\" -> \"%s\" [label=\"%s\",style=bold];\n", i.GetName(), j.GetName(), k.Name)
|
||||||
|
|||||||
189
pgraph/pgraph.go
189
pgraph/pgraph.go
@@ -55,7 +55,11 @@ type Flags struct {
|
|||||||
// * This is also the direction that the notify should happen in...
|
// * This is also the direction that the notify should happen in...
|
||||||
type Graph struct {
|
type Graph struct {
|
||||||
Name string
|
Name string
|
||||||
Adjacency map[*Vertex]map[*Vertex]*Edge // *Vertex -> *Vertex (edge)
|
|
||||||
|
adjacency map[*Vertex]map[*Vertex]*Edge // *Vertex -> *Vertex (edge)
|
||||||
|
kv map[string]interface{} // some values associated with the graph
|
||||||
|
|
||||||
|
// legacy
|
||||||
Flags Flags
|
Flags Flags
|
||||||
state graphState
|
state graphState
|
||||||
fastPause bool // used to disable pokes for a fast pause
|
fastPause bool // used to disable pokes for a fast pause
|
||||||
@@ -81,18 +85,34 @@ type Edge struct {
|
|||||||
refresh bool // is there a notify pending for the dest vertex ?
|
refresh bool // is there a notify pending for the dest vertex ?
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGraph builds a new graph.
|
// Init initializes the graph which populates all the internal structures.
|
||||||
func NewGraph(name string) *Graph {
|
func (g *Graph) Init() error {
|
||||||
return &Graph{
|
if g.Name == "" {
|
||||||
Name: name,
|
return fmt.Errorf("can't initialize graph with empty name")
|
||||||
Adjacency: make(map[*Vertex]map[*Vertex]*Edge),
|
|
||||||
state: graphStateNil,
|
|
||||||
// ptr b/c: Mutex/WaitGroup must not be copied after first use
|
|
||||||
mutex: &sync.Mutex{},
|
|
||||||
wg: &sync.WaitGroup{},
|
|
||||||
semas: make(map[string]*semaphore.Semaphore),
|
|
||||||
slock: &sync.Mutex{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g.adjacency = make(map[*Vertex]map[*Vertex]*Edge)
|
||||||
|
g.kv = make(map[string]interface{})
|
||||||
|
|
||||||
|
// legacy
|
||||||
|
g.state = graphStateNil
|
||||||
|
// ptr b/c: Mutex/WaitGroup must not be copied after first use
|
||||||
|
g.mutex = &sync.Mutex{}
|
||||||
|
g.wg = &sync.WaitGroup{}
|
||||||
|
g.semas = make(map[string]*semaphore.Semaphore)
|
||||||
|
g.slock = &sync.Mutex{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGraph builds a new graph.
|
||||||
|
func NewGraph(name string) (*Graph, error) {
|
||||||
|
g := &Graph{
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
if err := g.Init(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return g, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewVertex returns a new graph vertex struct with a contained resource.
|
// NewVertex returns a new graph vertex struct with a contained resource.
|
||||||
@@ -119,11 +139,25 @@ func (obj *Edge) SetRefresh(b bool) {
|
|||||||
obj.refresh = b
|
obj.refresh = b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Value returns a value stored alongside the graph in a particular key.
|
||||||
|
func (g *Graph) Value(key string) (interface{}, bool) {
|
||||||
|
val, exists := g.kv[key]
|
||||||
|
return val, exists
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetValue sets a value to be stored alongside the graph in a particular key.
|
||||||
|
func (g *Graph) SetValue(key string, val interface{}) {
|
||||||
|
g.kv[key] = val
|
||||||
|
}
|
||||||
|
|
||||||
// Copy makes a copy of the graph struct
|
// Copy makes a copy of the graph struct
|
||||||
func (g *Graph) Copy() *Graph {
|
func (g *Graph) Copy() *Graph {
|
||||||
newGraph := &Graph{
|
newGraph := &Graph{
|
||||||
Name: g.Name,
|
Name: g.Name,
|
||||||
Adjacency: make(map[*Vertex]map[*Vertex]*Edge, len(g.Adjacency)),
|
adjacency: make(map[*Vertex]map[*Vertex]*Edge, len(g.adjacency)),
|
||||||
|
kv: g.kv,
|
||||||
|
|
||||||
|
// legacy
|
||||||
Flags: g.Flags,
|
Flags: g.Flags,
|
||||||
state: g.state,
|
state: g.state,
|
||||||
mutex: g.mutex,
|
mutex: g.mutex,
|
||||||
@@ -134,8 +168,8 @@ func (g *Graph) Copy() *Graph {
|
|||||||
|
|
||||||
prometheus: g.prometheus,
|
prometheus: g.prometheus,
|
||||||
}
|
}
|
||||||
for k, v := range g.Adjacency {
|
for k, v := range g.adjacency {
|
||||||
newGraph.Adjacency[k] = v // copy
|
newGraph.adjacency[k] = v // copy
|
||||||
}
|
}
|
||||||
return newGraph
|
return newGraph
|
||||||
}
|
}
|
||||||
@@ -171,17 +205,17 @@ func (g *Graph) setState(state graphState) graphState {
|
|||||||
// AddVertex uses variadic input to add all listed vertices to the graph
|
// AddVertex uses variadic input to add all listed vertices to the graph
|
||||||
func (g *Graph) AddVertex(xv ...*Vertex) {
|
func (g *Graph) AddVertex(xv ...*Vertex) {
|
||||||
for _, v := range xv {
|
for _, v := range xv {
|
||||||
if _, exists := g.Adjacency[v]; !exists {
|
if _, exists := g.adjacency[v]; !exists {
|
||||||
g.Adjacency[v] = make(map[*Vertex]*Edge)
|
g.adjacency[v] = make(map[*Vertex]*Edge)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteVertex deletes a particular vertex from the graph.
|
// DeleteVertex deletes a particular vertex from the graph.
|
||||||
func (g *Graph) DeleteVertex(v *Vertex) {
|
func (g *Graph) DeleteVertex(v *Vertex) {
|
||||||
delete(g.Adjacency, v)
|
delete(g.adjacency, v)
|
||||||
for k := range g.Adjacency {
|
for k := range g.adjacency {
|
||||||
delete(g.Adjacency[k], v)
|
delete(g.adjacency[k], v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,16 +225,16 @@ func (g *Graph) AddEdge(v1, v2 *Vertex, e *Edge) {
|
|||||||
g.AddVertex(v1, v2) // supports adding N vertices now
|
g.AddVertex(v1, v2) // supports adding N vertices now
|
||||||
// TODO: check if an edge exists to avoid overwriting it!
|
// TODO: check if an edge exists to avoid overwriting it!
|
||||||
// NOTE: VertexMerge() depends on overwriting it at the moment...
|
// NOTE: VertexMerge() depends on overwriting it at the moment...
|
||||||
g.Adjacency[v1][v2] = e
|
g.adjacency[v1][v2] = e
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteEdge deletes a particular edge from the graph.
|
// DeleteEdge deletes a particular edge from the graph.
|
||||||
// FIXME: add test cases
|
// FIXME: add test cases
|
||||||
func (g *Graph) DeleteEdge(e *Edge) {
|
func (g *Graph) DeleteEdge(e *Edge) {
|
||||||
for v1 := range g.Adjacency {
|
for v1 := range g.adjacency {
|
||||||
for v2, edge := range g.Adjacency[v1] {
|
for v2, edge := range g.adjacency[v1] {
|
||||||
if e == edge {
|
if e == edge {
|
||||||
delete(g.Adjacency[v1], v2)
|
delete(g.adjacency[v1], v2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,7 +243,7 @@ func (g *Graph) DeleteEdge(e *Edge) {
|
|||||||
// CompareMatch searches for an equivalent resource in the graph and returns the
|
// CompareMatch searches for an equivalent resource in the graph and returns the
|
||||||
// vertex it is found in, or nil if not found.
|
// vertex it is found in, or nil if not found.
|
||||||
func (g *Graph) CompareMatch(obj resources.Res) *Vertex {
|
func (g *Graph) CompareMatch(obj resources.Res) *Vertex {
|
||||||
for v := range g.Adjacency {
|
for v := range g.adjacency {
|
||||||
if v.Res.Compare(obj) {
|
if v.Res.Compare(obj) {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
@@ -219,7 +253,7 @@ func (g *Graph) CompareMatch(obj resources.Res) *Vertex {
|
|||||||
|
|
||||||
// TODO: consider adding a mutate API.
|
// TODO: consider adding a mutate API.
|
||||||
//func (g *Graph) MutateMatch(obj resources.Res) *Vertex {
|
//func (g *Graph) MutateMatch(obj resources.Res) *Vertex {
|
||||||
// for v := range g.Adjacency {
|
// for v := range g.adjacency {
|
||||||
// if err := v.Res.Mutate(obj); err == nil {
|
// if err := v.Res.Mutate(obj); err == nil {
|
||||||
// // transmogrified!
|
// // transmogrified!
|
||||||
// return v
|
// return v
|
||||||
@@ -230,7 +264,7 @@ func (g *Graph) CompareMatch(obj resources.Res) *Vertex {
|
|||||||
|
|
||||||
// HasVertex returns if the input vertex exists in the graph.
|
// HasVertex returns if the input vertex exists in the graph.
|
||||||
func (g *Graph) HasVertex(v *Vertex) bool {
|
func (g *Graph) HasVertex(v *Vertex) bool {
|
||||||
if _, exists := g.Adjacency[v]; exists {
|
if _, exists := g.adjacency[v]; exists {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -238,14 +272,14 @@ func (g *Graph) HasVertex(v *Vertex) bool {
|
|||||||
|
|
||||||
// NumVertices returns the number of vertices in the graph.
|
// NumVertices returns the number of vertices in the graph.
|
||||||
func (g *Graph) NumVertices() int {
|
func (g *Graph) NumVertices() int {
|
||||||
return len(g.Adjacency)
|
return len(g.adjacency)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NumEdges returns the number of edges in the graph.
|
// NumEdges returns the number of edges in the graph.
|
||||||
func (g *Graph) NumEdges() int {
|
func (g *Graph) NumEdges() int {
|
||||||
count := 0
|
count := 0
|
||||||
for k := range g.Adjacency {
|
for k := range g.adjacency {
|
||||||
count += len(g.Adjacency[k])
|
count += len(g.adjacency[k])
|
||||||
}
|
}
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
@@ -254,7 +288,7 @@ func (g *Graph) NumEdges() int {
|
|||||||
// The order is random, because the map implementation is intentionally so!
|
// The order is random, because the map implementation is intentionally so!
|
||||||
func (g *Graph) GetVertices() []*Vertex {
|
func (g *Graph) GetVertices() []*Vertex {
|
||||||
var vertices []*Vertex
|
var vertices []*Vertex
|
||||||
for k := range g.Adjacency {
|
for k := range g.adjacency {
|
||||||
vertices = append(vertices, k)
|
vertices = append(vertices, k)
|
||||||
}
|
}
|
||||||
return vertices
|
return vertices
|
||||||
@@ -264,7 +298,7 @@ func (g *Graph) GetVertices() []*Vertex {
|
|||||||
func (g *Graph) GetVerticesChan() chan *Vertex {
|
func (g *Graph) GetVerticesChan() chan *Vertex {
|
||||||
ch := make(chan *Vertex)
|
ch := make(chan *Vertex)
|
||||||
go func(ch chan *Vertex) {
|
go func(ch chan *Vertex) {
|
||||||
for k := range g.Adjacency {
|
for k := range g.adjacency {
|
||||||
ch <- k
|
ch <- k
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
@@ -283,7 +317,7 @@ func (vs VertexSlice) Less(i, j int) bool { return vs[i].String() < vs[j].String
|
|||||||
// The order is sorted by String() to avoid the non-determinism in the map type
|
// The order is sorted by String() to avoid the non-determinism in the map type
|
||||||
func (g *Graph) GetVerticesSorted() []*Vertex {
|
func (g *Graph) GetVerticesSorted() []*Vertex {
|
||||||
var vertices []*Vertex
|
var vertices []*Vertex
|
||||||
for k := range g.Adjacency {
|
for k := range g.adjacency {
|
||||||
vertices = append(vertices, k)
|
vertices = append(vertices, k)
|
||||||
}
|
}
|
||||||
sort.Sort(VertexSlice(vertices)) // add determinism
|
sort.Sort(VertexSlice(vertices)) // add determinism
|
||||||
@@ -306,8 +340,8 @@ func (g *Graph) IncomingGraphVertices(v *Vertex) []*Vertex {
|
|||||||
// TODO: we might be able to implement this differently by reversing
|
// TODO: we might be able to implement this differently by reversing
|
||||||
// the Adjacency graph and then looping through it again...
|
// the Adjacency graph and then looping through it again...
|
||||||
var s []*Vertex
|
var s []*Vertex
|
||||||
for k := range g.Adjacency { // reverse paths
|
for k := range g.adjacency { // reverse paths
|
||||||
for w := range g.Adjacency[k] {
|
for w := range g.adjacency[k] {
|
||||||
if w == v {
|
if w == v {
|
||||||
s = append(s, k)
|
s = append(s, k)
|
||||||
}
|
}
|
||||||
@@ -320,7 +354,7 @@ func (g *Graph) IncomingGraphVertices(v *Vertex) []*Vertex {
|
|||||||
// points to (v -> ???). Poke should probably use this.
|
// points to (v -> ???). Poke should probably use this.
|
||||||
func (g *Graph) OutgoingGraphVertices(v *Vertex) []*Vertex {
|
func (g *Graph) OutgoingGraphVertices(v *Vertex) []*Vertex {
|
||||||
var s []*Vertex
|
var s []*Vertex
|
||||||
for k := range g.Adjacency[v] { // forward paths
|
for k := range g.adjacency[v] { // forward paths
|
||||||
s = append(s, k)
|
s = append(s, k)
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
@@ -338,8 +372,8 @@ func (g *Graph) GraphVertices(v *Vertex) []*Vertex {
|
|||||||
// IncomingGraphEdges returns all of the edges that point to vertex v (??? -> v).
|
// IncomingGraphEdges returns all of the edges that point to vertex v (??? -> v).
|
||||||
func (g *Graph) IncomingGraphEdges(v *Vertex) []*Edge {
|
func (g *Graph) IncomingGraphEdges(v *Vertex) []*Edge {
|
||||||
var edges []*Edge
|
var edges []*Edge
|
||||||
for v1 := range g.Adjacency { // reverse paths
|
for v1 := range g.adjacency { // reverse paths
|
||||||
for v2, e := range g.Adjacency[v1] {
|
for v2, e := range g.adjacency[v1] {
|
||||||
if v2 == v {
|
if v2 == v {
|
||||||
edges = append(edges, e)
|
edges = append(edges, e)
|
||||||
}
|
}
|
||||||
@@ -351,7 +385,7 @@ func (g *Graph) IncomingGraphEdges(v *Vertex) []*Edge {
|
|||||||
// OutgoingGraphEdges returns all of the edges that point from vertex v (v -> ???).
|
// OutgoingGraphEdges returns all of the edges that point from vertex v (v -> ???).
|
||||||
func (g *Graph) OutgoingGraphEdges(v *Vertex) []*Edge {
|
func (g *Graph) OutgoingGraphEdges(v *Vertex) []*Edge {
|
||||||
var edges []*Edge
|
var edges []*Edge
|
||||||
for _, e := range g.Adjacency[v] { // forward paths
|
for _, e := range g.adjacency[v] { // forward paths
|
||||||
edges = append(edges, e)
|
edges = append(edges, e)
|
||||||
}
|
}
|
||||||
return edges
|
return edges
|
||||||
@@ -370,7 +404,7 @@ func (g *Graph) GraphEdges(v *Vertex) []*Edge {
|
|||||||
func (g *Graph) DFS(start *Vertex) []*Vertex {
|
func (g *Graph) DFS(start *Vertex) []*Vertex {
|
||||||
var d []*Vertex // discovered
|
var d []*Vertex // discovered
|
||||||
var s []*Vertex // stack
|
var s []*Vertex // stack
|
||||||
if _, exists := g.Adjacency[start]; !exists {
|
if _, exists := g.adjacency[start]; !exists {
|
||||||
return nil // TODO: error
|
return nil // TODO: error
|
||||||
}
|
}
|
||||||
v := start
|
v := start
|
||||||
@@ -390,24 +424,25 @@ func (g *Graph) DFS(start *Vertex) []*Vertex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FilterGraph builds a new graph containing only vertices from the list.
|
// FilterGraph builds a new graph containing only vertices from the list.
|
||||||
func (g *Graph) FilterGraph(name string, vertices []*Vertex) *Graph {
|
func (g *Graph) FilterGraph(name string, vertices []*Vertex) (*Graph, error) {
|
||||||
newgraph := NewGraph(name)
|
newGraph := &Graph{Name: name}
|
||||||
for k1, x := range g.Adjacency {
|
if err := newGraph.Init(); err != nil {
|
||||||
|
return nil, errwrap.Wrapf(err, "could not run FilterGraph() properly")
|
||||||
|
}
|
||||||
|
for k1, x := range g.adjacency {
|
||||||
for k2, e := range x {
|
for k2, e := range x {
|
||||||
//log.Printf("Filter: %s -> %s # %s", k1.Name, k2.Name, e.Name)
|
//log.Printf("Filter: %s -> %s # %s", k1.Name, k2.Name, e.Name)
|
||||||
if VertexContains(k1, vertices) || VertexContains(k2, vertices) {
|
if VertexContains(k1, vertices) || VertexContains(k2, vertices) {
|
||||||
newgraph.AddEdge(k1, k2, e)
|
newGraph.AddEdge(k1, k2, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newgraph
|
return newGraph, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDisconnectedGraphs returns a channel containing the N disconnected graphs
|
// GetDisconnectedGraphs returns a list containing the N disconnected graphs.
|
||||||
// in our main graph. We can then process each of these in parallel.
|
func (g *Graph) GetDisconnectedGraphs() ([]*Graph, error) {
|
||||||
func (g *Graph) GetDisconnectedGraphs() chan *Graph {
|
graphs := []*Graph{}
|
||||||
ch := make(chan *Graph)
|
|
||||||
go func() {
|
|
||||||
var start *Vertex
|
var start *Vertex
|
||||||
var d []*Vertex // discovered
|
var d []*Vertex // discovered
|
||||||
c := g.NumVertices()
|
c := g.NumVertices()
|
||||||
@@ -423,31 +458,31 @@ func (g *Graph) GetDisconnectedGraphs() chan *Graph {
|
|||||||
// dfs through the graph
|
// dfs through the graph
|
||||||
dfs := g.DFS(start)
|
dfs := g.DFS(start)
|
||||||
// filter all the collected elements into a new graph
|
// filter all the collected elements into a new graph
|
||||||
newgraph := g.FilterGraph(g.Name, dfs)
|
newgraph, err := g.FilterGraph(g.Name, dfs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errwrap.Wrapf(err, "could not run GetDisconnectedGraphs() properly")
|
||||||
|
}
|
||||||
// add number of elements found to found variable
|
// add number of elements found to found variable
|
||||||
d = append(d, dfs...) // extend
|
d = append(d, dfs...) // extend
|
||||||
|
|
||||||
// return this new graph to the channel
|
// append this new graph to the list
|
||||||
ch <- newgraph
|
graphs = append(graphs, newgraph)
|
||||||
|
|
||||||
// if we've found all the elements, then we're done
|
// if we've found all the elements, then we're done
|
||||||
// otherwise loop through to continue...
|
// otherwise loop through to continue...
|
||||||
}
|
}
|
||||||
close(ch)
|
return graphs, nil
|
||||||
}()
|
|
||||||
return ch
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InDegree returns the count of vertices that point to me in one big lookup map.
|
// InDegree returns the count of vertices that point to me in one big lookup map.
|
||||||
func (g *Graph) InDegree() map[*Vertex]int {
|
func (g *Graph) InDegree() map[*Vertex]int {
|
||||||
result := make(map[*Vertex]int)
|
result := make(map[*Vertex]int)
|
||||||
for k := range g.Adjacency {
|
for k := range g.adjacency {
|
||||||
result[k] = 0 // initialize
|
result[k] = 0 // initialize
|
||||||
}
|
}
|
||||||
|
|
||||||
for k := range g.Adjacency {
|
for k := range g.adjacency {
|
||||||
for z := range g.Adjacency[k] {
|
for z := range g.adjacency[k] {
|
||||||
result[z]++
|
result[z]++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -458,9 +493,9 @@ func (g *Graph) InDegree() map[*Vertex]int {
|
|||||||
func (g *Graph) OutDegree() map[*Vertex]int {
|
func (g *Graph) OutDegree() map[*Vertex]int {
|
||||||
result := make(map[*Vertex]int)
|
result := make(map[*Vertex]int)
|
||||||
|
|
||||||
for k := range g.Adjacency {
|
for k := range g.adjacency {
|
||||||
result[k] = 0 // initialize
|
result[k] = 0 // initialize
|
||||||
for range g.Adjacency[k] {
|
for range g.adjacency[k] {
|
||||||
result[k]++
|
result[k]++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -490,7 +525,7 @@ func (g *Graph) TopologicalSort() ([]*Vertex, error) { // kahn's algorithm
|
|||||||
v := S[last]
|
v := S[last]
|
||||||
S = S[:last]
|
S = S[:last]
|
||||||
L = append(L, v) // add v to tail of L
|
L = append(L, v) // add v to tail of L
|
||||||
for n := range g.Adjacency[v] {
|
for n := range g.adjacency[v] {
|
||||||
// for each node n remaining in the graph, consume from
|
// for each node n remaining in the graph, consume from
|
||||||
// remaining, so for remaining[n] > 0
|
// remaining, so for remaining[n] > 0
|
||||||
if remaining[n] > 0 {
|
if remaining[n] > 0 {
|
||||||
@@ -505,7 +540,7 @@ func (g *Graph) TopologicalSort() ([]*Vertex, error) { // kahn's algorithm
|
|||||||
// if graph has edges, eg if any value in rem is > 0
|
// if graph has edges, eg if any value in rem is > 0
|
||||||
for c, in := range remaining {
|
for c, in := range remaining {
|
||||||
if in > 0 {
|
if in > 0 {
|
||||||
for n := range g.Adjacency[c] {
|
for n := range g.adjacency[c] {
|
||||||
if remaining[n] > 0 {
|
if remaining[n] > 0 {
|
||||||
return nil, fmt.Errorf("not a dag")
|
return nil, fmt.Errorf("not a dag")
|
||||||
}
|
}
|
||||||
@@ -563,7 +598,11 @@ func (g *Graph) Reachability(a, b *Vertex) []*Vertex {
|
|||||||
func (g *Graph) GraphSync(oldGraph *Graph) (*Graph, error) {
|
func (g *Graph) GraphSync(oldGraph *Graph) (*Graph, error) {
|
||||||
|
|
||||||
if oldGraph == nil {
|
if oldGraph == nil {
|
||||||
oldGraph = NewGraph(g.GetName()) // copy over the name
|
var err error
|
||||||
|
oldGraph, err = NewGraph(g.GetName()) // copy over the name
|
||||||
|
if err != nil {
|
||||||
|
return nil, errwrap.Wrapf(err, "could not run GraphSync() properly")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
oldGraph.SetName(g.GetName()) // overwrite the name
|
oldGraph.SetName(g.GetName()) // overwrite the name
|
||||||
|
|
||||||
@@ -571,7 +610,7 @@ func (g *Graph) GraphSync(oldGraph *Graph) (*Graph, error) {
|
|||||||
var vertexKeep []*Vertex // list of vertices which are the same in new graph
|
var vertexKeep []*Vertex // list of vertices which are the same in new graph
|
||||||
var edgeKeep []*Edge // list of vertices which are the same in new graph
|
var edgeKeep []*Edge // list of vertices which are the same in new graph
|
||||||
|
|
||||||
for v := range g.Adjacency { // loop through the vertices (resources)
|
for v := range g.adjacency { // loop through the vertices (resources)
|
||||||
res := v.Res // resource
|
res := v.Res // resource
|
||||||
var vertex *Vertex
|
var vertex *Vertex
|
||||||
|
|
||||||
@@ -598,7 +637,7 @@ func (g *Graph) GraphSync(oldGraph *Graph) (*Graph, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get rid of any vertices we shouldn't keep (that aren't in new graph)
|
// get rid of any vertices we shouldn't keep (that aren't in new graph)
|
||||||
for v := range oldGraph.Adjacency {
|
for v := range oldGraph.adjacency {
|
||||||
if !VertexContains(v, vertexKeep) {
|
if !VertexContains(v, vertexKeep) {
|
||||||
// wait for exit before starting new graph!
|
// wait for exit before starting new graph!
|
||||||
v.SendEvent(event.EventExit, nil) // sync
|
v.SendEvent(event.EventExit, nil) // sync
|
||||||
@@ -608,8 +647,8 @@ func (g *Graph) GraphSync(oldGraph *Graph) (*Graph, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// compare edges
|
// compare edges
|
||||||
for v1 := range g.Adjacency { // loop through the vertices (resources)
|
for v1 := range g.adjacency { // loop through the vertices (resources)
|
||||||
for v2, e := range g.Adjacency[v1] {
|
for v2, e := range g.adjacency[v1] {
|
||||||
// we have an edge!
|
// we have an edge!
|
||||||
|
|
||||||
// lookup vertices (these should exist now)
|
// lookup vertices (these should exist now)
|
||||||
@@ -624,18 +663,18 @@ func (g *Graph) GraphSync(oldGraph *Graph) (*Graph, error) {
|
|||||||
return nil, fmt.Errorf("new vertices weren't found") // programming error
|
return nil, fmt.Errorf("new vertices weren't found") // programming error
|
||||||
}
|
}
|
||||||
|
|
||||||
edge, exists := oldGraph.Adjacency[vertex1][vertex2]
|
edge, exists := oldGraph.adjacency[vertex1][vertex2]
|
||||||
if !exists || edge.Name != e.Name { // TODO: edgeCmp
|
if !exists || edge.Name != e.Name { // TODO: edgeCmp
|
||||||
edge = e // use or overwrite edge
|
edge = e // use or overwrite edge
|
||||||
}
|
}
|
||||||
oldGraph.Adjacency[vertex1][vertex2] = edge // store it (AddEdge)
|
oldGraph.adjacency[vertex1][vertex2] = edge // store it (AddEdge)
|
||||||
edgeKeep = append(edgeKeep, edge) // mark as saved
|
edgeKeep = append(edgeKeep, edge) // mark as saved
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete unused edges
|
// delete unused edges
|
||||||
for v1 := range oldGraph.Adjacency {
|
for v1 := range oldGraph.adjacency {
|
||||||
for _, e := range oldGraph.Adjacency[v1] {
|
for _, e := range oldGraph.adjacency[v1] {
|
||||||
// we have an edge!
|
// we have an edge!
|
||||||
if !EdgeContains(e, edgeKeep) {
|
if !EdgeContains(e, edgeKeep) {
|
||||||
oldGraph.DeleteEdge(e)
|
oldGraph.DeleteEdge(e)
|
||||||
@@ -649,7 +688,7 @@ func (g *Graph) GraphSync(oldGraph *Graph) (*Graph, error) {
|
|||||||
// GraphMetas returns a list of pointers to each of the resource MetaParams.
|
// GraphMetas returns a list of pointers to each of the resource MetaParams.
|
||||||
func (g *Graph) GraphMetas() []*resources.MetaParams {
|
func (g *Graph) GraphMetas() []*resources.MetaParams {
|
||||||
metas := []*resources.MetaParams{}
|
metas := []*resources.MetaParams{}
|
||||||
for v := range g.Adjacency { // loop through the vertices (resources))
|
for v := range g.adjacency { // loop through the vertices (resources))
|
||||||
res := v.Res // resource
|
res := v.Res // resource
|
||||||
meta := res.Meta()
|
meta := res.Meta()
|
||||||
metas = append(metas, meta)
|
metas = append(metas, meta)
|
||||||
@@ -662,7 +701,7 @@ func (g *Graph) AssociateData(data *resources.Data) {
|
|||||||
// prometheus needs to be associated to this graph as well
|
// prometheus needs to be associated to this graph as well
|
||||||
g.prometheus = data.Prometheus
|
g.prometheus = data.Prometheus
|
||||||
|
|
||||||
for k := range g.Adjacency {
|
for k := range g.adjacency {
|
||||||
*k.Res.Data() = *data
|
*k.Res.Data() = *data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func NV(s string) *Vertex {
|
|||||||
|
|
||||||
func TestPgraphT1(t *testing.T) {
|
func TestPgraphT1(t *testing.T) {
|
||||||
|
|
||||||
G := NewGraph("g1")
|
G, _ := NewGraph("g1")
|
||||||
|
|
||||||
if i := G.NumVertices(); i != 0 {
|
if i := G.NumVertices(); i != 0 {
|
||||||
t.Errorf("should have 0 vertices instead of: %d", i)
|
t.Errorf("should have 0 vertices instead of: %d", i)
|
||||||
@@ -68,7 +68,7 @@ func TestPgraphT1(t *testing.T) {
|
|||||||
|
|
||||||
func TestPgraphT2(t *testing.T) {
|
func TestPgraphT2(t *testing.T) {
|
||||||
|
|
||||||
G := NewGraph("g2")
|
G, _ := NewGraph("g2")
|
||||||
v1 := NV("v1")
|
v1 := NV("v1")
|
||||||
v2 := NV("v2")
|
v2 := NV("v2")
|
||||||
v3 := NV("v3")
|
v3 := NV("v3")
|
||||||
@@ -95,7 +95,7 @@ func TestPgraphT2(t *testing.T) {
|
|||||||
|
|
||||||
func TestPgraphT3(t *testing.T) {
|
func TestPgraphT3(t *testing.T) {
|
||||||
|
|
||||||
G := NewGraph("g3")
|
G, _ := NewGraph("g3")
|
||||||
v1 := NV("v1")
|
v1 := NV("v1")
|
||||||
v2 := NV("v2")
|
v2 := NV("v2")
|
||||||
v3 := NV("v3")
|
v3 := NV("v3")
|
||||||
@@ -136,7 +136,7 @@ func TestPgraphT3(t *testing.T) {
|
|||||||
|
|
||||||
func TestPgraphT4(t *testing.T) {
|
func TestPgraphT4(t *testing.T) {
|
||||||
|
|
||||||
G := NewGraph("g4")
|
G, _ := NewGraph("g4")
|
||||||
v1 := NV("v1")
|
v1 := NV("v1")
|
||||||
v2 := NV("v2")
|
v2 := NV("v2")
|
||||||
v3 := NV("v3")
|
v3 := NV("v3")
|
||||||
@@ -158,7 +158,7 @@ func TestPgraphT4(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPgraphT5(t *testing.T) {
|
func TestPgraphT5(t *testing.T) {
|
||||||
G := NewGraph("g5")
|
G, _ := NewGraph("g5")
|
||||||
v1 := NV("v1")
|
v1 := NV("v1")
|
||||||
v2 := NV("v2")
|
v2 := NV("v2")
|
||||||
v3 := NV("v3")
|
v3 := NV("v3")
|
||||||
@@ -180,14 +180,18 @@ func TestPgraphT5(t *testing.T) {
|
|||||||
//G.AddEdge(v6, v4, e6)
|
//G.AddEdge(v6, v4, e6)
|
||||||
|
|
||||||
save := []*Vertex{v1, v2, v3}
|
save := []*Vertex{v1, v2, v3}
|
||||||
out := G.FilterGraph("new g5", save)
|
out, err := G.FilterGraph("new g5", save)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed with: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
if i := out.NumVertices(); i != 3 {
|
if i := out.NumVertices(); i != 3 {
|
||||||
t.Errorf("should have 3 vertices instead of: %d", i)
|
t.Errorf("should have 3 vertices instead of: %d", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPgraphT6(t *testing.T) {
|
func TestPgraphT6(t *testing.T) {
|
||||||
G := NewGraph("g6")
|
G, _ := NewGraph("g6")
|
||||||
v1 := NV("v1")
|
v1 := NV("v1")
|
||||||
v2 := NV("v2")
|
v2 := NV("v2")
|
||||||
v3 := NV("v3")
|
v3 := NV("v3")
|
||||||
@@ -208,24 +212,19 @@ func TestPgraphT6(t *testing.T) {
|
|||||||
G.AddEdge(v5, v6, e5)
|
G.AddEdge(v5, v6, e5)
|
||||||
//G.AddEdge(v6, v4, e6)
|
//G.AddEdge(v6, v4, e6)
|
||||||
|
|
||||||
graphs := G.GetDisconnectedGraphs()
|
graphs, err := G.GetDisconnectedGraphs()
|
||||||
HeisenbergGraphCount := func(ch chan *Graph) int {
|
if err != nil {
|
||||||
c := 0
|
t.Errorf("failed with: %v", err)
|
||||||
for x := range ch {
|
|
||||||
_ = x
|
|
||||||
c++
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if i := HeisenbergGraphCount(graphs); i != 2 {
|
if i := len(graphs); i != 2 {
|
||||||
t.Errorf("should have 2 graphs instead of: %d", i)
|
t.Errorf("should have 2 graphs instead of: %d", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPgraphT7(t *testing.T) {
|
func TestPgraphT7(t *testing.T) {
|
||||||
|
|
||||||
G := NewGraph("g7")
|
G, _ := NewGraph("g7")
|
||||||
v1 := NV("v1")
|
v1 := NV("v1")
|
||||||
v2 := NV("v2")
|
v2 := NV("v2")
|
||||||
v3 := NV("v3")
|
v3 := NV("v3")
|
||||||
@@ -296,7 +295,7 @@ func TestPgraphT8(t *testing.T) {
|
|||||||
|
|
||||||
func TestPgraphT9(t *testing.T) {
|
func TestPgraphT9(t *testing.T) {
|
||||||
|
|
||||||
G := NewGraph("g9")
|
G, _ := NewGraph("g9")
|
||||||
v1 := NV("v1")
|
v1 := NV("v1")
|
||||||
v2 := NV("v2")
|
v2 := NV("v2")
|
||||||
v3 := NV("v3")
|
v3 := NV("v3")
|
||||||
@@ -372,7 +371,7 @@ func TestPgraphT9(t *testing.T) {
|
|||||||
|
|
||||||
func TestPgraphT10(t *testing.T) {
|
func TestPgraphT10(t *testing.T) {
|
||||||
|
|
||||||
G := NewGraph("g10")
|
G, _ := NewGraph("g10")
|
||||||
v1 := NV("v1")
|
v1 := NV("v1")
|
||||||
v2 := NV("v2")
|
v2 := NV("v2")
|
||||||
v3 := NV("v3")
|
v3 := NV("v3")
|
||||||
@@ -400,7 +399,7 @@ func TestPgraphT10(t *testing.T) {
|
|||||||
// empty
|
// empty
|
||||||
func TestPgraphReachability0(t *testing.T) {
|
func TestPgraphReachability0(t *testing.T) {
|
||||||
{
|
{
|
||||||
G := NewGraph("g")
|
G, _ := NewGraph("g")
|
||||||
result := G.Reachability(nil, nil)
|
result := G.Reachability(nil, nil)
|
||||||
if result != nil {
|
if result != nil {
|
||||||
t.Logf("reachability failed")
|
t.Logf("reachability failed")
|
||||||
@@ -412,7 +411,7 @@ func TestPgraphReachability0(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
G := NewGraph("g")
|
G, _ := NewGraph("g")
|
||||||
v1 := NV("v1")
|
v1 := NV("v1")
|
||||||
v6 := NV("v6")
|
v6 := NV("v6")
|
||||||
|
|
||||||
@@ -429,7 +428,7 @@ func TestPgraphReachability0(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
G := NewGraph("g")
|
G, _ := NewGraph("g")
|
||||||
v1 := NV("v1")
|
v1 := NV("v1")
|
||||||
v2 := NV("v2")
|
v2 := NV("v2")
|
||||||
v3 := NV("v3")
|
v3 := NV("v3")
|
||||||
@@ -463,7 +462,7 @@ func TestPgraphReachability0(t *testing.T) {
|
|||||||
|
|
||||||
// simple linear path
|
// simple linear path
|
||||||
func TestPgraphReachability1(t *testing.T) {
|
func TestPgraphReachability1(t *testing.T) {
|
||||||
G := NewGraph("g")
|
G, _ := NewGraph("g")
|
||||||
v1 := NV("v1")
|
v1 := NV("v1")
|
||||||
v2 := NV("v2")
|
v2 := NV("v2")
|
||||||
v3 := NV("v3")
|
v3 := NV("v3")
|
||||||
@@ -497,7 +496,7 @@ func TestPgraphReachability1(t *testing.T) {
|
|||||||
|
|
||||||
// pick one of two correct paths
|
// pick one of two correct paths
|
||||||
func TestPgraphReachability2(t *testing.T) {
|
func TestPgraphReachability2(t *testing.T) {
|
||||||
G := NewGraph("g")
|
G, _ := NewGraph("g")
|
||||||
v1 := NV("v1")
|
v1 := NV("v1")
|
||||||
v2 := NV("v2")
|
v2 := NV("v2")
|
||||||
v3 := NV("v3")
|
v3 := NV("v3")
|
||||||
@@ -534,7 +533,7 @@ func TestPgraphReachability2(t *testing.T) {
|
|||||||
|
|
||||||
// pick shortest path
|
// pick shortest path
|
||||||
func TestPgraphReachability3(t *testing.T) {
|
func TestPgraphReachability3(t *testing.T) {
|
||||||
G := NewGraph("g")
|
G, _ := NewGraph("g")
|
||||||
v1 := NV("v1")
|
v1 := NV("v1")
|
||||||
v2 := NV("v2")
|
v2 := NV("v2")
|
||||||
v3 := NV("v3")
|
v3 := NV("v3")
|
||||||
@@ -569,7 +568,7 @@ func TestPgraphReachability3(t *testing.T) {
|
|||||||
|
|
||||||
// direct path
|
// direct path
|
||||||
func TestPgraphReachability4(t *testing.T) {
|
func TestPgraphReachability4(t *testing.T) {
|
||||||
G := NewGraph("g")
|
G, _ := NewGraph("g")
|
||||||
v1 := NV("v1")
|
v1 := NV("v1")
|
||||||
v2 := NV("v2")
|
v2 := NV("v2")
|
||||||
v3 := NV("v3")
|
v3 := NV("v3")
|
||||||
@@ -693,7 +692,7 @@ func GraphCmp(g1, g2 *Graph) error {
|
|||||||
var m = make(map[*Vertex]*Vertex) // g1 to g2 vertex correspondence
|
var m = make(map[*Vertex]*Vertex) // g1 to g2 vertex correspondence
|
||||||
Loop:
|
Loop:
|
||||||
// check vertices
|
// check vertices
|
||||||
for v1 := range g1.Adjacency { // for each vertex in g1
|
for v1 := range g1.adjacency { // for each vertex in g1
|
||||||
|
|
||||||
l1 := strings.Split(v1.GetName(), ",") // make list of everyone's names...
|
l1 := strings.Split(v1.GetName(), ",") // make list of everyone's names...
|
||||||
for _, x1 := range v1.GetGroup() {
|
for _, x1 := range v1.GetGroup() {
|
||||||
@@ -703,7 +702,7 @@ Loop:
|
|||||||
sort.Strings(l1)
|
sort.Strings(l1)
|
||||||
|
|
||||||
// inner loop
|
// inner loop
|
||||||
for v2 := range g2.Adjacency { // does it match in g2 ?
|
for v2 := range g2.adjacency { // does it match in g2 ?
|
||||||
|
|
||||||
l2 := strings.Split(v2.GetName(), ",")
|
l2 := strings.Split(v2.GetName(), ",")
|
||||||
for _, x2 := range v2.GetGroup() {
|
for _, x2 := range v2.GetGroup() {
|
||||||
@@ -723,16 +722,16 @@ Loop:
|
|||||||
// vertices (and groups) match :)
|
// vertices (and groups) match :)
|
||||||
|
|
||||||
// check edges
|
// check edges
|
||||||
for v1 := range g1.Adjacency { // for each vertex in g1
|
for v1 := range g1.adjacency { // for each vertex in g1
|
||||||
v2 := m[v1] // lookup in map to get correspondance
|
v2 := m[v1] // lookup in map to get correspondance
|
||||||
// g1.Adjacency[v1] corresponds to g2.Adjacency[v2]
|
// g1.adjacency[v1] corresponds to g2.adjacency[v2]
|
||||||
if e1, e2 := len(g1.Adjacency[v1]), len(g2.Adjacency[v2]); e1 != e2 {
|
if e1, e2 := len(g1.adjacency[v1]), len(g2.adjacency[v2]); e1 != e2 {
|
||||||
return fmt.Errorf("graph g1, vertex(%v) has %d edges, while g2, vertex(%v) has %d", v1.GetName(), e1, v2.GetName(), e2)
|
return fmt.Errorf("graph g1, vertex(%v) has %d edges, while g2, vertex(%v) has %d", v1.GetName(), e1, v2.GetName(), e2)
|
||||||
}
|
}
|
||||||
|
|
||||||
for vv1, ee1 := range g1.Adjacency[v1] {
|
for vv1, ee1 := range g1.adjacency[v1] {
|
||||||
vv2 := m[vv1]
|
vv2 := m[vv1]
|
||||||
ee2 := g2.Adjacency[v2][vv2]
|
ee2 := g2.adjacency[v2][vv2]
|
||||||
|
|
||||||
// these are edges from v1 -> vv1 via ee1 (graph 1)
|
// these are edges from v1 -> vv1 via ee1 (graph 1)
|
||||||
// to cmp to edges from v2 -> vv2 via ee2 (graph 2)
|
// to cmp to edges from v2 -> vv2 via ee2 (graph 2)
|
||||||
@@ -765,8 +764,8 @@ Loop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check meta parameters
|
// check meta parameters
|
||||||
for v1 := range g1.Adjacency { // for each vertex in g1
|
for v1 := range g1.adjacency { // for each vertex in g1
|
||||||
for v2 := range g2.Adjacency { // does it match in g2 ?
|
for v2 := range g2.adjacency { // does it match in g2 ?
|
||||||
s1, s2 := v1.Meta().Sema, v2.Meta().Sema
|
s1, s2 := v1.Meta().Sema, v2.Meta().Sema
|
||||||
sort.Strings(s1)
|
sort.Strings(s1)
|
||||||
sort.Strings(s2)
|
sort.Strings(s2)
|
||||||
@@ -816,7 +815,7 @@ func (ag *testGrouper) edgeMerge(e1, e2 *Edge) *Edge {
|
|||||||
|
|
||||||
func (g *Graph) fullPrint() (str string) {
|
func (g *Graph) fullPrint() (str string) {
|
||||||
str += "\n"
|
str += "\n"
|
||||||
for v := range g.Adjacency {
|
for v := range g.adjacency {
|
||||||
if semas := v.Meta().Sema; len(semas) > 0 {
|
if semas := v.Meta().Sema; len(semas) > 0 {
|
||||||
str += fmt.Sprintf("* v: %v; sema: %v\n", v.GetName(), semas)
|
str += fmt.Sprintf("* v: %v; sema: %v\n", v.GetName(), semas)
|
||||||
} else {
|
} else {
|
||||||
@@ -824,8 +823,8 @@ func (g *Graph) fullPrint() (str string) {
|
|||||||
}
|
}
|
||||||
// TODO: add explicit grouping data?
|
// TODO: add explicit grouping data?
|
||||||
}
|
}
|
||||||
for v1 := range g.Adjacency {
|
for v1 := range g.adjacency {
|
||||||
for v2, e := range g.Adjacency[v1] {
|
for v2, e := range g.adjacency[v1] {
|
||||||
str += fmt.Sprintf("* e: %v -> %v # %v\n", v1.GetName(), v2.GetName(), e.Name)
|
str += fmt.Sprintf("* e: %v -> %v # %v\n", v1.GetName(), v2.GetName(), e.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func NewNoopResTestSema(name string, semas []string) *NoopResTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPgraphSemaphoreGrouping1(t *testing.T) {
|
func TestPgraphSemaphoreGrouping1(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTestSema("a1", []string{"s:1"}))
|
a1 := NewVertex(NewNoopResTestSema("a1", []string{"s:1"}))
|
||||||
a2 := NewVertex(NewNoopResTestSema("a2", []string{"s:2"}))
|
a2 := NewVertex(NewNoopResTestSema("a2", []string{"s:2"}))
|
||||||
@@ -61,7 +61,7 @@ func TestPgraphSemaphoreGrouping1(t *testing.T) {
|
|||||||
g1.AddVertex(a2)
|
g1.AddVertex(a2)
|
||||||
g1.AddVertex(a3)
|
g1.AddVertex(a3)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a123 := NewVertex(NewNoopResTestSema("a1,a2,a3", []string{"s:1", "s:2", "s:3"}))
|
a123 := NewVertex(NewNoopResTestSema("a1,a2,a3", []string{"s:1", "s:2", "s:3"}))
|
||||||
g2.AddVertex(a123)
|
g2.AddVertex(a123)
|
||||||
@@ -70,7 +70,7 @@ func TestPgraphSemaphoreGrouping1(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPgraphSemaphoreGrouping2(t *testing.T) {
|
func TestPgraphSemaphoreGrouping2(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTestSema("a1", []string{"s:10", "s:11"}))
|
a1 := NewVertex(NewNoopResTestSema("a1", []string{"s:10", "s:11"}))
|
||||||
a2 := NewVertex(NewNoopResTestSema("a2", []string{"s:2"}))
|
a2 := NewVertex(NewNoopResTestSema("a2", []string{"s:2"}))
|
||||||
@@ -79,7 +79,7 @@ func TestPgraphSemaphoreGrouping2(t *testing.T) {
|
|||||||
g1.AddVertex(a2)
|
g1.AddVertex(a2)
|
||||||
g1.AddVertex(a3)
|
g1.AddVertex(a3)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a123 := NewVertex(NewNoopResTestSema("a1,a2,a3", []string{"s:10", "s:11", "s:2", "s:3"}))
|
a123 := NewVertex(NewNoopResTestSema("a1,a2,a3", []string{"s:10", "s:11", "s:2", "s:3"}))
|
||||||
g2.AddVertex(a123)
|
g2.AddVertex(a123)
|
||||||
@@ -88,7 +88,7 @@ func TestPgraphSemaphoreGrouping2(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPgraphSemaphoreGrouping3(t *testing.T) {
|
func TestPgraphSemaphoreGrouping3(t *testing.T) {
|
||||||
g1 := NewGraph("g1") // original graph
|
g1, _ := NewGraph("g1") // original graph
|
||||||
{
|
{
|
||||||
a1 := NewVertex(NewNoopResTestSema("a1", []string{"s:1", "s:2"}))
|
a1 := NewVertex(NewNoopResTestSema("a1", []string{"s:1", "s:2"}))
|
||||||
a2 := NewVertex(NewNoopResTestSema("a2", []string{"s:2"}))
|
a2 := NewVertex(NewNoopResTestSema("a2", []string{"s:2"}))
|
||||||
@@ -97,7 +97,7 @@ func TestPgraphSemaphoreGrouping3(t *testing.T) {
|
|||||||
g1.AddVertex(a2)
|
g1.AddVertex(a2)
|
||||||
g1.AddVertex(a3)
|
g1.AddVertex(a3)
|
||||||
}
|
}
|
||||||
g2 := NewGraph("g2") // expected result
|
g2, _ := NewGraph("g2") // expected result
|
||||||
{
|
{
|
||||||
a123 := NewVertex(NewNoopResTestSema("a1,a2,a3", []string{"s:1", "s:2", "s:3"}))
|
a123 := NewVertex(NewNoopResTestSema("a1,a2,a3", []string{"s:1", "s:2", "s:3"}))
|
||||||
g2.AddVertex(a123)
|
g2.AddVertex(a123)
|
||||||
|
|||||||
@@ -57,7 +57,10 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
|
|||||||
}
|
}
|
||||||
// FIXME: these are being specified temporarily until it's the default!
|
// FIXME: these are being specified temporarily until it's the default!
|
||||||
metaparams := resources.DefaultMetaParams
|
metaparams := resources.DefaultMetaParams
|
||||||
g := pgraph.NewGraph(obj.Name)
|
g, err := pgraph.NewGraph(obj.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
n0 := &resources.NoopRes{
|
n0 := &resources.NoopRes{
|
||||||
BaseRes: resources.BaseRes{
|
BaseRes: resources.BaseRes{
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import (
|
|||||||
"github.com/purpleidea/mgmt/pgraph"
|
"github.com/purpleidea/mgmt/pgraph"
|
||||||
"github.com/purpleidea/mgmt/resources"
|
"github.com/purpleidea/mgmt/resources"
|
||||||
|
|
||||||
|
errwrap "github.com/pkg/errors"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -96,7 +97,11 @@ func (c *GraphConfig) NewGraphFromConfig(hostname string, world resources.World,
|
|||||||
// hostname is the uuid for the host
|
// hostname is the uuid for the host
|
||||||
|
|
||||||
var graph *pgraph.Graph // new graph to return
|
var graph *pgraph.Graph // new graph to return
|
||||||
graph = pgraph.NewGraph("Graph") // give graph a default name
|
var err error
|
||||||
|
graph, err = pgraph.NewGraph("Graph") // give graph a default name
|
||||||
|
if err != nil {
|
||||||
|
return nil, errwrap.Wrapf(err, "could not run NewGraphFromConfig() properly")
|
||||||
|
}
|
||||||
|
|
||||||
var lookup = make(map[string]map[string]*pgraph.Vertex)
|
var lookup = make(map[string]map[string]*pgraph.Vertex)
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import (
|
|||||||
"github.com/purpleidea/mgmt/pgraph"
|
"github.com/purpleidea/mgmt/pgraph"
|
||||||
"github.com/purpleidea/mgmt/resources"
|
"github.com/purpleidea/mgmt/resources"
|
||||||
|
|
||||||
|
errwrap "github.com/pkg/errors"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -156,7 +157,11 @@ func (c *GraphConfig) NewGraphFromConfig(hostname string, world resources.World,
|
|||||||
// hostname is the uuid for the host
|
// hostname is the uuid for the host
|
||||||
|
|
||||||
var graph *pgraph.Graph // new graph to return
|
var graph *pgraph.Graph // new graph to return
|
||||||
graph = pgraph.NewGraph("Graph") // give graph a default name
|
var err error
|
||||||
|
graph, err = pgraph.NewGraph("Graph") // give graph a default name
|
||||||
|
if err != nil {
|
||||||
|
return nil, errwrap.Wrapf(err, "could not run NewGraphFromConfig() properly")
|
||||||
|
}
|
||||||
|
|
||||||
var lookup = make(map[string]map[string]*pgraph.Vertex)
|
var lookup = make(map[string]map[string]*pgraph.Vertex)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user