package tester import ( //"log" "strconv" "sync" "6.5840/labrpc" ) type Tgid int // A service must support Kill(); the tester will Kill() // on service returned by FstartServer() type IService interface { Kill() } // Start server and return the services to register with labrpc type FstartServer func(ends []*labrpc.ClientEnd, grp Tgid, srv int, persister *Persister) []IService // Each server has a name: i'th server of group gid. If there is only a single // server, it its gid = 0 and its i is 0. func ServerName(gid Tgid, i int) string { return "server-" + strconv.Itoa(int(gid)) + "-" + strconv.Itoa(i) } // The tester may have many groups of servers (e.g., one per Raft group). // Groups are named 0, 1, and so on. type Groups struct { mu sync.Mutex net *labrpc.Network grps map[Tgid]*ServerGrp } func newGroups(net *labrpc.Network) *Groups { return &Groups{net: net, grps: make(map[Tgid]*ServerGrp)} } func (gs *Groups) MakeGroup(gid Tgid, nsrv int, mks FstartServer) { gs.mu.Lock() defer gs.mu.Unlock() gs.grps[gid] = makeSrvGrp(gs.net, gid, nsrv, mks) } func (gs *Groups) lookupGroup(gid Tgid) *ServerGrp { gs.mu.Lock() defer gs.mu.Unlock() return gs.grps[gid] } func (gs *Groups) delete(gid Tgid) { gs.mu.Lock() defer gs.mu.Unlock() delete(gs.grps, gid) } func (gs *Groups) cleanup() { gs.mu.Lock() defer gs.mu.Unlock() for _, sg := range gs.grps { sg.cleanup() } } type ServerGrp struct { net *labrpc.Network srvs []*Server servernames []string gid Tgid connected []bool // whether each server is on the net mks FstartServer mu sync.Mutex } func makeSrvGrp(net *labrpc.Network, gid Tgid, n int, mks FstartServer) *ServerGrp { sg := &ServerGrp{ net: net, srvs: make([]*Server, n), gid: gid, connected: make([]bool, n), mks: mks, } for i, _ := range sg.srvs { sg.srvs[i] = makeServer(net, gid, n) } sg.servernames = make([]string, n) for i := 0; i < n; i++ { sg.servernames[i] = ServerName(gid, i) } return sg } func (sg *ServerGrp) N() int { return len(sg.srvs) } func (sg *ServerGrp) SrvNames() []string { return sg.servernames } func (sg *ServerGrp) SrvName(i int) string { return sg.servernames[i] } func (sg *ServerGrp) Services() [][]IService { ss := make([][]IService, 0, len(sg.srvs)) for _, s := range sg.srvs { ss = append(ss, s.svcs) } return ss } func (sg *ServerGrp) SrvNamesTo(to []int) []string { ns := make([]string, 0, len(to)) for _, i := range to { ns = append(ns, sg.servernames[i]) } return ns } func (sg *ServerGrp) all() []int { all := make([]int, len(sg.srvs)) for i, _ := range sg.srvs { all[i] = i } return all } func (sg *ServerGrp) ConnectAll() { for i, _ := range sg.srvs { sg.ConnectOne(i) } } func (sg *ServerGrp) ConnectOne(i int) { sg.connect(i, sg.all()) } func (sg *ServerGrp) cleanup() { for _, s := range sg.srvs { if s.svcs != nil { for _, svc := range s.svcs { svc.Kill() } } } } // attach server i to servers listed in to caller must hold cfg.mu. func (sg *ServerGrp) connect(i int, to []int) { //log.Printf("connect peer %d to %v\n", i, to) sg.connected[i] = true // connect outgoing end points sg.srvs[i].connect(sg, to) // connect incoming end points to me for j := 0; j < len(to); j++ { if sg.IsConnected(to[j]) { //log.Printf("connect %d (%v) to %d", to[j], sg.srvs[to[j]].endNames[i], i) endname := sg.srvs[to[j]].endNames[i] sg.net.Enable(endname, true) } } } // detach server from the servers listed in from // caller must hold cfg.mu func (sg *ServerGrp) disconnect(i int, from []int) { // log.Printf("%p: disconnect peer %d from %v\n", sg, i, from) sg.mu.Lock() sg.connected[i] = false sg.mu.Unlock() // outgoing socket files sg.srvs[i].disconnect(from) // incoming socket files for j := 0; j < len(from); j++ { s := sg.srvs[from[j]] if s.endNames != nil { endname := s.endNames[i] // log.Printf("%p: disconnect: %v", sg, endname) sg.net.Enable(endname, false) } } } func (sg *ServerGrp) DisconnectAll(i int) { sg.disconnect(i, sg.all()) } func (sg *ServerGrp) IsConnected(i int) bool { defer sg.mu.Unlock() sg.mu.Lock() return sg.connected[i] } func (sg *ServerGrp) GetConnected() []bool { return sg.connected } // Maximum log size across all servers func (sg *ServerGrp) LogSize() int { logsize := 0 for _, s := range sg.srvs { n := s.saved.RaftStateSize() if n > logsize { logsize = n } } return logsize } // Maximum snapshot size across all servers func (sg *ServerGrp) SnapshotSize() int { snapshotsize := 0 for _, s := range sg.srvs { n := s.saved.SnapshotSize() if n > snapshotsize { snapshotsize = n } } return snapshotsize } // If restart servers, first call shutdownserver func (sg *ServerGrp) StartServer(i int) { srv := sg.srvs[i].startServer(sg.gid) sg.srvs[i] = srv srv.svcs = sg.mks(srv.clntEnds, sg.gid, i, srv.saved) labsrv := labrpc.MakeServer() for _, svc := range srv.svcs { s := labrpc.MakeService(svc) labsrv.AddService(s) } sg.net.AddServer(ServerName(sg.gid, i), labsrv) } // create a full set of KV servers. func (sg *ServerGrp) StartServers() { sg.start() sg.ConnectAll() } // Shutdown a server by isolating it func (sg *ServerGrp) ShutdownServer(i int) { //log.Printf("ShutdownServer %v", ServerName(sg.gid, i)) sg.disconnect(i, sg.all()) // disable client connections to the server. // it's important to do this before creating // the new Persister in saved[i], to avoid // the possibility of the server returning a // positive reply to an Append but persisting // the result in the superseded Persister. sg.net.DeleteServer(ServerName(sg.gid, i)) sg.srvs[i].shutdownServer() } func (sg *ServerGrp) Shutdown() { for i, _ := range sg.srvs { sg.ShutdownServer(i) } } func (sg *ServerGrp) start() { for i, _ := range sg.srvs { sg.StartServer(i) } } // Partition servers into 2 groups and put current leader in minority func (sg *ServerGrp) MakePartition(l int) ([]int, []int) { n := len(sg.srvs) p1 := make([]int, n/2+1) p2 := make([]int, n/2) j := 0 for i := 0; i < n; i++ { if i != l { if j < len(p1) { p1[j] = i } else { p2[j-len(p1)] = i } j++ } } p2[len(p2)-1] = l return p1, p2 } func (sg *ServerGrp) Partition(p1 []int, p2 []int) { //log.Printf("partition servers into: %v %v\n", p1, p2) for i := 0; i < len(p1); i++ { sg.disconnect(p1[i], p2) sg.connect(p1[i], p1) } for i := 0; i < len(p2); i++ { sg.disconnect(p2[i], p1) sg.connect(p2[i], p2) } } func (sg *ServerGrp) RpcCount(server int) int { return sg.net.GetCount(ServerName(sg.gid, server)) }