github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/dbs/cmd/config/config.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package config
    15  
    16  import (
    17  	"crypto/tls"
    18  	"crypto/x509"
    19  	"encoding/base64"
    20  	"encoding/json"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"net/url"
    24  	"os"
    25  	"os/user"
    26  	"path/filepath"
    27  	"strings"
    28  	"sync/atomic"
    29  	"time"
    30  
    31  	"github.com/BurntSushi/toml"
    32  	"github.com/whtcorpsinc/errors"
    33  	zaplog "github.com/whtcorpsinc/log"
    34  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    35  	"github.com/whtcorpsinc/BerolinaSQL/terror"
    36  	"github.com/whtcorpsinc/milevadb/soliton/logutil"
    37  	"github.com/whtcorpsinc/milevadb/soliton/versioninfo"
    38  	tracing "github.com/uber/jaeger-client-go/config"
    39  
    40  	"go.uber.org/zap"
    41  )
    42  
    43  // Config number limitations
    44  const (
    45  	MaxLogFileSize = 4096 // MB
    46  	// DefTxnEntrySizeLimit is the default value of TxnEntrySizeLimit.
    47  	DefTxnEntrySizeLimit = 6 * 1024 * 1024
    48  	// DefTxnTotalSizeLimit is the default value of TxnTxnTotalSizeLimit.
    49  	DefTxnTotalSizeLimit = 100 * 1024 * 1024
    50  	// DefMaxIndexLength is the maximum index length(in bytes). This value is consistent with MyALLEGROSQL.
    51  	DefMaxIndexLength = 3072
    52  	// DefMaxOfMaxIndexLength is the maximum index length(in bytes) for MilevaDB v3.0.7 and previous version.
    53  	DefMaxOfMaxIndexLength = 3072 * 4
    54  	// DefPort is the default port of MilevaDB
    55  	DefPort = 4000
    56  	// DefStatusPort is the default status port of MilevaDB
    57  	DefStatusPort = 10080
    58  	// DefHost is the default host of MilevaDB
    59  	DefHost = "0.0.0.0"
    60  	// DefStatusHost is the default status host of MilevaDB
    61  	DefStatusHost = "0.0.0.0"
    62  	// DefStoreLivenessTimeout is the default value for causetstore liveness timeout.
    63  	DefStoreLivenessTimeout = "5s"
    64  	// DefMilevaDBRedactLog is the default value for redact log.
    65  	DefMilevaDBRedactLog = 0
    66  )
    67  
    68  // Valid config maps
    69  var (
    70  	ValidStorage = map[string]bool{
    71  		"mockeinsteindb": true,
    72  		"einsteindb":     true,
    73  		"entangledstore": true,
    74  	}
    75  	// checkBlockBeforeDrop enable to execute `admin check causet` before `drop causet`.
    76  	CheckBlockBeforeDrop = false
    77  	// checkBeforeDropLDFlag is a go build flag.
    78  	checkBeforeDropLDFlag = "None"
    79  	// tempStorageDirName is the default temporary storage dir name by base64 encoding a string `port/statusPort`
    80  	tempStorageDirName = encodeDefTempStorageDir(os.TemFIDelir(), DefHost, DefStatusHost, DefPort, DefStatusPort)
    81  )
    82  
    83  // Config contains configuration options.
    84  type Config struct {
    85  	Host                        string `toml:"host" json:"host"`
    86  	AdvertiseAddress            string `toml:"advertise-address" json:"advertise-address"`
    87  	Port                        uint   `toml:"port" json:"port"`
    88  	Cors                        string `toml:"cors" json:"cors"`
    89  	CausetStore                       string `toml:"causetstore" json:"causetstore"`
    90  	Path                        string `toml:"path" json:"path"`
    91  	Socket                      string `toml:"socket" json:"socket"`
    92  	Lease                       string `toml:"lease" json:"lease"`
    93  	RunDBS                      bool   `toml:"run-dbs" json:"run-dbs"`
    94  	SplitBlock                  bool   `toml:"split-causet" json:"split-causet"`
    95  	TokenLimit                  uint   `toml:"token-limit" json:"token-limit"`
    96  	OOMUseTmpStorage            bool   `toml:"oom-use-tmp-storage" json:"oom-use-tmp-storage"`
    97  	TempStoragePath             string `toml:"tmp-storage-path" json:"tmp-storage-path"`
    98  	OOMCausetAction                   string `toml:"oom-action" json:"oom-action"`
    99  	MemQuotaQuery               int64  `toml:"mem-quota-query" json:"mem-quota-query"`
   100  	NestedLoopJoinCacheCapacity int64  `toml:"nested-loop-join-cache-capacity" json:"nested-loop-join-cache-capacity"`
   101  	// TempStorageQuota describe the temporary storage Quota during query exector when OOMUseTmpStorage is enabled
   102  	// If the quota exceed the capacity of the TempStoragePath, the milevadb-server would exit with fatal error
   103  	TempStorageQuota int64           `toml:"tmp-storage-quota" json:"tmp-storage-quota"` // Bytes
   104  	EnableStreaming  bool            `toml:"enable-streaming" json:"enable-streaming"`
   105  	EnableBatchDML   bool            `toml:"enable-batch-dml" json:"enable-batch-dml"`
   106  	TxnLocalLatches  TxnLocalLatches `toml:"-" json:"-"`
   107  	// Set sys variable lower-case-causet-names, ref: https://dev.allegrosql.com/doc/refman/5.7/en/identifier-case-sensitivity.html.
   108  	// TODO: We actually only support mode 2, which keeps the original case, but the comparison is case-insensitive.
   109  	LowerCaseBlockNames int               `toml:"lower-case-causet-names" json:"lower-case-causet-names"`
   110  	ServerVersion       string            `toml:"server-version" json:"server-version"`
   111  	Log                 Log               `toml:"log" json:"log"`
   112  	Security            Security          `toml:"security" json:"security"`
   113  	Status              Status            `toml:"status" json:"status"`
   114  	Performance         Performance       `toml:"performance" json:"performance"`
   115  	PreparedCausetCache   PreparedCausetCache `toml:"prepared-plan-cache" json:"prepared-plan-cache"`
   116  	OpenTracing         OpenTracing       `toml:"opentracing" json:"opentracing"`
   117  	ProxyProtocol       ProxyProtocol     `toml:"proxy-protocol" json:"proxy-protocol"`
   118  	EinsteinDBClient          EinsteinDBClient        `toml:"einsteindb-client" json:"einsteindb-client"`
   119  	Binlog              Binlog            `toml:"binlog" json:"binlog"`
   120  	CompatibleKillQuery bool              `toml:"compatible-kill-query" json:"compatible-kill-query"`
   121  	Plugin              Plugin            `toml:"plugin" json:"plugin"`
   122  	PessimisticTxn      PessimisticTxn    `toml:"pessimistic-txn" json:"pessimistic-txn"`
   123  	CheckMb4ValueInUTF8 bool              `toml:"check-mb4-value-in-utf8" json:"check-mb4-value-in-utf8"`
   124  	MaxIndexLength      int               `toml:"max-index-length" json:"max-index-length"`
   125  	// AlterPrimaryKey is used to control alter primary key feature.
   126  	AlterPrimaryKey bool `toml:"alter-primary-key" json:"alter-primary-key"`
   127  	// TreatOldVersionUTF8AsUTF8MB4 is use to treat old version causet/column UTF8 charset as UTF8MB4. This is for compatibility.
   128  	// Currently not support dynamic modify, because this need to reload all old version schemaReplicant.
   129  	TreatOldVersionUTF8AsUTF8MB4 bool `toml:"treat-old-version-utf8-as-utf8mb4" json:"treat-old-version-utf8-as-utf8mb4"`
   130  	// EnableBlockLock indicate whether enable causet dagger.
   131  	// TODO: remove this after causet dagger features sblock.
   132  	EnableBlockLock     bool        `toml:"enable-causet-dagger" json:"enable-causet-dagger"`
   133  	DelayCleanBlockLock uint64      `toml:"delay-clean-causet-dagger" json:"delay-clean-causet-dagger"`
   134  	SplitRegionMaxNum   uint64      `toml:"split-region-max-num" json:"split-region-max-num"`
   135  	StmtSummary         StmtSummary `toml:"stmt-summary" json:"stmt-summary"`
   136  	// RepairMode indicates that the MilevaDB is in the repair mode for causet spacetime.
   137  	RepairMode      bool     `toml:"repair-mode" json:"repair-mode"`
   138  	RepairBlockList []string `toml:"repair-causet-list" json:"repair-causet-list"`
   139  	// IsolationRead indicates that the MilevaDB reads data from which isolation level(engine and label).
   140  	IsolationRead IsolationRead `toml:"isolation-read" json:"isolation-read"`
   141  	// MaxServerConnections is the maximum permitted number of simultaneous client connections.
   142  	MaxServerConnections uint32 `toml:"max-server-connections" json:"max-server-connections"`
   143  	// NewDefCauslationsEnabledOnFirstBootstrap indicates if the new collations are enabled, it effects only when a MilevaDB cluster bootstrapped on the first time.
   144  	NewDefCauslationsEnabledOnFirstBootstrap bool `toml:"new_collations_enabled_on_first_bootstrap" json:"new_collations_enabled_on_first_bootstrap"`
   145  	// Experimental contains parameters for experimental features.
   146  	Experimental Experimental `toml:"experimental" json:"experimental"`
   147  	// EnableDefCauslectInterDircutionInfo enables the MilevaDB to collect execution info.
   148  	EnableDefCauslectInterDircutionInfo bool `toml:"enable-collect-execution-info" json:"enable-collect-execution-info"`
   149  	// SkipRegisterToDashboard tells MilevaDB don't register itself to the dashboard.
   150  	SkipRegisterToDashboard bool `toml:"skip-register-to-dashboard" json:"skip-register-to-dashboard"`
   151  	// EnableTelemetry enables the usage data report to WHTCORPS INC.
   152  	EnableTelemetry bool `toml:"enable-telemetry" json:"enable-telemetry"`
   153  	// Labels indicates the labels set for the milevadb server. The labels describe some specific properties for the milevadb
   154  	// server like `zone`/`rack`/`host`. Currently, labels won't affect the milevadb server except for some special
   155  	// label keys. Now we only have `group` as a special label key.
   156  	// Note that: 'group' is a special label key which should be automatically set by milevadb-operator. We don't suggest
   157  	// users to set 'group' in labels.
   158  	Labels map[string]string `toml:"labels" json:"labels"`
   159  	// EnableGlobalIndex enables creating global index.
   160  	EnableGlobalIndex bool `toml:"enable-global-index" json:"enable-global-index"`
   161  	// DeprecateIntegerDisplayWidth indicates whether deprecating the max display length for integer.
   162  	DeprecateIntegerDisplayWidth bool `toml:"deprecate-integer-display-length" json:"deprecate-integer-display-length"`
   163  	// EnableRedactLog indicates that whether redact log, 0 is disable. 1 is enable.
   164  	EnableRedactLog int32 `toml:"enable-redact-log" json:"enable-redact-log"`
   165  }
   166  
   167  // UFIDelateTempStoragePath is to uFIDelate the `TempStoragePath` if port/statusPort was changed
   168  // and the `tmp-storage-path` was not specified in the conf.toml or was specified the same as the default value.
   169  func (c *Config) UFIDelateTempStoragePath() {
   170  	if c.TempStoragePath == tempStorageDirName {
   171  		c.TempStoragePath = encodeDefTempStorageDir(os.TemFIDelir(), c.Host, c.Status.StatusHost, c.Port, c.Status.StatusPort)
   172  	} else {
   173  		c.TempStoragePath = encodeDefTempStorageDir(c.TempStoragePath, c.Host, c.Status.StatusHost, c.Port, c.Status.StatusPort)
   174  	}
   175  }
   176  
   177  func encodeDefTempStorageDir(temFIDelir string, host, statusHost string, port, statusPort uint) string {
   178  	dirName := base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf("%v:%v/%v:%v", host, port, statusHost, statusPort)))
   179  	var osUID string
   180  	currentUser, err := user.Current()
   181  	if err != nil {
   182  		osUID = ""
   183  	} else {
   184  		osUID = currentUser.Uid
   185  	}
   186  	return filepath.Join(temFIDelir, osUID+"_milevadb", dirName, "tmp-storage")
   187  }
   188  
   189  // nullableBool defaults unset bool options to unset instead of false, which enables us to know if the user has set 2
   190  // conflict options at the same time.
   191  type nullableBool struct {
   192  	IsValid bool
   193  	IsTrue  bool
   194  }
   195  
   196  var (
   197  	nbUnset = nullableBool{false, false}
   198  	nbFalse = nullableBool{true, false}
   199  	nbTrue  = nullableBool{true, true}
   200  )
   201  
   202  func (b *nullableBool) toBool() bool {
   203  	return b.IsValid && b.IsTrue
   204  }
   205  
   206  func (b nullableBool) MarshalJSON() ([]byte, error) {
   207  	switch b {
   208  	case nbTrue:
   209  		return json.Marshal(true)
   210  	case nbFalse:
   211  		return json.Marshal(false)
   212  	default:
   213  		return json.Marshal(nil)
   214  	}
   215  }
   216  
   217  func (b *nullableBool) UnmarshalText(text []byte) error {
   218  	str := string(text)
   219  	switch str {
   220  	case "", "null":
   221  		*b = nbUnset
   222  		return nil
   223  	case "true":
   224  		*b = nbTrue
   225  	case "false":
   226  		*b = nbFalse
   227  	default:
   228  		*b = nbUnset
   229  		return errors.New("Invalid value for bool type: " + str)
   230  	}
   231  	return nil
   232  }
   233  
   234  func (b nullableBool) MarshalText() ([]byte, error) {
   235  	if !b.IsValid {
   236  		return []byte(""), nil
   237  	}
   238  	if b.IsTrue {
   239  		return []byte("true"), nil
   240  	}
   241  	return []byte("false"), nil
   242  }
   243  
   244  func (b *nullableBool) UnmarshalJSON(data []byte) error {
   245  	var err error
   246  	var v interface{}
   247  	if err = json.Unmarshal(data, &v); err != nil {
   248  		return err
   249  	}
   250  	switch raw := v.(type) {
   251  	case bool:
   252  		*b = nullableBool{true, raw}
   253  	default:
   254  		*b = nbUnset
   255  	}
   256  	return err
   257  }
   258  
   259  // Log is the log section of config.
   260  type Log struct {
   261  	// Log level.
   262  	Level string `toml:"level" json:"level"`
   263  	// Log format. one of json, text, or console.
   264  	Format string `toml:"format" json:"format"`
   265  	// Disable automatic timestamps in output. Deprecated: use EnableTimestamp instead.
   266  	DisableTimestamp nullableBool `toml:"disable-timestamp" json:"disable-timestamp"`
   267  	// EnableTimestamp enables automatic timestamps in log output.
   268  	EnableTimestamp nullableBool `toml:"enable-timestamp" json:"enable-timestamp"`
   269  	// DisableErrorStack stops annotating logs with the full stack error
   270  	// message. Deprecated: use EnableErrorStack instead.
   271  	DisableErrorStack nullableBool `toml:"disable-error-stack" json:"disable-error-stack"`
   272  	// EnableErrorStack enables annotating logs with the full stack error
   273  	// message.
   274  	EnableErrorStack nullableBool `toml:"enable-error-stack" json:"enable-error-stack"`
   275  	// File log config.
   276  	File logutil.FileLogConfig `toml:"file" json:"file"`
   277  
   278  	EnableSlowLog       bool   `toml:"enable-slow-log" json:"enable-slow-log"`
   279  	SlowQueryFile       string `toml:"slow-query-file" json:"slow-query-file"`
   280  	SlowThreshold       uint64 `toml:"slow-threshold" json:"slow-threshold"`
   281  	ExpensiveThreshold  uint   `toml:"expensive-threshold" json:"expensive-threshold"`
   282  	QueryLogMaxLen      uint64 `toml:"query-log-max-len" json:"query-log-max-len"`
   283  	RecordCausetInSlowLog uint32 `toml:"record-plan-in-slow-log" json:"record-plan-in-slow-log"`
   284  }
   285  
   286  func (l *Log) getDisableTimestamp() bool {
   287  	if l.EnableTimestamp == nbUnset && l.DisableTimestamp == nbUnset {
   288  		return false
   289  	}
   290  	if l.EnableTimestamp == nbUnset {
   291  		return l.DisableTimestamp.toBool()
   292  	}
   293  	return !l.EnableTimestamp.toBool()
   294  }
   295  
   296  func (l *Log) getDisableErrorStack() bool {
   297  	if l.EnableErrorStack == nbUnset && l.DisableErrorStack == nbUnset {
   298  		return true
   299  	}
   300  	if l.EnableErrorStack == nbUnset {
   301  		return l.DisableErrorStack.toBool()
   302  	}
   303  	return !l.EnableErrorStack.toBool()
   304  }
   305  
   306  // The following constants represents the valid action configurations for Security.SpilledFileEncryptionMethod.
   307  // "plaintext" means encryption is disabled.
   308  // NOTE: Although the values is case insensitive, we should use lower-case
   309  // strings because the configuration value will be transformed to lower-case
   310  // string and compared with these constants in the further usage.
   311  const (
   312  	SpilledFileEncryptionMethodPlaintext = "plaintext"
   313  	SpilledFileEncryptionMethodAES128CTR = "aes128-ctr"
   314  )
   315  
   316  // Security is the security section of the config.
   317  type Security struct {
   318  	SkipGrantBlock         bool     `toml:"skip-grant-causet" json:"skip-grant-causet"`
   319  	SSLCA                  string   `toml:"ssl-ca" json:"ssl-ca"`
   320  	SSLCert                string   `toml:"ssl-cert" json:"ssl-cert"`
   321  	SSLKey                 string   `toml:"ssl-key" json:"ssl-key"`
   322  	RequireSecureTransport bool     `toml:"require-secure-transport" json:"require-secure-transport"`
   323  	ClusterSSLCA           string   `toml:"cluster-ssl-ca" json:"cluster-ssl-ca"`
   324  	ClusterSSLCert         string   `toml:"cluster-ssl-cert" json:"cluster-ssl-cert"`
   325  	ClusterSSLKey          string   `toml:"cluster-ssl-key" json:"cluster-ssl-key"`
   326  	ClusterVerifyCN        []string `toml:"cluster-verify-cn" json:"cluster-verify-cn"`
   327  	// If set to "plaintext", the spilled files will not be encrypted.
   328  	SpilledFileEncryptionMethod string `toml:"spilled-file-encryption-method" json:"spilled-file-encryption-method"`
   329  }
   330  
   331  // The ErrConfigValidationFailed error is used so that external callers can do a type assertion
   332  // to defer handling of this specific error when someone does not want strict type checking.
   333  // This is needed only because logging hasn't been set up at the time we parse the config file.
   334  // This should all be ripped out once strict config checking is made the default behavior.
   335  type ErrConfigValidationFailed struct {
   336  	confFile       string
   337  	UndecodedItems []string
   338  }
   339  
   340  func (e *ErrConfigValidationFailed) Error() string {
   341  	return fmt.Sprintf("config file %s contained invalid configuration options: %s; check "+
   342  		"MilevaDB manual to make sure this option has not been deprecated and removed from your MilevaDB "+
   343  		"version if the option does not appear to be a typo", e.confFile, strings.Join(
   344  		e.UndecodedItems, ", "))
   345  
   346  }
   347  
   348  // ToTLSConfig generates tls's config based on security section of the config.
   349  func (s *Security) ToTLSConfig() (tlsConfig *tls.Config, err error) {
   350  	if len(s.ClusterSSLCA) != 0 {
   351  		certPool := x509.NewCertPool()
   352  		// Create a certificate pool from the certificate authority
   353  		var ca []byte
   354  		ca, err = ioutil.ReadFile(s.ClusterSSLCA)
   355  		if err != nil {
   356  			err = errors.Errorf("could not read ca certificate: %s", err)
   357  			return
   358  		}
   359  		// Append the certificates from the CA
   360  		if !certPool.AppendCertsFromPEM(ca) {
   361  			err = errors.New("failed to append ca certs")
   362  			return
   363  		}
   364  		tlsConfig = &tls.Config{
   365  			RootCAs:   certPool,
   366  			ClientCAs: certPool,
   367  		}
   368  
   369  		if len(s.ClusterSSLCert) != 0 && len(s.ClusterSSLKey) != 0 {
   370  			getCert := func() (*tls.Certificate, error) {
   371  				// Load the client certificates from disk
   372  				cert, err := tls.LoadX509KeyPair(s.ClusterSSLCert, s.ClusterSSLKey)
   373  				if err != nil {
   374  					return nil, errors.Errorf("could not load client key pair: %s", err)
   375  				}
   376  				return &cert, nil
   377  			}
   378  			// pre-test cert's loading.
   379  			if _, err = getCert(); err != nil {
   380  				return
   381  			}
   382  			tlsConfig.GetClientCertificate = func(info *tls.CertificateRequestInfo) (certificate *tls.Certificate, err error) {
   383  				return getCert()
   384  			}
   385  			tlsConfig.GetCertificate = func(info *tls.ClientHelloInfo) (certificate *tls.Certificate, err error) {
   386  				return getCert()
   387  			}
   388  		}
   389  	}
   390  	return
   391  }
   392  
   393  // Status is the status section of the config.
   394  type Status struct {
   395  	StatusHost      string `toml:"status-host" json:"status-host"`
   396  	MetricsAddr     string `toml:"metrics-addr" json:"metrics-addr"`
   397  	StatusPort      uint   `toml:"status-port" json:"status-port"`
   398  	MetricsInterval uint   `toml:"metrics-interval" json:"metrics-interval"`
   399  	ReportStatus    bool   `toml:"report-status" json:"report-status"`
   400  	RecordQPSbyDB   bool   `toml:"record-EDB-qps" json:"record-EDB-qps"`
   401  }
   402  
   403  // Performance is the performance section of the config.
   404  type Performance struct {
   405  	MaxProcs uint `toml:"max-procs" json:"max-procs"`
   406  	// Deprecated: use ServerMemoryQuota instead
   407  	MaxMemory            uint64  `toml:"max-memory" json:"max-memory"`
   408  	ServerMemoryQuota    uint64  `toml:"server-memory-quota" json:"server-memory-quota"`
   409  	StatsLease           string  `toml:"stats-lease" json:"stats-lease"`
   410  	StmtCountLimit       uint    `toml:"stmt-count-limit" json:"stmt-count-limit"`
   411  	FeedbackProbability  float64 `toml:"feedback-probability" json:"feedback-probability"`
   412  	QueryFeedbackLimit   uint    `toml:"query-feedback-limit" json:"query-feedback-limit"`
   413  	PseudoEstimateRatio  float64 `toml:"pseudo-estimate-ratio" json:"pseudo-estimate-ratio"`
   414  	ForcePriority        string  `toml:"force-priority" json:"force-priority"`
   415  	BindInfoLease        string  `toml:"bind-info-lease" json:"bind-info-lease"`
   416  	TxnEntrySizeLimit    uint64  `toml:"txn-entry-size-limit" json:"txn-entry-size-limit"`
   417  	TxnTotalSizeLimit    uint64  `toml:"txn-total-size-limit" json:"txn-total-size-limit"`
   418  	TCPKeepAlive         bool    `toml:"tcp-keep-alive" json:"tcp-keep-alive"`
   419  	CrossJoin            bool    `toml:"cross-join" json:"cross-join"`
   420  	RunAutoAnalyze       bool    `toml:"run-auto-analyze" json:"run-auto-analyze"`
   421  	DistinctAggPushDown  bool    `toml:"distinct-agg-push-down" json:"agg-push-down-join"`
   422  	CommitterConcurrency int     `toml:"committer-concurrency" json:"committer-concurrency"`
   423  	MaxTxnTTL            uint64  `toml:"max-txn-ttl" json:"max-txn-ttl"`
   424  	MemProfileInterval   string  `toml:"mem-profile-interval" json:"mem-profile-interval"`
   425  	IndexUsageSyncLease  string  `toml:"index-usage-sync-lease" json:"index-usage-sync-lease"`
   426  }
   427  
   428  // CausetCache is the CausetCache section of the config.
   429  type CausetCache struct {
   430  	Enabled  bool `toml:"enabled" json:"enabled"`
   431  	Capacity uint `toml:"capacity" json:"capacity"`
   432  	Shards   uint `toml:"shards" json:"shards"`
   433  }
   434  
   435  // TxnLocalLatches is the TxnLocalLatches section of the config.
   436  type TxnLocalLatches struct {
   437  	Enabled  bool `toml:"-" json:"-"`
   438  	Capacity uint `toml:"-" json:"-"`
   439  }
   440  
   441  // PreparedCausetCache is the PreparedCausetCache section of the config.
   442  type PreparedCausetCache struct {
   443  	Enabled          bool    `toml:"enabled" json:"enabled"`
   444  	Capacity         uint    `toml:"capacity" json:"capacity"`
   445  	MemoryGuardRatio float64 `toml:"memory-guard-ratio" json:"memory-guard-ratio"`
   446  }
   447  
   448  // OpenTracing is the opentracing section of the config.
   449  type OpenTracing struct {
   450  	Enable     bool                `toml:"enable" json:"enable"`
   451  	RPCMetrics bool                `toml:"rpc-metrics" json:"rpc-metrics"`
   452  	Sampler    OpenTracingSampler  `toml:"sampler" json:"sampler"`
   453  	Reporter   OpenTracingReporter `toml:"reporter" json:"reporter"`
   454  }
   455  
   456  // OpenTracingSampler is the config for opentracing sampler.
   457  // See https://godoc.org/github.com/uber/jaeger-client-go/config#SamplerConfig
   458  type OpenTracingSampler struct {
   459  	Type                    string        `toml:"type" json:"type"`
   460  	Param                   float64       `toml:"param" json:"param"`
   461  	SamplingServerURL       string        `toml:"sampling-server-url" json:"sampling-server-url"`
   462  	MaxOperations           int           `toml:"max-operations" json:"max-operations"`
   463  	SamplingRefreshInterval time.Duration `toml:"sampling-refresh-interval" json:"sampling-refresh-interval"`
   464  }
   465  
   466  // OpenTracingReporter is the config for opentracing reporter.
   467  // See https://godoc.org/github.com/uber/jaeger-client-go/config#ReporterConfig
   468  type OpenTracingReporter struct {
   469  	QueueSize           int           `toml:"queue-size" json:"queue-size"`
   470  	BufferFlushInterval time.Duration `toml:"buffer-flush-interval" json:"buffer-flush-interval"`
   471  	LogSpans            bool          `toml:"log-spans" json:"log-spans"`
   472  	LocalAgentHostPort  string        `toml:"local-agent-host-port" json:"local-agent-host-port"`
   473  }
   474  
   475  // ProxyProtocol is the PROXY protocol section of the config.
   476  type ProxyProtocol struct {
   477  	// PROXY protocol accepblock client networks.
   478  	// Empty string means disable PROXY protocol,
   479  	// * means all networks.
   480  	Networks string `toml:"networks" json:"networks"`
   481  	// PROXY protocol header read timeout, Unit is second.
   482  	HeaderTimeout uint `toml:"header-timeout" json:"header-timeout"`
   483  }
   484  
   485  // EinsteinDBClient is the config for einsteindb client.
   486  type EinsteinDBClient struct {
   487  	// GrpcConnectionCount is the max gRPC connections that will be established
   488  	// with each einsteindb-server.
   489  	GrpcConnectionCount uint `toml:"grpc-connection-count" json:"grpc-connection-count"`
   490  	// After a duration of this time in seconds if the client doesn't see any activity it pings
   491  	// the server to see if the transport is still alive.
   492  	GrpcKeepAliveTime uint `toml:"grpc-keepalive-time" json:"grpc-keepalive-time"`
   493  	// After having pinged for keepalive check, the client waits for a duration of Timeout in seconds
   494  	// and if no activity is seen even after that the connection is closed.
   495  	GrpcKeepAliveTimeout uint `toml:"grpc-keepalive-timeout" json:"grpc-keepalive-timeout"`
   496  	// CommitTimeout is the max time which command 'commit' will wait.
   497  	CommitTimeout string `toml:"commit-timeout" json:"commit-timeout"`
   498  	// EnableAsyncCommit enables async commit for all transactions.
   499  	EnableAsyncCommit    bool `toml:"enable-async-commit" json:"enable-async-commit"`
   500  	AsyncCommitKeysLimit uint `toml:"async-commit-keys-limit" json:"async-commit-keys-limit"`
   501  
   502  	// MaxBatchSize is the max batch size when calling batch commands API.
   503  	MaxBatchSize uint `toml:"max-batch-size" json:"max-batch-size"`
   504  	// If EinsteinDB load is greater than this, MilevaDB will wait for a while to avoid little batch.
   505  	OverloadThreshold uint `toml:"overload-threshold" json:"overload-threshold"`
   506  	// MaxBatchWaitTime in nanosecond is the max wait time for batch.
   507  	MaxBatchWaitTime time.Duration `toml:"max-batch-wait-time" json:"max-batch-wait-time"`
   508  	// BatchWaitSize is the max wait size for batch.
   509  	BatchWaitSize uint `toml:"batch-wait-size" json:"batch-wait-size"`
   510  	// EnableChunkRPC indicate the data encode in chunk format for interlock requests.
   511  	EnableChunkRPC bool `toml:"enable-chunk-rpc" json:"enable-chunk-rpc"`
   512  	// If a Region has not been accessed for more than the given duration (in seconds), it
   513  	// will be reloaded from the FIDel.
   514  	RegionCacheTTL uint `toml:"region-cache-ttl" json:"region-cache-ttl"`
   515  	// If a causetstore has been up to the limit, it will return error for successive request to
   516  	// prevent the causetstore occupying too much token in dispatching level.
   517  	StoreLimit int64 `toml:"causetstore-limit" json:"causetstore-limit"`
   518  	// StoreLivenessTimeout is the timeout for causetstore liveness check request.
   519  	StoreLivenessTimeout string           `toml:"causetstore-liveness-timeout" json:"causetstore-liveness-timeout"`
   520  	CoprCache            CoprocessorCache `toml:"copr-cache" json:"copr-cache"`
   521  	// TTLRefreshedTxnSize controls whether a transaction should uFIDelate its TTL or not.
   522  	TTLRefreshedTxnSize int64 `toml:"ttl-refreshed-txn-size" json:"ttl-refreshed-txn-size"`
   523  }
   524  
   525  // CoprocessorCache is the config for interlock cache.
   526  type CoprocessorCache struct {
   527  	// Whether to enable the copr cache. The copr cache saves the result from EinsteinDB Coprocessor in the memory and
   528  	// reuses the result when corresponding data in EinsteinDB is unchanged, on a region basis.
   529  	Enable bool `toml:"enable" json:"enable"`
   530  	// The capacity in MB of the cache.
   531  	CapacityMB float64 `toml:"capacity-mb" json:"capacity-mb"`
   532  	// Only cache requests whose result set is small.
   533  	AdmissionMaxResultMB float64 `toml:"admission-max-result-mb" json:"admission-max-result-mb"`
   534  	// Only cache requests takes noblock time to process.
   535  	AdmissionMinProcessMs uint64 `toml:"admission-min-process-ms" json:"admission-min-process-ms"`
   536  }
   537  
   538  // Binlog is the config for binlog.
   539  type Binlog struct {
   540  	Enable bool `toml:"enable" json:"enable"`
   541  	// If IgnoreError is true, when writing binlog meets error, MilevaDB would
   542  	// ignore the error.
   543  	IgnoreError  bool   `toml:"ignore-error" json:"ignore-error"`
   544  	WriteTimeout string `toml:"write-timeout" json:"write-timeout"`
   545  	// Use socket file to write binlog, for compatible with kafka version milevadb-binlog.
   546  	BinlogSocket string `toml:"binlog-socket" json:"binlog-socket"`
   547  	// The strategy for sending binlog to pump, value can be "range" or "hash" now.
   548  	Strategy string `toml:"strategy" json:"strategy"`
   549  }
   550  
   551  // Plugin is the config for plugin
   552  type Plugin struct {
   553  	Dir  string `toml:"dir" json:"dir"`
   554  	Load string `toml:"load" json:"load"`
   555  }
   556  
   557  // PessimisticTxn is the config for pessimistic transaction.
   558  type PessimisticTxn struct {
   559  	// The max count of retry for a single memex in a pessimistic transaction.
   560  	MaxRetryCount uint `toml:"max-retry-count" json:"max-retry-count"`
   561  }
   562  
   563  // StmtSummary is the config for memex summary.
   564  type StmtSummary struct {
   565  	// Enable memex summary or not.
   566  	Enable bool `toml:"enable" json:"enable"`
   567  	// Enable summary internal query.
   568  	EnableInternalQuery bool `toml:"enable-internal-query" json:"enable-internal-query"`
   569  	// The maximum number of memexs kept in memory.
   570  	MaxStmtCount uint `toml:"max-stmt-count" json:"max-stmt-count"`
   571  	// The maximum length of displayed normalized ALLEGROALLEGROSQL and sample ALLEGROALLEGROSQL.
   572  	MaxALLEGROSQLLength uint `toml:"max-allegrosql-length" json:"max-allegrosql-length"`
   573  	// The refresh interval of memex summary.
   574  	RefreshInterval int `toml:"refresh-interval" json:"refresh-interval"`
   575  	// The maximum history size of memex summary.
   576  	HistorySize int `toml:"history-size" json:"history-size"`
   577  }
   578  
   579  // IsolationRead is the config for isolation read.
   580  type IsolationRead struct {
   581  	// Engines filters milevadb-server access paths by engine type.
   582  	Engines []string `toml:"engines" json:"engines"`
   583  }
   584  
   585  // Experimental controls the features that are still experimental: their semantics, interfaces are subject to change.
   586  // Using these features in the production environment is not recommended.
   587  type Experimental struct {
   588  }
   589  
   590  var defaultConf = Config{
   591  	Host:                         DefHost,
   592  	AdvertiseAddress:             "",
   593  	Port:                         DefPort,
   594  	Cors:                         "",
   595  	CausetStore:                        "entangledstore",
   596  	Path:                         "/tmp/milevadb",
   597  	RunDBS:                       true,
   598  	SplitBlock:                   true,
   599  	Lease:                        "45s",
   600  	TokenLimit:                   1000,
   601  	OOMUseTmpStorage:             true,
   602  	TempStorageQuota:             -1,
   603  	TempStoragePath:              tempStorageDirName,
   604  	OOMCausetAction:                    OOMCausetActionCancel,
   605  	MemQuotaQuery:                1 << 30,
   606  	NestedLoopJoinCacheCapacity:  20971520,
   607  	EnableStreaming:              false,
   608  	EnableBatchDML:               false,
   609  	CheckMb4ValueInUTF8:          true,
   610  	MaxIndexLength:               3072,
   611  	AlterPrimaryKey:              false,
   612  	TreatOldVersionUTF8AsUTF8MB4: true,
   613  	EnableBlockLock:              false,
   614  	DelayCleanBlockLock:          0,
   615  	SplitRegionMaxNum:            1000,
   616  	RepairMode:                   false,
   617  	RepairBlockList:              []string{},
   618  	MaxServerConnections:         0,
   619  	TxnLocalLatches: TxnLocalLatches{
   620  		Enabled:  false,
   621  		Capacity: 0,
   622  	},
   623  	LowerCaseBlockNames: 2,
   624  	ServerVersion:       "",
   625  	Log: Log{
   626  		Level:               "info",
   627  		Format:              "text",
   628  		File:                logutil.NewFileLogConfig(logutil.DefaultLogMaxSize),
   629  		SlowQueryFile:       "milevadb-slow.log",
   630  		SlowThreshold:       logutil.DefaultSlowThreshold,
   631  		ExpensiveThreshold:  10000,
   632  		DisableErrorStack:   nbUnset,
   633  		EnableErrorStack:    nbUnset, // If both options are nbUnset, getDisableErrorStack() returns true
   634  		EnableTimestamp:     nbUnset,
   635  		DisableTimestamp:    nbUnset, // If both options are nbUnset, getDisableTimestamp() returns false
   636  		QueryLogMaxLen:      logutil.DefaultQueryLogMaxLen,
   637  		RecordCausetInSlowLog: logutil.DefaultRecordCausetInSlowLog,
   638  		EnableSlowLog:       logutil.DefaultMilevaDBEnableSlowLog,
   639  	},
   640  	Status: Status{
   641  		ReportStatus:    true,
   642  		StatusHost:      DefStatusHost,
   643  		StatusPort:      DefStatusPort,
   644  		MetricsInterval: 15,
   645  		RecordQPSbyDB:   false,
   646  	},
   647  	Performance: Performance{
   648  		MaxMemory:            0,
   649  		ServerMemoryQuota:    0,
   650  		TCPKeepAlive:         true,
   651  		CrossJoin:            true,
   652  		StatsLease:           "3s",
   653  		RunAutoAnalyze:       true,
   654  		StmtCountLimit:       5000,
   655  		FeedbackProbability:  0.05,
   656  		QueryFeedbackLimit:   512,
   657  		PseudoEstimateRatio:  0.8,
   658  		ForcePriority:        "NO_PRIORITY",
   659  		BindInfoLease:        "3s",
   660  		TxnEntrySizeLimit:    DefTxnEntrySizeLimit,
   661  		TxnTotalSizeLimit:    DefTxnTotalSizeLimit,
   662  		DistinctAggPushDown:  false,
   663  		CommitterConcurrency: 16,
   664  		MaxTxnTTL:            60 * 60 * 1000, // 1hour
   665  		MemProfileInterval:   "1m",
   666  		IndexUsageSyncLease:  "60s",
   667  	},
   668  	ProxyProtocol: ProxyProtocol{
   669  		Networks:      "",
   670  		HeaderTimeout: 5,
   671  	},
   672  	PreparedCausetCache: PreparedCausetCache{
   673  		Enabled:          false,
   674  		Capacity:         100,
   675  		MemoryGuardRatio: 0.1,
   676  	},
   677  	OpenTracing: OpenTracing{
   678  		Enable: false,
   679  		Sampler: OpenTracingSampler{
   680  			Type:  "const",
   681  			Param: 1.0,
   682  		},
   683  		Reporter: OpenTracingReporter{},
   684  	},
   685  	EinsteinDBClient: EinsteinDBClient{
   686  		GrpcConnectionCount:  4,
   687  		GrpcKeepAliveTime:    10,
   688  		GrpcKeepAliveTimeout: 3,
   689  		CommitTimeout:        "41s",
   690  		EnableAsyncCommit:    false,
   691  		AsyncCommitKeysLimit: 256,
   692  
   693  		MaxBatchSize:      128,
   694  		OverloadThreshold: 200,
   695  		MaxBatchWaitTime:  0,
   696  		BatchWaitSize:     8,
   697  
   698  		EnableChunkRPC: true,
   699  
   700  		RegionCacheTTL:       600,
   701  		StoreLimit:           0,
   702  		StoreLivenessTimeout: DefStoreLivenessTimeout,
   703  
   704  		TTLRefreshedTxnSize: 32 * 1024 * 1024,
   705  
   706  		CoprCache: CoprocessorCache{
   707  			Enable:                true,
   708  			CapacityMB:            1000,
   709  			AdmissionMaxResultMB:  10,
   710  			AdmissionMinProcessMs: 5,
   711  		},
   712  	},
   713  	Binlog: Binlog{
   714  		WriteTimeout: "15s",
   715  		Strategy:     "range",
   716  	},
   717  	PessimisticTxn: PessimisticTxn{
   718  		MaxRetryCount: 256,
   719  	},
   720  	StmtSummary: StmtSummary{
   721  		Enable:              true,
   722  		EnableInternalQuery: false,
   723  		MaxStmtCount:        200,
   724  		MaxALLEGROSQLLength:        4096,
   725  		RefreshInterval:     1800,
   726  		HistorySize:         24,
   727  	},
   728  	IsolationRead: IsolationRead{
   729  		Engines: []string{"einsteindb", "tiflash", "milevadb"},
   730  	},
   731  	Experimental:               Experimental{},
   732  	EnableDefCauslectInterDircutionInfo: true,
   733  	EnableTelemetry:            true,
   734  	Labels:                     make(map[string]string),
   735  	EnableGlobalIndex:          false,
   736  	Security: Security{
   737  		SpilledFileEncryptionMethod: SpilledFileEncryptionMethodPlaintext,
   738  	},
   739  	DeprecateIntegerDisplayWidth: false,
   740  	EnableRedactLog:              DefMilevaDBRedactLog,
   741  }
   742  
   743  var (
   744  	globalConf atomic.Value
   745  )
   746  
   747  // NewConfig creates a new config instance with default value.
   748  func NewConfig() *Config {
   749  	conf := defaultConf
   750  	return &conf
   751  }
   752  
   753  // GetGlobalConfig returns the global configuration for this server.
   754  // It should causetstore configuration from command line and configuration file.
   755  // Other parts of the system can read the global configuration use this function.
   756  func GetGlobalConfig() *Config {
   757  	return globalConf.Load().(*Config)
   758  }
   759  
   760  // StoreGlobalConfig stores a new config to the globalConf. It mostly uses in the test to avoid some data races.
   761  func StoreGlobalConfig(config *Config) {
   762  	globalConf.CausetStore(config)
   763  }
   764  
   765  var deprecatedConfig = map[string]struct{}{
   766  	"pessimistic-txn.ttl":            {},
   767  	"pessimistic-txn.enable":         {},
   768  	"log.file.log-rotate":            {},
   769  	"log.log-slow-query":             {},
   770  	"txn-local-latches":              {},
   771  	"txn-local-latches.enabled":      {},
   772  	"txn-local-latches.capacity":     {},
   773  	"performance.max-memory":         {},
   774  	"max-txn-time-use":               {},
   775  	"experimental.allow-auto-random": {},
   776  }
   777  
   778  func isAllDeprecatedConfigItems(items []string) bool {
   779  	for _, item := range items {
   780  		if _, ok := deprecatedConfig[item]; !ok {
   781  			return false
   782  		}
   783  	}
   784  	return true
   785  }
   786  
   787  // InitializeConfig initialize the global config handler.
   788  // The function enforceCmdArgs is used to merge the config file with command arguments:
   789  // For example, if you start MilevaDB by the command "./milevadb-server --port=3000", the port number should be
   790  // overwritten to 3000 and ignore the port number in the config file.
   791  func InitializeConfig(confPath string, configCheck, configStrict bool, reloadFunc ConfReloadFunc, enforceCmdArgs func(*Config)) {
   792  	cfg := GetGlobalConfig()
   793  	var err error
   794  	if confPath != "" {
   795  		if err = cfg.Load(confPath); err != nil {
   796  			// Unused config item error turns to warnings.
   797  			if tmp, ok := err.(*ErrConfigValidationFailed); ok {
   798  				// This causet is to accommodate an interim situation where strict config checking
   799  				// is not the default behavior of MilevaDB. The warning message must be deferred until
   800  				// logging has been set up. After strict config checking is the default behavior,
   801  				// This should all be removed.
   802  				if (!configCheck && !configStrict) || isAllDeprecatedConfigItems(tmp.UndecodedItems) {
   803  					fmt.Fprintln(os.Stderr, err.Error())
   804  					err = nil
   805  				}
   806  			}
   807  		}
   808  
   809  		terror.MustNil(err)
   810  	} else {
   811  		// configCheck should have the config file specified.
   812  		if configCheck {
   813  			fmt.Fprintln(os.Stderr, "config check failed", errors.New("no config file specified for config-check"))
   814  			os.Exit(1)
   815  		}
   816  	}
   817  	enforceCmdArgs(cfg)
   818  
   819  	if err := cfg.Valid(); err != nil {
   820  		if !filepath.IsAbs(confPath) {
   821  			if tmp, err := filepath.Abs(confPath); err == nil {
   822  				confPath = tmp
   823  			}
   824  		}
   825  		fmt.Fprintln(os.Stderr, "load config file:", confPath)
   826  		fmt.Fprintln(os.Stderr, "invalid config", err)
   827  		os.Exit(1)
   828  	}
   829  	if configCheck {
   830  		fmt.Println("config check successful")
   831  		os.Exit(0)
   832  	}
   833  	StoreGlobalConfig(cfg)
   834  }
   835  
   836  // Load loads config options from a toml file.
   837  func (c *Config) Load(confFile string) error {
   838  	spacetimeData, err := toml.DecodeFile(confFile, c)
   839  	if c.TokenLimit == 0 {
   840  		c.TokenLimit = 1000
   841  	}
   842  	if len(c.ServerVersion) > 0 {
   843  		allegrosql.ServerVersion = c.ServerVersion
   844  	}
   845  	// If any items in confFile file are not mapped into the Config struct, issue
   846  	// an error and stop the server from starting.
   847  	undecoded := spacetimeData.Undecoded()
   848  	if len(undecoded) > 0 && err == nil {
   849  		var undecodedItems []string
   850  		for _, item := range undecoded {
   851  			undecodedItems = append(undecodedItems, item.String())
   852  		}
   853  		err = &ErrConfigValidationFailed{confFile, undecodedItems}
   854  	}
   855  
   856  	return err
   857  }
   858  
   859  // Valid checks if this config is valid.
   860  func (c *Config) Valid() error {
   861  	if c.Log.EnableErrorStack == c.Log.DisableErrorStack && c.Log.EnableErrorStack != nbUnset {
   862  		logutil.BgLogger().Warn(fmt.Sprintf("\"enable-error-stack\" (%v) conflicts \"disable-error-stack\" (%v). \"disable-error-stack\" is deprecated, please use \"enable-error-stack\" instead. disable-error-stack is ignored.", c.Log.EnableErrorStack, c.Log.DisableErrorStack))
   863  		// if two options conflict, we will use the value of EnableErrorStack
   864  		c.Log.DisableErrorStack = nbUnset
   865  	}
   866  	if c.Log.EnableTimestamp == c.Log.DisableTimestamp && c.Log.EnableTimestamp != nbUnset {
   867  		logutil.BgLogger().Warn(fmt.Sprintf("\"enable-timestamp\" (%v) conflicts \"disable-timestamp\" (%v). \"disable-timestamp\" is deprecated, please use \"enable-timestamp\" instead", c.Log.EnableTimestamp, c.Log.DisableTimestamp))
   868  		// if two options conflict, we will use the value of EnableTimestamp
   869  		c.Log.DisableTimestamp = nbUnset
   870  	}
   871  	if c.Security.SkipGrantBlock && !hasRootPrivilege() {
   872  		return fmt.Errorf("MilevaDB run with skip-grant-causet need root privilege")
   873  	}
   874  	if _, ok := ValidStorage[c.CausetStore]; !ok {
   875  		nameList := make([]string, 0, len(ValidStorage))
   876  		for k, v := range ValidStorage {
   877  			if v {
   878  				nameList = append(nameList, k)
   879  			}
   880  		}
   881  		return fmt.Errorf("invalid causetstore=%s, valid storages=%v", c.CausetStore, nameList)
   882  	}
   883  	if c.CausetStore == "mockeinsteindb" && !c.RunDBS {
   884  		return fmt.Errorf("can't disable DBS on mockeinsteindb")
   885  	}
   886  	if c.MaxIndexLength < DefMaxIndexLength || c.MaxIndexLength > DefMaxOfMaxIndexLength {
   887  		return fmt.Errorf("max-index-length should be [%d, %d]", DefMaxIndexLength, DefMaxOfMaxIndexLength)
   888  	}
   889  	if c.Log.File.MaxSize > MaxLogFileSize {
   890  		return fmt.Errorf("invalid max log file size=%v which is larger than max=%v", c.Log.File.MaxSize, MaxLogFileSize)
   891  	}
   892  	c.OOMCausetAction = strings.ToLower(c.OOMCausetAction)
   893  	if c.OOMCausetAction != OOMCausetActionLog && c.OOMCausetAction != OOMCausetActionCancel {
   894  		return fmt.Errorf("unsupported OOMCausetAction %v, MilevaDB only supports [%v, %v]", c.OOMCausetAction, OOMCausetActionLog, OOMCausetActionCancel)
   895  	}
   896  
   897  	// lower_case_block_names is allowed to be 0, 1, 2
   898  	if c.LowerCaseBlockNames < 0 || c.LowerCaseBlockNames > 2 {
   899  		return fmt.Errorf("lower-case-causet-names should be 0 or 1 or 2")
   900  	}
   901  
   902  	if c.TxnLocalLatches.Enabled && c.TxnLocalLatches.Capacity == 0 {
   903  		return fmt.Errorf("txn-local-latches.capacity can not be 0")
   904  	}
   905  
   906  	// For einsteindbclient.
   907  	if c.EinsteinDBClient.GrpcConnectionCount == 0 {
   908  		return fmt.Errorf("grpc-connection-count should be greater than 0")
   909  	}
   910  
   911  	if c.Performance.TxnTotalSizeLimit > 10<<30 {
   912  		return fmt.Errorf("txn-total-size-limit should be less than %d", 10<<30)
   913  	}
   914  
   915  	if c.StmtSummary.MaxStmtCount <= 0 {
   916  		return fmt.Errorf("max-stmt-count in [stmt-summary] should be greater than 0")
   917  	}
   918  	if c.StmtSummary.HistorySize < 0 {
   919  		return fmt.Errorf("history-size in [stmt-summary] should be greater than or equal to 0")
   920  	}
   921  	if c.StmtSummary.RefreshInterval <= 0 {
   922  		return fmt.Errorf("refresh-interval in [stmt-summary] should be greater than 0")
   923  	}
   924  
   925  	if c.PreparedCausetCache.Capacity < 1 {
   926  		return fmt.Errorf("capacity in [prepared-plan-cache] should be at least 1")
   927  	}
   928  	if c.PreparedCausetCache.MemoryGuardRatio < 0 || c.PreparedCausetCache.MemoryGuardRatio > 1 {
   929  		return fmt.Errorf("memory-guard-ratio in [prepared-plan-cache] must be NOT less than 0 and more than 1")
   930  	}
   931  	if len(c.IsolationRead.Engines) < 1 {
   932  		return fmt.Errorf("the number of [isolation-read]engines for isolation read should be at least 1")
   933  	}
   934  	for _, engine := range c.IsolationRead.Engines {
   935  		if engine != "milevadb" && engine != "einsteindb" && engine != "tiflash" {
   936  			return fmt.Errorf("type of [isolation-read]engines can't be %v should be one of milevadb or einsteindb or tiflash", engine)
   937  		}
   938  	}
   939  
   940  	// test security
   941  	c.Security.SpilledFileEncryptionMethod = strings.ToLower(c.Security.SpilledFileEncryptionMethod)
   942  	switch c.Security.SpilledFileEncryptionMethod {
   943  	case SpilledFileEncryptionMethodPlaintext, SpilledFileEncryptionMethodAES128CTR:
   944  	default:
   945  		return fmt.Errorf("unsupported [security]spilled-file-encryption-method %v, MilevaDB only supports [%v, %v]",
   946  			c.Security.SpilledFileEncryptionMethod, SpilledFileEncryptionMethodPlaintext, SpilledFileEncryptionMethodAES128CTR)
   947  	}
   948  
   949  	// test log level
   950  	l := zap.NewAtomicLevel()
   951  	return l.UnmarshalText([]byte(c.Log.Level))
   952  }
   953  
   954  // UFIDelateGlobal uFIDelates the global config, and provide a restore function that can be used to restore to the original.
   955  func UFIDelateGlobal(f func(conf *Config)) {
   956  	g := GetGlobalConfig()
   957  	newConf := *g
   958  	f(&newConf)
   959  	StoreGlobalConfig(&newConf)
   960  }
   961  
   962  // RestoreFunc gets a function that restore the config to the current value.
   963  func RestoreFunc() (restore func()) {
   964  	g := GetGlobalConfig()
   965  	return func() {
   966  		StoreGlobalConfig(g)
   967  	}
   968  }
   969  
   970  func hasRootPrivilege() bool {
   971  	return os.Geteuid() == 0
   972  }
   973  
   974  // BlockLockEnabled uses to check whether enabled the causet dagger feature.
   975  func BlockLockEnabled() bool {
   976  	return GetGlobalConfig().EnableBlockLock
   977  }
   978  
   979  // BlockLockDelayClean uses to get the time of delay clean causet dagger.
   980  var BlockLockDelayClean = func() uint64 {
   981  	return GetGlobalConfig().DelayCleanBlockLock
   982  }
   983  
   984  // RedactLogEnabled uses to check whether enabled the log redact.
   985  func RedactLogEnabled() bool {
   986  	return atomic.LoadInt32(&GetGlobalConfig().EnableRedactLog) == 1
   987  }
   988  
   989  // SetRedactLog uses to set log redact status.
   990  func SetRedactLog(enable bool) {
   991  	value := int32(0)
   992  	if enable {
   993  		value = 1
   994  	}
   995  	g := GetGlobalConfig()
   996  	newConf := *g
   997  	newConf.EnableRedactLog = value
   998  	StoreGlobalConfig(&newConf)
   999  }
  1000  
  1001  // ToLogConfig converts *Log to *logutil.LogConfig.
  1002  func (l *Log) ToLogConfig() *logutil.LogConfig {
  1003  	return logutil.NewLogConfig(l.Level, l.Format, l.SlowQueryFile, l.File, l.getDisableTimestamp(), func(config *zaplog.Config) { config.DisableErrorVerbose = l.getDisableErrorStack() })
  1004  }
  1005  
  1006  // ToTracingConfig converts *OpenTracing to *tracing.Configuration.
  1007  func (t *OpenTracing) ToTracingConfig() *tracing.Configuration {
  1008  	ret := &tracing.Configuration{
  1009  		Disabled:   !t.Enable,
  1010  		RPCMetrics: t.RPCMetrics,
  1011  		Reporter:   &tracing.ReporterConfig{},
  1012  		Sampler:    &tracing.SamplerConfig{},
  1013  	}
  1014  	ret.Reporter.QueueSize = t.Reporter.QueueSize
  1015  	ret.Reporter.BufferFlushInterval = t.Reporter.BufferFlushInterval
  1016  	ret.Reporter.LogSpans = t.Reporter.LogSpans
  1017  	ret.Reporter.LocalAgentHostPort = t.Reporter.LocalAgentHostPort
  1018  
  1019  	ret.Sampler.Type = t.Sampler.Type
  1020  	ret.Sampler.Param = t.Sampler.Param
  1021  	ret.Sampler.SamplingServerURL = t.Sampler.SamplingServerURL
  1022  	ret.Sampler.MaxOperations = t.Sampler.MaxOperations
  1023  	ret.Sampler.SamplingRefreshInterval = t.Sampler.SamplingRefreshInterval
  1024  	return ret
  1025  }
  1026  
  1027  func init() {
  1028  	initByLDFlags(versioninfo.MilevaDBEdition, checkBeforeDropLDFlag)
  1029  }
  1030  
  1031  func initByLDFlags(edition, checkBeforeDropLDFlag string) {
  1032  	if edition != versioninfo.CommunityEdition {
  1033  		defaultConf.EnableTelemetry = false
  1034  	}
  1035  	conf := defaultConf
  1036  	StoreGlobalConfig(&conf)
  1037  	if checkBeforeDropLDFlag == "1" {
  1038  		CheckBlockBeforeDrop = true
  1039  	}
  1040  }
  1041  
  1042  // The following constants represents the valid action configurations for OOMCausetAction.
  1043  // NOTE: Although the values is case insensitive, we should use lower-case
  1044  // strings because the configuration value will be transformed to lower-case
  1045  // string and compared with these constants in the further usage.
  1046  const (
  1047  	OOMCausetActionCancel = "cancel"
  1048  	OOMCausetActionLog    = "log"
  1049  )
  1050  
  1051  // ParsePath parses this path.
  1052  func ParsePath(path string) (etcdAddrs []string, disableGC bool, err error) {
  1053  	var u *url.URL
  1054  	u, err = url.Parse(path)
  1055  	if err != nil {
  1056  		err = errors.Trace(err)
  1057  		return
  1058  	}
  1059  	if strings.ToLower(u.Scheme) != "einsteindb" {
  1060  		err = errors.Errorf("Uri scheme expected [einsteindb] but found [%s]", u.Scheme)
  1061  		logutil.BgLogger().Error("parsePath error", zap.Error(err))
  1062  		return
  1063  	}
  1064  	switch strings.ToLower(u.Query().Get("disableGC")) {
  1065  	case "true":
  1066  		disableGC = true
  1067  	case "false", "":
  1068  	default:
  1069  		err = errors.New("disableGC flag should be true/false")
  1070  		return
  1071  	}
  1072  	etcdAddrs = strings.Split(u.Host, ",")
  1073  	return
  1074  }