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