diff --git a/etcdserver/config.go b/etcdserver/config.go index e83680ad0..f405effc4 100644 --- a/etcdserver/config.go +++ b/etcdserver/config.go @@ -43,6 +43,9 @@ type ServerConfig struct { NewCluster bool ForceNewCluster bool Transport *http.Transport + + // Only for testing purpose + ElectionTimeoutTicks int } // VerifyBootstrapConfig sanity-checks the initial config and returns an error diff --git a/etcdserver/server.go b/etcdserver/server.go index 4aa180750..f172712ae 100644 --- a/etcdserver/server.go +++ b/etcdserver/server.go @@ -870,8 +870,12 @@ func startNode(cfg *ServerConfig, ids []types.ID) (id types.ID, n raft.Node, s * } id = member.ID log.Printf("etcdserver: start member %s in cluster %s", id, cfg.Cluster.ID()) + election := cfg.ElectionTimeoutTicks + if election == 0 { + election = 10 + } s = raft.NewMemoryStorage() - n = raft.StartNode(uint64(id), peers, 10, 1, s) + n = raft.StartNode(uint64(id), peers, election, 1, s) return } @@ -884,13 +888,17 @@ func restartNode(cfg *ServerConfig, snapshot *raftpb.Snapshot) (types.ID, raft.N cfg.Cluster.SetID(cid) log.Printf("etcdserver: restart member %s in cluster %s at commit index %d", id, cfg.Cluster.ID(), st.Commit) + election := cfg.ElectionTimeoutTicks + if election == 0 { + election = 10 + } s := raft.NewMemoryStorage() if snapshot != nil { s.ApplySnapshot(*snapshot) } s.SetHardState(st) s.Append(ents) - n := raft.RestartNode(uint64(id), 10, 1, s) + n := raft.RestartNode(uint64(id), election, 1, s) return id, n, s, w } diff --git a/integration/cluster_test.go b/integration/cluster_test.go index c64d9392b..cacd55621 100644 --- a/integration/cluster_test.go +++ b/integration/cluster_test.go @@ -27,6 +27,7 @@ import ( "os" "reflect" "sort" + "strconv" "strings" "testing" "time" @@ -49,9 +50,18 @@ const ( requestTimeout = 2 * time.Second ) +var ( + electionTicks = 10 +) + func init() { // open microsecond-level time log for integration test debugging log.SetFlags(log.Ltime | log.Lmicroseconds | log.Lshortfile) + if t := os.Getenv("ETCD_ELECTION_TIMEOUT_TICKS"); t != "" { + if i, err := strconv.ParseInt(t, 10, 64); err == nil { + electionTicks = int(i) + } + } } func TestClusterOf1(t *testing.T) { testCluster(t, 1) } @@ -298,8 +308,9 @@ func (c *cluster) RemoveMember(t *testing.T, id uint64) { select { case <-m.s.StopNotify(): m.Terminate(t) - case <-time.After(time.Second): - t.Fatalf("failed to remove member %s in one second", m.s.ID()) + // stop delay / election timeout + 1s disk and network delay + case <-time.After(time.Duration(electionTicks)*tickDuration + time.Second): + t.Fatalf("failed to remove member %s in time", m.s.ID()) } } } @@ -431,6 +442,7 @@ func mustNewMember(t *testing.T, name string) *member { } m.NewCluster = true m.Transport = mustNewTransport(t) + m.ElectionTimeoutTicks = electionTicks return m } @@ -460,6 +472,7 @@ func (m *member) Clone(t *testing.T) *member { panic(err) } mm.Transport = mustNewTransport(t) + mm.ElectionTimeoutTicks = m.ElectionTimeoutTicks return mm } diff --git a/test b/test index 444f77c95..27e192eb8 100755 --- a/test +++ b/test @@ -39,7 +39,7 @@ split=(${TEST// / }) TEST=${split[@]/#/${REPO_PATH}/} echo "Running tests..." -go test -timeout 60s ${COVER} $@ ${TEST} --race +go test -timeout 3m ${COVER} $@ ${TEST} --race echo "Checking gofmt..." fmtRes=$(gofmt -l $FMT)