github.com/matrixorigin/matrixone@v1.2.0/pkg/tests/service/logservice.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 service 16 17 import ( 18 "path/filepath" 19 "sync" 20 21 "github.com/google/uuid" 22 "github.com/lni/dragonboat/v4" 23 "github.com/lni/vfs" 24 "github.com/matrixorigin/matrixone/pkg/common/runtime" 25 "github.com/matrixorigin/matrixone/pkg/taskservice" 26 "github.com/stretchr/testify/assert" 27 "go.uber.org/zap" 28 29 "github.com/matrixorigin/matrixone/pkg/fileservice" 30 "github.com/matrixorigin/matrixone/pkg/logservice" 31 logpb "github.com/matrixorigin/matrixone/pkg/pb/logservice" 32 ) 33 34 var ( 35 defaultDeploymentID uint64 = 1 36 defaultRTTMillisecond uint64 = 5 37 ) 38 39 // LogService describes expected behavior for log service. 40 type LogService interface { 41 // Start sends heartbeat and start to handle command. 42 Start() error 43 // Close stops store 44 Close() error 45 // Status returns the status of service 46 Status() ServiceStatus 47 48 // ID returns uuid of store 49 ID() string 50 51 // IsLeaderHakeeper checks hakeeper information. 52 IsLeaderHakeeper() (bool, error) 53 54 // GetClusterState returns cluster information from hakeeper leader. 55 GetClusterState() (*logpb.CheckerState, error) 56 57 // SetInitialClusterInfo sets cluster initialize state. 58 SetInitialClusterInfo(numOfLogShards, numOfTNShards, numOfLogReplicas uint64) error 59 60 // StartHAKeeperReplica starts hakeeper replicas. 61 StartHAKeeperReplica(replicaID uint64, initialReplicas map[uint64]dragonboat.Target, join bool) error 62 63 // GetTaskService returns the taskService 64 GetTaskService() (taskservice.TaskService, bool) 65 } 66 67 // logService wraps logservice.WrappedService. 68 // 69 // The main purpose of this structure is to maintain status 70 type logService struct { 71 sync.Mutex 72 status ServiceStatus 73 svc *logservice.WrappedService 74 } 75 76 func (ls *logService) Start() error { 77 ls.Lock() 78 defer ls.Unlock() 79 80 if ls.status == ServiceInitialized { 81 err := ls.svc.Start() 82 if err != nil { 83 return err 84 } 85 ls.status = ServiceStarted 86 } 87 88 return nil 89 } 90 91 func (ls *logService) Close() error { 92 ls.Lock() 93 defer ls.Unlock() 94 95 if ls.status == ServiceStarted { 96 err := ls.svc.Close() 97 if err != nil { 98 return err 99 } 100 ls.status = ServiceClosed 101 } 102 103 return nil 104 } 105 106 func (ls *logService) Status() ServiceStatus { 107 ls.Lock() 108 defer ls.Unlock() 109 return ls.status 110 } 111 112 func (ls *logService) ID() string { 113 return ls.svc.ID() 114 } 115 116 func (ls *logService) IsLeaderHakeeper() (bool, error) { 117 return ls.svc.IsLeaderHakeeper() 118 } 119 120 func (ls *logService) GetClusterState() (*logpb.CheckerState, error) { 121 return ls.svc.GetClusterState() 122 } 123 124 func (ls *logService) SetInitialClusterInfo( 125 numOfLogShards, numOfTNShards, numOfLogReplicas uint64, 126 ) error { 127 return ls.svc.SetInitialClusterInfo( 128 numOfLogShards, numOfTNShards, numOfLogReplicas, 129 ) 130 } 131 132 func (ls *logService) StartHAKeeperReplica( 133 replicaID uint64, initialReplicas map[uint64]dragonboat.Target, join bool, 134 ) error { 135 return ls.svc.StartHAKeeperReplica(replicaID, initialReplicas, join) 136 } 137 138 func (ls *logService) GetTaskService() (taskservice.TaskService, bool) { 139 return ls.svc.GetTaskService() 140 } 141 142 // logOptions is options for a log service. 143 type logOptions []logservice.Option 144 145 // newLogService constructs an instance of `LogService`. 146 func newLogService( 147 cfg logservice.Config, 148 fs fileservice.FileService, 149 opts logOptions, 150 ) (LogService, error) { 151 svc, err := logservice.NewWrappedService(cfg, fs, nil, opts...) 152 if err != nil { 153 return nil, err 154 } 155 return &logService{status: ServiceInitialized, svc: svc}, nil 156 } 157 158 // buildLogConfig builds configuration for a log service. 159 func buildLogConfig( 160 index int, opt Options, address *serviceAddresses, 161 ) logservice.Config { 162 cfg := logservice.DefaultConfig() 163 uid, _ := uuid.NewV7() 164 cfg.UUID = uid.String() 165 cfg.FS = vfs.NewStrictMem() 166 cfg.DeploymentID = defaultDeploymentID 167 cfg.RTTMillisecond = defaultRTTMillisecond 168 cfg.LogServicePort = getPort(address.getLogListenAddress(index)) // hakeeper client use this address 169 cfg.RaftPort = getPort(address.getLogRaftAddress(index)) 170 cfg.GossipPort = getPort(address.getLogGossipAddress(index)) 171 cfg.GossipSeedAddresses = address.getLogGossipSeedAddresses() 172 cfg.GossipAllowSelfAsSeed = opt.initial.logReplicaNum == 1 173 cfg.DataDir = filepath.Join(opt.rootDataDir, cfg.UUID) 174 cfg.HeartbeatInterval.Duration = opt.heartbeat.log 175 cfg.HAKeeperCheckInterval.Duration = opt.hakeeper.checkInterval 176 cfg.HAKeeperClientConfig.ServiceAddresses = address.listHAKeeperListenAddresses() 177 // setting hakeeper configuration 178 cfg.HAKeeperConfig.TickPerSecond = opt.hakeeper.tickPerSecond 179 cfg.HAKeeperConfig.LogStoreTimeout.Duration = opt.hakeeper.logStoreTimeout 180 cfg.HAKeeperConfig.TNStoreTimeout.Duration = opt.hakeeper.tnStoreTimeout 181 cfg.HAKeeperConfig.CNStoreTimeout.Duration = opt.hakeeper.cnStoreTimeout 182 183 return cfg 184 } 185 186 // buildLogOptions builds options for a log service. 187 // 188 // NB: We need the filled version of logservice.Config. 189 func buildLogOptions(cfg logservice.Config, filter FilterFunc) logOptions { 190 return []logservice.Option{ 191 logservice.WithBackendFilter(filter), 192 logservice.WithRuntime(runtime.ProcessLevelRuntime()), 193 } 194 } 195 196 // startHAKeeperReplica selects the first `n` log services to start hakeeper replica. 197 func (c *testCluster) startHAKeeperReplica() error { 198 selected := c.selectHAkeeperServices() 199 assert.NotZero(c.t, len(selected)) 200 201 c.logger.Info("start hakeeper replicas", zap.Int("batch", len(selected))) 202 203 indexToReplicaID := func(index int) uint64 { 204 return uint64(index + 1) 205 } 206 207 // construct peers 208 peers := make(map[uint64]dragonboat.Target) 209 for i, logsvc := range selected { 210 replicaID := indexToReplicaID(i) 211 peers[replicaID] = logsvc.ID() 212 } 213 214 // start all hakeeper replicas 215 for i, logsvc := range selected { 216 replicaID := indexToReplicaID(i) 217 err := logsvc.StartHAKeeperReplica(replicaID, peers, false) 218 if err != nil { 219 c.logger.Error("fail to start hakeeper replica", zap.Error(err), zap.Int("index", i)) 220 return err 221 } 222 c.logger.Info("hakeeper replica started", zap.Int("index", i)) 223 } 224 225 return nil 226 } 227 228 // setInitialClusterInfo initializes cluster information. 229 func (c *testCluster) setInitialClusterInfo() error { 230 errChan := make(chan error, 1) 231 232 initialize := func() { 233 var err error 234 defer func() { 235 errChan <- err 236 }() 237 238 selected := c.selectHAkeeperServices() 239 assert.NotZero(c.t, len(selected)) 240 241 c.logger.Info("initialize cluster information") 242 243 err = selected[0].SetInitialClusterInfo( 244 c.opt.initial.logShardNum, 245 c.opt.initial.tnShardNum, 246 c.opt.initial.logReplicaNum, 247 ) 248 if err != nil { 249 c.logger.Error("fail to initialize cluster", zap.Error(err)) 250 return 251 } 252 253 c.logger.Info("cluster information initialized") 254 } 255 256 // initialize cluster only once 257 c.log.once.Do(initialize) 258 return <-errChan 259 } 260 261 // listHAKeeperService lists all log services that start hakeeper. 262 func (c *testCluster) selectHAkeeperServices() []LogService { 263 n := haKeeperNum(c.opt.initial.logServiceNum) 264 svcs := make([]LogService, n) 265 for i := 0; i < n; i++ { 266 svcs[i] = c.log.svcs[i] 267 } 268 return svcs 269 }