func livetestlibConflictedCommands(total int) (res []message.Commands) { res = make([]message.Commands, total) for i := range res { res[i] = message.Commands{ message.Command("c"), message.Command(strconv.Itoa(i)), } } return }
// test the correctness of the propose id without batching func TestProposeIdNoBatch(t *testing.T) { N := 5000 param := &Param{ ReplicaId: 0, Size: 5, StateMachine: new(test.DummySM), EnableBatching: false, Transporter: transporter.NewDummyTR(0, 5), PersistentPath: tempfile(), } r, _ := New(param) // only start the propose go r.proposeLoop() go r.eventLoop() defer close(r.stop) resultIDs := make([]chan uint64, N) expectIDs := make([]uint64, N) j := uint64(0) for i := 0; i < N; i++ { if r.IsCheckpoint(j) { j++ } resultIDs[i] = r.Propose(message.Command("hello")) expectIDs[i] = j j++ } for i := 0; i < N; i++ { assert.Equal(t, <-resultIDs[i], expectIDs[i]) } }
// This func tests if executeList() will return error when there is // an error returned by the state machine func TestExecuteListWithError(t *testing.T) { r := commonTestlibExampleReplica() r.StateMachine = test.NewDummySM() makeCommitedInstances(r) // create an error r.InstanceMatrix[0][6].cmds = message.Commands{ message.Command("error"), } // resolve conflicts assert.True(t, r.resolveConflicts(r.InstanceMatrix[0][6])) // should return an error assert.Equal(t, r.executeList(), epaxos.ErrStateMachineExecution) // construct executionLog expectLogStr := "[" expectLogStr += "[0][2] [0][2] " expectLogStr += "[0][4] [0][4] " expectLogStr += "[1][3] [1][3] " expectLogStr += "[1][5] [1][5] " for i := 2; i < int(r.Size); i++ { expectLogStr += fmt.Sprintf("[%d][%d] [%d][%d] ", i, i+2, i, i+2) expectLogStr += fmt.Sprintf("[%d][%d] [%d][%d] ", i, i+4, i, i+4) } expectLogStr = expectLogStr[:len(expectLogStr)-1] expectLogStr += "]" // test the exection result executionLogStr := fmt.Sprint(r.StateMachine.(*test.DummySM).ExecutionLog) assert.Equal(t, executionLogStr, expectLogStr) }
func (d *DummySM) Execute(c []message.Command) ([]interface{}, error) { result := make([]interface{}, 0) for i := range c { if bytes.Compare(c[i], message.Command("error")) == 0 { return nil, epaxos.ErrStateMachineExecution } result = append(result, string(c[i])) d.ExecutionLog = append(d.ExecutionLog, string(c[i])) } return result, nil }
// test the correctness of the propose id with batching func TestProposeIdWithBatch(t *testing.T) { N := 5000 B := 100 param := &Param{ ReplicaId: 0, Size: 5, StateMachine: new(test.DummySM), EnableBatching: true, BatchInterval: time.Millisecond * 50, Transporter: transporter.NewDummyTR(0, 5), PersistentPath: tempfile(), } r, _ := New(param) // only start the propose go r.proposeLoop() go r.eventLoop() defer close(r.stop) resultIDs := make([]chan uint64, N) expectIDs := make([]uint64, N) // let's batch 100 commands in a group exp := uint64(0) for i := 0; i < N/B; i++ { for j := 0; j < B; j++ { if r.IsCheckpoint(exp) { exp++ } resultIDs[i*B+j] = r.Propose(message.Command("hello")) expectIDs[i*B+j] = exp } time.Sleep(param.BatchInterval * 2) exp++ } for i := 0; i < N; i++ { assert.Equal(t, <-resultIDs[i], expectIDs[i]) } }
func livetestlibExampleCommands(i int) message.Commands { return message.Commands{ message.Command(strconv.Itoa(i)), } }
// a helper to make committed instances, containing scc, no un-committed, nor executed instances func makeCommitedInstances(r *Replica) { r.InstanceMatrix[0][6] = NewInstance(r, 0, 6) r.InstanceMatrix[0][6].cmds = message.Commands{ message.Command("[0][6]"), message.Command("[0][6]"), } r.InstanceMatrix[0][6].status = committed r.InstanceMatrix[0][6].deps = message.Dependencies{4, 5, 6, 7, 8} // create 1st level deps (4, 5, 6, 7, 8) for i := range r.InstanceMatrix { r.InstanceMatrix[i][i+4] = NewInstance(r, uint8(i), uint64(i+4)) r.InstanceMatrix[i][i+4].status = committed } r.InstanceMatrix[0][4].deps = message.Dependencies{2, 0, 0, 0, 0} r.InstanceMatrix[0][4].cmds = message.Commands{ message.Command("[0][4]"), message.Command("[0][4]"), } r.InstanceMatrix[1][5].deps = message.Dependencies{0, 3, 0, 0, 0} r.InstanceMatrix[1][5].cmds = message.Commands{ message.Command("[1][5]"), message.Command("[1][5]"), } r.InstanceMatrix[2][6].deps = message.Dependencies{0, 0, 4, 0, 0} r.InstanceMatrix[2][6].cmds = message.Commands{ message.Command("[2][6]"), message.Command("[2][6]"), } r.InstanceMatrix[3][7].deps = message.Dependencies{0, 0, 0, 5, 0} r.InstanceMatrix[3][7].cmds = message.Commands{ message.Command("[3][7]"), message.Command("[3][7]"), } r.InstanceMatrix[4][8].deps = message.Dependencies{0, 0, 0, 0, 6} r.InstanceMatrix[4][8].cmds = message.Commands{ message.Command("[4][8]"), message.Command("[4][8]"), } // create 2nd level deps (2, 3, 4, 5, 6) for i := range r.InstanceMatrix { r.InstanceMatrix[i][i+2] = NewInstance(r, uint8(i), uint64(i+2)) r.InstanceMatrix[i][i+2].status = committed r.InstanceMatrix[i][i+2].cmds = message.Commands{ message.Command(fmt.Sprintf("[%d][%d]", i, i+2)), message.Command(fmt.Sprintf("[%d][%d]", i, i+2)), } } // create a scc (2->4, 2->5, 3->4, 3->5) r.InstanceMatrix[0][2].deps = message.Dependencies{4, 5, 0, 0, 0} r.InstanceMatrix[1][3].deps = message.Dependencies{4, 5, 0, 0, 0} }
func main() { var id int var restore bool flag.IntVar(&id, "id", -1, "id of the server") flag.BoolVar(&restore, "restore", false, "if recover") flag.Parse() if id < 0 { fmt.Println("id is required!") flag.PrintDefaults() return } addrs := []string{ ":9000", ":9001", ":9002", //":9003", ":9004", } tr, err := transporter.NewUDPTransporter(addrs, uint8(id), len(addrs)) if err != nil { panic(err) } param := &replica.Param{ Addrs: addrs, ReplicaId: uint8(id), Size: uint8(len(addrs)), StateMachine: new(Voter), Transporter: tr, EnablePersistent: true, Restore: restore, TimeoutInterval: time.Second, //ExecuteInterval: time.Second, } if restore { fmt.Fprintln(os.Stderr, "===restore===") } fmt.Println("====== Spawn new replica ======") r, err := replica.New(param) if err != nil { glog.Fatal(err) } fmt.Println("Done!") fmt.Printf("Wait %d seconds to start\n", prepareInterval) time.Sleep(prepareInterval * time.Second) err = r.Start() if err != nil { glog.Fatal(err) } fmt.Println("====== start ======") rand.Seed(time.Now().UTC().UnixNano()) counter := 1 for { time.Sleep(time.Millisecond * 500) c := "From: " + strconv.Itoa(id) + ", Command: " + strconv.Itoa(id) + ":" + strconv.Itoa(counter) + ", " + time.Now().String() counter++ cmds := make([]message.Command, 0) cmds = append(cmds, message.Command(c)) r.Propose(cmds...) } }