diff --git a/conf/config.toml b/conf/config.toml index 3e50a622794..6d87e6241d6 100644 --- a/conf/config.toml +++ b/conf/config.toml @@ -19,6 +19,8 @@ tso-save-interval = "3s" namespace-classifier = "table" +enable-prevote = true + [security] # Path of file that contains list of trusted SSL CAs. if set, following four settings shouldn't be empty cacert-path = "" diff --git a/server/config.go b/server/config.go index f9090c0df84..c5b00d4db95 100644 --- a/server/config.go +++ b/server/config.go @@ -94,6 +94,11 @@ type Config struct { TickInterval typeutil.Duration `toml:"tick-interval"` // ElectionInterval is the interval for etcd Raft election. ElectionInterval typeutil.Duration `toml:"election-interval"` + // Prevote is true to enable Raft Pre-Vote. + // If enabled, Raft runs an additional election phase + // to check whether it would get enough votes to win + // an election, thus minimizing disruptions. + PreVote bool `toml:"enable-prevote"` Security SecurityConfig `toml:"security" json:"security"` @@ -220,8 +225,9 @@ func (c *Config) Parse(arguments []string) error { } // Load config file if specified. + var meta *toml.MetaData if c.configFile != "" { - err = c.configFromFile(c.configFile) + meta, err = c.configFromFile(c.configFile) if err != nil { return errors.Trace(err) } @@ -249,7 +255,7 @@ func (c *Config) Parse(arguments []string) error { return errors.Errorf("'%s' is an invalid flag", c.FlagSet.Arg(0)) } - err = c.adjust() + err = c.adjust(meta) return errors.Trace(err) } @@ -276,7 +282,7 @@ func (c *Config) validate() error { return nil } -func (c *Config) adjust() error { +func (c *Config) adjust(meta *toml.MetaData) error { adjustString(&c.Name, defaultName) adjustString(&c.DataDir, fmt.Sprintf("default.%s", c.Name)) @@ -334,6 +340,11 @@ func (c *Config) adjust() error { adjustDuration(&c.heartbeatStreamBindInterval, defaultHeartbeatStreamRebindInterval) adjustDuration(&c.leaderPriorityCheckInterval, defaultLeaderPriorityCheckInterval) + + // enable PreVote by default + if meta == nil || !meta.IsDefined("enable-prevote") { + c.PreVote = true + } return nil } @@ -352,9 +363,9 @@ func (c *Config) String() string { } // configFromFile loads config from file. -func (c *Config) configFromFile(path string) error { - _, err := toml.DecodeFile(path, c) - return errors.Trace(err) +func (c *Config) configFromFile(path string) (*toml.MetaData, error) { + meta, err := toml.DecodeFile(path, c) + return &meta, errors.Trace(err) } // ScheduleConfig is the schedule configuration. @@ -636,6 +647,7 @@ func (c *Config) genEmbedEtcdConfig() (*embed.Config, error) { cfg.InitialCluster = c.InitialCluster cfg.ClusterState = c.InitialClusterState cfg.EnablePprof = true + cfg.PreVote = c.PreVote cfg.StrictReconfigCheck = !c.disableStrictReconfigCheck cfg.TickMs = uint(c.TickInterval.Duration / time.Millisecond) cfg.ElectionMs = uint(c.ElectionInterval.Duration / time.Millisecond) diff --git a/server/config_test.go b/server/config_test.go index 045521c04c6..eb2ac239f7d 100644 --- a/server/config_test.go +++ b/server/config_test.go @@ -34,7 +34,7 @@ func (s *testConfigSuite) TestTLS(c *C) { func (s *testConfigSuite) TestBadFormatJoinAddr(c *C) { cfg := NewTestSingleConfig() cfg.Join = "127.0.0.1:2379" // Wrong join addr without scheme. - c.Assert(cfg.adjust(), NotNil) + c.Assert(cfg.adjust(nil), NotNil) } func (s *testConfigSuite) TestReloadConfig(c *C) { @@ -62,7 +62,7 @@ func (s *testConfigSuite) TestReloadConfig(c *C) { func (s *testConfigSuite) TestValidation(c *C) { cfg := NewConfig() - c.Assert(cfg.adjust(), IsNil) + c.Assert(cfg.adjust(nil), IsNil) cfg.Log.File.Filename = path.Join(cfg.DataDir, "test") c.Assert(cfg.validate(), NotNil) diff --git a/server/coordinator_test.go b/server/coordinator_test.go index 42c9dd6847d..1133596c6a3 100644 --- a/server/coordinator_test.go +++ b/server/coordinator_test.go @@ -35,7 +35,7 @@ func newTestOperator(regionID uint64, regionEpoch *metapb.RegionEpoch, kind sche func newTestScheduleConfig() (*ScheduleConfig, *scheduleOption) { cfg := NewConfig() - cfg.adjust() + cfg.adjust(nil) opt := newScheduleOption(cfg) return &cfg.Schedule, opt } diff --git a/server/join_test.go b/server/join_test.go index bd01b2a6c8d..55efa1ac3fb 100644 --- a/server/join_test.go +++ b/server/join_test.go @@ -90,7 +90,7 @@ func startPdWith(cfg *Config) (*Server, error) { abortCh := make(chan struct{}, 1) go func() { - err := cfg.adjust() + err := cfg.adjust(nil) if err != nil { errCh <- errors.Trace(err) return diff --git a/server/testutil.go b/server/testutil.go index 7301a797b41..213eba77976 100644 --- a/server/testutil.go +++ b/server/testutil.go @@ -77,7 +77,7 @@ func NewTestSingleConfig() *Config { cfg.ElectionInterval = typeutil.NewDuration(3000 * time.Millisecond) cfg.leaderPriorityCheckInterval = typeutil.NewDuration(100 * time.Millisecond) - cfg.adjust() + cfg.adjust(nil) return cfg }