github.com/matrixorigin/matrixone@v0.7.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 "github.com/BurntSushi/toml" 29 "github.com/matrixorigin/matrixone/pkg/cnservice" 30 "github.com/matrixorigin/matrixone/pkg/common/moerr" 31 "github.com/matrixorigin/matrixone/pkg/config" 32 "github.com/matrixorigin/matrixone/pkg/defines" 33 "github.com/matrixorigin/matrixone/pkg/dnservice" 34 "github.com/matrixorigin/matrixone/pkg/fileservice" 35 "github.com/matrixorigin/matrixone/pkg/logservice" 36 "github.com/matrixorigin/matrixone/pkg/logutil" 37 "github.com/matrixorigin/matrixone/pkg/pb/metadata" 38 tomlutil "github.com/matrixorigin/matrixone/pkg/util/toml" 39 ) 40 41 var ( 42 defaultMaxClockOffset = time.Millisecond * 500 43 defaultMemoryLimit = 1 << 40 44 45 supportServiceTypes = map[string]metadata.ServiceType{ 46 metadata.ServiceType_CN.String(): metadata.ServiceType_CN, 47 metadata.ServiceType_DN.String(): metadata.ServiceType_DN, 48 metadata.ServiceType_LOG.String(): metadata.ServiceType_LOG, 49 } 50 ) 51 52 // LaunchConfig Start a MO cluster with launch 53 type LaunchConfig struct { 54 // LogServiceConfigFiles log service config files 55 LogServiceConfigFiles []string `toml:"logservices"` 56 // DNServiceConfigsFiles log service config files 57 DNServiceConfigsFiles []string `toml:"dnservices"` 58 // CNServiceConfigsFiles log service config files 59 CNServiceConfigsFiles []string `toml:"cnservices"` 60 } 61 62 // Config mo-service configuration 63 type Config struct { 64 // DataDir data dir 65 DataDir string `toml:"data-dir"` 66 // Log log config 67 Log logutil.LogConfig `toml:"log"` 68 // ServiceType service type, select the corresponding configuration to start the 69 // service according to the service type. [CN|DN|LOG] 70 ServiceType string `toml:"service-type"` 71 // FileServices the config for file services 72 FileServices []fileservice.Config `toml:"fileservice"` 73 // HAKeeperClient hakeeper client config 74 HAKeeperClient logservice.HAKeeperClientConfig `toml:"hakeeper-client"` 75 // DN dn service config 76 DN dnservice.Config `toml:"dn"` 77 // LogService is the config for log service 78 LogService logservice.Config `toml:"logservice"` 79 // CN cn service config 80 CN cnservice.Config `toml:"cn"` 81 // Observability parameters for the metric/trace 82 Observability config.ObservabilityParameters `toml:"observability"` 83 84 // Clock txn clock type. [LOCAL|HLC]. Default is LOCAL. 85 Clock struct { 86 // Backend clock backend implementation. [LOCAL|HLC], default LOCAL. 87 Backend string `toml:"source"` 88 // MaxClockOffset max clock offset between two nodes. Default is 500ms. 89 // Only valid when enable-check-clock-offset is true 90 MaxClockOffset tomlutil.Duration `toml:"max-clock-offset"` 91 // EnableCheckMaxClockOffset enable local clock offset checker 92 EnableCheckMaxClockOffset bool `toml:"enable-check-clock-offset"` 93 } 94 95 // Limit limit configuration 96 Limit struct { 97 // Memory memory usage limit, see mpool for details 98 Memory tomlutil.ByteSize `toml:"memory"` 99 } 100 } 101 102 func parseConfigFromFile(file string, cfg any) error { 103 if file == "" { 104 return moerr.NewInternalError(context.Background(), "toml config file not set") 105 } 106 data, err := os.ReadFile(file) 107 if err != nil { 108 return err 109 } 110 return parseFromString(string(data), cfg) 111 } 112 113 func parseFromString(data string, cfg any) error { 114 if _, err := toml.Decode(data, cfg); err != nil { 115 return err 116 } 117 return nil 118 } 119 120 func (c *Config) validate() error { 121 if c.DataDir == "" { 122 c.DataDir = "./mo-data" 123 } 124 if _, err := c.getServiceType(); err != nil { 125 return err 126 } 127 if c.Clock.MaxClockOffset.Duration == 0 { 128 c.Clock.MaxClockOffset.Duration = defaultMaxClockOffset 129 } 130 if c.Clock.Backend == "" { 131 c.Clock.Backend = localClockBackend 132 } 133 if _, ok := supportTxnClockBackends[strings.ToUpper(c.Clock.Backend)]; !ok { 134 return moerr.NewInternalError(context.Background(), "%s clock backend not support", c.Clock.Backend) 135 } 136 if !c.Clock.EnableCheckMaxClockOffset { 137 c.Clock.MaxClockOffset.Duration = 0 138 } 139 for idx := range c.FileServices { 140 switch c.FileServices[idx].Name { 141 case defines.LocalFileServiceName, defines.ETLFileServiceName: 142 if c.FileServices[idx].DataDir == "" { 143 c.FileServices[idx].DataDir = filepath.Join(c.DataDir, strings.ToLower(c.FileServices[idx].Name)) 144 } 145 } 146 } 147 if c.Limit.Memory == 0 { 148 c.Limit.Memory = tomlutil.ByteSize(defaultMemoryLimit) 149 } 150 return nil 151 } 152 153 func (c *Config) createFileService(defaultName string) (*fileservice.FileServices, error) { 154 // create all services 155 services := make([]fileservice.FileService, 0, len(c.FileServices)) 156 for _, config := range c.FileServices { 157 158 // for old config compatibility 159 if strings.EqualFold(config.Name, "s3") { 160 config.Name = defines.SharedFileServiceName 161 } 162 163 service, err := fileservice.NewFileService(config) 164 if err != nil { 165 return nil, err 166 } 167 services = append(services, service) 168 } 169 170 // create FileServices 171 fs, err := fileservice.NewFileServices( 172 defaultName, 173 services..., 174 ) 175 if err != nil { 176 return nil, err 177 } 178 179 // validate default name 180 _, err = fileservice.Get[fileservice.FileService](fs, defaultName) 181 if err != nil { 182 return nil, err 183 } 184 185 // ensure local exists 186 _, err = fileservice.Get[fileservice.FileService](fs, defines.LocalFileServiceName) 187 if err != nil { 188 return nil, err 189 } 190 191 // ensure shared exists 192 _, err = fileservice.Get[fileservice.FileService](fs, defines.SharedFileServiceName) 193 if err != nil { 194 return nil, err 195 } 196 197 // ensure etl exists, for trace & metric 198 if !c.Observability.DisableMetric || !c.Observability.DisableTrace { 199 _, err = fileservice.Get[fileservice.FileService](fs, defines.ETLFileServiceName) 200 if err != nil { 201 return nil, moerr.ConvertPanicError(context.Background(), err) 202 } 203 } 204 205 return fs, nil 206 } 207 208 func (c *Config) getLogServiceConfig() logservice.Config { 209 cfg := c.LogService 210 logutil.Infof("hakeeper client cfg: %v", c.HAKeeperClient) 211 cfg.HAKeeperClientConfig = c.HAKeeperClient 212 cfg.DataDir = filepath.Join(c.DataDir, "logservice-data", cfg.UUID) 213 // Should sync directory structure with dragonboat. 214 hostname, err := os.Hostname() 215 if err != nil { 216 panic(fmt.Sprintf("cannot get hostname: %s", err)) 217 } 218 cfg.SnapshotExportDir = filepath.Join(cfg.DataDir, hostname, 219 fmt.Sprintf("%020d", cfg.DeploymentID), "exported-snapshot") 220 return cfg 221 } 222 223 func (c *Config) getDNServiceConfig() dnservice.Config { 224 cfg := c.DN 225 cfg.HAKeeper.ClientConfig = c.HAKeeperClient 226 cfg.DataDir = filepath.Join(c.DataDir, "dn-data", cfg.UUID) 227 return cfg 228 } 229 230 func (c *Config) getCNServiceConfig() cnservice.Config { 231 cfg := c.CN 232 cfg.HAKeeper.ClientConfig = c.HAKeeperClient 233 cfg.Frontend.SetLogAndVersion(&c.Log, Version) 234 cfg.Frontend.StorePath = filepath.Join(c.DataDir, "cn-data", cfg.UUID) 235 return cfg 236 } 237 238 func (c *Config) getObservabilityConfig() config.ObservabilityParameters { 239 cfg := c.Observability 240 cfg.SetDefaultValues(Version) 241 return cfg 242 } 243 244 // memberlist requires all gossip seed addresses to be provided as IP:PORT 245 func (c *Config) resolveGossipSeedAddresses() error { 246 result := make([]string, 0) 247 for _, addr := range c.LogService.GossipSeedAddresses { 248 host, port, err := net.SplitHostPort(addr) 249 if err != nil { 250 return err 251 } 252 ips, err := net.LookupIP(host) 253 if err != nil { 254 // the configured member may be failed currently, keep the host name anyway since 255 // memberlist would try to resolve it again 256 result = append(result, addr) 257 continue 258 } 259 // only keep IPv4 addresses 260 filtered := make([]string, 0) 261 for _, ip := range ips { 262 if ip.To4() != nil { 263 filtered = append(filtered, ip.String()) 264 } 265 } 266 if len(filtered) != 1 { 267 return moerr.NewBadConfig(context.Background(), "GossipSeedAddress %s", addr) 268 } 269 result = append(result, net.JoinHostPort(filtered[0], port)) 270 } 271 c.LogService.GossipSeedAddresses = result 272 return nil 273 } 274 275 func (c *Config) hashNodeID() uint16 { 276 st, err := c.getServiceType() 277 if err != nil { 278 panic(err) 279 } 280 281 uuid := "" 282 switch st { 283 case metadata.ServiceType_CN: 284 uuid = c.CN.UUID 285 case metadata.ServiceType_DN: 286 uuid = c.DN.UUID 287 case metadata.ServiceType_LOG: 288 uuid = c.LogService.UUID 289 } 290 if uuid == "" { 291 return 0 292 } 293 294 h := fnv.New32() 295 if _, err := h.Write([]byte(uuid)); err != nil { 296 panic(err) 297 } 298 v := h.Sum32() 299 return uint16(v % math.MaxUint16) 300 } 301 302 func (c *Config) getServiceType() (metadata.ServiceType, error) { 303 if v, ok := supportServiceTypes[strings.ToUpper(c.ServiceType)]; ok { 304 return v, nil 305 } 306 return metadata.ServiceType(0), moerr.NewInternalError(context.Background(), "service type %s not support", c.ServiceType) 307 } 308 309 func (c *Config) mustGetServiceType() metadata.ServiceType { 310 v, err := c.getServiceType() 311 if err != nil { 312 panic(err) 313 } 314 return v 315 } 316 317 func (c *Config) mustGetServiceUUID() string { 318 switch c.mustGetServiceType() { 319 case metadata.ServiceType_CN: 320 return c.CN.UUID 321 case metadata.ServiceType_DN: 322 return c.DN.UUID 323 case metadata.ServiceType_LOG: 324 return c.LogService.UUID 325 } 326 panic("impossible") 327 }