Some checks failed
DCO action / DCO (pull_request) Successful in 37s
Vulncheck / Vulncheck (pull_request) Successful in 1m9s
Tests and linters / Lint (pull_request) Failing after 1m28s
Tests and linters / Run gofumpt (pull_request) Successful in 1m36s
Pre-commit hooks / Pre-commit (pull_request) Failing after 1m58s
Build / Build Components (pull_request) Successful in 2m4s
Tests and linters / Staticcheck (pull_request) Successful in 1m58s
Tests and linters / gopls check (pull_request) Failing after 2m18s
Tests and linters / Tests (pull_request) Successful in 3m18s
Tests and linters / Tests with -race (pull_request) Successful in 3m53s
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
88 lines
2.6 KiB
Go
88 lines
2.6 KiB
Go
package qos
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/engine/shard/limits"
|
|
)
|
|
|
|
var errWeightsMustBeSpecified = errors.New("invalid weights: weights must be specified for all tags or not specified for any")
|
|
|
|
type tagConfig struct {
|
|
Shares, Limit, Reserved *float64
|
|
}
|
|
|
|
func ValidateConfig(c *limits.Config) error {
|
|
if c.MaxReadRunningOps() <= 0 {
|
|
return fmt.Errorf("invalid 'max_read_running_ops = %d': must be greater than zero", c.MaxReadRunningOps())
|
|
}
|
|
if c.MaxReadWaitingOps() <= 0 {
|
|
return fmt.Errorf("invalid 'max_read_waiting_ops = %d': must be greater than zero", c.MaxReadWaitingOps())
|
|
}
|
|
if c.MaxWriteRunningOps() <= 0 {
|
|
return fmt.Errorf("invalid 'max_write_running_ops = %d': must be greater than zero", c.MaxWriteRunningOps())
|
|
}
|
|
if c.MaxWriteWaitingOps() <= 0 {
|
|
return fmt.Errorf("invalid 'max_write_waiting_ops = %d': must be greater than zero", c.MaxWriteWaitingOps())
|
|
}
|
|
if err := validateTags(c.ReadTags()); err != nil {
|
|
return fmt.Errorf("'read' config validation error: %w", err)
|
|
}
|
|
if err := validateTags(c.WriteTags()); err != nil {
|
|
return fmt.Errorf("'write' config validation error: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateTags(configTags []limits.IOTagConfig) error {
|
|
tags := map[IOTag]tagConfig{
|
|
IOTagClient: {},
|
|
IOTagInternal: {},
|
|
IOTagBackground: {},
|
|
IOTagWritecache: {},
|
|
IOTagPolicer: {},
|
|
}
|
|
for _, t := range configTags {
|
|
tag, err := FromRawString(t.Tag)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid tag %s: %w", t.Tag, err)
|
|
}
|
|
if _, ok := tags[tag]; !ok {
|
|
return fmt.Errorf("tag %s is not configurable", t.Tag)
|
|
}
|
|
tags[tag] = tagConfig{
|
|
Shares: t.Weight,
|
|
Limit: t.LimitOps,
|
|
Reserved: t.ReservedOps,
|
|
}
|
|
}
|
|
idx := 0
|
|
var shares float64
|
|
for t, v := range tags {
|
|
if idx == 0 {
|
|
idx++
|
|
shares = float64Value(v.Shares)
|
|
} else if (shares != 0 && float64Value(v.Shares) == 0) || (shares == 0 && float64Value(v.Shares) != 0) {
|
|
return errWeightsMustBeSpecified
|
|
}
|
|
if float64Value(v.Shares) < 0 || math.IsNaN(float64Value(v.Shares)) {
|
|
return fmt.Errorf("invalid weight for tag %s: must be positive value", t.String())
|
|
}
|
|
if float64Value(v.Limit) < 0 || math.IsNaN(float64Value(v.Limit)) {
|
|
return fmt.Errorf("invalid limit_ops for tag %s: must be positive value", t.String())
|
|
}
|
|
if float64Value(v.Reserved) < 0 || math.IsNaN(float64Value(v.Reserved)) {
|
|
return fmt.Errorf("invalid limit_ops for tag %s: must be positive value", t.String())
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func float64Value(f *float64) float64 {
|
|
if f == nil {
|
|
return 0.0
|
|
}
|
|
return *f
|
|
}
|