migrate experimental-compact-hash-check-enabled to feature gate.
Signed-off-by: Siyuan Zhang <sizhang@google.com>
This commit is contained in:
parent
b4450d510d
commit
85363bda32
@ -91,6 +91,8 @@ type FeatureGate interface {
|
||||
// set on the copy without mutating the original. This is useful for validating
|
||||
// config against potential feature gate changes before committing those changes.
|
||||
DeepCopy() MutableFeatureGate
|
||||
// String returns a string containing all enabled feature gates, formatted as "key1=value1,key2=value2,...".
|
||||
String() string
|
||||
}
|
||||
|
||||
// MutableFeatureGate parses and stores flag gates for known features from
|
||||
|
@ -147,10 +147,9 @@ type ServerConfig struct {
|
||||
|
||||
// InitialCorruptCheck is true to check data corruption on boot
|
||||
// before serving any peer/client traffic.
|
||||
InitialCorruptCheck bool
|
||||
CorruptCheckTime time.Duration
|
||||
CompactHashCheckEnabled bool
|
||||
CompactHashCheckTime time.Duration
|
||||
InitialCorruptCheck bool
|
||||
CorruptCheckTime time.Duration
|
||||
CompactHashCheckTime time.Duration
|
||||
|
||||
// PreVote is true to enable Raft Pre-Vote.
|
||||
PreVote bool
|
||||
|
@ -58,21 +58,21 @@ const (
|
||||
ClusterStateFlagNew = "new"
|
||||
ClusterStateFlagExisting = "existing"
|
||||
|
||||
DefaultName = "default"
|
||||
DefaultMaxSnapshots = 5
|
||||
DefaultMaxWALs = 5
|
||||
DefaultMaxTxnOps = uint(128)
|
||||
DefaultWarningApplyDuration = 100 * time.Millisecond
|
||||
DefaultWarningUnaryRequestDuration = 300 * time.Millisecond
|
||||
DefaultMaxRequestBytes = 1.5 * 1024 * 1024
|
||||
DefaultMaxConcurrentStreams = math.MaxUint32
|
||||
DefaultGRPCKeepAliveMinTime = 5 * time.Second
|
||||
DefaultGRPCKeepAliveInterval = 2 * time.Hour
|
||||
DefaultGRPCKeepAliveTimeout = 20 * time.Second
|
||||
DefaultDowngradeCheckTime = 5 * time.Second
|
||||
DefaultAutoCompactionMode = "periodic"
|
||||
DefaultAuthToken = "simple"
|
||||
DefaultExperimentalCompactHashCheckTime = time.Minute
|
||||
DefaultName = "default"
|
||||
DefaultMaxSnapshots = 5
|
||||
DefaultMaxWALs = 5
|
||||
DefaultMaxTxnOps = uint(128)
|
||||
DefaultWarningApplyDuration = 100 * time.Millisecond
|
||||
DefaultWarningUnaryRequestDuration = 300 * time.Millisecond
|
||||
DefaultMaxRequestBytes = 1.5 * 1024 * 1024
|
||||
DefaultMaxConcurrentStreams = math.MaxUint32
|
||||
DefaultGRPCKeepAliveMinTime = 5 * time.Second
|
||||
DefaultGRPCKeepAliveInterval = 2 * time.Hour
|
||||
DefaultGRPCKeepAliveTimeout = 20 * time.Second
|
||||
DefaultDowngradeCheckTime = 5 * time.Second
|
||||
DefaultAutoCompactionMode = "periodic"
|
||||
DefaultAuthToken = "simple"
|
||||
DefaultCompactHashCheckTime = time.Minute
|
||||
|
||||
DefaultDiscoveryDialTimeout = 2 * time.Second
|
||||
DefaultDiscoveryRequestTimeOut = 5 * time.Second
|
||||
@ -128,6 +128,13 @@ var (
|
||||
|
||||
// indirection for testing
|
||||
getCluster = srv.GetCluster
|
||||
|
||||
// in 3.6, we are migration all the --experimental flags to feature gate and flags without the prefix.
|
||||
// This is the mapping from the non boolean `experimental-` to the new flags.
|
||||
// TODO: delete in v3.7
|
||||
experimentalNonBoolFlagMigrationMap = map[string]string{
|
||||
"experimental-compact-hash-check-time": "compact-hash-check-time",
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
@ -356,10 +363,17 @@ type Config struct {
|
||||
// AuthTokenTTL in seconds of the simple token
|
||||
AuthTokenTTL uint `json:"auth-token-ttl"`
|
||||
|
||||
ExperimentalInitialCorruptCheck bool `json:"experimental-initial-corrupt-check"`
|
||||
ExperimentalCorruptCheckTime time.Duration `json:"experimental-corrupt-check-time"`
|
||||
ExperimentalCompactHashCheckEnabled bool `json:"experimental-compact-hash-check-enabled"`
|
||||
ExperimentalCompactHashCheckTime time.Duration `json:"experimental-compact-hash-check-time"`
|
||||
ExperimentalInitialCorruptCheck bool `json:"experimental-initial-corrupt-check"`
|
||||
ExperimentalCorruptCheckTime time.Duration `json:"experimental-corrupt-check-time"`
|
||||
// ExperimentalCompactHashCheckEnabled enables leader to periodically check followers compaction hashes.
|
||||
// Deprecated in v3.6 and will be decommissioned in v3.7.
|
||||
// TODO: delete in v3.7
|
||||
ExperimentalCompactHashCheckEnabled bool `json:"experimental-compact-hash-check-enabled"`
|
||||
// ExperimentalCompactHashCheckTime is the duration of time between leader checks followers compaction hashes.
|
||||
// Deprecated in v3.6 and will be decommissioned in v3.7.
|
||||
// TODO: delete in v3.7
|
||||
ExperimentalCompactHashCheckTime time.Duration `json:"experimental-compact-hash-check-time"`
|
||||
CompactHashCheckTime time.Duration `json:"compact-hash-check-time"`
|
||||
|
||||
// ExperimentalEnableLeaseCheckpoint enables leader to send regular checkpoints to other members to prevent reset of remaining TTL on leader change.
|
||||
ExperimentalEnableLeaseCheckpoint bool `json:"experimental-enable-lease-checkpoint"`
|
||||
@ -468,6 +482,8 @@ type Config struct {
|
||||
|
||||
// ServerFeatureGate is a server level feature gate
|
||||
ServerFeatureGate featuregate.FeatureGate
|
||||
// FlagsExplicitlySet stores if a flag is explicitly set from the cmd line or config file.
|
||||
FlagsExplicitlySet map[string]bool
|
||||
}
|
||||
|
||||
// configYAML holds the config suitable for yaml parsing
|
||||
@ -573,8 +589,9 @@ func NewConfig() *Config {
|
||||
ExperimentalStopGRPCServiceOnDefrag: false,
|
||||
ExperimentalMaxLearners: membership.DefaultMaxLearners,
|
||||
|
||||
ExperimentalCompactHashCheckEnabled: false,
|
||||
ExperimentalCompactHashCheckTime: DefaultExperimentalCompactHashCheckTime,
|
||||
CompactHashCheckTime: DefaultCompactHashCheckTime,
|
||||
// TODO: delete in v3.7
|
||||
ExperimentalCompactHashCheckTime: DefaultCompactHashCheckTime,
|
||||
|
||||
V2Deprecation: config.V2DeprDefault,
|
||||
|
||||
@ -592,6 +609,7 @@ func NewConfig() *Config {
|
||||
|
||||
AutoCompactionMode: DefaultAutoCompactionMode,
|
||||
ServerFeatureGate: features.NewDefaultServerFeatureGate(DefaultName, nil),
|
||||
FlagsExplicitlySet: map[string]bool{},
|
||||
}
|
||||
cfg.InitialCluster = cfg.InitialClusterFromName(cfg.Name)
|
||||
return cfg
|
||||
@ -755,8 +773,11 @@ func (cfg *Config) AddFlags(fs *flag.FlagSet) {
|
||||
// experimental
|
||||
fs.BoolVar(&cfg.ExperimentalInitialCorruptCheck, "experimental-initial-corrupt-check", cfg.ExperimentalInitialCorruptCheck, "Enable to check data corruption before serving any client/peer traffic.")
|
||||
fs.DurationVar(&cfg.ExperimentalCorruptCheckTime, "experimental-corrupt-check-time", cfg.ExperimentalCorruptCheckTime, "Duration of time between cluster corruption check passes.")
|
||||
fs.BoolVar(&cfg.ExperimentalCompactHashCheckEnabled, "experimental-compact-hash-check-enabled", cfg.ExperimentalCompactHashCheckEnabled, "Enable leader to periodically check followers compaction hashes.")
|
||||
fs.DurationVar(&cfg.ExperimentalCompactHashCheckTime, "experimental-compact-hash-check-time", cfg.ExperimentalCompactHashCheckTime, "Duration of time between leader checks followers compaction hashes.")
|
||||
// TODO: delete in v3.7
|
||||
fs.BoolVar(&cfg.ExperimentalCompactHashCheckEnabled, "experimental-compact-hash-check-enabled", cfg.ExperimentalCompactHashCheckEnabled, "Enable leader to periodically check followers compaction hashes. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--feature-gates=CompactHashCheck=true' instead")
|
||||
fs.DurationVar(&cfg.ExperimentalCompactHashCheckTime, "experimental-compact-hash-check-time", cfg.ExperimentalCompactHashCheckTime, "Duration of time between leader checks followers compaction hashes. Deprecated in v3.6 and will be decommissioned in v3.7. Use --compact-hash-check-time instead.")
|
||||
|
||||
fs.DurationVar(&cfg.CompactHashCheckTime, "compact-hash-check-time", cfg.CompactHashCheckTime, "Duration of time between leader checks followers compaction hashes.")
|
||||
|
||||
fs.BoolVar(&cfg.ExperimentalEnableLeaseCheckpoint, "experimental-enable-lease-checkpoint", false, "Enable leader to send regular checkpoints to other members to prevent reset of remaining TTL on leader change.")
|
||||
// TODO: delete in v3.7
|
||||
@ -817,6 +838,11 @@ func (cfg *configYAML) configFromFile(path string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for flg := range cfgMap {
|
||||
cfg.FlagsExplicitlySet[flg] = true
|
||||
}
|
||||
|
||||
getBoolFlagVal := func(flagName string) *bool {
|
||||
flagVal, ok := cfgMap[flagName]
|
||||
if !ok {
|
||||
@ -979,6 +1005,14 @@ func updateMinMaxVersions(info *transport.TLSInfo, min, max string) {
|
||||
|
||||
// Validate ensures that '*embed.Config' fields are properly configured.
|
||||
func (cfg *Config) Validate() error {
|
||||
// make sure there is no conflict in the flag settings in the ExperimentalNonBoolFlagMigrationMap
|
||||
// TODO: delete in v3.7
|
||||
for oldFlag, newFlag := range experimentalNonBoolFlagMigrationMap {
|
||||
if cfg.FlagsExplicitlySet[oldFlag] && cfg.FlagsExplicitlySet[newFlag] {
|
||||
return fmt.Errorf("cannot set --%s and --%s at the same time, please use --%s only", oldFlag, newFlag, newFlag)
|
||||
}
|
||||
}
|
||||
|
||||
if err := cfg.setupLogging(); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1083,10 +1117,13 @@ func (cfg *Config) Validate() error {
|
||||
if cfg.ExperimentalEnableLeaseCheckpointPersist && !cfg.ExperimentalEnableLeaseCheckpoint {
|
||||
return fmt.Errorf("setting experimental-enable-lease-checkpoint-persist requires experimental-enable-lease-checkpoint")
|
||||
}
|
||||
|
||||
// TODO: delete in v3.7
|
||||
if cfg.ExperimentalCompactHashCheckTime <= 0 {
|
||||
return fmt.Errorf("--experimental-compact-hash-check-time must be >0 (set to %v)", cfg.ExperimentalCompactHashCheckTime)
|
||||
}
|
||||
if cfg.CompactHashCheckTime <= 0 {
|
||||
return fmt.Errorf("--compact-hash-check-time must be >0 (set to %v)", cfg.CompactHashCheckTime)
|
||||
}
|
||||
|
||||
// If `--name` isn't configured, then multiple members may have the same "default" name.
|
||||
// When adding a new member with the "default" name as well, etcd may regards its peerURL
|
||||
|
@ -98,6 +98,7 @@ func TestConfigFileFeatureGates(t *testing.T) {
|
||||
serverFeatureGatesJSON string
|
||||
experimentalStopGRPCServiceOnDefrag string
|
||||
experimentalInitialCorruptCheck string
|
||||
experimentalCompactHashCheckEnabled string
|
||||
expectErr bool
|
||||
expectedFeatures map[featuregate.Feature]bool
|
||||
}{
|
||||
@ -194,12 +195,46 @@ func TestConfigFileFeatureGates(t *testing.T) {
|
||||
features.InitialCorruptCheck: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cannot set both experimental flag and feature gate flag for ExperimentalCompactHashCheckEnabled",
|
||||
serverFeatureGatesJSON: "CompactHashCheck=true",
|
||||
experimentalCompactHashCheckEnabled: "false",
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "can set feature gate experimentalCompactHashCheckEnabled to true from experimental flag",
|
||||
experimentalCompactHashCheckEnabled: "true",
|
||||
expectedFeatures: map[featuregate.Feature]bool{
|
||||
features.StopGRPCServiceOnDefrag: false,
|
||||
features.DistributedTracing: false,
|
||||
features.CompactHashCheck: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "can set feature gate experimentalCompactHashCheckEnabled to false from experimental flag",
|
||||
experimentalCompactHashCheckEnabled: "false",
|
||||
expectedFeatures: map[featuregate.Feature]bool{
|
||||
features.StopGRPCServiceOnDefrag: false,
|
||||
features.DistributedTracing: false,
|
||||
features.CompactHashCheck: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "can set feature gate CompactHashCheck to true from feature gate flag",
|
||||
serverFeatureGatesJSON: "CompactHashCheck=true",
|
||||
expectedFeatures: map[featuregate.Feature]bool{
|
||||
features.StopGRPCServiceOnDefrag: false,
|
||||
features.DistributedTracing: false,
|
||||
features.CompactHashCheck: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
yc := struct {
|
||||
ExperimentalStopGRPCServiceOnDefrag *bool `json:"experimental-stop-grpc-service-on-defrag,omitempty"`
|
||||
ExperimentalInitialCorruptCheck *bool `json:"experimental-initial-corrupt-check,omitempty"`
|
||||
ExperimentalCompactHashCheckEnabled *bool `json:"experimental-compact-hash-check-enabled,omitempty"`
|
||||
ServerFeatureGatesJSON string `json:"feature-gates"`
|
||||
}{
|
||||
ServerFeatureGatesJSON: tc.serverFeatureGatesJSON,
|
||||
@ -221,6 +256,14 @@ func TestConfigFileFeatureGates(t *testing.T) {
|
||||
yc.ExperimentalStopGRPCServiceOnDefrag = &experimentalStopGRPCServiceOnDefrag
|
||||
}
|
||||
|
||||
if tc.experimentalCompactHashCheckEnabled != "" {
|
||||
experimentalCompactHashCheckEnabled, err := strconv.ParseBool(tc.experimentalCompactHashCheckEnabled)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
yc.ExperimentalCompactHashCheckEnabled = &experimentalCompactHashCheckEnabled
|
||||
}
|
||||
|
||||
b, err := yaml.Marshal(&yc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -205,8 +205,7 @@ func StartEtcd(inCfg *Config) (e *Etcd, err error) {
|
||||
CORS: cfg.CORS,
|
||||
HostWhitelist: cfg.HostWhitelist,
|
||||
CorruptCheckTime: cfg.ExperimentalCorruptCheckTime,
|
||||
CompactHashCheckEnabled: cfg.ExperimentalCompactHashCheckEnabled,
|
||||
CompactHashCheckTime: cfg.ExperimentalCompactHashCheckTime,
|
||||
CompactHashCheckTime: cfg.CompactHashCheckTime,
|
||||
PreVote: cfg.PreVote,
|
||||
Logger: cfg.logger,
|
||||
ForceNewCluster: cfg.ForceNewCluster,
|
||||
@ -351,9 +350,9 @@ func print(lg *zap.Logger, ec Config, sc config.ServerConfig, memberInitialized
|
||||
zap.Uint32("max-concurrent-streams", sc.MaxConcurrentStreams),
|
||||
|
||||
zap.Bool("pre-vote", sc.PreVote),
|
||||
zap.String(ServerFeatureGateFlagName, sc.ServerFeatureGate.String()),
|
||||
zap.Bool("initial-corrupt-check", sc.InitialCorruptCheck),
|
||||
zap.String("corrupt-check-time-interval", sc.CorruptCheckTime.String()),
|
||||
zap.Bool("compact-check-time-enabled", sc.CompactHashCheckEnabled),
|
||||
zap.Duration("compact-check-time-interval", sc.CompactHashCheckTime),
|
||||
zap.String("auto-compaction-mode", sc.AutoCompactionMode),
|
||||
zap.Duration("auto-compaction-retention", sc.AutoCompactionRetention),
|
||||
|
@ -62,6 +62,8 @@ var (
|
||||
"snapshot-count": "--snapshot-count is deprecated in 3.6 and will be decommissioned in 3.7.",
|
||||
"max-snapshots": "--max-snapshots is deprecated in 3.6 and will be decommissioned in 3.7.",
|
||||
"v2-deprecation": "--v2-deprecation is deprecated and scheduled for removal in v3.8. The default value is enforced, ignoring user input.",
|
||||
"experimental-compact-hash-check-enabled": "--experimental-compact-hash-check-enabled is deprecated in 3.6 and will be decommissioned in 3.7. Use '--feature-gates=CompactHashCheck=true' instead.",
|
||||
"experimental-compact-hash-check-time": "--experimental-compact-hash-check-time is deprecated in 3.6 and will be decommissioned in 3.7. Use '--compact-hash-check-time' instead.",
|
||||
}
|
||||
)
|
||||
|
||||
@ -165,6 +167,12 @@ func (cfg *config) parse(arguments []string) error {
|
||||
err = cfg.configFromCmdLine()
|
||||
}
|
||||
|
||||
// params related to experimental flag deprecation
|
||||
// TODO: delete in v3.7
|
||||
if cfg.ec.FlagsExplicitlySet["experimental-compact-hash-check-time"] {
|
||||
cfg.ec.CompactHashCheckTime = cfg.ec.ExperimentalCompactHashCheckTime
|
||||
}
|
||||
|
||||
// `V2Deprecation` (--v2-deprecation) is deprecated and scheduled for removal in v3.8. The default value is enforced, ignoring user input.
|
||||
cfg.ec.V2Deprecation = cconfig.V2DeprDefault
|
||||
|
||||
@ -260,6 +268,10 @@ func (cfg *config) configFromCmdLine() error {
|
||||
cfg.ec.InitialCluster = ""
|
||||
}
|
||||
|
||||
cfg.cf.flagSet.Visit(func(f *flag.Flag) {
|
||||
cfg.ec.FlagsExplicitlySet[f.Name] = true
|
||||
})
|
||||
|
||||
getBoolFlagVal := func(flagName string) *bool {
|
||||
boolVal, parseErr := flags.GetBoolFlagVal(cfg.cf.flagSet, flagName)
|
||||
if parseErr != nil {
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
@ -475,6 +476,99 @@ func TestParseFeatureGateFlags(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestCompactHashCheckTimeFlagMigration tests the migration from
|
||||
// --experimental-compact-hash-check-time to --compact-hash-check-time
|
||||
// TODO: delete in v3.7
|
||||
func TestCompactHashCheckTimeFlagMigration(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
compactHashCheckTime string
|
||||
experimentalCompactHashCheckTime string
|
||||
useConfigFile bool
|
||||
expectErr bool
|
||||
expectedCompactHashCheckTime time.Duration
|
||||
}{
|
||||
{
|
||||
name: "default",
|
||||
expectedCompactHashCheckTime: time.Minute,
|
||||
},
|
||||
{
|
||||
name: "cannot set both experimental flag and non experimental flag",
|
||||
compactHashCheckTime: "2m",
|
||||
experimentalCompactHashCheckTime: "3m",
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "can set experimental flag",
|
||||
experimentalCompactHashCheckTime: "3m",
|
||||
expectedCompactHashCheckTime: 3 * time.Minute,
|
||||
},
|
||||
{
|
||||
name: "can set non experimental flag",
|
||||
compactHashCheckTime: "2m",
|
||||
expectedCompactHashCheckTime: 2 * time.Minute,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cmdLineArgs := []string{}
|
||||
yc := struct {
|
||||
ExperimentalCompactHashCheckTime time.Duration `json:"experimental-compact-hash-check-time,omitempty"`
|
||||
CompactHashCheckTime time.Duration `json:"compact-hash-check-time,omitempty"`
|
||||
}{}
|
||||
|
||||
if tc.compactHashCheckTime != "" {
|
||||
cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--compact-hash-check-time=%s", tc.compactHashCheckTime))
|
||||
compactHashCheckTime, err := time.ParseDuration(tc.compactHashCheckTime)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
yc.CompactHashCheckTime = compactHashCheckTime
|
||||
}
|
||||
|
||||
if tc.experimentalCompactHashCheckTime != "" {
|
||||
cmdLineArgs = append(cmdLineArgs, fmt.Sprintf("--experimental-compact-hash-check-time=%s", tc.experimentalCompactHashCheckTime))
|
||||
experimentalCompactHashCheckTime, err := time.ParseDuration(tc.experimentalCompactHashCheckTime)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
yc.ExperimentalCompactHashCheckTime = experimentalCompactHashCheckTime
|
||||
}
|
||||
|
||||
b, err := yaml.Marshal(&yc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tmpfile := mustCreateCfgFile(t, b)
|
||||
defer os.Remove(tmpfile.Name())
|
||||
|
||||
cfgFromCmdLine := newConfig()
|
||||
errFromCmdLine := cfgFromCmdLine.parse(cmdLineArgs)
|
||||
|
||||
cfgFromFile := newConfig()
|
||||
errFromFile := cfgFromFile.parse([]string{fmt.Sprintf("--config-file=%s", tmpfile.Name())})
|
||||
|
||||
if tc.expectErr {
|
||||
if errFromCmdLine == nil || errFromFile == nil {
|
||||
t.Fatal("expect parse error")
|
||||
}
|
||||
return
|
||||
}
|
||||
if errFromCmdLine != nil || errFromFile != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if cfgFromCmdLine.ec.CompactHashCheckTime != tc.expectedCompactHashCheckTime {
|
||||
t.Errorf("expected CompactHashCheckTime=%v, got %v", tc.expectedCompactHashCheckTime, cfgFromCmdLine.ec.CompactHashCheckTime)
|
||||
}
|
||||
if cfgFromFile.ec.CompactHashCheckTime != tc.expectedCompactHashCheckTime {
|
||||
t.Errorf("expected CompactHashCheckTime=%v, got %v", tc.expectedCompactHashCheckTime, cfgFromFile.ec.CompactHashCheckTime)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func mustCreateCfgFile(t *testing.T, b []byte) *os.File {
|
||||
tmpfile, err := os.CreateTemp("", "servercfg")
|
||||
if err != nil {
|
||||
|
@ -277,9 +277,11 @@ Experimental feature:
|
||||
Enable to check data corruption before serving any client/peer traffic.
|
||||
--experimental-corrupt-check-time '0s'
|
||||
Duration of time between cluster corruption check passes.
|
||||
--experimental-compact-hash-check-enabled 'false'
|
||||
--experimental-compact-hash-check-enabled 'false'. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--feature-gates=CompactHashCheck=true' instead.
|
||||
Enable leader to periodically check followers compaction hashes.
|
||||
--experimental-compact-hash-check-time '1m'
|
||||
Duration of time between leader checks followers compaction hashes. Deprecated in v3.6 and will be decommissioned in v3.7. Use '--compact-hash-check-time' instead.
|
||||
--compact-hash-check-time '1m'
|
||||
Duration of time between leader checks followers compaction hashes.
|
||||
--experimental-enable-lease-checkpoint 'false'
|
||||
ExperimentalEnableLeaseCheckpoint enables primary lessor to persist lease remainingTTL to prevent indefinite auto-renewal of long lived leases.
|
||||
|
@ -64,6 +64,7 @@ import (
|
||||
"go.etcd.io/etcd/server/v3/etcdserver/errors"
|
||||
"go.etcd.io/etcd/server/v3/etcdserver/txn"
|
||||
serverversion "go.etcd.io/etcd/server/v3/etcdserver/version"
|
||||
"go.etcd.io/etcd/server/v3/features"
|
||||
"go.etcd.io/etcd/server/v3/lease"
|
||||
"go.etcd.io/etcd/server/v3/lease/leasehttp"
|
||||
serverstorage "go.etcd.io/etcd/server/v3/storage"
|
||||
@ -2328,7 +2329,7 @@ func (s *EtcdServer) monitorKVHash() {
|
||||
}
|
||||
|
||||
func (s *EtcdServer) monitorCompactHash() {
|
||||
if !s.Cfg.CompactHashCheckEnabled {
|
||||
if !s.FeatureEnabled(features.CompactHashCheck) {
|
||||
return
|
||||
}
|
||||
t := s.Cfg.CompactHashCheckTime
|
||||
|
@ -50,6 +50,11 @@ const (
|
||||
// alpha: v3.6
|
||||
// main PR: https://github.com/etcd-io/etcd/pull/10524
|
||||
InitialCorruptCheck featuregate.Feature = "InitialCorruptCheck"
|
||||
// CompactHashCheck enables leader to periodically check followers compaction hashes.
|
||||
// owner: @serathius
|
||||
// alpha: v3.6
|
||||
// main PR: https://github.com/etcd-io/etcd/pull/14120
|
||||
CompactHashCheck featuregate.Feature = "CompactHashCheck"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -57,6 +62,7 @@ var (
|
||||
DistributedTracing: {Default: false, PreRelease: featuregate.Alpha},
|
||||
StopGRPCServiceOnDefrag: {Default: false, PreRelease: featuregate.Alpha},
|
||||
InitialCorruptCheck: {Default: false, PreRelease: featuregate.Alpha},
|
||||
CompactHashCheck: {Default: false, PreRelease: featuregate.Alpha},
|
||||
}
|
||||
// ExperimentalFlagToFeatureMap is the map from the cmd line flags of experimental features
|
||||
// to their corresponding feature gates.
|
||||
@ -64,6 +70,7 @@ var (
|
||||
ExperimentalFlagToFeatureMap = map[string]featuregate.Feature{
|
||||
"experimental-stop-grpc-service-on-defrag": StopGRPCServiceOnDefrag,
|
||||
"experimental-initial-corrupt-check": InitialCorruptCheck,
|
||||
"experimental-compact-hash-check-enabled": CompactHashCheck,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -228,15 +228,25 @@ func TestPeriodicCheckDetectsCorruption(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCompactHashCheckDetectCorruption(t *testing.T) {
|
||||
testCompactHashCheckDetectCorruption(t, false)
|
||||
}
|
||||
|
||||
func TestCompactHashCheckDetectCorruptionWithFeatureGate(t *testing.T) {
|
||||
testCompactHashCheckDetectCorruption(t, true)
|
||||
}
|
||||
|
||||
func testCompactHashCheckDetectCorruption(t *testing.T, useFeatureGate bool) {
|
||||
checkTime := time.Second
|
||||
e2e.BeforeTest(t)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
epc, err := e2e.NewEtcdProcessCluster(ctx, t,
|
||||
e2e.WithKeepDataDir(true),
|
||||
e2e.WithCompactHashCheckEnabled(true),
|
||||
e2e.WithCompactHashCheckTime(checkTime),
|
||||
)
|
||||
opts := []e2e.EPClusterOption{e2e.WithKeepDataDir(true), e2e.WithCompactHashCheckTime(checkTime)}
|
||||
if useFeatureGate {
|
||||
opts = append(opts, e2e.WithServerFeatureGate("CompactHashCheck", true))
|
||||
} else {
|
||||
opts = append(opts, e2e.WithCompactHashCheckEnabled(true))
|
||||
}
|
||||
epc, err := e2e.NewEtcdProcessCluster(ctx, t, opts...)
|
||||
if err != nil {
|
||||
t.Fatalf("could not start etcd process cluster (%v)", err)
|
||||
}
|
||||
@ -270,6 +280,14 @@ func TestCompactHashCheckDetectCorruption(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCompactHashCheckDetectCorruptionInterrupt(t *testing.T) {
|
||||
testCompactHashCheckDetectCorruptionInterrupt(t, false)
|
||||
}
|
||||
|
||||
func TestCompactHashCheckDetectCorruptionInterruptWithFeatureGate(t *testing.T) {
|
||||
testCompactHashCheckDetectCorruptionInterrupt(t, true)
|
||||
}
|
||||
|
||||
func testCompactHashCheckDetectCorruptionInterrupt(t *testing.T, useFeatureGate bool) {
|
||||
checkTime := time.Second
|
||||
e2e.BeforeTest(t)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
@ -281,14 +299,20 @@ func TestCompactHashCheckDetectCorruptionInterrupt(t *testing.T) {
|
||||
t.Log("creating a new cluster with 3 nodes...")
|
||||
|
||||
dataDirPath := t.TempDir()
|
||||
cfg := e2e.NewConfig(
|
||||
opts := []e2e.EPClusterOption{
|
||||
e2e.WithKeepDataDir(true),
|
||||
e2e.WithCompactHashCheckEnabled(true),
|
||||
e2e.WithCompactHashCheckTime(checkTime),
|
||||
e2e.WithClusterSize(3),
|
||||
e2e.WithDataDirPath(dataDirPath),
|
||||
e2e.WithLogLevel("info"),
|
||||
)
|
||||
}
|
||||
if useFeatureGate {
|
||||
opts = append(opts, e2e.WithServerFeatureGate("CompactHashCheck", true))
|
||||
} else {
|
||||
opts = append(opts, e2e.WithCompactHashCheckEnabled(true))
|
||||
}
|
||||
|
||||
cfg := e2e.NewConfig(opts...)
|
||||
epc, err := e2e.InitEtcdProcessCluster(t, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -328,7 +328,7 @@ func WithCompactHashCheckEnabled(enabled bool) EPClusterOption {
|
||||
}
|
||||
|
||||
func WithCompactHashCheckTime(time time.Duration) EPClusterOption {
|
||||
return func(c *EtcdProcessClusterConfig) { c.ServerConfig.ExperimentalCompactHashCheckTime = time }
|
||||
return func(c *EtcdProcessClusterConfig) { c.ServerConfig.CompactHashCheckTime = time }
|
||||
}
|
||||
|
||||
func WithGoFailEnabled(enabled bool) EPClusterOption {
|
||||
|
Loading…
Reference in New Issue
Block a user