mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-12-23 07:35:39 +00:00
198 lines
4.7 KiB
Go
198 lines
4.7 KiB
Go
package main
|
|
|
|
import "fmt"
|
|
import "bufio"
|
|
import "os"
|
|
import "strings"
|
|
import "strconv"
|
|
import "time"
|
|
|
|
import "runtime/pprof"
|
|
import "flag"
|
|
|
|
import "router"
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
type Node struct {
|
|
nodeID router.NodeID
|
|
table router.Table
|
|
links []*Node
|
|
}
|
|
|
|
func (n *Node) init(nodeID router.NodeID) {
|
|
n.nodeID = nodeID
|
|
n.table.Init(nodeID)
|
|
n.links = append(n.links, n)
|
|
}
|
|
|
|
func linkNodes(m, n *Node) {
|
|
for _, o := range m.links {
|
|
if o.nodeID == n.nodeID {
|
|
// Don't allow duplicates
|
|
return
|
|
}
|
|
}
|
|
m.links = append(m.links, n)
|
|
n.links = append(n.links, m)
|
|
}
|
|
|
|
func makeStoreSquareGrid(sideLength int) map[router.NodeID]*Node {
|
|
store := make(map[router.NodeID]*Node)
|
|
nNodes := sideLength * sideLength
|
|
nodeIDs := make([]router.NodeID, 0, nNodes)
|
|
// TODO shuffle nodeIDs
|
|
for nodeID := 1; nodeID <= nNodes; nodeID++ {
|
|
nodeIDs = append(nodeIDs, router.NodeID(nodeID))
|
|
}
|
|
for _, nodeID := range nodeIDs {
|
|
node := &Node{}
|
|
node.init(nodeID)
|
|
store[nodeID] = node
|
|
}
|
|
for idx := 0; idx < nNodes; idx++ {
|
|
if (idx % sideLength) != 0 {
|
|
linkNodes(store[nodeIDs[idx]], store[nodeIDs[idx-1]])
|
|
}
|
|
if idx >= sideLength {
|
|
linkNodes(store[nodeIDs[idx]], store[nodeIDs[idx-sideLength]])
|
|
}
|
|
}
|
|
return store
|
|
}
|
|
|
|
func loadGraph(path string) map[router.NodeID]*Node {
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer f.Close()
|
|
store := make(map[router.NodeID]*Node)
|
|
s := bufio.NewScanner(f)
|
|
for s.Scan() {
|
|
line := s.Text()
|
|
nodeIDstrs := strings.Split(line, " ")
|
|
nodeIDi0, _ := strconv.Atoi(nodeIDstrs[0])
|
|
nodeIDi1, _ := strconv.Atoi(nodeIDstrs[1])
|
|
nodeID0 := router.NodeID(nodeIDi0)
|
|
nodeID1 := router.NodeID(nodeIDi1)
|
|
if store[nodeID0] == nil {
|
|
node := &Node{}
|
|
node.init(nodeID0)
|
|
store[nodeID0] = node
|
|
}
|
|
if store[nodeID1] == nil {
|
|
node := &Node{}
|
|
node.init(nodeID1)
|
|
store[nodeID1] = node
|
|
}
|
|
linkNodes(store[nodeID0], store[nodeID1])
|
|
}
|
|
return store
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
func idleUntilConverged(store map[router.NodeID]*Node) {
|
|
timeOfLastChange := 0
|
|
step := 0
|
|
// Idle untl the network has converged
|
|
for step-timeOfLastChange < 4*router.TIMEOUT {
|
|
step++
|
|
fmt.Println("Step:", step, "--", "last change:", timeOfLastChange)
|
|
for _, node := range store {
|
|
node.table.Tick()
|
|
for idx, link := range node.links[1:] {
|
|
msg := node.table.CreateMessage(router.Iface(idx))
|
|
for idx, fromNode := range link.links {
|
|
if fromNode == node {
|
|
//fmt.Println("Sending from node", node.nodeID, "to", link.nodeID)
|
|
link.table.HandleMessage(msg, router.Iface(idx))
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//for _, node := range store {
|
|
// if node.table.DEBUG_isDirty() { timeOfLastChange = step }
|
|
//}
|
|
//time.Sleep(10*time.Millisecond)
|
|
}
|
|
}
|
|
|
|
func testPaths(store map[router.NodeID]*Node) {
|
|
nNodes := len(store)
|
|
nodeIDs := make([]router.NodeID, 0, nNodes)
|
|
for nodeID := range store {
|
|
nodeIDs = append(nodeIDs, nodeID)
|
|
}
|
|
lookups := 0
|
|
count := 0
|
|
start := time.Now()
|
|
for _, source := range store {
|
|
count++
|
|
fmt.Printf("Testing paths from node %d / %d (%d)\n", count, nNodes, source.nodeID)
|
|
for _, dest := range store {
|
|
//if source == dest { continue }
|
|
destLoc := dest.table.GetLocator()
|
|
temp := 0
|
|
for here := source; here != dest; {
|
|
temp++
|
|
if temp > 16 {
|
|
panic("Loop?")
|
|
}
|
|
next := here.links[here.table.Lookup(destLoc)]
|
|
if next == here {
|
|
//for idx, link := range here.links {
|
|
// fmt.Println("DUMP:", idx, link.nodeID)
|
|
//}
|
|
panic(fmt.Sprintln("Routing Loop:",
|
|
source.nodeID,
|
|
here.nodeID,
|
|
dest.nodeID))
|
|
}
|
|
//fmt.Println("DEBUG:", source.nodeID, here.nodeID, dest.nodeID)
|
|
here = next
|
|
lookups++
|
|
}
|
|
}
|
|
}
|
|
timed := time.Since(start)
|
|
fmt.Printf("%f lookups per second\n", float64(lookups)/timed.Seconds())
|
|
}
|
|
|
|
func dumpStore(store map[router.NodeID]*Node) {
|
|
for _, node := range store {
|
|
fmt.Println("DUMPSTORE:", node.nodeID, node.table.GetLocator())
|
|
node.table.DEBUG_dumpTable()
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
if *cpuprofile != "" {
|
|
f, err := os.Create(*cpuprofile)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
|
}
|
|
if err := pprof.StartCPUProfile(f); err != nil {
|
|
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
|
}
|
|
defer pprof.StopCPUProfile()
|
|
}
|
|
fmt.Println("Test")
|
|
store := makeStoreSquareGrid(4)
|
|
idleUntilConverged(store)
|
|
dumpStore(store)
|
|
testPaths(store)
|
|
//panic("DYING")
|
|
store = loadGraph("hype-2016-09-19.list")
|
|
idleUntilConverged(store)
|
|
dumpStore(store)
|
|
testPaths(store)
|
|
}
|