// Start fsm and create new pirates func Start() { listener = make(chan gotocol.Message) // listener for fsm if archaius.Conf.Population < 2 { log.Fatal("fsm: can't create less than 2 pirates") } // create map of channels and a name index to select randoml nodes from noodles = make(map[string]chan gotocol.Message, archaius.Conf.Population) pnames = make([]string, archaius.Conf.Population) // indexable name list log.Println("fsm: population", archaius.Conf.Population, "pirates") for i := 1; i <= archaius.Conf.Population; i++ { name := names.Make(archaius.Conf.Arch, "atlantic", "bermuda", "blackbeard", "pirate", i) noodles[name] = make(chan gotocol.Message) go pirate.Start(noodles[name]) } i := 0 msgcount := 1 start := time.Now() for name, noodle := range noodles { pnames[i] = name i++ // tell the pirate it's name and how to talk back to it's fsm // this must be the first message the pirate sees noodle <- gotocol.Message{gotocol.Hello, listener, time.Now(), gotocol.NilContext, name} if edda.Logchan != nil { // tell the pirate to report itself and new edges to the logger noodle <- gotocol.Message{gotocol.Inform, edda.Logchan, time.Now(), gotocol.NilContext, ""} msgcount = 2 } } log.Println("fsm: Talk amongst yourselves for", archaius.Conf.RunDuration) rand.Seed(int64(len(noodles))) for _, name := range pnames { // for each pirate tell them about two other random pirates noodle := noodles[name] // lookup the channel // pick a first random pirate to tell this one about talkto := pnames[rand.Intn(len(pnames))] noodle <- gotocol.Message{gotocol.NameDrop, noodles[talkto], time.Now(), gotocol.NewTrace(), talkto} // pick a second random pirate to tell this one about talkto = pnames[rand.Intn(len(pnames))] noodle <- gotocol.Message{gotocol.NameDrop, noodles[talkto], time.Now(), gotocol.NewTrace(), talkto} // anonymously send this pirate a random amount of GoldCoin up to 100 gold := fmt.Sprintf("%d", rand.Intn(100)) noodle <- gotocol.Message{gotocol.GoldCoin, nil, time.Now(), gotocol.NewTrace(), gold} // tell this pirate to start chatting with friends every 0.1 to 10 secs delay := fmt.Sprintf("%dms", 100+rand.Intn(9900)) noodle <- gotocol.Message{gotocol.Chat, nil, time.Now(), gotocol.NewTrace(), delay} } msgcount += 4 d := time.Since(start) log.Println("fsm: Delivered", msgcount*len(pnames), "messages in", d) shutdown() }
// Reload the network from a file func Reload(arch string) { listener = make(chan gotocol.Message) // listener for fsm log.Println("fsm reloading from " + arch + ".json") g := graphjson.ReadArch(arch) pop := 0 // count how many nodes there are for _, element := range g.Graph { if element.Node != "" { pop++ } } archaius.Conf.Population = pop // create the map of channels noodles = make(map[string]chan gotocol.Message, archaius.Conf.Population) // Start all the services for _, element := range g.Graph { if element.Node != "" && element.Service != "" { name := element.Node noodles[name] = make(chan gotocol.Message) // start the service and tell it it's name switch element.Service { case "pirate": go pirate.Start(noodles[name]) noodles[name] <- gotocol.Message{gotocol.Hello, listener, time.Now(), gotocol.NilContext, name} if edda.Logchan != nil { // tell the pirate to report itself and new edges to the logger noodles[name] <- gotocol.Message{gotocol.Inform, edda.Logchan, time.Now(), gotocol.NilContext, ""} } default: log.Println("fsm: unknown service: " + element.Service) } } } // Make all the connections for _, element := range g.Graph { if element.Edge != "" && element.Source != "" && element.Target != "" { noodles[element.Source] <- gotocol.Message{gotocol.NameDrop, noodles[element.Target], time.Now(), gotocol.NewTrace(), element.Target} log.Println("Link " + element.Source + " > " + element.Target) } } // send money and start the pirates chatting for _, noodle := range noodles { // same as below for now, but will save and read back from file later // anonymously send this pirate a random amount of GoldCoin up to 100 gold := fmt.Sprintf("%d", rand.Intn(100)) noodle <- gotocol.Message{gotocol.GoldCoin, nil, time.Now(), gotocol.NewTrace(), gold} // tell this pirate to start chatting with friends every 0.1 to 10 secs delay := fmt.Sprintf("%dms", 100+rand.Intn(9900)) noodle <- gotocol.Message{gotocol.Chat, nil, time.Now(), gotocol.NilContext, delay} } shutdown() }
// Start a node using the named package, and connect it to any dependencies func StartNode(name string, dependencies ...string) { if names.Package(name) == EurekaPkg { eurekachan[name] = make(chan gotocol.Message, archaius.Conf.Population/len(archaius.Conf.ZoneNames)) // buffer sized to a zone go eureka.Start(eurekachan[name], name) return } else { noodles[name] = make(chan gotocol.Message) } // start the service and tell it it's name switch names.Package(name) { case PiratePkg: go pirate.Start(noodles[name]) case ElbPkg: go elb.Start(noodles[name]) case DenominatorPkg: go denominator.Start(noodles[name]) case ZuulPkg: go zuul.Start(noodles[name]) case KaryonPkg: go karyon.Start(noodles[name]) case MonolithPkg: go monolith.Start(noodles[name]) case StaashPkg: go staash.Start(noodles[name]) case RiakPkg: fallthrough // fake Riak using priamCassandra case PriamCassandraPkg: go priamCassandra.Start(noodles[name]) case CachePkg: fallthrough // fake memcache using store case VolumePkg: fallthrough // fake disk volume using store case StorePkg: go store.Start(noodles[name]) default: log.Fatal("asgard: unknown package: " + names.Package(name)) } noodles[name] <- gotocol.Message{gotocol.Hello, listener, time.Now(), gotocol.NilContext, name} // there is a eureka service registry in each zone, so in-zone services just get to talk to their local registry // elb are cross zone, so need to see all registries in a region // denominator are cross region so need to see all registries globally // priamCassandra depends explicitly on eureka for cross region clusters crossregion := false for _, d := range dependencies { if d == "eureka" { crossregion = true } } for n, ch := range eurekachan { if names.Region(name) == "*" || crossregion { // need to know every eureka in all zones and regions gotocol.Send(noodles[name], gotocol.Message{gotocol.Inform, ch, time.Now(), gotocol.NilContext, n}) } else { if names.Zone(name) == "*" && names.Region(name) == names.Region(n) { // need every eureka in my region gotocol.Send(noodles[name], gotocol.Message{gotocol.Inform, ch, time.Now(), gotocol.NilContext, n}) } else { if names.RegionZone(name) == names.RegionZone(n) { // just the eureka in this specific zone gotocol.Send(noodles[name], gotocol.Message{gotocol.Inform, ch, time.Now(), gotocol.NilContext, n}) } } } } //log.Println(dependencies) // pass on symbolic dependencies without channels that will be looked up in Eureka later for _, dep := range dependencies { if dep != "" && dep != "eureka" { // ignore special case of eureka in dependency list //log.Println(name + " depends on " + dep) gotocol.Send(noodles[name], gotocol.Message{gotocol.NameDrop, nil, time.Now(), gotocol.NilContext, dep}) } } }