modelRT/diagram/graph.go

159 lines
4.0 KiB
Go
Raw Normal View History

package diagram
import (
"errors"
"fmt"
"sync"
constants "modelRT/constant"
"modelRT/network"
"github.com/gofrs/uuid"
)
// Graph represents a topological structure using an adjacency list
type Graph struct {
sync.RWMutex
// 根节点
RootVertex uuid.UUID
// 游离节点
FreeVertexs map[string]struct{}
VerticeLinks map[string][]uuid.UUID
// 存储多个上级节点同时指向同一下级节点的情况,key为下级节点,value为上级节点集合
BackLinks map[string][]uuid.UUID
}
// NewGraph creates a new graph
func NewGraph(root uuid.UUID) *Graph {
return &Graph{
RootVertex: root,
FreeVertexs: make(map[string]struct{}),
VerticeLinks: make(map[string][]uuid.UUID),
BackLinks: make(map[string][]uuid.UUID),
}
}
// AddNode adds a node to the graph
func (g *Graph) AddNode(vertex string) {
if _, exists := g.VerticeLinks[vertex]; !exists {
g.VerticeLinks[vertex] = []uuid.UUID{}
}
}
// CreateBackLink adds a node to the graph
func (g *Graph) CreateBackLink(vertex string) {
if _, exists := g.BackLinks[vertex]; !exists {
g.BackLinks[vertex] = []uuid.UUID{}
}
}
// AddEdge adds an edge between two verticeLinks
// TODO 在添加拓扑信息时是否考虑过滤重复节点
func (g *Graph) AddEdge(from, to uuid.UUID) {
g.Lock()
defer g.Unlock()
fromKey := from.String()
toKey := to.String()
g.CreateBackLink(toKey)
g.BackLinks[toKey] = append(g.BackLinks[toKey], from)
g.AddNode(fromKey)
g.AddNode(toKey)
g.VerticeLinks[fromKey] = append(g.VerticeLinks[fromKey], to)
// 创建新的拓扑信息时,如果被链接的点已经存在于游离节点中
// 则将其移除
if _, exist := g.FreeVertexs[toKey]; exist {
delete(g.FreeVertexs, toKey)
}
}
// DelNode delete a node to the graph
func (g *Graph) DelNode(vertex string) error {
childNodes, exists := g.VerticeLinks[vertex]
if exists {
if len(childNodes) > 1 {
return errors.New("delete node failed,that vertex contains more than one child node")
}
delete(g.VerticeLinks, vertex)
}
parentNodes, exists := g.BackLinks[vertex]
if exists {
if len(parentNodes) > 1 {
return errors.New("delete node failed,that vertex contains more than one parent node")
}
delete(g.BackLinks, vertex)
} else {
return errors.New("that vertex don't have parent node")
}
return nil
}
// DelEdge delete an edge between two verticeLinks
func (g *Graph) DelEdge(from, to uuid.UUID) error {
g.Lock()
defer g.Unlock()
toKey := to.String()
var fromKeys []uuid.UUID
if _, exist := g.BackLinks[toKey]; exist {
fromKeys = g.BackLinks[toKey]
} else {
fromKeys = []uuid.UUID{from}
}
// Process the situation where the to node is taken as the parent node while deleting edges
childvertex := g.VerticeLinks[toKey]
err := g.DelNode(toKey)
if err != nil {
return fmt.Errorf("delete edge failed: %w", err)
}
fmt.Println("fromKeys:", fromKeys)
for _, fromUUID := range fromKeys {
fromKey := fromUUID.String()
var delIndex int
for index, vertex := range g.VerticeLinks[fromKey] {
if vertex == to {
delIndex = index
}
}
vertex := g.VerticeLinks[fromKey]
if len(vertex) == 1 {
g.DelNode(fromKey)
} else {
copy(vertex[delIndex:], vertex[delIndex+1:])
vertex = vertex[:len(vertex)-1]
g.VerticeLinks[fromKey] = vertex
}
}
fromKey := from.String()
g.VerticeLinks[fromKey] = append(g.VerticeLinks[fromKey], childvertex...)
return nil
}
// PrintGraph prints the graph in adjacency list format
func (g *Graph) PrintGraph() {
g.RLock() // 读锁
defer g.RUnlock()
for vertex, edges := range g.VerticeLinks {
fmt.Printf("%s -> %v\n", vertex, edges)
}
}
// UpdateEdge update edge link info between two verticeLinks
func (g *Graph) UpdateEdge(changeInfo network.TopologicUUIDChangeInfos) error {
if changeInfo.ChangeType == constants.UUIDFromChangeType || changeInfo.ChangeType == constants.UUIDToChangeType {
g.DelEdge(changeInfo.OldUUIDFrom, changeInfo.OldUUIDTo)
g.AddEdge(changeInfo.NewUUIDFrom, changeInfo.NewUUIDTo)
} else {
g.AddEdge(changeInfo.NewUUIDFrom, changeInfo.NewUUIDTo)
}
return nil
}