Mega patch

This is still a dirty prototype, so please excuse the mess. Please
excuse the fact that this is a mega patch. Once things settle down this
won't happen any more.

Some of the changes squashed into here include:
* Merge vertex loop with type loop
(The file watcher seems to cache events anyways)
* Improve pgraph library
* Add indegree, outdegree, and topological sort with tests
* Add reverse function for vertex list
* Tons of additional cleanup!

Amazingly, on my first successful compile, this seemed to run!

A special thanks to Ira Cooper who helped me talk through some of the
algorithmic decisions and for his help in finding better ones!
This commit is contained in:
James Shubin
2015-12-10 03:34:51 -05:00
parent 0ea6f30ef2
commit 6b4fa21074
20 changed files with 1411 additions and 363 deletions

90
main.go
View File

@@ -63,6 +63,8 @@ func run(c *cli.Context) {
var wg sync.WaitGroup
exit := make(chan bool) // exit signal
log.Printf("This is: %v, version: %v\n", program, version)
log.Printf("Start: %v\n", start)
G := NewGraph("Graph") // give graph a default name
// exit after `exittime` seconds for no reason at all...
if i := c.Int("exittime"); i > 0 {
@@ -72,29 +74,58 @@ func run(c *cli.Context) {
}()
}
// build the graph from a config file
G := GraphFromConfig(c.String("file"))
log.Printf("Graph: %v\n", G) // show graph
log.Printf("Start: %v\n", start)
for x := range G.GetVerticesChan() { // XXX ?
log.Printf("Main->Starting[%v]\n", x.Name)
wg.Add(1)
// must pass in value to avoid races...
// see: https://ttboj.wordpress.com/2015/07/27/golang-parallelism-issues-causing-too-many-open-files-error/
go func(v *Vertex) {
defer wg.Done()
v.Start()
log.Printf("Main->Finish[%v]\n", v.Name)
}(x)
// generate a startup "poke" so that an initial check happens
go func(v *Vertex) {
v.Events <- fmt.Sprintf("Startup(%v)", v.Name)
}(x)
// etcd
hostname := c.String("hostname")
if hostname == "" {
hostname, _ = os.Hostname() // etcd watch key // XXX: this is not the correct key name this is the set key name... WOOPS
}
go func(hostname string) {
log.Printf("Starting etcd...\n")
kapi := EtcdGetKAPI()
first := true // first loop or not
for x := range EtcdWatch(kapi, true) {
// run graph vertex LOCK...
if !first {
log.Printf("Watcher().Node.Value(%v): %+v", hostname, x)
G.SetState(graphPausing)
log.Printf("State: %v", G.State())
G.Pause() // sync
G.SetState(graphPaused)
log.Printf("State: %v", G.State())
}
// build the graph from a config file
// build the graph on events (eg: from etcd) but kick it once...
if !UpdateGraphFromConfig(c.String("file"), hostname, G, kapi) {
log.Fatal("Graph failure")
}
log.Printf("Graph: %v\n", G) // show graph
G.SetVertex()
if first {
// G.Start(...) needs to be synchronous or wait,
// because if half of the nodes are started and
// some are not ready yet and the EtcdWatch
// loops, we'll cause G.Pause(...) before we
// even got going, thus causing nil pointer errors
G.SetState(graphStarting)
log.Printf("State: %v", G.State())
G.Start(&wg)
G.SetState(graphStarted)
log.Printf("State: %v", G.State())
} else {
G.SetState(graphContinuing)
log.Printf("State: %v", G.State())
G.Continue() // sync
G.SetState(graphStarted)
log.Printf("State: %v", G.State())
}
first = false
}
}(hostname)
log.Println("Running...")
@@ -116,6 +147,10 @@ func run(c *cli.Context) {
}
func main() {
//if DEBUG {
log.SetFlags(log.LstdFlags | log.Lshortfile)
//}
log.SetFlags(log.Flags() - log.Ldate) // remove the date for now
app := cli.NewApp()
app.Name = program
app.Usage = "next generation config management"
@@ -134,6 +169,17 @@ func main() {
Value: "",
Usage: "graph definition to run",
},
cli.StringFlag{
Name: "code, c",
Value: "",
Usage: "code definition to run",
},
// useful for testing multiple instances on same machine
cli.StringFlag{
Name: "hostname",
Value: "",
Usage: "hostname to use",
},
cli.IntFlag{
Name: "exittime",
Value: 0,