Skip to content

Commit

Permalink
migrate to use memory-mlock flag
Browse files Browse the repository at this point in the history
Signed-off-by: Jiayin Mao <jiayin.mao@datadoghq.com>
  • Loading branch information
jmao-dd committed Jan 26, 2025
1 parent 0ae9c72 commit 84d7608
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 5 deletions.
4 changes: 2 additions & 2 deletions server/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,13 @@ type ServerConfig struct {

DowngradeCheckTime time.Duration

// ExperimentalMemoryMlock enables mlocking of etcd owned memory pages.
// MemoryMlock enables mlocking of etcd owned memory pages.
// The setting improves etcd tail latency in environments were:
// - memory pressure might lead to swapping pages to disk
// - disk latency might be unstable
// Currently all etcd memory gets mlocked, but in future the flag can
// be refined to mlock in-use area of bbolt only.
ExperimentalMemoryMlock bool `json:"experimental-memory-mlock"`
MemoryMlock bool `json:"memory-mlock"`

// ExperimentalTxnModeWriteWithSharedBuffer enable write transaction to use
// a shared buffer in its readonly check operations.
Expand Down
9 changes: 8 additions & 1 deletion server/embed/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -471,12 +471,16 @@ type Config struct {

ExperimentalDowngradeCheckTime time.Duration `json:"experimental-downgrade-check-time"`

// ExperimentalMemoryMlock enables mlocking of etcd owned memory pages.
// MemoryMlock enables mlocking of etcd owned memory pages.
// The setting improves etcd tail latency in environments were:
// - memory pressure might lead to swapping pages to disk
// - disk latency might be unstable
// Currently all etcd memory gets mlocked, but in future the flag can
// be refined to mlock in-use area of bbolt only.
MemoryMlock bool `json:"memory-mlock"`

// Deprecated in v3.6 and will be decommissioned in v3.7. Use MemoryMlock.
// TODO: Delete in v3.7
ExperimentalMemoryMlock bool `json:"experimental-memory-mlock"`

// ExperimentalTxnModeWriteWithSharedBuffer enables write transaction to use a shared buffer in its readonly check operations.
Expand Down Expand Up @@ -594,6 +598,7 @@ func NewConfig() *Config {
EnableGRPCGateway: true,

ExperimentalDowngradeCheckTime: DefaultDowngradeCheckTime,
MemoryMlock: false,
ExperimentalMemoryMlock: false,
ExperimentalStopGRPCServiceOnDefrag: false,
ExperimentalMaxLearners: membership.DefaultMaxLearners,
Expand Down Expand Up @@ -802,7 +807,9 @@ func (cfg *Config) AddFlags(fs *flag.FlagSet) {
fs.DurationVar(&cfg.ExperimentalWarningApplyDuration, "experimental-warning-apply-duration", cfg.ExperimentalWarningApplyDuration, "Time duration after which a warning is generated if request takes more time.")
fs.DurationVar(&cfg.WarningUnaryRequestDuration, "warning-unary-request-duration", cfg.WarningUnaryRequestDuration, "Time duration after which a warning is generated if a unary request takes more time.")
fs.DurationVar(&cfg.ExperimentalWarningUnaryRequestDuration, "experimental-warning-unary-request-duration", cfg.ExperimentalWarningUnaryRequestDuration, "Time duration after which a warning is generated if a unary request takes more time. It's deprecated, and will be decommissioned in v3.7. Use --warning-unary-request-duration instead.")
// TODO: delete in v3.7
fs.BoolVar(&cfg.ExperimentalMemoryMlock, "experimental-memory-mlock", cfg.ExperimentalMemoryMlock, "Enable to enforce etcd pages (in particular bbolt) to stay in RAM.")
fs.BoolVar(&cfg.MemoryMlock, "memory-mlock", cfg.MemoryMlock, "Enable to enforce etcd pages (in particular bbolt) to stay in RAM.")
fs.BoolVar(&cfg.ExperimentalTxnModeWriteWithSharedBuffer, "experimental-txn-mode-write-with-shared-buffer", true, "Enable the write transaction to use a shared buffer in its readonly check operations.")
fs.BoolVar(&cfg.ExperimentalStopGRPCServiceOnDefrag, "experimental-stop-grpc-service-on-defrag", cfg.ExperimentalStopGRPCServiceOnDefrag, "Enable etcd gRPC service to stop serving client requests on defragmentation.")
fs.UintVar(&cfg.ExperimentalBootstrapDefragThresholdMegabytes, "experimental-bootstrap-defrag-threshold-megabytes", 0, "Enable the defrag during etcd server bootstrap on condition that it will free at least the provided threshold of disk space. Needs to be set to non-zero value to take effect.")
Expand Down
2 changes: 1 addition & 1 deletion server/embed/etcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ func StartEtcd(inCfg *Config) (e *Etcd, err error) {
DowngradeCheckTime: cfg.ExperimentalDowngradeCheckTime,
WarningApplyDuration: cfg.ExperimentalWarningApplyDuration,
WarningUnaryRequestDuration: cfg.WarningUnaryRequestDuration,
ExperimentalMemoryMlock: cfg.ExperimentalMemoryMlock,
MemoryMlock: cfg.MemoryMlock,
ExperimentalBootstrapDefragThresholdMegabytes: cfg.ExperimentalBootstrapDefragThresholdMegabytes,
ExperimentalMaxLearners: cfg.ExperimentalMaxLearners,
V2Deprecation: cfg.V2DeprecationEffective(),
Expand Down
5 changes: 5 additions & 0 deletions server/etcdmain/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ var (
"experimental-txn-mode-write-with-shared-buffer": "--experimental-txn-mode-write-with-shared-buffer is deprecated in v3.6 and will be decommissioned in v3.7. Use '--feature-gates=TxnModeWriteWithSharedBuffer=true' instead.",
"experimental-corrupt-check-time": "--experimental-corrupt-check-time is deprecated in v3.6 and will be decommissioned in v3.7. Use '--corrupt-check-time' instead.",
"experimental-compaction-batch-limit": "--experimental-compaction-batch-limit is deprecated in v3.6 and will be decommissioned in v3.7. Use '--compaction-batch-limit' instead.",
"experimental-memory-mlock": "--experimental-memory-mlock is deprecated in v3.6 and will be decommissioned in v3.7. Use '--memory-mlock' instead.",
}
)

Expand Down Expand Up @@ -184,6 +185,10 @@ func (cfg *config) parse(arguments []string) error {
cfg.ec.CompactionBatchLimit = cfg.ec.ExperimentalCompactionBatchLimit
}

if cfg.ec.FlagsExplicitlySet["experimental-memory-mlock"] {
cfg.ec.MemoryMlock = cfg.ec.ExperimentalMemoryMlock
}

// `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

Expand Down
59 changes: 59 additions & 0 deletions server/etcdmain/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,65 @@ func TestCompactionBatchLimitFlagMigration(t *testing.T) {
}
}

// TestMemoryMlockFlagMigration tests the migration from
// --experimental-memory-mlock to --memory-mlock
// TODO: delete in v3.7
func TestMemoryMlockFlagMigration(t *testing.T) {
testCases := []struct {
name string
memoryMlock bool
experimentalMemoryMlock bool
expectedMemoryMlock bool
}{
{
name: "default",
expectedMemoryMlock: false,
},
{
name: "can set experimental flag",
experimentalMemoryMlock: true,
expectedMemoryMlock: true,
},
{
name: "can set non experimental flag",
memoryMlock: true,
expectedMemoryMlock: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
cmdLineArgs := []string{}
yc := struct {
MemoryMlock bool `json:"memory-mlock,omitempty"`
ExperimentalMemoryMlock bool `json:"experimental-memory-mlock,omitempty"`
}{}

if tc.memoryMlock {
cmdLineArgs = append(cmdLineArgs, "--memory-mlock")
yc.MemoryMlock = tc.memoryMlock
}

if tc.experimentalMemoryMlock {
cmdLineArgs = append(cmdLineArgs, "--experimental-memory-mlock")
yc.ExperimentalMemoryMlock = tc.experimentalMemoryMlock
}

cfgFromCmdLine, errFromCmdLine, cfgFromFile, errFromFile := generateCfgsFromFileAndCmdLine(t, yc, cmdLineArgs)

if errFromCmdLine != nil || errFromFile != nil {
t.Fatal("error parsing config")
}

if cfgFromCmdLine.ec.MemoryMlock != tc.expectedMemoryMlock {
t.Errorf("expected MemoryMlock=%v, got %v", tc.expectedMemoryMlock, cfgFromCmdLine.ec.MemoryMlock)
}
if cfgFromFile.ec.MemoryMlock != tc.expectedMemoryMlock {
t.Errorf("expected MemoryMlock=%v, got %v", tc.expectedMemoryMlock, cfgFromFile.ec.MemoryMlock)
}
})
}
}

// TODO delete in v3.7
func generateCfgsFromFileAndCmdLine(t *testing.T, yc any, cmdLineArgs []string) (*config, error, *config, error) {
b, err := yaml.Marshal(&yc)
Expand Down
2 changes: 2 additions & 0 deletions server/etcdmain/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ Member:
Maximum number of snapshot files to retain (0 is unlimited). Deprecated in v3.6 and will be decommissioned in v3.7.
--max-wals '` + strconv.Itoa(embed.DefaultMaxWALs) + `'
Maximum number of wal files to retain (0 is unlimited).
--memory-mlock
Enable to enforce etcd pages (in particular bbolt) to stay in RAM.
--quota-backend-bytes '0'
Raise alarms when backend size exceeds the given quota (0 defaults to low space quota).
--backend-bbolt-freelist-type 'map'
Expand Down
2 changes: 1 addition & 1 deletion server/storage/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func newBackend(cfg config.ServerConfig, hooks backend.Hooks) backend.Backend {
// permit 10% excess over quota for disarm
bcfg.MmapSize = uint64(cfg.QuotaBackendBytes + cfg.QuotaBackendBytes/10)
}
bcfg.Mlock = cfg.ExperimentalMemoryMlock
bcfg.Mlock = cfg.MemoryMlock
bcfg.Hooks = hooks
return backend.New(bcfg)
}
Expand Down

0 comments on commit 84d7608

Please sign in to comment.