Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

config: support to dynamically update some config items read from PD #14393

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 89 additions & 79 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,24 @@
package config

import (
"bytes"
"crypto/tls"
"crypto/x509"
"encoding/json"
"fmt"
"io/ioutil"
"net/url"
"os"
"reflect"
"strings"
"sync"
"time"

"github.com/BurntSushi/toml"
"github.com/pingcap/errors"
zaplog "github.com/pingcap/log"
"github.com/pingcap/parser/mysql"
"github.com/pingcap/parser/terror"
"github.com/pingcap/tidb/util/logutil"
tracing "github.com/uber/jaeger-client-go/config"
"go.uber.org/atomic"
"go.uber.org/zap"
)

// Config number limitations
Expand Down Expand Up @@ -153,6 +152,16 @@ func (b *nullableBool) UnmarshalText(text []byte) error {
return nil
}

func (b nullableBool) MarshalText() ([]byte, error) {
if !b.IsValid {
return []byte(""), nil
}
if b.IsTrue {
return []byte("true"), nil
}
return []byte("false"), nil
}

func (b *nullableBool) UnmarshalJSON(data []byte) error {
var err error
var v interface{}
Expand Down Expand Up @@ -589,12 +598,7 @@ var defaultConf = Config{
}

var (
globalConf = atomic.Value{}
reloadConfPath = ""
confReloader func(nc, c *Config)
confReloadLock sync.Mutex
supportedReloadConfigs = make(map[string]struct{}, 32)
supportedReloadConfList = make([]string, 0, 32)
globalConfHandler ConfHandler
)

// NewConfig creates a new config instance with default value.
Expand All @@ -603,94 +607,74 @@ func NewConfig() *Config {
return &conf
}

// SetConfReloader sets reload config path and a reloader.
// It should be called only once at start time.
func SetConfReloader(cpath string, reloader func(nc, c *Config), confItems ...string) {
reloadConfPath = cpath
confReloader = reloader
for _, item := range confItems {
supportedReloadConfigs[item] = struct{}{}
supportedReloadConfList = append(supportedReloadConfList, item)
}
}

// GetGlobalConfig returns the global configuration for this server.
// It should store configuration from command line and configuration file.
// Other parts of the system can read the global configuration use this function.
// NOTE: the returned config is read-only.
func GetGlobalConfig() *Config {
return globalConf.Load().(*Config)
return globalConfHandler.GetConfig()
}

// StoreGlobalConfig stores a new config to the globalConf. It mostly uses in the test to avoid some data races.
func StoreGlobalConfig(config *Config) {
globalConf.Store(config)
if err := globalConfHandler.SetConfig(config); err != nil {
logutil.BgLogger().Error("update the global config error", zap.Error(err))
}
}

// ReloadGlobalConfig reloads global configuration for this server.
func ReloadGlobalConfig() error {
confReloadLock.Lock()
defer confReloadLock.Unlock()

nc := NewConfig()
if err := nc.Load(reloadConfPath); err != nil {
return err
}
if err := nc.Valid(); err != nil {
return err
}
c := GetGlobalConfig()
var deprecatedConfig = map[string]struct{}{
"pessimistic-txn.ttl": {},
"log.rotate": {},
}

diffs := collectsDiff(*nc, *c, "")
if len(diffs) == 0 {
return nil
}
var formattedDiff bytes.Buffer
for k, vs := range diffs {
formattedDiff.WriteString(fmt.Sprintf(", %v:%v->%v", k, vs[1], vs[0]))
}
unsupported := make([]string, 0, 2)
for k := range diffs {
if _, ok := supportedReloadConfigs[k]; !ok {
unsupported = append(unsupported, k)
func isDeprecatedConfigItem(items []string) bool {
for _, item := range items {
if _, ok := deprecatedConfig[item]; !ok {
return false
}
}
if len(unsupported) > 0 {
return fmt.Errorf("reloading config %v is not supported, only %v are supported now, "+
"your changes%s", unsupported, supportedReloadConfList, formattedDiff.String())
}

confReloader(nc, c)
globalConf.Store(nc)
logutil.BgLogger().Info("reload config changes" + formattedDiff.String())
return nil
return true
}

// collectsDiff collects different config items.
// map[string][]string -> map[field path][]{new value, old value}
func collectsDiff(i1, i2 interface{}, fieldPath string) map[string][]interface{} {
diff := make(map[string][]interface{})
t := reflect.TypeOf(i1)
if t.Kind() != reflect.Struct {
if reflect.DeepEqual(i1, i2) {
return diff
// InitializeConfig initialize the global config handler.
func InitializeConfig(confPath string, configCheck, configStrict bool, reloadFunc ConfReloadFunc, overwriteFunc OverwriteFunc) {
cfg := GetGlobalConfig()
var err error
if confPath != "" {
err = cfg.Load(confPath)
if err == nil {
return
}
diff[fieldPath] = []interface{}{i1, i2}
return diff
}

v1 := reflect.ValueOf(i1)
v2 := reflect.ValueOf(i2)
for i := 0; i < v1.NumField(); i++ {
p := t.Field(i).Name
if fieldPath != "" {
p = fieldPath + "." + p
// Unused config item erro turns to warnings.
if tmp, ok := err.(*ErrConfigValidationFailed); ok {
if isDeprecatedConfigItem(tmp.UndecodedItems) {
fmt.Fprintln(os.Stderr, err.Error())
err = nil
}
// This block is to accommodate an interim situation where strict config checking
// is not the default behavior of TiDB. The warning message must be deferred until
// logging has been set up. After strict config checking is the default behavior,
// This should all be removed.
if !configCheck && !configStrict {
fmt.Fprintln(os.Stderr, err.Error())
err = nil
}
}
m := collectsDiff(v1.Field(i).Interface(), v2.Field(i).Interface(), p)
for k, v := range m {
diff[k] = v

terror.MustNil(err)
} else {
// configCheck should have the config file specified.
if configCheck {
fmt.Fprintln(os.Stderr, "config check failed", errors.New("no config file specified for config-check"))
os.Exit(1)
}
}
return diff

overwriteFunc(cfg)
globalConfHandler, err = NewConfHandler(cfg, reloadFunc, overwriteFunc)
terror.MustNil(err)
globalConfHandler.Start()
}

// Load loads config options from a toml file.
Expand Down Expand Up @@ -829,7 +813,8 @@ func (t *OpenTracing) ToTracingConfig() *tracing.Configuration {
}

func init() {
globalConf.Store(&defaultConf)
conf := defaultConf
globalConfHandler = &constantConfHandler{&conf}
if checkBeforeDropLDFlag == "1" {
CheckTableBeforeDrop = true
}
Expand All @@ -843,3 +828,28 @@ const (
OOMActionCancel = "cancel"
OOMActionLog = "log"
)

// ParsePath parses this path.
func ParsePath(path string) (etcdAddrs []string, disableGC bool, err error) {
var u *url.URL
u, err = url.Parse(path)
if err != nil {
err = errors.Trace(err)
return
}
if strings.ToLower(u.Scheme) != "tikv" {
err = errors.Errorf("Uri scheme expected[tikv] but found [%s]", u.Scheme)
logutil.BgLogger().Error("parsePath error", zap.Error(err))
return
}
switch strings.ToLower(u.Query().Get("disableGC")) {
case "true":
disableGC = true
case "false", "":
default:
err = errors.New("disableGC flag should be true/false")
return
}
etcdAddrs = strings.Split(u.Host, ",")
return
}
Loading