github.com/matrixorigin/matrixone@v1.2.0/pkg/cnservice/server_task.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 cnservice 16 17 import ( 18 "context" 19 "fmt" 20 "strings" 21 "time" 22 23 "github.com/matrixorigin/matrixone/pkg/common/moerr" 24 "github.com/matrixorigin/matrixone/pkg/common/runtime" 25 "github.com/matrixorigin/matrixone/pkg/config" 26 "github.com/matrixorigin/matrixone/pkg/frontend" 27 "github.com/matrixorigin/matrixone/pkg/logutil" 28 "github.com/matrixorigin/matrixone/pkg/objectio" 29 "github.com/matrixorigin/matrixone/pkg/pb/api" 30 logservicepb "github.com/matrixorigin/matrixone/pkg/pb/logservice" 31 "github.com/matrixorigin/matrixone/pkg/pb/task" 32 moconnector "github.com/matrixorigin/matrixone/pkg/stream/connector" 33 "github.com/matrixorigin/matrixone/pkg/taskservice" 34 "github.com/matrixorigin/matrixone/pkg/util" 35 "github.com/matrixorigin/matrixone/pkg/util/executor" 36 "github.com/matrixorigin/matrixone/pkg/util/export" 37 db_holder "github.com/matrixorigin/matrixone/pkg/util/export/etl/db" 38 ie "github.com/matrixorigin/matrixone/pkg/util/internalExecutor" 39 "github.com/matrixorigin/matrixone/pkg/util/metric/mometric" 40 "go.uber.org/zap" 41 ) 42 43 func (s *service) adjustSQLAddress() { 44 if s.cfg.SQLAddress == "" { 45 ip := "127.0.0.1" 46 if s.cfg.Frontend.Host != "" && 47 s.cfg.Frontend.Host != "0.0.0.0" { 48 ip = s.cfg.Frontend.Host 49 } 50 51 s.cfg.SQLAddress = fmt.Sprintf("%s:%d", 52 ip, 53 s.cfg.Frontend.Port) 54 } 55 } 56 57 func (s *service) initTaskServiceHolder() { 58 s.adjustSQLAddress() 59 60 getClient := func() util.HAKeeperClient { 61 client, _ := s.getHAKeeperClient() 62 return client 63 } 64 s.task.Lock() 65 defer s.task.Unlock() 66 if s.task.storageFactory == nil { 67 s.task.holder = taskservice.NewTaskServiceHolder( 68 runtime.ProcessLevelRuntime(), 69 util.AddressFunc(getClient)) 70 } else { 71 s.task.holder = taskservice.NewTaskServiceHolderWithTaskStorageFactorySelector( 72 runtime.ProcessLevelRuntime(), 73 util.AddressFunc(getClient), 74 func(_, _, _ string) taskservice.TaskStorageFactory { 75 return s.task.storageFactory 76 }) 77 } 78 } 79 80 func (s *service) createTaskService(command *logservicepb.CreateTaskService) { 81 // Notify frontend to setup the special account used to task framework create and query async tasks. 82 // The account is always in the memory. 83 frontend.SetSpecialUser(command.User.Username, []byte(command.User.Password)) 84 85 if err := s.task.holder.Create(*command); err != nil { 86 s.logger.Error("create task service failed", zap.Error(err)) 87 return 88 } 89 s.startTaskRunner() 90 91 ts, ok := s.task.holder.Get() 92 if !ok { 93 panic("no task service is initialized") 94 } 95 s.pu.TaskService = ts 96 } 97 98 func (s *service) initSqlWriterFactory() { 99 getClient := func() util.HAKeeperClient { 100 client, _ := s.getHAKeeperClient() 101 return client 102 } 103 db_holder.SetSQLWriterDBAddressFunc(util.AddressFunc(getClient)) 104 } 105 106 func (s *service) createSQLLogger(command *logservicepb.CreateTaskService) { 107 frontend.SetSpecialUser(db_holder.MOLoggerUser, []byte(command.User.Password)) 108 db_holder.SetSQLWriterDBUser(db_holder.MOLoggerUser, command.User.Password) 109 } 110 111 func (s *service) canClaimDaemonTask(taskAccount string) bool { 112 const accountKey = "account" 113 ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) 114 defer cancel() 115 116 state, err := s._hakeeperClient.GetClusterState(ctx) 117 if err != nil { 118 return false 119 } 120 stores := state.CNState.Stores 121 122 info, ok := stores[s.cfg.UUID] 123 // 1. Cannot find current CN service UUID in cluster state. 124 if !ok { 125 return false 126 } 127 128 // We assume that the runner is a shard runner. 129 localShared := true 130 131 // 2. If the current runner has the same account info, return true. 132 for _, account := range info.Labels[accountKey].Labels { 133 if account != "" { 134 // This CN node has account, so it is not a shared one. 135 localShared = false 136 } 137 if strings.EqualFold(account, taskAccount) { 138 return true 139 } 140 } 141 142 isSysTask := strings.EqualFold(taskAccount, frontend.GetDefaultTenant()) 143 144 var taskHasRunner bool 145 for _, store := range stores { 146 for key, labelInfo := range store.Labels { 147 if strings.EqualFold(accountKey, key) { 148 for _, label := range labelInfo.Labels { 149 if strings.EqualFold(label, taskAccount) { 150 taskHasRunner = true 151 } 152 } 153 } 154 } 155 } 156 157 // 3. If there are no other runners for this task, and local runner is a shared one or the 158 // task is belongs to sys account, we could run it. 159 if !taskHasRunner && (localShared || isSysTask) { 160 return true 161 } 162 163 // 4. Otherwise, we could not run this task. 164 return false 165 } 166 167 func (s *service) startTaskRunner() { 168 s.task.Lock() 169 defer s.task.Unlock() 170 171 if s.task.runner != nil { 172 return 173 } 174 175 ts, ok := s.task.holder.Get() 176 if !ok { 177 panic("task service must created") 178 } 179 180 s.task.runner = taskservice.NewTaskRunner(s.cfg.UUID, 181 ts, 182 s.canClaimDaemonTask, 183 taskservice.WithRunnerLogger(s.logger), 184 taskservice.WithOptions( 185 s.cfg.TaskRunner.QueryLimit, 186 s.cfg.TaskRunner.Parallelism, 187 s.cfg.TaskRunner.MaxWaitTasks, 188 s.cfg.TaskRunner.FetchInterval.Duration, 189 s.cfg.TaskRunner.FetchTimeout.Duration, 190 s.cfg.TaskRunner.RetryInterval.Duration, 191 s.cfg.TaskRunner.HeartbeatInterval.Duration, 192 s.cfg.TaskRunner.HeartbeatTimeout.Duration, 193 ), 194 ) 195 196 s.registerExecutorsLocked() 197 if err := s.task.runner.Start(); err != nil { 198 s.logger.Error("start task runner failed", 199 zap.Error(err)) 200 } 201 } 202 203 func (s *service) GetTaskRunner() taskservice.TaskRunner { 204 s.task.RLock() 205 defer s.task.RUnlock() 206 return s.task.runner 207 } 208 209 func (s *service) GetTaskService() (taskservice.TaskService, bool) { 210 s.task.RLock() 211 defer s.task.RUnlock() 212 return s.task.holder.Get() 213 } 214 215 func (s *service) stopTask() error { 216 defer logutil.LogClose(s.logger, "cnservice/task")() 217 218 s.task.Lock() 219 defer s.task.Unlock() 220 if err := s.task.holder.Close(); err != nil { 221 return err 222 } 223 if s.task.runner != nil { 224 return s.task.runner.Stop() 225 } 226 return nil 227 } 228 229 func (s *service) registerExecutorsLocked() { 230 if s.task.runner == nil { 231 return 232 } 233 234 pu := config.NewParameterUnit( 235 &s.cfg.Frontend, 236 nil, 237 nil, 238 nil) 239 pu.StorageEngine = s.storeEngine 240 pu.TxnClient = s._txnClient 241 s.cfg.Frontend.SetDefaultValues() 242 pu.FileService = s.fileService 243 pu.LockService = s.lockService 244 ieFactory := func() ie.InternalExecutor { 245 return frontend.NewInternalExecutor() 246 } 247 248 ts, ok := s.task.holder.Get() 249 if !ok { 250 panic(moerr.NewInternalErrorNoCtx("task Service not ok")) 251 } 252 253 // init metric/log merge task executor 254 s.task.runner.RegisterExecutor(task.TaskCode_MetricLogMerge, 255 export.MergeTaskExecutorFactory(export.WithFileService(s.etlFS))) 256 // init metric task 257 s.task.runner.RegisterExecutor(task.TaskCode_MetricStorageUsage, 258 mometric.GetMetricStorageUsageExecutor(ieFactory)) 259 // streaming connector task 260 s.task.runner.RegisterExecutor(task.TaskCode_ConnectorKafkaSink, 261 moconnector.KafkaSinkConnectorExecutor(s.logger, ts, ieFactory, s.task.runner.Attach)) 262 s.task.runner.RegisterExecutor(task.TaskCode_MergeObject, 263 func(ctx context.Context, task task.Task) error { 264 metadata := task.GetMetadata() 265 var mergeTask api.MergeTaskEntry 266 err := mergeTask.Unmarshal(metadata.Context) 267 if err != nil { 268 return err 269 } 270 271 objs := make([]string, len(mergeTask.ToMergeObjs)) 272 for i, b := range mergeTask.ToMergeObjs { 273 stats := objectio.ObjectStats(b) 274 objs[i] = stats.ObjectName().String() 275 } 276 sql := fmt.Sprintf("select mo_ctl('DN', 'MERGEOBJECTS', '%s.%s:%s')", 277 mergeTask.DbName, mergeTask.TableName, strings.Join(objs, ",")) 278 ctx, cancel := context.WithTimeout(ctx, 10*time.Minute) 279 defer cancel() 280 opts := executor.Options{}.WithAccountID(mergeTask.AccountId).WithWaitCommittedLogApplied() 281 _, err = s.sqlExecutor.Exec(ctx, sql, opts) 282 return err 283 }, 284 ) 285 }