github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/milevadb-server/main.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 main
    15  
    16  import (
    17  	"context"
    18  	"flag"
    19  	"fmt"
    20  	"io/ioutil"
    21  	"os"
    22  	"runtime"
    23  	"strconv"
    24  	"strings"
    25  	"sync/atomic"
    26  	"time"
    27  
    28  	fidel "github.com/einsteindb/fidel/client"
    29  	"github.com/opentracing/opentracing-go"
    30  	"github.com/prometheus/client_golang/prometheus"
    31  	"github.com/prometheus/client_golang/prometheus/push"
    32  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    33  	"github.com/whtcorpsinc/BerolinaSQL/terror"
    34  	BerolinaSQLtypes "github.com/whtcorpsinc/BerolinaSQL/types"
    35  	"github.com/whtcorpsinc/errors"
    36  	"github.com/whtcorpsinc/log"
    37  	pumpcli "github.com/whtcorpsinc/milevadb-tools/milevadb-binlog/pump_client"
    38  	"github.com/whtcorpsinc/milevadb/bindinfo"
    39  	causetembedded "github.com/whtcorpsinc/milevadb/causet/embedded"
    40  	ekvstore "github.com/whtcorpsinc/milevadb/causetstore"
    41  	"github.com/whtcorpsinc/milevadb/causetstore/einsteindb"
    42  	"github.com/whtcorpsinc/milevadb/causetstore/einsteindb/gcworker"
    43  	"github.com/whtcorpsinc/milevadb/causetstore/mockstore"
    44  	"github.com/whtcorpsinc/milevadb/config"
    45  	"github.com/whtcorpsinc/milevadb/dbs"
    46  	"github.com/whtcorpsinc/milevadb/ekv"
    47  	"github.com/whtcorpsinc/milevadb/interlock"
    48  	"github.com/whtcorpsinc/milevadb/metrics"
    49  	"github.com/whtcorpsinc/milevadb/petri"
    50  	"github.com/whtcorpsinc/milevadb/plugin"
    51  	"github.com/whtcorpsinc/milevadb/privilege/privileges"
    52  	"github.com/whtcorpsinc/milevadb/server"
    53  	"github.com/whtcorpsinc/milevadb/soliton"
    54  	"github.com/whtcorpsinc/milevadb/soliton/disk"
    55  	"github.com/whtcorpsinc/milevadb/soliton/ekvcache"
    56  	"github.com/whtcorpsinc/milevadb/soliton/logutil"
    57  	"github.com/whtcorpsinc/milevadb/soliton/memory"
    58  	"github.com/whtcorpsinc/milevadb/soliton/petriutil"
    59  	"github.com/whtcorpsinc/milevadb/soliton/printer"
    60  	"github.com/whtcorpsinc/milevadb/soliton/profile"
    61  	"github.com/whtcorpsinc/milevadb/soliton/signal"
    62  	"github.com/whtcorpsinc/milevadb/soliton/storeutil"
    63  	"github.com/whtcorpsinc/milevadb/soliton/sys/linux"
    64  	storageSys "github.com/whtcorpsinc/milevadb/soliton/sys/storage"
    65  	"github.com/whtcorpsinc/milevadb/soliton/systimemon"
    66  	"github.com/whtcorpsinc/milevadb/statistics"
    67  	"github.com/whtcorpsinc/milevadb/stochastik"
    68  	"github.com/whtcorpsinc/milevadb/stochastikctx/binloginfo"
    69  	"github.com/whtcorpsinc/milevadb/stochastikctx/variable"
    70  	"go.uber.org/automaxprocs/maxprocs"
    71  	"go.uber.org/zap"
    72  	"google.golang.org/grpc/grpclog"
    73  )
    74  
    75  // Flag Names
    76  const (
    77  	nmVersion                = "V"
    78  	nmConfig                 = "config"
    79  	nmConfigCheck            = "config-check"
    80  	nmConfigStrict           = "config-strict"
    81  	nmStore                  = "causetstore"
    82  	nmStorePath              = "path"
    83  	nmHost                   = "host"
    84  	nmAdvertiseAddress       = "advertise-address"
    85  	nmPort                   = "P"
    86  	nmCors                   = "cors"
    87  	nmSocket                 = "socket"
    88  	nmEnableBinlog           = "enable-binlog"
    89  	nmRunDBS                 = "run-dbs"
    90  	nmLogLevel               = "L"
    91  	nmLogFile                = "log-file"
    92  	nmLogSlowQuery           = "log-slow-query"
    93  	nmReportStatus           = "report-status"
    94  	nmStatusHost             = "status-host"
    95  	nmStatusPort             = "status"
    96  	nmMetricsAddr            = "metrics-addr"
    97  	nmMetricsInterval        = "metrics-interval"
    98  	nmDdlLease               = "lease"
    99  	nmTokenLimit             = "token-limit"
   100  	nmPluginDir              = "plugin-dir"
   101  	nmPluginLoad             = "plugin-load"
   102  	nmRepairMode             = "repair-mode"
   103  	nmRepairList             = "repair-list"
   104  	nmRequireSecureTransport = "require-secure-transport"
   105  
   106  	nmProxyProtocolNetworks      = "proxy-protocol-networks"
   107  	nmProxyProtocolHeaderTimeout = "proxy-protocol-header-timeout"
   108  	nmAffinityCPU                = "affinity-cpus"
   109  )
   110  
   111  var (
   112  	version      = flagBoolean(nmVersion, false, "print version information and exit")
   113  	configPath   = flag.String(nmConfig, "", "config file path")
   114  	configCheck  = flagBoolean(nmConfigCheck, false, "check config file validity and exit")
   115  	configStrict = flagBoolean(nmConfigStrict, false, "enforce config file validity")
   116  
   117  	// Base
   118  	causetstore      = flag.String(nmStore, "entangledstore", "registered causetstore name, [einsteindb, mockeinsteindb, entangledstore]")
   119  	storePath        = flag.String(nmStorePath, "/tmp/milevadb", "milevadb storage path")
   120  	host             = flag.String(nmHost, "0.0.0.0", "milevadb server host")
   121  	advertiseAddress = flag.String(nmAdvertiseAddress, "", "milevadb server advertise IP")
   122  	port             = flag.String(nmPort, "4000", "milevadb server port")
   123  	cors             = flag.String(nmCors, "", "milevadb server allow cors origin")
   124  	socket           = flag.String(nmSocket, "", "The socket file to use for connection.")
   125  	enableBinlog     = flagBoolean(nmEnableBinlog, false, "enable generate binlog")
   126  	runDBS           = flagBoolean(nmRunDBS, true, "run dbs worker on this milevadb-server")
   127  	dbsLease         = flag.String(nmDdlLease, "45s", "schemaReplicant lease duration, very dangerous to change only if you know what you do")
   128  	tokenLimit       = flag.Int(nmTokenLimit, 1000, "the limit of concurrent executed stochastik")
   129  	pluginDir        = flag.String(nmPluginDir, "/data/deploy/plugin", "the folder that hold plugin")
   130  	pluginLoad       = flag.String(nmPluginLoad, "", "wait load plugin name(separated by comma)")
   131  	affinityCPU      = flag.String(nmAffinityCPU, "", "affinity cpu (cpu-no. separated by comma, e.g. 1,2,3)")
   132  	repairMode       = flagBoolean(nmRepairMode, false, "enable admin repair mode")
   133  	repairList       = flag.String(nmRepairList, "", "admin repair causet list")
   134  	requireTLS       = flag.Bool(nmRequireSecureTransport, false, "require client use secure transport")
   135  
   136  	// Log
   137  	logLevel     = flag.String(nmLogLevel, "info", "log level: info, debug, warn, error, fatal")
   138  	logFile      = flag.String(nmLogFile, "", "log file path")
   139  	logSlowQuery = flag.String(nmLogSlowQuery, "", "slow query file path")
   140  
   141  	// Status
   142  	reportStatus    = flagBoolean(nmReportStatus, true, "If enable status report HTTP service.")
   143  	statusHost      = flag.String(nmStatusHost, "0.0.0.0", "milevadb server status host")
   144  	statusPort      = flag.String(nmStatusPort, "10080", "milevadb server status port")
   145  	metricsAddr     = flag.String(nmMetricsAddr, "", "prometheus pushgateway address, leaves it empty will disable prometheus push.")
   146  	metricsInterval = flag.Uint(nmMetricsInterval, 15, "prometheus client push interval in second, set \"0\" to disable prometheus push.")
   147  
   148  	// PROXY Protocol
   149  	proxyProtocolNetworks      = flag.String(nmProxyProtocolNetworks, "", "proxy protocol networks allowed IP or *, empty mean disable proxy protocol support")
   150  	proxyProtocolHeaderTimeout = flag.Uint(nmProxyProtocolHeaderTimeout, 5, "proxy protocol header read timeout, unit is second.")
   151  )
   152  
   153  var (
   154  	storage  ekv.CausetStorage
   155  	dom      *petri.Petri
   156  	svr      *server.Server
   157  	graceful bool
   158  )
   159  
   160  func main() {
   161  	flag.Parse()
   162  	if *version {
   163  		fmt.Println(printer.GetMilevaDBInfo())
   164  		os.Exit(0)
   165  	}
   166  	registerStores()
   167  	registerMetrics()
   168  	config.InitializeConfig(*configPath, *configCheck, *configStrict, reloadConfig, overrideConfig)
   169  	if config.GetGlobalConfig().OOMUseTmpStorage {
   170  		config.GetGlobalConfig().UFIDelateTempStoragePath()
   171  		err := disk.InitializeTemFIDelir()
   172  		terror.MustNil(err)
   173  		checkTempStorageQuota()
   174  	}
   175  	setGlobalVars()
   176  	setCPUAffinity()
   177  	setupLog()
   178  	setHeapProfileTracker()
   179  	setupTracing() // Should before createServer and after setup config.
   180  	printInfo()
   181  	setupBinlogClient()
   182  	setupMetrics()
   183  	createStoreAndPetri()
   184  	createServer()
   185  	signal.SetupSignalHandler(serverShutdown)
   186  	runServer()
   187  	cleanup()
   188  	syncLog()
   189  }
   190  
   191  func exit() {
   192  	syncLog()
   193  	os.Exit(0)
   194  }
   195  
   196  func syncLog() {
   197  	if err := log.Sync(); err != nil {
   198  		fmt.Fprintln(os.Stderr, "sync log err:", err)
   199  		os.Exit(1)
   200  	}
   201  }
   202  
   203  func checkTempStorageQuota() {
   204  	// check capacity and the quota when OOMUseTmpStorage is enabled
   205  	c := config.GetGlobalConfig()
   206  	if c.TempStorageQuota < 0 {
   207  		// means unlimited, do nothing
   208  	} else {
   209  		capacityByte, err := storageSys.GetTargetDirectoryCapacity(c.TempStoragePath)
   210  		if err != nil {
   211  			log.Fatal(err.Error())
   212  		} else if capacityByte < uint64(c.TempStorageQuota) {
   213  			log.Fatal(fmt.Sprintf("value of [tmp-storage-quota](%d byte) exceeds the capacity(%d byte) of the [%s] directory", c.TempStorageQuota, capacityByte, c.TempStoragePath))
   214  		}
   215  	}
   216  }
   217  
   218  func setCPUAffinity() {
   219  	if affinityCPU == nil || len(*affinityCPU) == 0 {
   220  		return
   221  	}
   222  	var cpu []int
   223  	for _, af := range strings.Split(*affinityCPU, ",") {
   224  		af = strings.TrimSpace(af)
   225  		if len(af) > 0 {
   226  			c, err := strconv.Atoi(af)
   227  			if err != nil {
   228  				fmt.Fprintf(os.Stderr, "wrong affinity cpu config: %s", *affinityCPU)
   229  				exit()
   230  			}
   231  			cpu = append(cpu, c)
   232  		}
   233  	}
   234  	err := linux.SetAffinity(cpu)
   235  	if err != nil {
   236  		fmt.Fprintf(os.Stderr, "set cpu affinity failure: %v", err)
   237  		exit()
   238  	}
   239  	runtime.GOMAXPROCS(len(cpu))
   240  	metrics.MaxProcs.Set(float64(runtime.GOMAXPROCS(0)))
   241  }
   242  
   243  func setHeapProfileTracker() {
   244  	c := config.GetGlobalConfig()
   245  	d := parseDuration(c.Performance.MemProfileInterval)
   246  	go profile.HeapProfileForGlobalMemTracker(d)
   247  }
   248  
   249  func registerStores() {
   250  	err := ekvstore.Register("einsteindb", einsteindb.Driver{})
   251  	terror.MustNil(err)
   252  	einsteindb.NewGCHandlerFunc = gcworker.NewGCWorker
   253  	err = ekvstore.Register("mockeinsteindb", mockstore.MockEinsteinDBDriver{})
   254  	terror.MustNil(err)
   255  	err = ekvstore.Register("entangledstore", mockstore.EmbedEntangledStoreDriver{})
   256  	terror.MustNil(err)
   257  }
   258  
   259  func registerMetrics() {
   260  	metrics.RegisterMetrics()
   261  }
   262  
   263  func createStoreAndPetri() {
   264  	cfg := config.GetGlobalConfig()
   265  	fullPath := fmt.Sprintf("%s://%s", cfg.CausetStore, cfg.Path)
   266  	var err error
   267  	storage, err = ekvstore.New(fullPath)
   268  	terror.MustNil(err)
   269  	// Bootstrap a stochastik to load information schemaReplicant.
   270  	dom, err = stochastik.BootstrapStochastik(storage)
   271  	terror.MustNil(err)
   272  }
   273  
   274  func setupBinlogClient() {
   275  	cfg := config.GetGlobalConfig()
   276  	if !cfg.Binlog.Enable {
   277  		return
   278  	}
   279  
   280  	if cfg.Binlog.IgnoreError {
   281  		binloginfo.SetIgnoreError(true)
   282  	}
   283  
   284  	var (
   285  		client *pumpcli.PumpsClient
   286  		err    error
   287  	)
   288  
   289  	securityOption := fidel.SecurityOption{
   290  		CAPath:   cfg.Security.ClusterSSLCA,
   291  		CertPath: cfg.Security.ClusterSSLCert,
   292  		KeyPath:  cfg.Security.ClusterSSLKey,
   293  	}
   294  
   295  	if len(cfg.Binlog.BinlogSocket) == 0 {
   296  		client, err = pumpcli.NewPumpsClient(cfg.Path, cfg.Binlog.Strategy, parseDuration(cfg.Binlog.WriteTimeout), securityOption)
   297  	} else {
   298  		client, err = pumpcli.NewLocalPumpsClient(cfg.Path, cfg.Binlog.BinlogSocket, parseDuration(cfg.Binlog.WriteTimeout), securityOption)
   299  	}
   300  
   301  	terror.MustNil(err)
   302  
   303  	err = pumpcli.InitLogger(cfg.Log.ToLogConfig())
   304  	terror.MustNil(err)
   305  
   306  	binloginfo.SetPumpsClient(client)
   307  	log.Info("milevadb-server", zap.Bool("create pumps client success, ignore binlog error", cfg.Binlog.IgnoreError))
   308  }
   309  
   310  // Prometheus push.
   311  const zeroDuration = time.Duration(0)
   312  
   313  // pushMetric pushes metrics in background.
   314  func pushMetric(addr string, interval time.Duration) {
   315  	if interval == zeroDuration || len(addr) == 0 {
   316  		log.Info("disable Prometheus push client")
   317  		return
   318  	}
   319  	log.Info("start prometheus push client", zap.String("server addr", addr), zap.String("interval", interval.String()))
   320  	go prometheusPushClient(addr, interval)
   321  }
   322  
   323  // prometheusPushClient pushes metrics to Prometheus Pushgateway.
   324  func prometheusPushClient(addr string, interval time.Duration) {
   325  	// TODO: MilevaDB do not have uniq name, so we use host+port to compose a name.
   326  	job := "milevadb"
   327  	pusher := push.New(addr, job)
   328  	pusher = pusher.Gatherer(prometheus.DefaultGatherer)
   329  	pusher = pusher.Grouping("instance", instanceName())
   330  	for {
   331  		err := pusher.Push()
   332  		if err != nil {
   333  			log.Error("could not push metrics to prometheus pushgateway", zap.String("err", err.Error()))
   334  		}
   335  		time.Sleep(interval)
   336  	}
   337  }
   338  
   339  func instanceName() string {
   340  	cfg := config.GetGlobalConfig()
   341  	hostname, err := os.Hostname()
   342  	if err != nil {
   343  		return "unknown"
   344  	}
   345  	return fmt.Sprintf("%s_%d", hostname, cfg.Port)
   346  }
   347  
   348  // parseDuration parses lease argument string.
   349  func parseDuration(lease string) time.Duration {
   350  	dur, err := time.ParseDuration(lease)
   351  	if err != nil {
   352  		dur, err = time.ParseDuration(lease + "s")
   353  	}
   354  	if err != nil || dur < 0 {
   355  		log.Fatal("invalid lease duration", zap.String("lease", lease))
   356  	}
   357  	return dur
   358  }
   359  
   360  func flagBoolean(name string, defaultVal bool, usage string) *bool {
   361  	if !defaultVal {
   362  		// Fix #4125, golang do not print default false value in usage, so we append it.
   363  		usage = fmt.Sprintf("%s (default false)", usage)
   364  		return flag.Bool(name, defaultVal, usage)
   365  	}
   366  	return flag.Bool(name, defaultVal, usage)
   367  }
   368  
   369  func reloadConfig(nc, c *config.Config) {
   370  	// Just a part of config items need to be reload explicitly.
   371  	// Some of them like OOMCausetAction are always used by getting from global config directly
   372  	// like config.GetGlobalConfig().OOMCausetAction.
   373  	// These config items will become available naturally after the global config pointer
   374  	// is uFIDelated in function ReloadGlobalConfig.
   375  	if nc.Performance.ServerMemoryQuota != c.Performance.ServerMemoryQuota {
   376  		causetembedded.PreparedCausetCacheMaxMemory.CausetStore(nc.Performance.ServerMemoryQuota)
   377  	}
   378  	if nc.Performance.CrossJoin != c.Performance.CrossJoin {
   379  		causetembedded.AllowCartesianProduct.CausetStore(nc.Performance.CrossJoin)
   380  	}
   381  	if nc.Performance.FeedbackProbability != c.Performance.FeedbackProbability {
   382  		statistics.FeedbackProbability.CausetStore(nc.Performance.FeedbackProbability)
   383  	}
   384  	if nc.Performance.QueryFeedbackLimit != c.Performance.QueryFeedbackLimit {
   385  		statistics.MaxQueryFeedbackCount.CausetStore(int64(nc.Performance.QueryFeedbackLimit))
   386  	}
   387  	if nc.Performance.PseudoEstimateRatio != c.Performance.PseudoEstimateRatio {
   388  		statistics.RatioOfPseudoEstimate.CausetStore(nc.Performance.PseudoEstimateRatio)
   389  	}
   390  	if nc.Performance.MaxProcs != c.Performance.MaxProcs {
   391  		runtime.GOMAXPROCS(int(nc.Performance.MaxProcs))
   392  		metrics.MaxProcs.Set(float64(runtime.GOMAXPROCS(0)))
   393  	}
   394  	if nc.EinsteinDBClient.StoreLimit != c.EinsteinDBClient.StoreLimit {
   395  		storeutil.StoreLimit.CausetStore(nc.EinsteinDBClient.StoreLimit)
   396  	}
   397  
   398  	if nc.PreparedCausetCache.Enabled != c.PreparedCausetCache.Enabled {
   399  		causetembedded.SetPreparedCausetCache(nc.PreparedCausetCache.Enabled)
   400  	}
   401  	if nc.Log.Level != c.Log.Level {
   402  		if err := logutil.SetLevel(nc.Log.Level); err != nil {
   403  			logutil.BgLogger().Error("uFIDelate log level error", zap.Error(err))
   404  		}
   405  	}
   406  }
   407  
   408  // overrideConfig considers command arguments and overrides some config items in the Config.
   409  func overrideConfig(cfg *config.Config) {
   410  	actualFlags := make(map[string]bool)
   411  	flag.Visit(func(f *flag.Flag) {
   412  		actualFlags[f.Name] = true
   413  	})
   414  
   415  	// Base
   416  	if actualFlags[nmHost] {
   417  		cfg.Host = *host
   418  	}
   419  	if actualFlags[nmAdvertiseAddress] {
   420  		cfg.AdvertiseAddress = *advertiseAddress
   421  	}
   422  	if len(cfg.AdvertiseAddress) == 0 {
   423  		cfg.AdvertiseAddress = soliton.GetLocalIP()
   424  	}
   425  	if len(cfg.AdvertiseAddress) == 0 {
   426  		cfg.AdvertiseAddress = cfg.Host
   427  	}
   428  	var err error
   429  	if actualFlags[nmPort] {
   430  		var p int
   431  		p, err = strconv.Atoi(*port)
   432  		terror.MustNil(err)
   433  		cfg.Port = uint(p)
   434  	}
   435  	if actualFlags[nmCors] {
   436  		fmt.Println(cors)
   437  		cfg.Cors = *cors
   438  	}
   439  	if actualFlags[nmStore] {
   440  		cfg.CausetStore = *causetstore
   441  	}
   442  	if actualFlags[nmStorePath] {
   443  		cfg.Path = *storePath
   444  	}
   445  	if actualFlags[nmSocket] {
   446  		cfg.Socket = *socket
   447  	}
   448  	if actualFlags[nmEnableBinlog] {
   449  		cfg.Binlog.Enable = *enableBinlog
   450  	}
   451  	if actualFlags[nmRunDBS] {
   452  		cfg.RunDBS = *runDBS
   453  	}
   454  	if actualFlags[nmDdlLease] {
   455  		cfg.Lease = *dbsLease
   456  	}
   457  	if actualFlags[nmTokenLimit] {
   458  		cfg.TokenLimit = uint(*tokenLimit)
   459  	}
   460  	if actualFlags[nmPluginLoad] {
   461  		cfg.Plugin.Load = *pluginLoad
   462  	}
   463  	if actualFlags[nmPluginDir] {
   464  		cfg.Plugin.Dir = *pluginDir
   465  	}
   466  	if actualFlags[nmRequireSecureTransport] {
   467  		cfg.Security.RequireSecureTransport = *requireTLS
   468  	}
   469  	if actualFlags[nmRepairMode] {
   470  		cfg.RepairMode = *repairMode
   471  	}
   472  	if actualFlags[nmRepairList] {
   473  		if cfg.RepairMode {
   474  			cfg.RepairTableList = stringToList(*repairList)
   475  		}
   476  	}
   477  
   478  	// Log
   479  	if actualFlags[nmLogLevel] {
   480  		cfg.Log.Level = *logLevel
   481  	}
   482  	if actualFlags[nmLogFile] {
   483  		cfg.Log.File.Filename = *logFile
   484  	}
   485  	if actualFlags[nmLogSlowQuery] {
   486  		cfg.Log.SlowQueryFile = *logSlowQuery
   487  	}
   488  
   489  	// Status
   490  	if actualFlags[nmReportStatus] {
   491  		cfg.Status.ReportStatus = *reportStatus
   492  	}
   493  	if actualFlags[nmStatusHost] {
   494  		cfg.Status.StatusHost = *statusHost
   495  	}
   496  	if actualFlags[nmStatusPort] {
   497  		var p int
   498  		p, err = strconv.Atoi(*statusPort)
   499  		terror.MustNil(err)
   500  		cfg.Status.StatusPort = uint(p)
   501  	}
   502  	if actualFlags[nmMetricsAddr] {
   503  		cfg.Status.MetricsAddr = *metricsAddr
   504  	}
   505  	if actualFlags[nmMetricsInterval] {
   506  		cfg.Status.MetricsInterval = *metricsInterval
   507  	}
   508  
   509  	// PROXY Protocol
   510  	if actualFlags[nmProxyProtocolNetworks] {
   511  		cfg.ProxyProtocol.Networks = *proxyProtocolNetworks
   512  	}
   513  	if actualFlags[nmProxyProtocolHeaderTimeout] {
   514  		cfg.ProxyProtocol.HeaderTimeout = *proxyProtocolHeaderTimeout
   515  	}
   516  }
   517  
   518  func setGlobalVars() {
   519  	cfg := config.GetGlobalConfig()
   520  
   521  	// Disable automaxprocs log
   522  	nopLog := func(string, ...interface{}) {}
   523  	_, err := maxprocs.Set(maxprocs.Logger(nopLog))
   524  	terror.MustNil(err)
   525  	// We should respect to user's settings in config file.
   526  	// The default value of MaxProcs is 0, runtime.GOMAXPROCS(0) is no-op.
   527  	runtime.GOMAXPROCS(int(cfg.Performance.MaxProcs))
   528  	metrics.MaxProcs.Set(float64(runtime.GOMAXPROCS(0)))
   529  
   530  	dbsLeaseDuration := parseDuration(cfg.Lease)
   531  	stochastik.SetSchemaLease(dbsLeaseDuration)
   532  	statsLeaseDuration := parseDuration(cfg.Performance.StatsLease)
   533  	stochastik.SetStatsLease(statsLeaseDuration)
   534  	indexUsageSyncLeaseDuration := parseDuration(cfg.Performance.IndexUsageSyncLease)
   535  	stochastik.SetIndexUsageSyncLease(indexUsageSyncLeaseDuration)
   536  	bindinfo.Lease = parseDuration(cfg.Performance.BindInfoLease)
   537  	petri.RunAutoAnalyze = cfg.Performance.RunAutoAnalyze
   538  	statistics.FeedbackProbability.CausetStore(cfg.Performance.FeedbackProbability)
   539  	statistics.MaxQueryFeedbackCount.CausetStore(int64(cfg.Performance.QueryFeedbackLimit))
   540  	statistics.RatioOfPseudoEstimate.CausetStore(cfg.Performance.PseudoEstimateRatio)
   541  	dbs.RunWorker = cfg.RunDBS
   542  	if cfg.SplitTable {
   543  		atomic.StoreUint32(&dbs.EnableSplitTableRegion, 1)
   544  	}
   545  	causetembedded.AllowCartesianProduct.CausetStore(cfg.Performance.CrossJoin)
   546  	privileges.SkipWithGrant = cfg.Security.SkipGrantTable
   547  	ekv.TxnTotalSizeLimit = cfg.Performance.TxnTotalSizeLimit
   548  	if cfg.Performance.TxnEntrySizeLimit > 120*1024*1024 {
   549  		log.Fatal("cannot set txn entry size limit larger than 120M")
   550  	}
   551  	ekv.TxnEntrySizeLimit = cfg.Performance.TxnEntrySizeLimit
   552  
   553  	priority := allegrosql.Str2Priority(cfg.Performance.ForcePriority)
   554  	variable.ForcePriority = int32(priority)
   555  	variable.SysVars[variable.MilevaDBForcePriority].Value = allegrosql.Priority2Str[priority]
   556  	variable.SysVars[variable.MilevaDBOptDistinctAggPushDown].Value = variable.BoolToIntStr(cfg.Performance.DistinctAggPushDown)
   557  
   558  	variable.SysVars[variable.MilevaDBMemQuotaQuery].Value = strconv.FormatInt(cfg.MemQuotaQuery, 10)
   559  	variable.SysVars["lower_case_block_names"].Value = strconv.Itoa(cfg.LowerCaseTableNames)
   560  	variable.SysVars[variable.LogBin].Value = variable.BoolToIntStr(config.GetGlobalConfig().Binlog.Enable)
   561  
   562  	variable.SysVars[variable.Port].Value = fmt.Sprintf("%d", cfg.Port)
   563  	variable.SysVars[variable.Socket].Value = cfg.Socket
   564  	variable.SysVars[variable.DataDir].Value = cfg.Path
   565  	variable.SysVars[variable.MilevaDBSlowQueryFile].Value = cfg.Log.SlowQueryFile
   566  	variable.SysVars[variable.MilevaDBIsolationReadEngines].Value = strings.Join(cfg.IsolationRead.Engines, ", ")
   567  
   568  	// For CI environment we default enable prepare-plan-cache.
   569  	causetembedded.SetPreparedCausetCache(config.CheckTableBeforeDrop || cfg.PreparedCausetCache.Enabled)
   570  	if causetembedded.PreparedCausetCacheEnabled() {
   571  		causetembedded.PreparedCausetCacheCapacity = cfg.PreparedCausetCache.Capacity
   572  		causetembedded.PreparedCausetCacheMemoryGuardRatio = cfg.PreparedCausetCache.MemoryGuardRatio
   573  		if causetembedded.PreparedCausetCacheMemoryGuardRatio < 0.0 || causetembedded.PreparedCausetCacheMemoryGuardRatio > 1.0 {
   574  			causetembedded.PreparedCausetCacheMemoryGuardRatio = 0.1
   575  		}
   576  		causetembedded.PreparedCausetCacheMaxMemory.CausetStore(cfg.Performance.ServerMemoryQuota)
   577  		total, err := memory.MemTotal()
   578  		terror.MustNil(err)
   579  		if causetembedded.PreparedCausetCacheMaxMemory.Load() > total || causetembedded.PreparedCausetCacheMaxMemory.Load() <= 0 {
   580  			causetembedded.PreparedCausetCacheMaxMemory.CausetStore(total)
   581  		}
   582  	}
   583  
   584  	atomic.StoreUint64(&einsteindb.CommitMaxBackoff, uint64(parseDuration(cfg.EinsteinDBClient.CommitTimeout).Seconds()*1000))
   585  	einsteindb.RegionCacheTTLSec = int64(cfg.EinsteinDBClient.RegionCacheTTL)
   586  	petriutil.RepairInfo.SetRepairMode(cfg.RepairMode)
   587  	petriutil.RepairInfo.SetRepairTableList(cfg.RepairTableList)
   588  	c := config.GetGlobalConfig()
   589  	interlock.GlobalDiskUsageTracker.SetBytesLimit(c.TempStorageQuota)
   590  	if c.Performance.ServerMemoryQuota < 1 {
   591  		// If MaxMemory equals 0, it means unlimited
   592  		interlock.GlobalMemoryUsageTracker.SetBytesLimit(-1)
   593  	} else {
   594  		interlock.GlobalMemoryUsageTracker.SetBytesLimit(int64(c.Performance.ServerMemoryQuota))
   595  	}
   596  	ekvcache.GlobalLRUMemUsageTracker.AttachToGlobalTracker(interlock.GlobalMemoryUsageTracker)
   597  
   598  	t, err := time.ParseDuration(cfg.EinsteinDBClient.StoreLivenessTimeout)
   599  	if err != nil {
   600  		logutil.BgLogger().Fatal("invalid duration value for causetstore-liveness-timeout",
   601  			zap.String("currentValue", config.GetGlobalConfig().EinsteinDBClient.StoreLivenessTimeout))
   602  	}
   603  	einsteindb.StoreLivenessTimeout = t
   604  	BerolinaSQLtypes.MilevaDBStrictIntegerDisplayWidth = config.GetGlobalConfig().DeprecateIntegerDisplayWidth
   605  }
   606  
   607  func setupLog() {
   608  	cfg := config.GetGlobalConfig()
   609  	err := logutil.InitZapLogger(cfg.Log.ToLogConfig())
   610  	terror.MustNil(err)
   611  
   612  	err = logutil.InitLogger(cfg.Log.ToLogConfig())
   613  	terror.MustNil(err)
   614  
   615  	if len(os.Getenv("GRPC_DEBUG")) > 0 {
   616  		grpclog.SetLoggerV2(grpclog.NewLoggerV2WithVerbosity(os.Stderr, os.Stderr, os.Stderr, 999))
   617  	} else {
   618  		grpclog.SetLoggerV2(grpclog.NewLoggerV2(ioutil.Discard, ioutil.Discard, os.Stderr))
   619  	}
   620  	// trigger internal http(s) client init.
   621  	soliton.InternalHTTPClient()
   622  }
   623  
   624  func printInfo() {
   625  	// Make sure the MilevaDB info is always printed.
   626  	level := log.GetLevel()
   627  	log.SetLevel(zap.InfoLevel)
   628  	printer.PrintMilevaDBInfo()
   629  	log.SetLevel(level)
   630  }
   631  
   632  func createServer() {
   633  	cfg := config.GetGlobalConfig()
   634  	driver := server.NewMilevaDBDriver(storage)
   635  	var err error
   636  	svr, err = server.NewServer(cfg, driver)
   637  	// Both petri and storage have started, so we have to clean them before exiting.
   638  	terror.MustNil(err, closePetriAndStorage)
   639  	svr.SetPetri(dom)
   640  	go dom.ExpensiveQueryHandle().SetStochastikManager(svr).Run()
   641  	dom.InfoSyncer().SetStochastikManager(svr)
   642  }
   643  
   644  func serverShutdown(isgraceful bool) {
   645  	if isgraceful {
   646  		graceful = true
   647  	}
   648  	svr.Close()
   649  }
   650  
   651  func setupMetrics() {
   652  	cfg := config.GetGlobalConfig()
   653  	// Enable the mutex profile, 1/10 of mutex blocking event sampling.
   654  	runtime.SetMutexProfileFraction(10)
   655  	systimeErrHandler := func() {
   656  		metrics.TimeJumpBackCounter.Inc()
   657  	}
   658  	callBackCount := 0
   659  	sucessCallBack := func() {
   660  		callBackCount++
   661  		// It is callback by monitor per second, we increase metrics.KeepAliveCounter per 5s.
   662  		if callBackCount >= 5 {
   663  			callBackCount = 0
   664  			metrics.KeepAliveCounter.Inc()
   665  		}
   666  	}
   667  	go systimemon.StartMonitor(time.Now, systimeErrHandler, sucessCallBack)
   668  
   669  	pushMetric(cfg.Status.MetricsAddr, time.Duration(cfg.Status.MetricsInterval)*time.Second)
   670  }
   671  
   672  func setupTracing() {
   673  	cfg := config.GetGlobalConfig()
   674  	tracingCfg := cfg.OpenTracing.ToTracingConfig()
   675  	tracingCfg.ServiceName = "MilevaDB"
   676  	tracer, _, err := tracingCfg.NewTracer()
   677  	if err != nil {
   678  		log.Fatal("setup jaeger tracer failed", zap.String("error message", err.Error()))
   679  	}
   680  	opentracing.SetGlobalTracer(tracer)
   681  }
   682  
   683  func runServer() {
   684  	err := svr.Run()
   685  	terror.MustNil(err)
   686  }
   687  
   688  func closePetriAndStorage() {
   689  	atomic.StoreUint32(&einsteindb.ShuttingDown, 1)
   690  	dom.Close()
   691  	err := storage.Close()
   692  	terror.Log(errors.Trace(err))
   693  }
   694  
   695  func cleanup() {
   696  	if graceful {
   697  		svr.GracefulDown(context.Background(), nil)
   698  	} else {
   699  		svr.TryGracefulDown()
   700  	}
   701  	plugin.Shutdown(context.Background())
   702  	closePetriAndStorage()
   703  	disk.CleanUp()
   704  }
   705  
   706  func stringToList(repairString string) []string {
   707  	if len(repairString) <= 0 {
   708  		return []string{}
   709  	}
   710  	if repairString[0] == '[' && repairString[len(repairString)-1] == ']' {
   711  		repairString = repairString[1 : len(repairString)-1]
   712  	}
   713  	return strings.FieldsFunc(repairString, func(r rune) bool {
   714  		return r == ',' || r == ' ' || r == '"'
   715  	})
   716  }