github.com/matrixorigin/matrixone@v1.2.0/cmd/mo-service/config.go (about)

     1  // Copyright 2022 Matrix Origin
     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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package main
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"hash/fnv"
    21  	"math"
    22  	"net"
    23  	"os"
    24  	"path/filepath"
    25  	"strings"
    26  	"time"
    27  
    28  	logservicepb "github.com/matrixorigin/matrixone/pkg/pb/logservice"
    29  	"github.com/matrixorigin/matrixone/pkg/util"
    30  
    31  	"github.com/BurntSushi/toml"
    32  	"github.com/matrixorigin/matrixone/pkg/cnservice"
    33  	"github.com/matrixorigin/matrixone/pkg/common/chaos"
    34  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    35  	"github.com/matrixorigin/matrixone/pkg/config"
    36  	"github.com/matrixorigin/matrixone/pkg/defines"
    37  	"github.com/matrixorigin/matrixone/pkg/fileservice"
    38  	"github.com/matrixorigin/matrixone/pkg/logservice"
    39  	"github.com/matrixorigin/matrixone/pkg/logutil"
    40  	"github.com/matrixorigin/matrixone/pkg/objectio"
    41  	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
    42  	"github.com/matrixorigin/matrixone/pkg/perfcounter"
    43  	"github.com/matrixorigin/matrixone/pkg/proxy"
    44  	"github.com/matrixorigin/matrixone/pkg/tnservice"
    45  	"github.com/matrixorigin/matrixone/pkg/udf/pythonservice"
    46  	"github.com/matrixorigin/matrixone/pkg/util/debug/goroutine"
    47  	"github.com/matrixorigin/matrixone/pkg/util/metric/stats"
    48  	tomlutil "github.com/matrixorigin/matrixone/pkg/util/toml"
    49  	"github.com/matrixorigin/matrixone/pkg/version"
    50  	"go.uber.org/zap"
    51  )
    52  
    53  var (
    54  	defaultMaxClockOffset = time.Millisecond * 500
    55  	defaultMemoryLimit    = 1 << 40
    56  
    57  	supportServiceTypes = map[string]metadata.ServiceType{
    58  		metadata.ServiceType_CN.String():         metadata.ServiceType_CN,
    59  		metadata.ServiceType_TN.String():         metadata.ServiceType_TN,
    60  		metadata.ServiceType_LOG.String():        metadata.ServiceType_LOG,
    61  		metadata.ServiceType_PROXY.String():      metadata.ServiceType_PROXY,
    62  		metadata.ServiceType_PYTHON_UDF.String(): metadata.ServiceType_PYTHON_UDF,
    63  	}
    64  )
    65  
    66  // LaunchConfig Start a MO cluster with launch
    67  type LaunchConfig struct {
    68  	// LogServiceConfigFiles log service config files
    69  	LogServiceConfigFiles []string `toml:"logservices"`
    70  	// TNServiceConfigsFiles log service config files
    71  	TNServiceConfigsFiles []string `toml:"tnservices"`
    72  	// CNServiceConfigsFiles log service config files
    73  	CNServiceConfigsFiles []string `toml:"cnservices"`
    74  	// CNServiceConfigsFiles log service config files
    75  	ProxyServiceConfigsFiles []string `toml:"proxy-services"`
    76  	// PythonUdfServiceConfigsFiles python udf service config files
    77  	PythonUdfServiceConfigsFiles []string `toml:"python-udf-services"`
    78  	// Dynamic dynamic cn service config
    79  	Dynamic Dynamic `toml:"dynamic"`
    80  }
    81  
    82  // Dynamic dynamic cn config
    83  type Dynamic struct {
    84  	// Enable enable dynamic cn config
    85  	Enable bool `toml:"enable"`
    86  	// CtlAddress http server port for ctl dynamic cn
    87  	CtlAddress string `toml:"ctl-address"`
    88  	// CNTemplate cn template file
    89  	CNTemplate string `toml:"cn-template"`
    90  	// ServiceCount how many cn services to start
    91  	ServiceCount int `toml:"service-count"`
    92  	// CpuCount how many cpu can used pr cn instance
    93  	CpuCount int `toml:"cpu-count"`
    94  	// Chaos chaos test config
    95  	Chaos chaos.Config `toml:"chaos"`
    96  }
    97  
    98  // Config mo-service configuration
    99  type Config struct {
   100  	// DataDir data dir
   101  	DataDir string `toml:"data-dir"`
   102  	// Log log config
   103  	Log logutil.LogConfig `toml:"log"`
   104  	// ServiceType service type, select the corresponding configuration to start the
   105  	// service according to the service type. [CN|TN|LOG|PROXY]
   106  	ServiceType string `toml:"service-type"`
   107  	// FileServices the config for file services
   108  	FileServices []fileservice.Config `toml:"fileservice"`
   109  	// HAKeeperClient hakeeper client config
   110  	HAKeeperClient logservice.HAKeeperClientConfig `toml:"hakeeper-client"`
   111  	// TN tn service config
   112  	TN_please_use_getTNServiceConfig *tnservice.Config `toml:"tn"`
   113  	TNCompatible                     *tnservice.Config `toml:"dn"` // for old config files compatibility
   114  	// LogService is the config for log service
   115  	LogService logservice.Config `toml:"logservice"`
   116  	// CN cn service config
   117  	CN cnservice.Config `toml:"cn"`
   118  	// ProxyConfig is the config of proxy.
   119  	ProxyConfig proxy.Config `toml:"proxy"`
   120  	// PythonUdfServerConfig is the config of python udf server
   121  	PythonUdfServerConfig pythonservice.Config `toml:"python-udf-server"`
   122  	// Observability parameters for the metric/trace
   123  	Observability config.ObservabilityParameters `toml:"observability"`
   124  
   125  	// Clock txn clock type. [LOCAL|HLC]. Default is LOCAL.
   126  	Clock struct {
   127  		// Backend clock backend implementation. [LOCAL|HLC], default LOCAL.
   128  		Backend string `toml:"source"`
   129  		// MaxClockOffset max clock offset between two nodes. Default is 500ms.
   130  		// Only valid when enable-check-clock-offset is true
   131  		MaxClockOffset tomlutil.Duration `toml:"max-clock-offset"`
   132  		// EnableCheckMaxClockOffset enable local clock offset checker
   133  		EnableCheckMaxClockOffset bool `toml:"enable-check-clock-offset"`
   134  	}
   135  
   136  	// Limit limit configuration
   137  	Limit struct {
   138  		// Memory memory usage limit, see mpool for details
   139  		Memory tomlutil.ByteSize `toml:"memory"`
   140  	}
   141  
   142  	// MetaCache the config for objectio metacache
   143  	MetaCache objectio.CacheConfig `toml:"metacache"`
   144  
   145  	// IsStandalone denotes the matrixone is running in standalone mode
   146  	// For the tn does not boost an independent queryservice.
   147  	// cn,tn shares the same queryservice in standalone mode.
   148  	// Under distributed deploy mode, cn,tn are independent os process.
   149  	// they have their own queryservice.
   150  	IsStandalone bool
   151  
   152  	// Goroutine goroutine config
   153  	Goroutine goroutine.Config `toml:"goroutine"`
   154  }
   155  
   156  // NewConfig return Config with default values.
   157  func NewConfig() *Config {
   158  	return &Config{
   159  		HAKeeperClient: logservice.HAKeeperClientConfig{
   160  			DiscoveryAddress: "",
   161  			ServiceAddresses: []string{logservice.DefaultLogServiceServiceAddress},
   162  			AllocateIDBatch:  100,
   163  			EnableCompress:   false,
   164  		},
   165  		Observability: *config.NewObservabilityParameters(),
   166  		LogService:    logservice.DefaultConfig(),
   167  		CN: cnservice.Config{
   168  			AutomaticUpgrade: true,
   169  		},
   170  	}
   171  }
   172  
   173  func parseConfigFromFile(file string, cfg any) error {
   174  	if file == "" {
   175  		return moerr.NewInternalError(context.Background(), "toml config file not set")
   176  	}
   177  	data, err := os.ReadFile(file)
   178  	if err != nil {
   179  		return err
   180  	}
   181  	return parseFromString(string(data), cfg)
   182  }
   183  
   184  func parseFromString(data string, cfg any) error {
   185  	if _, err := toml.Decode(data, cfg); err != nil {
   186  		return err
   187  	}
   188  	return nil
   189  }
   190  
   191  func (c *Config) validate() error {
   192  	if c.DataDir == "" ||
   193  		c.DataDir == "./mo-data" ||
   194  		c.DataDir == "mo-data" {
   195  		path, err := os.Getwd()
   196  		if err != nil {
   197  			panic(err)
   198  		}
   199  		c.DataDir = filepath.Join(path, "mo-data")
   200  	}
   201  	if _, err := c.getServiceType(); err != nil {
   202  		return err
   203  	}
   204  	if c.Clock.MaxClockOffset.Duration == 0 {
   205  		c.Clock.MaxClockOffset.Duration = defaultMaxClockOffset
   206  	}
   207  	if c.Clock.Backend == "" {
   208  		c.Clock.Backend = localClockBackend
   209  	}
   210  	if _, ok := supportTxnClockBackends[strings.ToUpper(c.Clock.Backend)]; !ok {
   211  		return moerr.NewInternalError(context.Background(), "%s clock backend not support", c.Clock.Backend)
   212  	}
   213  	if !c.Clock.EnableCheckMaxClockOffset {
   214  		c.Clock.MaxClockOffset.Duration = 0
   215  	}
   216  	for i, config := range c.FileServices {
   217  		// rename 's3' to 'shared'
   218  		if strings.EqualFold(config.Name, "s3") {
   219  			c.FileServices[i].Name = defines.SharedFileServiceName
   220  		}
   221  		// set default data dir
   222  		if config.DataDir == "" {
   223  			c.FileServices[i].DataDir = c.defaultFileServiceDataDir(config.Name)
   224  		}
   225  		// set default disk cache dir
   226  		if config.Cache.DiskPath == nil {
   227  			path := filepath.Join(c.DataDir, strings.ToLower(config.Name)+"-cache")
   228  			c.FileServices[i].Cache.DiskPath = &path
   229  		}
   230  	}
   231  	if c.Limit.Memory == 0 {
   232  		c.Limit.Memory = tomlutil.ByteSize(defaultMemoryLimit)
   233  	}
   234  	if c.Log.StacktraceLevel == "" {
   235  		c.Log.StacktraceLevel = zap.PanicLevel.String()
   236  	}
   237  	return nil
   238  }
   239  
   240  func (c *Config) setDefaultValue() error {
   241  	if c.DataDir == "" {
   242  		c.DataDir = "./mo-data"
   243  	}
   244  	if c.Clock.MaxClockOffset.Duration == 0 {
   245  		c.Clock.MaxClockOffset.Duration = defaultMaxClockOffset
   246  	}
   247  	if c.Clock.Backend == "" {
   248  		c.Clock.Backend = localClockBackend
   249  	}
   250  	if _, ok := supportTxnClockBackends[strings.ToUpper(c.Clock.Backend)]; !ok {
   251  		return moerr.NewInternalError(context.Background(), "%s clock backend not support", c.Clock.Backend)
   252  	}
   253  	if !c.Clock.EnableCheckMaxClockOffset {
   254  		c.Clock.MaxClockOffset.Duration = 0
   255  	}
   256  	for i, config := range c.FileServices {
   257  		// rename 's3' to 'shared'
   258  		if strings.EqualFold(config.Name, "s3") {
   259  			c.FileServices[i].Name = defines.SharedFileServiceName
   260  		}
   261  		// set default data dir
   262  		if config.DataDir == "" {
   263  			c.FileServices[i].DataDir = c.defaultFileServiceDataDir(config.Name)
   264  		}
   265  		// set default disk cache dir
   266  		if config.Cache.DiskPath == nil {
   267  			path := filepath.Join(c.DataDir, strings.ToLower(config.Name)+"-cache")
   268  			c.FileServices[i].Cache.DiskPath = &path
   269  		}
   270  	}
   271  	if c.Limit.Memory == 0 {
   272  		c.Limit.Memory = tomlutil.ByteSize(defaultMemoryLimit)
   273  	}
   274  	if c.Log.StacktraceLevel == "" {
   275  		c.Log.StacktraceLevel = zap.PanicLevel.String()
   276  	}
   277  	//set set default value
   278  	c.Log = logutil.GetDefaultConfig()
   279  	// HAKeeperClient has been set in NewConfig
   280  	if c.TN_please_use_getTNServiceConfig != nil {
   281  		c.TN_please_use_getTNServiceConfig.SetDefaultValue()
   282  	}
   283  	if c.TNCompatible != nil {
   284  		c.TNCompatible.SetDefaultValue()
   285  	}
   286  	// LogService has been set in NewConfig
   287  	c.CN.SetDefaultValue()
   288  	//no default proxy config
   289  	// Observability has been set in NewConfig
   290  	c.initMetaCache()
   291  	return nil
   292  }
   293  
   294  func (c *Config) initMetaCache() {
   295  	if c.MetaCache.MemoryCapacity > 0 {
   296  		objectio.InitMetaCache(int64(c.MetaCache.MemoryCapacity))
   297  	}
   298  }
   299  
   300  func (c *Config) defaultFileServiceDataDir(name string) string {
   301  	return filepath.Join(c.DataDir, strings.ToLower(name))
   302  }
   303  
   304  func (c *Config) createFileService(
   305  	ctx context.Context,
   306  	serviceType metadata.ServiceType,
   307  	nodeUUID string,
   308  ) (*fileservice.FileServices, error) {
   309  	// create all services
   310  	services := make([]fileservice.FileService, 0, len(c.FileServices))
   311  
   312  	// default LOCAL fs
   313  	ok := false
   314  	for _, config := range c.FileServices {
   315  		if strings.EqualFold(config.Name, defines.LocalFileServiceName) {
   316  			ok = true
   317  			break
   318  		}
   319  	}
   320  	// default to local disk
   321  	if !ok {
   322  		c.FileServices = append(c.FileServices, fileservice.Config{
   323  			Name:    defines.LocalFileServiceName,
   324  			Backend: "DISK",
   325  			DataDir: c.defaultFileServiceDataDir(defines.LocalFileServiceName),
   326  		})
   327  	}
   328  
   329  	// default SHARED fs
   330  	ok = false
   331  	for _, config := range c.FileServices {
   332  		if strings.EqualFold(config.Name, defines.SharedFileServiceName) {
   333  			ok = true
   334  			break
   335  		}
   336  	}
   337  	// default to local disk
   338  	if !ok {
   339  		c.FileServices = append(c.FileServices, fileservice.Config{
   340  			Name:    defines.SharedFileServiceName,
   341  			Backend: "DISK",
   342  			DataDir: c.defaultFileServiceDataDir(defines.SharedFileServiceName),
   343  		})
   344  	}
   345  
   346  	// default ETL fs
   347  	ok = false
   348  	for _, config := range c.FileServices {
   349  		if strings.EqualFold(config.Name, defines.ETLFileServiceName) {
   350  			ok = true
   351  			break
   352  		}
   353  	}
   354  	// default to local disk
   355  	if !ok {
   356  		c.FileServices = append(c.FileServices, fileservice.Config{
   357  			Name:    defines.ETLFileServiceName,
   358  			Backend: "DISK-ETL", // must be ETL
   359  			DataDir: c.defaultFileServiceDataDir(defines.ETLFileServiceName),
   360  		})
   361  	}
   362  
   363  	// set distributed cache callbacks
   364  	for i := range c.FileServices {
   365  		c.setCacheCallbacks(&c.FileServices[i])
   366  	}
   367  
   368  	for _, config := range c.FileServices {
   369  		counterSet := new(perfcounter.CounterSet)
   370  		service, err := fileservice.NewFileService(
   371  			ctx,
   372  			config,
   373  			[]*perfcounter.CounterSet{
   374  				counterSet,
   375  			},
   376  		)
   377  		if err != nil {
   378  			return nil, err
   379  		}
   380  		services = append(services, service)
   381  
   382  		// perf counter
   383  		counterSetName := perfcounter.NameForFileService(
   384  			serviceType.String(),
   385  			nodeUUID,
   386  			service.Name(),
   387  		)
   388  		perfcounter.Named.Store(counterSetName, counterSet)
   389  
   390  		// set shared fs perf counter as node perf counter
   391  		if service.Name() == defines.SharedFileServiceName {
   392  			perfcounter.Named.Store(
   393  				perfcounter.NameForNode(serviceType.String(), nodeUUID),
   394  				counterSet,
   395  			)
   396  		}
   397  
   398  		// Create "Log Exporter" for this PerfCounter
   399  		counterLogExporter := perfcounter.NewCounterLogExporter(counterSet)
   400  		// Register this PerfCounter's "Log Exporter" to global stats registry.
   401  		stats.Register(counterSetName, stats.WithLogExporter(counterLogExporter))
   402  	}
   403  
   404  	// create FileServices
   405  	fs, err := fileservice.NewFileServices(
   406  		"",
   407  		services...,
   408  	)
   409  	if err != nil {
   410  		return nil, err
   411  	}
   412  
   413  	// ensure local exists
   414  	_, err = fileservice.Get[fileservice.FileService](fs, defines.LocalFileServiceName)
   415  	if err != nil {
   416  		return nil, err
   417  	}
   418  
   419  	// ensure shared exists
   420  	_, err = fileservice.Get[fileservice.FileService](fs, defines.SharedFileServiceName)
   421  	if err != nil {
   422  		return nil, err
   423  	}
   424  
   425  	// ensure etl exists and is ETL
   426  	if !c.Observability.DisableMetric || !c.Observability.DisableTrace {
   427  		_, err = fileservice.Get[fileservice.ETLFileService](fs, defines.ETLFileServiceName)
   428  		if err != nil {
   429  			return nil, moerr.ConvertPanicError(context.Background(), err)
   430  		}
   431  	}
   432  
   433  	return fs, nil
   434  }
   435  
   436  func (c *Config) getLogServiceConfig() logservice.Config {
   437  	cfg := c.LogService
   438  	logutil.Infof("hakeeper client cfg: %v", c.HAKeeperClient)
   439  	cfg.HAKeeperClientConfig = c.HAKeeperClient
   440  	cfg.DataDir = filepath.Join(c.DataDir, "logservice-data", cfg.UUID)
   441  	var hostname string
   442  	var err error
   443  	hostname = cfg.ExplicitHostname
   444  	if len(hostname) == 0 {
   445  		// Should sync directory structure with dragonboat.
   446  		hostname, err = os.Hostname()
   447  		if err != nil {
   448  			panic(fmt.Sprintf("cannot get hostname: %s", err))
   449  		}
   450  	}
   451  	cfg.SnapshotExportDir = filepath.Join(cfg.DataDir, hostname,
   452  		fmt.Sprintf("%020d", cfg.DeploymentID), "exported-snapshot")
   453  	return cfg
   454  }
   455  
   456  func (c *Config) getTNServiceConfig() tnservice.Config {
   457  	if c.TN_please_use_getTNServiceConfig == nil && c.TNCompatible != nil {
   458  		c.TN_please_use_getTNServiceConfig = c.TNCompatible
   459  	}
   460  	var cfg tnservice.Config
   461  	if c.TN_please_use_getTNServiceConfig != nil {
   462  		cfg = *c.TN_please_use_getTNServiceConfig
   463  	}
   464  	cfg.HAKeeper.ClientConfig = c.HAKeeperClient
   465  	cfg.DataDir = filepath.Join(c.DataDir, "dn-data", cfg.UUID)
   466  	return cfg
   467  }
   468  
   469  func (c *Config) getCNServiceConfig() cnservice.Config {
   470  	cfg := c.CN
   471  	cfg.HAKeeper.ClientConfig = c.HAKeeperClient
   472  	cfg.Frontend.SetLogAndVersion(&c.Log, version.Version)
   473  	if cfg.Txn.Trace.Dir == "" {
   474  		cfg.Txn.Trace.Dir = "trace"
   475  	}
   476  	return cfg
   477  }
   478  
   479  func (c *Config) getProxyConfig() proxy.Config {
   480  	cfg := c.ProxyConfig
   481  	cfg.HAKeeper.ClientConfig = c.HAKeeperClient
   482  	return cfg
   483  }
   484  
   485  func (c *Config) getObservabilityConfig() config.ObservabilityParameters {
   486  	cfg := c.Observability
   487  	cfg.SetDefaultValues(version.Version)
   488  	return cfg
   489  }
   490  
   491  // memberlist requires all gossip seed addresses to be provided as IP:PORT
   492  func (c *Config) resolveGossipSeedAddresses() error {
   493  	result := make([]string, 0)
   494  	for _, addr := range c.LogService.GossipSeedAddresses {
   495  		host, port, err := net.SplitHostPort(addr)
   496  		if err != nil {
   497  			return err
   498  		}
   499  		ips, err := net.LookupIP(host)
   500  		if err != nil {
   501  			// the configured member may be failed currently, keep the host name anyway since
   502  			// memberlist would try to resolve it again
   503  			result = append(result, addr)
   504  			continue
   505  		}
   506  		// only keep IPv4 addresses
   507  		filtered := make([]string, 0)
   508  		for _, ip := range ips {
   509  			if ip.To4() != nil {
   510  				filtered = append(filtered, ip.String())
   511  			}
   512  		}
   513  		if len(filtered) != 1 {
   514  			return moerr.NewBadConfig(context.Background(), "GossipSeedAddress %s", addr)
   515  		}
   516  		result = append(result, net.JoinHostPort(filtered[0], port))
   517  	}
   518  	c.LogService.GossipSeedAddresses = result
   519  	return nil
   520  }
   521  
   522  func (c *Config) hashNodeID() uint16 {
   523  	st, err := c.getServiceType()
   524  	if err != nil {
   525  		panic(err)
   526  	}
   527  
   528  	uuid := ""
   529  	switch st {
   530  	case metadata.ServiceType_CN:
   531  		uuid = c.CN.UUID
   532  	case metadata.ServiceType_TN:
   533  		uuid = c.getTNServiceConfig().UUID
   534  	case metadata.ServiceType_LOG:
   535  		uuid = c.LogService.UUID
   536  	}
   537  	if uuid == "" {
   538  		return 0
   539  	}
   540  
   541  	h := fnv.New32()
   542  	if _, err := h.Write([]byte(uuid)); err != nil {
   543  		panic(err)
   544  	}
   545  	v := h.Sum32()
   546  	return uint16(v % math.MaxUint16)
   547  }
   548  
   549  func (c *Config) getServiceType() (metadata.ServiceType, error) {
   550  	if c.ServiceType == "DN" { // for old config files compatibility
   551  		c.ServiceType = metadata.ServiceType_TN.String()
   552  	}
   553  	if v, ok := supportServiceTypes[strings.ToUpper(c.ServiceType)]; ok {
   554  		return v, nil
   555  	}
   556  	return metadata.ServiceType(0), moerr.NewInternalError(context.Background(), "service type %s not support", c.ServiceType)
   557  }
   558  
   559  func (c *Config) mustGetServiceType() metadata.ServiceType {
   560  	v, err := c.getServiceType()
   561  	if err != nil {
   562  		panic(err)
   563  	}
   564  	return v
   565  }
   566  
   567  func (c *Config) mustGetServiceUUID() string {
   568  	switch c.mustGetServiceType() {
   569  	case metadata.ServiceType_CN:
   570  		return c.CN.UUID
   571  	case metadata.ServiceType_TN:
   572  		return c.getTNServiceConfig().UUID
   573  	case metadata.ServiceType_LOG:
   574  		return c.LogService.UUID
   575  	case metadata.ServiceType_PROXY:
   576  		return c.ProxyConfig.UUID
   577  	}
   578  	panic("impossible")
   579  }
   580  
   581  func (c *Config) setCacheCallbacks(fsConfig *fileservice.Config) {
   582  	fsConfig.Cache.SetRemoteCacheCallback()
   583  }
   584  
   585  // dumpCommonConfig gets the common config items except cn,tn,log,proxy
   586  func dumpCommonConfig(cfg Config) (map[string]*logservicepb.ConfigItem, error) {
   587  	defCfg := *NewConfig()
   588  	err := defCfg.setDefaultValue()
   589  	if err != nil {
   590  		return nil, err
   591  	}
   592  	ret, err := util.DumpConfig(cfg, defCfg)
   593  	if err != nil {
   594  		return nil, err
   595  	}
   596  
   597  	//specific config items should be remoted
   598  	filters := []string{
   599  		"config.tn_please_use_gettnserviceconfig",
   600  		"config.tncompatible",
   601  		"config.logservice",
   602  		"config.cn",
   603  		"config.proxyconfig",
   604  	}
   605  
   606  	//denote the common for cn,tn,log or proxy
   607  	prefix := "common"
   608  
   609  	newMap := make(map[string]*logservicepb.ConfigItem)
   610  	for s, item := range ret {
   611  		needDrop := false
   612  		for _, filter := range filters {
   613  			if strings.HasPrefix(strings.ToLower(s), strings.ToLower(filter)) {
   614  				needDrop = true
   615  				break
   616  			}
   617  		}
   618  		if needDrop {
   619  			continue
   620  		}
   621  
   622  		s = prefix + s
   623  		item.Name = s
   624  		newMap[s] = item
   625  	}
   626  
   627  	return newMap, err
   628  }