github.com/matrixorigin/matrixone@v1.2.0/pkg/logservice/config.go (about)

     1  // Copyright 2021 - 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 logservice
    16  
    17  import (
    18  	"fmt"
    19  	logservicepb "github.com/matrixorigin/matrixone/pkg/pb/logservice"
    20  	"github.com/matrixorigin/matrixone/pkg/util"
    21  	"strconv"
    22  	"strings"
    23  	"time"
    24  
    25  	"github.com/google/uuid"
    26  	"github.com/lni/dragonboat/v4"
    27  	"github.com/lni/vfs"
    28  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    29  	"github.com/matrixorigin/matrixone/pkg/hakeeper"
    30  	"github.com/matrixorigin/matrixone/pkg/util/toml"
    31  )
    32  
    33  const (
    34  	defaultDeploymentID      = 1
    35  	defaultDataDir           = "mo-data/logservice"
    36  	defaultSnapshotExportDir = "exported-snapshot"
    37  	defaultRaftAddress       = "0.0.0.0:32000"
    38  	defaultServiceAddress    = "0.0.0.0:32001"
    39  	defaultGossipAddress     = "0.0.0.0:32002"
    40  	defaultGossipSeedAddress = "127.0.0.1:32002"
    41  	defaultRaftPort          = 32000
    42  	defaultGossipPort        = 32002
    43  
    44  	defaultGossipProbeInterval = 5 * time.Second
    45  	defaultHeartbeatInterval   = time.Second
    46  	defaultLogDBBufferSize     = 768 * 1024
    47  	defaultTruncateInterval    = 10 * time.Second
    48  	defaultMaxExportedSnapshot = 20
    49  	defaultMaxMessageSize      = 1024 * 1024 * 100
    50  	// The default value for HAKeeper truncate interval.
    51  	defaultHAKeeperTruncateInterval = 24 * time.Hour
    52  
    53  	DefaultListenHost     = "0.0.0.0"
    54  	DefaultServiceHost    = "127.0.0.1"
    55  	DefaultLogServicePort = 32001
    56  
    57  	defaultRestoreFilePath = "hk_data"
    58  )
    59  
    60  var (
    61  	DefaultLogServiceServiceAddress = fmt.Sprintf("%s:%d", DefaultServiceHost, DefaultLogServicePort)
    62  	DefaultGossipServiceAddress     = fmt.Sprintf("%s:%d", DefaultServiceHost, defaultGossipPort)
    63  )
    64  
    65  // Config defines the Configurations supported by the Log Service.
    66  type Config struct {
    67  	// FS is the underlying virtual FS used by the log service. Leave it as empty
    68  	// in production.
    69  	FS vfs.FS
    70  	// DeploymentID is basically the Cluster ID, nodes with different DeploymentID
    71  	// will not be able to communicate via raft.
    72  	DeploymentID uint64 `toml:"deployment-id"`
    73  	// UUID is the UUID of the log service node. UUID value must be set.
    74  	UUID string `toml:"uuid" user_setting:"basic"`
    75  	// RTTMillisecond is the average round trip time between log service nodes in
    76  	// milliseconds.
    77  	RTTMillisecond uint64 `toml:"rttmillisecond"`
    78  	// DataDir is the name of the directory for storing all log service data. It
    79  	// should a locally mounted partition with good write and fsync performance.
    80  	DataDir string `toml:"data-dir" user_setting:"basic"`
    81  	// SnapshotExportDir is the directory where the dragonboat snapshots are
    82  	// exported.
    83  	SnapshotExportDir string `toml:"snapshot-export-dir"`
    84  	// MaxExportedSnapshot is the max count of exported snapshots. If there are
    85  	// already MaxExportedSnapshot exported snapshots, no exported snapshot will
    86  	// be generated.
    87  	MaxExportedSnapshot int `toml:"max-exported-snapshot"`
    88  	// ServiceHost is the host name/IP for the service address of RPC request. There is
    89  	// no port value in it.
    90  	ServiceHost string `toml:"service-host"`
    91  	// ServiceAddress is log service's service address that can be reached by
    92  	// other nodes such as TN nodes. It is deprecated and will be removed.
    93  	ServiceAddress string `toml:"logservice-address" user_setting:"advanced"`
    94  	// ServiceListenAddress is the local listen address of the ServiceAddress.
    95  	// It is deprecated and will be removed.
    96  	ServiceListenAddress string `toml:"logservice-listen-address"`
    97  	// ServicePort is log service's service address port that can be reached by
    98  	// other nodes such as TN nodes.
    99  	LogServicePort int `toml:"logservice-port"`
   100  	// RaftAddress is the address that can be reached by other log service nodes
   101  	// via their raft layer. It is deprecated and will be removed.
   102  	RaftAddress string `toml:"raft-address" user_setting:"advanced"`
   103  	// RaftListenAddress is the local listen address of the RaftAddress.
   104  	// It is deprecated and will be removed.
   105  	RaftListenAddress string `toml:"raft-listen-address"`
   106  	// RaftPort is the address port that can be reached by other log service nodes
   107  	// via their raft layer.
   108  	RaftPort int `toml:"raft-port"`
   109  	// UseTeeLogDB enables the log service to use tee based LogDB which is backed
   110  	// by both a pebble and a tan based LogDB. This field should only be set to
   111  	// true during testing.
   112  	UseTeeLogDB bool `toml:"use-tee-logdb"`
   113  	// LogDBBufferSize is the size of the logdb buffer in bytes.
   114  	LogDBBufferSize uint64 `toml:"logdb-buffer-size"`
   115  	// GossipAddress is the address used for accepting gossip communication.
   116  	// It is deprecated and will be removed.
   117  	GossipAddress string `toml:"gossip-address" user_setting:"advanced"`
   118  	// GossipAddressV2 is the address used for accepting gossip communication.
   119  	// This is for domain name support. It is deprecated and will be removed.
   120  	GossipAddressV2 string `toml:"gossip-address-v2"`
   121  	// GossipListenAddress is the local listen address of the GossipAddress
   122  	// It is deprecated and will be removed.
   123  	GossipListenAddress string `toml:"gossip-listen-address"`
   124  	// GossipPort is the port address port used for accepting gossip communication.
   125  	GossipPort int `toml:"gossip-port"`
   126  	// GossipSeedAddresses is list of seed addresses that are used for
   127  	// introducing the local node into the gossip network.
   128  	GossipSeedAddresses []string `toml:"gossip-seed-addresses" user_setting:"advanced"`
   129  	// GossipProbeInterval how often gossip nodes probe each other.
   130  	GossipProbeInterval toml.Duration `toml:"gossip-probe-interval"`
   131  	// GossipAllowSelfAsSeed allow use self as gossip seed
   132  	GossipAllowSelfAsSeed bool `toml:"gossip-allow-self-as-seed"`
   133  	// HeartbeatInterval is the interval of how often log service node should be
   134  	// sending heartbeat message to the HAKeeper.
   135  	HeartbeatInterval toml.Duration `toml:"logservice-heartbeat-interval"`
   136  	// HAKeeperTickInterval is the interval of how often log service node should
   137  	// tick the HAKeeper.
   138  	HAKeeperTickInterval toml.Duration `toml:"hakeeper-tick-interval"`
   139  	// HAKeeperCheckInterval is the interval of how often HAKeeper should run
   140  	// cluster health checks.
   141  	HAKeeperCheckInterval toml.Duration `toml:"hakeeper-check-interval"`
   142  	// TruncateInterval is the interval of how often log service should
   143  	// process truncate for regular shards.
   144  	TruncateInterval toml.Duration `toml:"truncate-interval"`
   145  	// HAKeeperTruncateInterval is the interval of how often log service should
   146  	// process truncate for HAKeeper shard.
   147  	HAKeeperTruncateInterval toml.Duration `toml:"hakeeper-truncate-interval"`
   148  	// ExplicitHostname is the hostname used in draogboat.
   149  	ExplicitHostname string `toml:"explicit-hostname"`
   150  
   151  	RPC struct {
   152  		// MaxMessageSize is the max size for RPC message. The default value is 10MiB.
   153  		MaxMessageSize toml.ByteSize `toml:"max-message-size"`
   154  		// EnableCompress enable compress
   155  		EnableCompress bool `toml:"enable-compress"`
   156  	}
   157  
   158  	// BootstrapConfig is the configuration specified for the bootstrapping
   159  	// procedure. It only needs to be specified for Log Stores selected to host
   160  	// initial HAKeeper replicas during bootstrapping.
   161  	BootstrapConfig struct {
   162  		// BootstrapCluster indicates whether the cluster should be bootstrapped.
   163  		// Note the bootstrapping procedure will only be executed if BootstrapCluster
   164  		// is true and Config.UUID is found in Config.BootstrapConfig.InitHAKeeperMembers.
   165  		BootstrapCluster bool `toml:"bootstrap-cluster"`
   166  		// NumOfLogShards defines the number of Log shards in the initial deployment.
   167  		NumOfLogShards uint64 `toml:"num-of-log-shards"`
   168  		// NumOfTNShards defines the number of TN shards in the initial deployment.
   169  		// The count must be the same as NumOfLogShards in the current implementation.
   170  		NumOfTNShards uint64 `toml:"num-of-tn-shards"`
   171  		// NumOfLogShardReplicas is the number of replicas for each shard managed by
   172  		// Log Stores, including Log Service shards and the HAKeeper.
   173  		NumOfLogShardReplicas uint64 `toml:"num-of-log-shard-replicas"`
   174  		// InitHAKeeperMembers defines the initial members of the HAKeeper as a list
   175  		// of HAKeeper replicaID and UUID pairs. For example,
   176  		// when the initial HAKeeper members are
   177  		// replica with replica ID 101 running on Log Store uuid1
   178  		// replica with replica ID 102 running on Log Store uuid2
   179  		// replica with replica ID 103 running on Log Store uuid3
   180  		// the InitHAKeeperMembers string value should be
   181  		// []string{"101:uuid1", "102:uuid2", "103:uuid3"}
   182  		// Note that these initial HAKeeper replica IDs must be assigned by k8s
   183  		// from the range [K8SIDRangeStart, K8SIDRangeEnd) as defined in pkg/hakeeper.
   184  		// All uuid values are assigned by k8s, they are used to uniquely identify
   185  		// CN/DN/Log stores.
   186  		// Config.UUID and Config.BootstrapConfig values are considered together to
   187  		// figure out what is the replica ID of the initial HAKeeper replica. That
   188  		// is when Config.UUID is found in InitHAKeeperMembers, then the corresponding
   189  		// replica ID value will be used to launch a HAKeeper replica on the Log
   190  		// Service instance.
   191  		InitHAKeeperMembers []string `toml:"init-hakeeper-members" user_setting:"advanced"`
   192  		// Restore structure is used when the cluster needs to restore data.
   193  		Restore struct {
   194  			// FilePath is the path of the file, which contains the backup data.
   195  			// If is not set, nothing will be done for restore.
   196  			FilePath string `toml:"file-path"`
   197  			// Force means that we force to do restore even if RESTORED tag file
   198  			// already exists.
   199  			Force bool `toml:"force"`
   200  		} `toml:"restore"`
   201  	}
   202  
   203  	HAKeeperConfig struct {
   204  		// TickPerSecond indicates how many ticks every second.
   205  		// In HAKeeper, we do not use actual time to measure time elapse.
   206  		// Instead, we use ticks.
   207  		TickPerSecond int `toml:"tick-per-second"`
   208  		// LogStoreTimeout is the actual time limit between a log store's heartbeat.
   209  		// If HAKeeper does not receive two heartbeat within LogStoreTimeout,
   210  		// it regards the log store as down.
   211  		LogStoreTimeout toml.Duration `toml:"log-store-timeout"`
   212  		// TNStoreTimeout is the actual time limit between a tn store's heartbeat.
   213  		// If HAKeeper does not receive two heartbeat within TNStoreTimeout,
   214  		// it regards the tn store as down.
   215  		TNStoreTimeout toml.Duration `toml:"tn-store-timeout"`
   216  		// CNStoreTimeout is the actual time limit between a cn store's heartbeat.
   217  		// If HAKeeper does not receive two heartbeat within CNStoreTimeout,
   218  		// it regards the tn store as down.
   219  		CNStoreTimeout toml.Duration `toml:"cn-store-timeout"`
   220  	}
   221  
   222  	// HAKeeperClientConfig is the config for HAKeeperClient
   223  	HAKeeperClientConfig HAKeeperClientConfig
   224  
   225  	// DisableWorkers disables the HAKeeper ticker and HAKeeper client in tests.
   226  	// Never set this field to true in production
   227  	DisableWorkers bool
   228  
   229  	Ctl struct {
   230  		// ListenAddress ctl service listen address for receiving ctl requests
   231  		ListenAddress string `toml:"listen-address"`
   232  		// ServiceAddress service address for communication, if this address is not set, use
   233  		// ListenAddress as the communication address.
   234  		ServiceAddress string `toml:"service-address"`
   235  	} `toml:"ctl"`
   236  }
   237  
   238  func (c *Config) GetHAKeeperConfig() hakeeper.Config {
   239  	return hakeeper.Config{
   240  		TickPerSecond:   c.HAKeeperConfig.TickPerSecond,
   241  		LogStoreTimeout: c.HAKeeperConfig.LogStoreTimeout.Duration,
   242  		TNStoreTimeout:  c.HAKeeperConfig.TNStoreTimeout.Duration,
   243  		CNStoreTimeout:  c.HAKeeperConfig.CNStoreTimeout.Duration,
   244  	}
   245  }
   246  
   247  func (c *Config) GetHAKeeperClientConfig() HAKeeperClientConfig {
   248  	saddr := make([]string, 0)
   249  	saddr = append(saddr, c.HAKeeperClientConfig.ServiceAddresses...)
   250  	return HAKeeperClientConfig{
   251  		DiscoveryAddress: c.HAKeeperClientConfig.DiscoveryAddress,
   252  		ServiceAddresses: saddr,
   253  	}
   254  }
   255  
   256  // returns replica ID of the HAKeeper replica and a boolean indicating whether
   257  // we should run the bootstrap procedure.
   258  func (c *Config) Bootstrapping() (uint64, bool) {
   259  	if !c.BootstrapConfig.BootstrapCluster {
   260  		return 0, false
   261  	}
   262  	members, err := c.GetInitHAKeeperMembers()
   263  	if err != nil {
   264  		return 0, false
   265  	}
   266  	for replicaID, uuid := range members {
   267  		if uuid == c.UUID {
   268  			return replicaID, true
   269  		}
   270  	}
   271  	return 0, false
   272  }
   273  
   274  func (c *Config) GetInitHAKeeperMembers() (map[uint64]dragonboat.Target, error) {
   275  	result := make(map[uint64]dragonboat.Target)
   276  	for _, pair := range c.BootstrapConfig.InitHAKeeperMembers {
   277  		pair = strings.TrimSpace(pair)
   278  		parts := strings.Split(pair, ":")
   279  		if len(parts) == 2 {
   280  			id := strings.TrimSpace(parts[0])
   281  			target := strings.TrimSpace(parts[1])
   282  			if _, err := uuid.Parse(target); err != nil {
   283  				return nil, moerr.NewBadConfigNoCtx("uuid %s", target)
   284  			}
   285  			idn, err := strconv.ParseUint(id, 10, 64)
   286  			if err != nil {
   287  				return nil, moerr.NewBadConfigNoCtx("replicateID '%v'", id)
   288  			}
   289  			if idn >= hakeeper.K8SIDRangeEnd || idn < hakeeper.K8SIDRangeStart {
   290  				return nil, moerr.NewBadConfigNoCtx("replicateID '%v'", id)
   291  			}
   292  			result[idn] = target
   293  		} else {
   294  			return nil, moerr.NewBadConfigNoCtx("replicaID:target %s", pair)
   295  		}
   296  	}
   297  	return result, nil
   298  }
   299  
   300  // Validate validates the configuration.
   301  func (c *Config) Validate() error {
   302  	if len(c.UUID) == 0 {
   303  		return moerr.NewBadConfigNoCtx("uuid not set")
   304  	}
   305  	if c.DeploymentID == 0 {
   306  		return moerr.NewBadConfigNoCtx("deploymentID not set")
   307  	}
   308  	// when *ListenAddress is not empty and *Address is empty, consider it as an
   309  	// error
   310  	if len(c.ServiceAddress) == 0 && len(c.ServiceListenAddress) != 0 && c.LogServicePort == 0 {
   311  		return moerr.NewBadConfigNoCtx("ServiceAddress and LogServicePort not set")
   312  	}
   313  	if len(c.RaftAddress) == 0 && len(c.RaftListenAddress) != 0 && c.RaftPort == 0 {
   314  		return moerr.NewBadConfigNoCtx("RaftAddress and RaftPort not set")
   315  	}
   316  	if c.LogDBBufferSize == 0 {
   317  		return moerr.NewBadConfigNoCtx("LogDBBufferSize not set")
   318  	}
   319  	if len(c.GossipAddress) == 0 && len(c.GossipListenAddress) != 0 && c.GossipPort == 0 {
   320  		return moerr.NewBadConfigNoCtx("GossipAddress and GossipPort not set")
   321  	}
   322  	if len(c.GossipSeedAddresses) == 0 {
   323  		return moerr.NewBadConfigNoCtx("GossipSeedAddress not set")
   324  	}
   325  	if c.HAKeeperConfig.TickPerSecond == 0 {
   326  		return moerr.NewBadConfigNoCtx("TickPerSecond not set")
   327  	}
   328  	if c.HAKeeperConfig.LogStoreTimeout.Duration == 0 {
   329  		return moerr.NewBadConfigNoCtx("LogStoreTimeout not set")
   330  	}
   331  	if c.HAKeeperConfig.TNStoreTimeout.Duration == 0 {
   332  		return moerr.NewBadConfigNoCtx("DNStoreTimeout not set")
   333  	}
   334  	if c.GossipProbeInterval.Duration == 0 {
   335  		return moerr.NewBadConfigNoCtx("GossipProbeInterval not set")
   336  	}
   337  	if c.TruncateInterval.Duration == 0 {
   338  		return moerr.NewBadConfigNoCtx("TruncateInterval not set")
   339  	}
   340  	if c.HAKeeperTruncateInterval.Duration == 0 {
   341  		return moerr.NewBadConfigNoCtx("HAKeeperTruncateInterval not set")
   342  	}
   343  	if c.RPC.MaxMessageSize == 0 {
   344  		return moerr.NewBadConfigNoCtx("MaxMessageSize not set")
   345  	}
   346  	// validate BootstrapConfig
   347  	if c.BootstrapConfig.BootstrapCluster {
   348  		if c.BootstrapConfig.NumOfLogShards == 0 {
   349  			return moerr.NewBadConfigNoCtx("NumOfLogShards not set")
   350  		}
   351  		if c.BootstrapConfig.NumOfTNShards == 0 {
   352  			return moerr.NewBadConfigNoCtx("NumOfDNShards not set")
   353  		}
   354  		if c.BootstrapConfig.NumOfLogShardReplicas == 0 {
   355  			return moerr.NewBadConfigNoCtx("NumOfLogShardReplica not set")
   356  		}
   357  		if c.BootstrapConfig.NumOfTNShards != c.BootstrapConfig.NumOfLogShards {
   358  			return moerr.NewBadConfigNoCtx("NumOfDNShards does not match NumOfLogShards")
   359  		}
   360  		members, err := c.GetInitHAKeeperMembers()
   361  		if err != nil {
   362  			return err
   363  		}
   364  		if len(members) == 0 {
   365  			return moerr.NewBadConfigNoCtx("InitHAKeeperMembers not set")
   366  		}
   367  		if uint64(len(members)) != c.BootstrapConfig.NumOfLogShardReplicas {
   368  			return moerr.NewBadConfigNoCtx("InitHAKeeperMembers does not match NumOfLogShardReplicas")
   369  		}
   370  	}
   371  
   372  	return nil
   373  }
   374  
   375  func DefaultConfig() Config {
   376  	uid := "7c4dccb4-4d3c-41f8-b482-5251dc7a41bf"
   377  	return Config{
   378  		FS:                       vfs.Default,
   379  		DeploymentID:             defaultDeploymentID,
   380  		UUID:                     uid,
   381  		RTTMillisecond:           200,
   382  		DataDir:                  defaultDataDir,
   383  		SnapshotExportDir:        defaultSnapshotExportDir,
   384  		MaxExportedSnapshot:      defaultMaxExportedSnapshot,
   385  		ServiceAddress:           defaultServiceAddress,
   386  		RaftAddress:              defaultRaftAddress,
   387  		ServiceHost:              DefaultServiceHost,
   388  		UseTeeLogDB:              false,
   389  		LogDBBufferSize:          defaultLogDBBufferSize,
   390  		GossipAddress:            defaultGossipAddress,
   391  		GossipSeedAddresses:      []string{DefaultGossipServiceAddress},
   392  		GossipProbeInterval:      toml.Duration{Duration: defaultGossipProbeInterval},
   393  		GossipAllowSelfAsSeed:    true,
   394  		HeartbeatInterval:        toml.Duration{Duration: defaultHeartbeatInterval},
   395  		HAKeeperTickInterval:     toml.Duration{Duration: time.Second / hakeeper.DefaultTickPerSecond},
   396  		HAKeeperCheckInterval:    toml.Duration{Duration: hakeeper.CheckDuration},
   397  		TruncateInterval:         toml.Duration{Duration: defaultTruncateInterval},
   398  		HAKeeperTruncateInterval: toml.Duration{Duration: defaultHAKeeperTruncateInterval},
   399  		RPC: struct {
   400  			MaxMessageSize toml.ByteSize `toml:"max-message-size"`
   401  			EnableCompress bool          `toml:"enable-compress"`
   402  		}(struct {
   403  			MaxMessageSize toml.ByteSize
   404  			EnableCompress bool
   405  		}{
   406  			MaxMessageSize: toml.ByteSize(defaultMaxMessageSize),
   407  			EnableCompress: false,
   408  		}),
   409  		BootstrapConfig: struct {
   410  			BootstrapCluster      bool     `toml:"bootstrap-cluster"`
   411  			NumOfLogShards        uint64   `toml:"num-of-log-shards"`
   412  			NumOfTNShards         uint64   `toml:"num-of-tn-shards"`
   413  			NumOfLogShardReplicas uint64   `toml:"num-of-log-shard-replicas"`
   414  			InitHAKeeperMembers   []string `toml:"init-hakeeper-members" user_setting:"advanced"`
   415  			Restore               struct {
   416  				FilePath string `toml:"file-path"`
   417  				Force    bool   `toml:"force"`
   418  			} `toml:"restore"`
   419  		}(struct {
   420  			BootstrapCluster      bool
   421  			NumOfLogShards        uint64
   422  			NumOfTNShards         uint64
   423  			NumOfLogShardReplicas uint64
   424  			InitHAKeeperMembers   []string
   425  			Restore               struct {
   426  				FilePath string
   427  				Force    bool
   428  			}
   429  		}{
   430  			BootstrapCluster:      true,
   431  			NumOfLogShards:        1,
   432  			NumOfTNShards:         1,
   433  			NumOfLogShardReplicas: 1,
   434  			InitHAKeeperMembers:   []string{"131072:" + uid},
   435  			Restore: struct {
   436  				FilePath string
   437  				Force    bool
   438  			}{
   439  				FilePath: defaultRestoreFilePath,
   440  				Force:    false,
   441  			},
   442  		}),
   443  		HAKeeperConfig: struct {
   444  			TickPerSecond   int           `toml:"tick-per-second"`
   445  			LogStoreTimeout toml.Duration `toml:"log-store-timeout"`
   446  			TNStoreTimeout  toml.Duration `toml:"tn-store-timeout"`
   447  			CNStoreTimeout  toml.Duration `toml:"cn-store-timeout"`
   448  		}(struct {
   449  			TickPerSecond   int
   450  			LogStoreTimeout toml.Duration
   451  			TNStoreTimeout  toml.Duration
   452  			CNStoreTimeout  toml.Duration
   453  		}{
   454  			TickPerSecond:   hakeeper.DefaultTickPerSecond,
   455  			LogStoreTimeout: toml.Duration{Duration: hakeeper.DefaultLogStoreTimeout},
   456  			TNStoreTimeout:  toml.Duration{Duration: hakeeper.DefaultTNStoreTimeout},
   457  			CNStoreTimeout:  toml.Duration{Duration: hakeeper.DefaultCNStoreTimeout},
   458  		}),
   459  		HAKeeperClientConfig: HAKeeperClientConfig{
   460  			DiscoveryAddress: "",
   461  			ServiceAddresses: []string{DefaultLogServiceServiceAddress},
   462  			AllocateIDBatch:  100,
   463  			EnableCompress:   false,
   464  		},
   465  		DisableWorkers: false,
   466  		// Not used for now.
   467  		Ctl: struct {
   468  			ListenAddress  string `toml:"listen-address"`
   469  			ServiceAddress string `toml:"service-address"`
   470  		}(struct {
   471  			ListenAddress  string
   472  			ServiceAddress string
   473  		}{ListenAddress: "", ServiceAddress: ""}),
   474  	}
   475  }
   476  
   477  // Fill just fills the listen addresses. This function is deprecated and will be removed
   478  // as the configurations are all deprecated.
   479  func (c *Config) Fill() {
   480  	if len(c.ServiceAddress) == 0 {
   481  		c.ServiceAddress = defaultServiceAddress
   482  		c.ServiceListenAddress = defaultServiceAddress
   483  	} else if len(c.ServiceAddress) != 0 && len(c.ServiceListenAddress) == 0 {
   484  		c.ServiceListenAddress = c.ServiceAddress
   485  	}
   486  	if len(c.RaftAddress) == 0 {
   487  		c.RaftAddress = defaultRaftAddress
   488  		c.RaftListenAddress = defaultRaftAddress
   489  	} else if len(c.RaftAddress) != 0 && len(c.RaftListenAddress) == 0 {
   490  		c.RaftListenAddress = c.RaftAddress
   491  	}
   492  	// If GossipAddressV2 is set, we use it as gossip address, and GossipAddress
   493  	// will be overridden by it.
   494  	if len(c.GossipAddressV2) != 0 {
   495  		c.GossipAddress = c.GossipAddressV2
   496  	}
   497  	if len(c.GossipAddress) == 0 {
   498  		c.GossipAddress = defaultGossipAddress
   499  		c.GossipListenAddress = defaultGossipAddress
   500  	} else if len(c.GossipAddress) != 0 && len(c.GossipListenAddress) == 0 {
   501  		c.GossipListenAddress = c.GossipAddress
   502  	}
   503  	if len(c.GossipSeedAddresses) == 0 {
   504  		c.GossipSeedAddresses = []string{defaultGossipSeedAddress}
   505  	}
   506  }
   507  
   508  // HAKeeperClientConfig is the config for HAKeeper clients.
   509  type HAKeeperClientConfig struct {
   510  	// DiscoveryAddress is the Log Service discovery address provided by k8s.
   511  	DiscoveryAddress string `toml:"discovery-address"`
   512  	// ServiceAddresses is a list of well known Log Services' service addresses.
   513  	ServiceAddresses []string `toml:"service-addresses"`
   514  	// AllocateIDBatch how many IDs are assigned from hakeeper each time. Default is
   515  	// 100.
   516  	AllocateIDBatch uint64 `toml:"allocate-id-batch"`
   517  	// EnableCompress enable compress
   518  	EnableCompress bool `toml:"enable-compress"`
   519  }
   520  
   521  // Validate validates the HAKeeperClientConfig.
   522  func (c *HAKeeperClientConfig) Validate() error {
   523  	if len(c.DiscoveryAddress) == 0 && len(c.ServiceAddresses) == 0 {
   524  		c.ServiceAddresses = []string{DefaultLogServiceServiceAddress}
   525  	}
   526  	if c.AllocateIDBatch == 0 {
   527  		c.AllocateIDBatch = 100
   528  	}
   529  	return nil
   530  }
   531  
   532  // ClientConfig is the configuration for log service clients.
   533  type ClientConfig struct {
   534  	// Tag client tag
   535  	Tag string
   536  	// ReadOnly indicates whether this is a read-only client.
   537  	ReadOnly bool
   538  	// LogShardID is the shard ID of the log service shard to be used.
   539  	LogShardID uint64
   540  	// TNReplicaID is the replica ID of the TN that owns the created client.
   541  	TNReplicaID uint64
   542  	// DiscoveryAddress is the Log Service discovery address provided by k8s.
   543  	DiscoveryAddress string
   544  	// LogService nodes service addresses. This field is provided for testing
   545  	// purposes only.
   546  	ServiceAddresses []string
   547  	// MaxMessageSize is the max message size for RPC.
   548  	MaxMessageSize int
   549  	// EnableCompress enable compress
   550  	EnableCompress bool
   551  }
   552  
   553  // Validate validates the ClientConfig.
   554  func (c *ClientConfig) Validate() error {
   555  	if c.LogShardID == 0 {
   556  		return moerr.NewBadConfigNoCtx("LogShardID value cannot be 0")
   557  	}
   558  	if c.TNReplicaID == 0 {
   559  		return moerr.NewBadConfigNoCtx("DNReplicaID value cannot be 0")
   560  	}
   561  	if len(c.DiscoveryAddress) == 0 && len(c.ServiceAddresses) == 0 {
   562  		c.ServiceAddresses = []string{DefaultLogServiceServiceAddress}
   563  	}
   564  	return nil
   565  }
   566  
   567  func splitAddresses(v string) []string {
   568  	results := make([]string, 0)
   569  	parts := strings.Split(v, ";")
   570  	for _, v := range parts {
   571  		t := strings.TrimSpace(v)
   572  		if len(t) > 0 {
   573  			results = append(results, t)
   574  		}
   575  	}
   576  	return results
   577  }
   578  
   579  func (c *Config) LogServiceListenAddr() string {
   580  	if c.LogServicePort != 0 {
   581  		return fmt.Sprintf("%s:%d", DefaultListenHost, c.LogServicePort)
   582  	}
   583  	return c.ServiceListenAddress
   584  }
   585  
   586  func (c *Config) LogServiceServiceAddr() string {
   587  	if c.LogServicePort != 0 {
   588  		return fmt.Sprintf("%s:%d", c.ServiceHost, c.LogServicePort)
   589  	}
   590  	return c.ServiceAddress
   591  }
   592  
   593  func (c *Config) RaftListenAddr() string {
   594  	if c.RaftPort != 0 {
   595  		return fmt.Sprintf("%s:%d", DefaultListenHost, c.RaftPort)
   596  	}
   597  	return c.RaftListenAddress
   598  }
   599  
   600  func (c *Config) RaftServiceAddr() string {
   601  	if c.RaftPort != 0 {
   602  		return fmt.Sprintf("%s:%d", c.ServiceHost, c.RaftPort)
   603  	}
   604  	return c.RaftAddress
   605  }
   606  
   607  func (c *Config) GossipListenAddr() string {
   608  	if c.GossipPort != 0 {
   609  		return fmt.Sprintf("%s:%d", DefaultListenHost, c.GossipPort)
   610  	}
   611  	return c.GossipListenAddress
   612  }
   613  
   614  func (c *Config) GossipServiceAddr() string {
   615  	if c.GossipPort != 0 {
   616  		return fmt.Sprintf("%s:%d", c.ServiceHost, c.GossipPort)
   617  	}
   618  	return c.GossipAddress
   619  }
   620  
   621  func dumpLogConfig(cfg Config) (map[string]*logservicepb.ConfigItem, error) {
   622  	defCfg := Config{}
   623  	return util.DumpConfig(cfg, defCfg)
   624  }