func (ln *leaseNode) dofunction(args *leaserpc.Args, reply *leaserpc.Reply, funcname string) error { replychan := make(chan *leaserpc.Reply, len(ln.peers)) for _, n := range ln.peers { go func(peernode Node) { if peernode.HostPort == ln.addrport { r := leaserpc.Reply{} switch { case funcname == "LeaseNode.Prepare": ln.Prepare(args, &r) case funcname == "LeaseNode.Accept": ln.Accept(args, &r) case funcname == "LeaseNode.RenewPrepare": ln.RenewPrepare(args, &r) case funcname == "LeaseNode.RenewAccept": ln.RenewAccept(args, &r) } replychan <- &r } else { r := leaserpc.Reply{} peer, err := rpcwrapper.DialHTTP("tcp", peernode.HostPort) if err != nil { r.Status = leaserpc.Reject replychan <- &r return } prepareCall := peer.Go(funcname, args, &r, nil) select { case _, _ = <-prepareCall.Done: replychan <- &r case _ = <-time.After(time.Second): r.Status = leaserpc.Reject replychan <- &r } peer.Close() } }(n) } numOK, numRej := 0, 0 for num := 0; num < len(ln.peers); num++ { r, _ := <-replychan if r.Status == leaserpc.OK { numOK++ } else { numRej++ } } if numOK > ln.numNodes/2 { reply.Status = leaserpc.OK return nil } else { reply.Status = leaserpc.Reject return nil } }
func (pn *paxosNode) DoAccept(args *paxosrpc.AcceptArgs, reply *paxosrpc.AcceptReply) error { LOGV.Printf("node %d DoAccept:%d %s %d\n", pn.nodeID, args.SlotIdx, args.V.ToString(), args.N) replychan := make(chan *paxosrpc.AcceptReply, len(pn.peers)) for i, n := range pn.peers { go func(idx int, peernode Node) { r := new(paxosrpc.AcceptReply) if peernode.HostPort == pn.addrport { pn.Accept(args, r) replychan <- r } else { peer, err := rpcwrapper.DialHTTP("tcp", peernode.HostPort) if err != nil { LOGE.Printf("node %d Cannot reach peer %d:%s\n", pn.nodeID, idx, peernode.HostPort) r.Status = paxosrpc.Reject replychan <- r return } prepareCall := peer.Go("PaxosNode.Accept", args, r, nil) select { case _, _ = <-prepareCall.Done: replychan <- r case _ = <-time.After(time.Second): r.Status = paxosrpc.Reject replychan <- r } peer.Close() } }(i, n) } numOK := 0 numRej := 0 for num := 0; num < pn.numNodes; num++ { r, _ := <-replychan if r.Status != paxosrpc.Reject { numOK++ } else { numRej++ } } LOGV.Printf("node %d DoAccept %d result: [%dOK %dRej]\n", pn.nodeID, args.SlotIdx, numOK, numRej) if numOK > len(pn.peers)/2 { reply.Status = paxosrpc.OK return nil } else { reply.Status = paxosrpc.Reject return nil } }
func (pn *paxosNode) DoCommit(args *paxosrpc.CommitArgs) error { LOGV.Printf("node %d DoCommit:%d %s %d\n", pn.nodeID, args.SlotIdx, args.V.ToString(), args.N) replychan := make(chan *paxosrpc.CommitReply, len(pn.peers)) for i, n := range pn.peers { go func(idx int, peernode Node) { r := new(paxosrpc.CommitReply) if peernode.HostPort == pn.addrport { pn.Commit(args, r) replychan <- r } else { peer, err := rpcwrapper.DialHTTP("tcp", peernode.HostPort) if err != nil { LOGE.Printf("node %d Cannot reach peer %d:%s\n", pn.nodeID, idx, peernode.HostPort) r.Status = paxosrpc.Reject replychan <- r return } prepareCall := peer.Go("PaxosNode.Commit", args, r, nil) select { case <-prepareCall.Done: replychan <- r case <-time.After(time.Second): r.Status = paxosrpc.Reject replychan <- r } peer.Close() } }(i, n) } for num := 0; num < pn.numNodes; num++ { _, _ = <-replychan LOGV.Printf("in loop, receive %d\n", num) } return nil }
func (pn *paxosNode) DoPrepare(args *paxosrpc.PrepareArgs, reply *paxosrpc.PrepareReply) error { LOGV.Printf("node %d DoPrepare:%d %s %d\n", pn.nodeID, args.SlotIdx, args.V.ToString(), args.N) replychan := make(chan *paxosrpc.PrepareReply, len(pn.peers)) for i, n := range pn.peers { go func(idx int, peernode Node) { r := paxosrpc.PrepareReply{} //if localhost, call locally if peernode.HostPort == pn.addrport { pn.Prepare(args, &r) replychan <- &r } else { //else, call rpc peer, err := rpcwrapper.DialHTTP("tcp", peernode.HostPort) if err != nil { LOGE.Printf("node %d Cannot reach peer %d:%s\n", pn.nodeID, idx, peernode.HostPort) r.Status = paxosrpc.Reject replychan <- &r return } prepareCall := peer.Go("PaxosNode.Prepare", args, &r, nil) select { case _, _ = <-prepareCall.Done: replychan <- &r case _ = <-time.After(time.Second): //TODO: how to handle timeout correctly? r.Status = paxosrpc.Reject replychan <- &r } peer.Close() } }(i, n) } numOK := 0 numRej := 0 reply.Na = -1 for num := 0; num < len(pn.peers); num++ { r, _ := <-replychan if r.Status != paxosrpc.Reject { numOK++ if r.Status == paxosrpc.Existed && r.Na > reply.Na { reply.Na = r.Na reply.Va = r.Va } } else { numRej++ } } if reply.Na == -1 { reply.Na = args.N reply.Va = args.V } LOGV.Printf("node %d DoPrepare %d result:%s %d[%dOK %dRej]\n", pn.nodeID, args.SlotIdx, reply.Va.ToString(), reply.Na, numOK, numRej) if numOK > len(pn.peers)/2 { reply.Status = paxosrpc.OK return nil //return nil error, and let caller to do the accept step } else { reply.Status = paxosrpc.Reject return nil } }