func getInitialView() (*view.View, error) { hostname, err := os.Hostname() if err != nil { log.Panicln(err) } if *initialProcess == "" { switch { case strings.Contains(hostname, "node-"): // emulab.net updates := []view.Update{view.Update{Type: view.Join, Process: view.Process{"10.1.1.2:5000"}}, view.Update{Type: view.Join, Process: view.Process{"10.1.1.3:5000"}}, view.Update{Type: view.Join, Process: view.Process{"10.1.1.4:5000"}}, } return view.NewWithUpdates(updates...), nil default: updates := []view.Update{view.Update{Type: view.Join, Process: view.Process{"[::]:5000"}}, view.Update{Type: view.Join, Process: view.Process{"[::]:5001"}}, view.Update{Type: view.Join, Process: view.Process{"[::]:5002"}}, } return view.NewWithUpdates(updates...), nil } } else { process := view.Process{*initialProcess} initialView, err := client.GetCurrentView(process) if err != nil { log.Fatalf("Failed to get current view from process %v: %v\n", process, err) } return initialView, nil } }
func TestDatabaseFunctions(t *testing.T) { initStorage() updates := []view.Update{view.Update{Type: view.Join, Process: view.Process{"[::]:5000"}}, view.Update{Type: view.Join, Process: view.Process{"[::]:5001"}}, view.Update{Type: view.Join, Process: view.Process{"[::]:5002"}}} associatedView := view.NewWithUpdates(updates...) thisProcess := view.Process{"[::]:5001"} if key, value, _ := storage.First(); key != nil && value != nil { t.Errorf("storage is not empty or unitinialized") } if proposalNumber, err := getLastProposalNumber(associatedView.NumberOfUpdates()); proposalNumber != 0 || err == nil { t.Errorf("getLastProposalNumber should return proposalNumber == 0 and err != nil, got %v and %v", proposalNumber, err) } saveProposalNumberOnStorage(associatedView.NumberOfUpdates(), 1) if proposalNumber, err := getLastProposalNumber(associatedView.NumberOfUpdates()); proposalNumber != 1 || err != nil { t.Errorf("getLastProposalNumber should return proposalNumber == 1 and err == nil, got %v and %v", proposalNumber, err) } if proposalNumber := getNextProposalNumber(associatedView, thisProcess); proposalNumber != 4 { t.Errorf("getNextProposalNumber: expected proposalNumber == 4, got %v", proposalNumber) } if proposalNumber, err := getLastProposalNumber(associatedView.NumberOfUpdates()); proposalNumber != 4 || err != nil { t.Errorf("getNextProposalNumber: expted proposalNumber == 4 and err == <nil>, got %v and %v", proposalNumber, err) } }
func BenchmarkRegisterMsgGobDecode(b *testing.B) { updates := []view.Update{view.Update{Type: view.Join, Process: view.Process{"10.1.1.2:5000"}}, view.Update{Type: view.Join, Process: view.Process{"10.1.1.3:5000"}}, view.Update{Type: view.Join, Process: view.Process{"10.1.1.4:5000"}}, } v1 := view.NewWithUpdates(updates...) msg := RegisterMsg{} msg.Value = createFakeData(512) msg.Timestamp = 1 msg.ViewRef = view.ViewToViewRef(v1) buf := new(bytes.Buffer) var msg2 RegisterMsg for i := 0; i < b.N; i++ { b.StopTimer() buf.Reset() encoder := gob.NewEncoder(buf) err := encoder.Encode(msg) if err != nil { b.Errorf(err.Error()) } buf2 := bytes.NewReader(buf.Bytes()) decoder := gob.NewDecoder(buf2) b.StartTimer() err = decoder.Decode(&msg2) if err != nil { b.Errorf(err.Error()) } } }
func TestRegisterMsgGob(t *testing.T) { updates := []view.Update{view.Update{Type: view.Join, Process: view.Process{"10.1.1.2:5000"}}, view.Update{Type: view.Join, Process: view.Process{"10.1.1.3:5000"}}, view.Update{Type: view.Join, Process: view.Process{"10.1.1.4:5000"}}, } v1 := view.NewWithUpdates(updates...) msg := RegisterMsg{} msg.Value = createFakeData(512) msg.Timestamp = 1 msg.ViewRef = view.ViewToViewRef(v1) buf := new(bytes.Buffer) encoder := gob.NewEncoder(buf) err := encoder.Encode(msg) if err != nil { t.Errorf(err.Error()) } var msg2 RegisterMsg buf2 := bytes.NewReader(buf.Bytes()) decoder := gob.NewDecoder(buf2) err = decoder.Decode(&msg2) if err != nil { t.Errorf(err.Error()) } }
func getInitialView(bindAddr string, initialProc string) *view.View { hostname, err := os.Hostname() if err != nil { log.Fatalln(err) } if initialProc == "" { var updates []view.Update switch { case strings.Contains(hostname, "node-"): // emulab.net updates = []view.Update{ view.Update{Type: view.Join, Process: view.Process{"10.1.1.2:5000"}}, view.Update{Type: view.Join, Process: view.Process{"10.1.1.3:5000"}}, view.Update{Type: view.Join, Process: view.Process{"10.1.1.4:5000"}}, } default: updates = []view.Update{ view.Update{Type: view.Join, Process: view.Process{"[::]:5000"}}, view.Update{Type: view.Join, Process: view.Process{"[::]:5001"}}, view.Update{Type: view.Join, Process: view.Process{"[::]:5002"}}, } } hardCodedView := view.NewWithUpdates(updates...) // don't ask for current view if the process is in the hardCodedView if hardCodedView.HasMember(view.Process{bindAddr}) { return hardCodedView } for _, u := range updates { v, err := client.GetCurrentView(u.Process) if err != nil { log.Println("Failed to get current view from process %v: %v\n", u.Process, err) continue } if v.Equal(hardCodedView) { return hardCodedView } else { return v } } log.Fatalln("Fatal: None of the hard coded initial processes are responsive.") return nil } else { process := view.Process{initialProc} initialView, err := client.GetCurrentView(process) if err != nil { log.Fatalf("Failed to get current view from process %v: %v\n", process, err) } return initialView } }
func (viewSeq ViewSeq) GetMostUpdatedView() *view.View { if len(viewSeq) == 0 { return view.NewWithUpdates() } mostUpdatedViewIndex := 0 for loopIndex, loopView := range viewSeq { if loopView.MoreUpdatedThan(viewSeq[mostUpdatedViewIndex]) { mostUpdatedViewIndex = loopIndex } } return viewSeq[mostUpdatedViewIndex] }
func (s *Server) viewGeneratorWorker(vgi viewGeneratorInstance, initialSeq ViewSeq) { log.Printf("Starting new viewGeneratorWorker with initialSeq: %v\n", initialSeq) associatedView := vgi.AssociatedView jobChan := vgi.jobChan var lastProposedSeq ViewSeq var lastConvergedSeq ViewSeq var viewSeqQuorumCounter viewSeqQuorumCounterType var seqConvQuorumCounter seqConvQuorumCounterType countViewSeq := func(viewSeqMsg ViewSeqMsg) { if viewSeqQuorumCounter.count(&viewSeqMsg, associatedView.QuorumSize()) { newConvergedSeq := viewSeqMsg.ProposedSeq log.Printf("sending newConvergedSeq: %v\n", newConvergedSeq) lastConvergedSeq = newConvergedSeq seqConvMsg := SeqConvMsg{} seqConvMsg.AssociatedView = associatedView seqConvMsg.Seq = newConvergedSeq // Send seq-conv to all go broadcastViewSequenceConv(associatedView, seqConvMsg) } } if len(initialSeq) != 0 { // Send viewSeqMsg to all viewSeqMsg := ViewSeqMsg{} viewSeqMsg.ProposedSeq = initialSeq viewSeqMsg.LastConvergedSeq = nil viewSeqMsg.AssociatedView = associatedView viewSeqMsg.Sender = s.thisProcess go broadcastViewSequence(associatedView, viewSeqMsg) countViewSeq(viewSeqMsg) lastProposedSeq = initialSeq } for { job := <-jobChan switch jobPointer := job.(type) { case ViewSeqMsg: receivedViewSeqMsg := jobPointer log.Println("received ViewSeqMsg:", receivedViewSeqMsg) var newProposeSeq ViewSeq hasChanges := false hasConflict := false OuterLoop: for _, v := range receivedViewSeqMsg.ProposedSeq { if lastProposedSeq.HasView(v) { continue } log.Printf("New view discovered: %v\n", v) hasChanges = true // check if v conflicts with any view from lastProposedSeq for _, v2 := range lastProposedSeq { if v.LessUpdatedThan(v2) && v2.LessUpdatedThan(v) { log.Printf("Has conflict between %v and %v!\n", v, v2) hasConflict = true break OuterLoop } } } if hasChanges { if hasConflict { // set lastConvergedSeq to the one with the most updated view receivedLastConvergedSeqMostUpdatedView := receivedViewSeqMsg.LastConvergedSeq.GetMostUpdatedView() thisProcessLastConvergedSeqMostUpdatedView := lastConvergedSeq.GetMostUpdatedView() if thisProcessLastConvergedSeqMostUpdatedView.LessUpdatedThan(receivedLastConvergedSeqMostUpdatedView) { lastConvergedSeq = receivedViewSeqMsg.LastConvergedSeq } oldMostUpdated := lastProposedSeq.GetMostUpdatedView() receivedMostUpdated := receivedViewSeqMsg.ProposedSeq.GetMostUpdatedView() updates := append(oldMostUpdated.GetUpdates(), receivedMostUpdated.GetUpdates()...) auxView := view.NewWithUpdates(updates...) newProposeSeq = lastConvergedSeq.Append(auxView) } else { newProposeSeq = lastProposedSeq.Append(receivedViewSeqMsg.ProposedSeq...) } log.Println("sending newProposeSeq:", newProposeSeq) viewSeqMsg := ViewSeqMsg{} viewSeqMsg.Sender = s.thisProcess viewSeqMsg.AssociatedView = associatedView viewSeqMsg.ProposedSeq = newProposeSeq viewSeqMsg.LastConvergedSeq = lastConvergedSeq go broadcastViewSequence(associatedView, viewSeqMsg) countViewSeq(viewSeqMsg) lastProposedSeq = newProposeSeq } // Quorum check countViewSeq(receivedViewSeqMsg) case *SeqConv: receivedSeqConvMsg := jobPointer log.Println("received SeqConvMsg:", receivedSeqConvMsg) // Quorum check if seqConvQuorumCounter.count(receivedSeqConvMsg, associatedView.QuorumSize()) { s.generatedViewSeqChan <- generatedViewSeq{ViewSeq: receivedSeqConvMsg.Seq, AssociatedView: associatedView} } default: log.Fatalln("Something is wrong with the switch statement") } } }