github.com/matrixorigin/matrixone@v1.2.0/pkg/cnservice/server_query.go (about) 1 // Copyright 2021 - 2023 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 20 "github.com/matrixorigin/matrixone/pkg/common/moerr" 21 "github.com/matrixorigin/matrixone/pkg/defines" 22 "github.com/matrixorigin/matrixone/pkg/fileservice" 23 "github.com/matrixorigin/matrixone/pkg/lockservice" 24 "github.com/matrixorigin/matrixone/pkg/logutil" 25 pblock "github.com/matrixorigin/matrixone/pkg/pb/lock" 26 "github.com/matrixorigin/matrixone/pkg/pb/query" 27 "github.com/matrixorigin/matrixone/pkg/pb/status" 28 "github.com/matrixorigin/matrixone/pkg/pb/task" 29 "github.com/matrixorigin/matrixone/pkg/pb/txn" 30 "github.com/matrixorigin/matrixone/pkg/perfcounter" 31 "github.com/matrixorigin/matrixone/pkg/queryservice" 32 qclient "github.com/matrixorigin/matrixone/pkg/queryservice/client" 33 "github.com/matrixorigin/matrixone/pkg/sql/plan/function/ctl" 34 "github.com/matrixorigin/matrixone/pkg/txn/client" 35 ) 36 37 func (s *service) initQueryService() error { 38 if s.gossipNode != nil { 39 s.gossipNode.SetListenAddrFn(s.gossipListenAddr) 40 s.gossipNode.SetServiceAddrFn(s.gossipServiceAddr) 41 s.gossipNode.SetCacheServerAddrFn(s.queryServiceServiceAddr) 42 if err := s.gossipNode.Create(); err != nil { 43 return err 44 } 45 } 46 47 var err error 48 s.queryService, err = queryservice.NewQueryService(s.cfg.UUID, 49 s.queryServiceListenAddr(), s.cfg.RPC) 50 if err != nil { 51 return err 52 } 53 s.initQueryCommandHandler() 54 55 s.queryClient, err = qclient.NewQueryClient(s.cfg.UUID, s.cfg.RPC) 56 if err != nil { 57 return err 58 } 59 return nil 60 } 61 62 func (s *service) initQueryCommandHandler() { 63 s.queryService.AddHandleFunc(query.CmdMethod_KillConn, s.handleKillConn, false) 64 s.queryService.AddHandleFunc(query.CmdMethod_AlterAccount, s.handleAlterAccount, false) 65 s.queryService.AddHandleFunc(query.CmdMethod_TraceSpan, s.handleTraceSpan, false) 66 s.queryService.AddHandleFunc(query.CmdMethod_GetLockInfo, s.handleGetLockInfo, false) 67 s.queryService.AddHandleFunc(query.CmdMethod_GetTxnInfo, s.handleGetTxnInfo, false) 68 s.queryService.AddHandleFunc(query.CmdMethod_GetCacheInfo, s.handleGetCacheInfo, false) 69 s.queryService.AddHandleFunc(query.CmdMethod_SyncCommit, s.handleSyncCommit, false) 70 s.queryService.AddHandleFunc(query.CmdMethod_GetCommit, s.handleGetCommit, false) 71 s.queryService.AddHandleFunc(query.CmdMethod_ShowProcessList, s.handleShowProcessList, false) 72 s.queryService.AddHandleFunc(query.CmdMethod_RunTask, s.handleRunTask, false) 73 s.queryService.AddHandleFunc(query.CmdMethod_RemoveRemoteLockTable, s.handleRemoveRemoteLockTable, false) 74 s.queryService.AddHandleFunc(query.CmdMethod_UnsubscribeTable, s.handleUnsubscribeTable, false) 75 s.queryService.AddHandleFunc(query.CmdMethod_GetCacheData, s.handleGetCacheData, false) 76 s.queryService.AddHandleFunc(query.CmdMethod_GetStatsInfo, s.handleGetStatsInfo, false) 77 s.queryService.AddHandleFunc(query.CmdMethod_GetPipelineInfo, s.handleGetPipelineInfo, false) 78 s.queryService.AddHandleFunc(query.CmdMethod_MigrateConnFrom, s.handleMigrateConnFrom, false) 79 s.queryService.AddHandleFunc(query.CmdMethod_MigrateConnTo, s.handleMigrateConnTo, false) 80 } 81 82 func (s *service) handleKillConn(ctx context.Context, req *query.Request, resp *query.Response) error { 83 if req == nil || req.KillConnRequest == nil { 84 return moerr.NewInternalError(ctx, "bad request") 85 } 86 rm := s.mo.GetRoutineManager() 87 if rm == nil { 88 return moerr.NewInternalError(ctx, "routine manager not initialized") 89 } 90 accountMgr := rm.GetAccountRoutineManager() 91 if accountMgr == nil { 92 return moerr.NewInternalError(ctx, "account routine manager not initialized") 93 } 94 95 accountMgr.EnKillQueue(req.KillConnRequest.AccountID, req.KillConnRequest.Version) 96 return nil 97 } 98 99 func (s *service) handleAlterAccount(ctx context.Context, req *query.Request, resp *query.Response) error { 100 if req == nil || req.AlterAccountRequest == nil { 101 return moerr.NewInternalError(ctx, "bad request") 102 } 103 rm := s.mo.GetRoutineManager() 104 if rm == nil { 105 return moerr.NewInternalError(ctx, "routine manager not initialized") 106 } 107 accountMgr := rm.GetAccountRoutineManager() 108 if accountMgr == nil { 109 return moerr.NewInternalError(ctx, "account routine manager not initialized") 110 } 111 112 accountMgr.AlterRoutineStatue(req.AlterAccountRequest.TenantId, req.AlterAccountRequest.Status) 113 return nil 114 } 115 116 func (s *service) handleTraceSpan(ctx context.Context, req *query.Request, resp *query.Response) error { 117 resp.TraceSpanResponse = new(query.TraceSpanResponse) 118 resp.TraceSpanResponse.Resp = ctl.SelfProcess( 119 req.TraceSpanRequest.Cmd, req.TraceSpanRequest.Spans, req.TraceSpanRequest.Threshold) 120 return nil 121 } 122 123 // handleGetLockInfo sends the lock info on current cn to another cn that needs. 124 func (s *service) handleGetLockInfo(ctx context.Context, req *query.Request, resp *query.Response) error { 125 resp.GetLockInfoResponse = new(query.GetLockInfoResponse) 126 127 //get lock info from lock service in current cn 128 locks := make([]*query.LockInfo, 0) 129 getAllLocks := func(tableID uint64, keys [][]byte, lock lockservice.Lock) bool { 130 //need copy keys 131 info := &query.LockInfo{ 132 TableId: tableID, 133 Keys: copyKeys(keys), 134 LockMode: lock.GetLockMode(), 135 IsRangeLock: lock.IsRangeLock(), 136 } 137 138 lock.IterHolders(func(holder pblock.WaitTxn) bool { 139 info.Holders = append(info.Holders, copyWaitTxn(holder)) 140 return true 141 }) 142 143 lock.IterWaiters(func(waiter pblock.WaitTxn) bool { 144 info.Waiters = append(info.Waiters, copyWaitTxn(waiter)) 145 return true 146 }) 147 148 locks = append(locks, info) 149 return true 150 } 151 152 s.lockService.IterLocks(getAllLocks) 153 154 // fill the response 155 resp.GetLockInfoResponse.CnId = s.metadata.UUID 156 resp.GetLockInfoResponse.LockInfoList = locks 157 return nil 158 } 159 160 func (s *service) handleGetTxnInfo(ctx context.Context, req *query.Request, resp *query.Response) error { 161 resp.GetTxnInfoResponse = new(query.GetTxnInfoResponse) 162 txns := make([]*query.TxnInfo, 0) 163 164 s._txnClient.IterTxns(func(view client.TxnOverview) bool { 165 info := &query.TxnInfo{ 166 CreateAt: view.CreateAt, 167 Meta: copyTxnMeta(view.Meta), 168 UserTxn: view.UserTxn, 169 } 170 171 for _, lock := range view.WaitLocks { 172 info.WaitLocks = append(info.WaitLocks, copyTxnInfo(lock)) 173 } 174 txns = append(txns, info) 175 return true 176 }) 177 178 resp.GetTxnInfoResponse.CnId = s.metadata.UUID 179 resp.GetTxnInfoResponse.TxnInfoList = txns 180 return nil 181 } 182 183 func (s *service) handleSyncCommit(ctx context.Context, req *query.Request, resp *query.Response) error { 184 s._txnClient.SyncLatestCommitTS(req.SycnCommit.LatestCommitTS) 185 return nil 186 } 187 188 func (s *service) handleGetCommit(ctx context.Context, req *query.Request, resp *query.Response) error { 189 resp.GetCommit = new(query.GetCommitResponse) 190 resp.GetCommit.CurrentCommitTS = s._txnClient.GetLatestCommitTS() 191 return nil 192 } 193 194 func (s *service) handleShowProcessList(ctx context.Context, req *query.Request, resp *query.Response) error { 195 if req.ShowProcessListRequest == nil { 196 return moerr.NewInternalError(ctx, "bad request") 197 } 198 sessions, err := s.processList(req.ShowProcessListRequest.Tenant, 199 req.ShowProcessListRequest.SysTenant) 200 if err != nil { 201 resp.WrapError(err) 202 return nil 203 } 204 resp.ShowProcessListResponse = &query.ShowProcessListResponse{ 205 Sessions: sessions, 206 } 207 return nil 208 } 209 210 func (s *service) handleRunTask(ctx context.Context, req *query.Request, resp *query.Response) error { 211 if req.RunTask == nil { 212 return moerr.NewInternalError(ctx, "bad request") 213 } 214 s.task.Lock() 215 defer s.task.Unlock() 216 217 code := task.TaskCode(req.RunTask.TaskCode) 218 if s.task.runner == nil { 219 resp.RunTask = &query.RunTaskResponse{ 220 Result: "Task Runner Not Ready", 221 } 222 return nil 223 } 224 exec := s.task.runner.GetExecutor(code) 225 if exec == nil { 226 resp.RunTask = &query.RunTaskResponse{ 227 Result: "Task Not Found", 228 } 229 return nil 230 } 231 go func() { 232 _ = exec(context.Background(), &task.AsyncTask{ 233 ID: 0, 234 Metadata: task.TaskMetadata{ID: code.String(), Executor: code}, 235 }) 236 }() 237 resp.RunTask = &query.RunTaskResponse{ 238 Result: "OK", 239 } 240 return nil 241 } 242 243 // processList returns all the sessions. For sys tenant, return all sessions; but for common 244 // tenant, just return the sessions belong to the tenant. 245 // It is called "processList" is because it is used in "SHOW PROCESSLIST" statement. 246 func (s *service) processList(tenant string, sysTenant bool) ([]*status.Session, error) { 247 if sysTenant { 248 return s.sessionMgr.GetAllStatusSessions(), nil 249 } 250 return s.sessionMgr.GetStatusSessionsByTenant(tenant), nil 251 } 252 253 func copyKeys(src [][]byte) [][]byte { 254 dst := make([][]byte, 0, len(src)) 255 for _, s := range src { 256 d := make([]byte, len(s)) 257 copy(d, s) 258 dst = append(dst, s) 259 } 260 return dst 261 } 262 263 func copyWaitTxn(src pblock.WaitTxn) *pblock.WaitTxn { 264 dst := &pblock.WaitTxn{} 265 dst.TxnID = make([]byte, len(src.TxnID)) 266 copy(dst.TxnID, src.GetTxnID()) 267 dst.CreatedOn = src.GetCreatedOn() 268 return dst 269 } 270 271 func copyBytes(src []byte) []byte { 272 dst := make([]byte, len(src)) 273 copy(dst, src) 274 return dst 275 } 276 277 func copyTxnMeta(src txn.TxnMeta) *txn.TxnMeta { 278 dst := &txn.TxnMeta{ 279 ID: copyBytes(src.GetID()), 280 Status: src.GetStatus(), 281 SnapshotTS: src.GetSnapshotTS(), 282 PreparedTS: src.GetPreparedTS(), 283 CommitTS: src.GetCommitTS(), 284 Mode: src.GetMode(), 285 Isolation: src.GetIsolation(), 286 } 287 return dst 288 } 289 290 func copyLockOptions(src pblock.LockOptions) *pblock.LockOptions { 291 dst := &pblock.LockOptions{ 292 Granularity: src.GetGranularity(), 293 Mode: src.GetMode(), 294 } 295 return dst 296 } 297 298 func copyTxnInfo(src client.Lock) *query.TxnLockInfo { 299 dst := &query.TxnLockInfo{ 300 TableId: src.TableID, 301 Rows: copyKeys(src.Rows), 302 Options: copyLockOptions(src.Options), 303 } 304 return dst 305 } 306 307 func (s *service) handleGetCacheInfo(ctx context.Context, req *query.Request, resp *query.Response) error { 308 resp.GetCacheInfoResponse = new(query.GetCacheInfoResponse) 309 310 perfcounter.GetCacheStats(func(infos []*query.CacheInfo) { 311 for _, info := range infos { 312 if info != nil { 313 resp.GetCacheInfoResponse.CacheInfoList = append(resp.GetCacheInfoResponse.CacheInfoList, info) 314 } 315 } 316 }) 317 318 return nil 319 } 320 321 func (s *service) handleRemoveRemoteLockTable( 322 ctx context.Context, 323 req *query.Request, 324 resp *query.Response) error { 325 removed, err := s.lockService.CloseRemoteLockTable( 326 req.RemoveRemoteLockTable.GroupID, 327 req.RemoveRemoteLockTable.TableID, 328 req.RemoveRemoteLockTable.Version) 329 if err != nil { 330 return err 331 } 332 333 resp.RemoveRemoteLockTable = &query.RemoveRemoteLockTableResponse{} 334 if removed { 335 resp.RemoveRemoteLockTable.Count = 1 336 } 337 return nil 338 } 339 340 func (s *service) handleUnsubscribeTable(ctx context.Context, req *query.Request, resp *query.Response) error { 341 if req.UnsubscribeTable == nil { 342 return moerr.NewInternalError(ctx, "bad request") 343 } 344 err := s.storeEngine.UnsubscribeTable(ctx, req.UnsubscribeTable.DatabaseID, req.UnsubscribeTable.TableID) 345 if err != nil { 346 resp.WrapError(err) 347 return nil 348 } 349 resp.UnsubscribeTable = &query.UnsubscribeTableResponse{ 350 Success: true, 351 } 352 return nil 353 } 354 355 // handleGetCacheData reads the cache data from the local data cache in fileservice. 356 func (s *service) handleGetCacheData(ctx context.Context, req *query.Request, resp *query.Response) error { 357 sharedFS, err := fileservice.Get[fileservice.FileService](s.fileService, defines.SharedFileServiceName) 358 if err != nil { 359 return err 360 } 361 wr := &query.WrappedResponse{ 362 Response: resp, 363 } 364 err = fileservice.HandleRemoteRead(ctx, sharedFS, req, wr) 365 if err != nil { 366 return err 367 } 368 s.queryService.SetReleaseFunc(resp, wr.ReleaseFunc) 369 return nil 370 } 371 372 func (s *service) handleGetStatsInfo(ctx context.Context, req *query.Request, resp *query.Response) error { 373 if req.GetStatsInfoRequest == nil { 374 return moerr.NewInternalError(ctx, "bad request") 375 } 376 // The parameter sync is false, as the read request is from remote node, 377 // and we do not need wait for the data sync. 378 resp.GetStatsInfoResponse = &query.GetStatsInfoResponse{ 379 StatsInfo: s.storeEngine.Stats(ctx, *req.GetStatsInfoRequest.StatsInfoKey, false), 380 } 381 return nil 382 } 383 384 // handleGetPipelineInfo handles the GetPipelineInfoRequest and respond with 385 // the pipeline info in the server. 386 func (s *service) handleGetPipelineInfo(ctx context.Context, req *query.Request, resp *query.Response) error { 387 if req.GetPipelineInfoRequest == nil { 388 return moerr.NewInternalError(ctx, "bad request") 389 } 390 count := s.pipelines.counter.Load() 391 resp.GetPipelineInfoResponse = &query.GetPipelineInfoResponse{ 392 Count: count, 393 } 394 return nil 395 } 396 397 func (s *service) handleMigrateConnFrom( 398 ctx context.Context, req *query.Request, resp *query.Response, 399 ) error { 400 if req.MigrateConnFromRequest == nil { 401 return moerr.NewInternalError(ctx, "bad request") 402 } 403 rm := s.mo.GetRoutineManager() 404 resp.MigrateConnFromResponse = &query.MigrateConnFromResponse{} 405 if err := rm.MigrateConnectionFrom(req.MigrateConnFromRequest, resp.MigrateConnFromResponse); err != nil { 406 logutil.Errorf("failed to migrate conn from: %v", err) 407 return err 408 } 409 return nil 410 } 411 412 func (s *service) handleMigrateConnTo( 413 ctx context.Context, req *query.Request, resp *query.Response, 414 ) error { 415 if req.MigrateConnToRequest == nil { 416 return moerr.NewInternalError(ctx, "bad request") 417 } 418 rm := s.mo.GetRoutineManager() 419 if err := rm.MigrateConnectionTo(ctx, req.MigrateConnToRequest); err != nil { 420 logutil.Errorf("failed to migrate conn to: %v", err) 421 return err 422 } 423 logutil.Infof("migrate ok, conn ID: %d, DB: %s, prepared stmt count: %d", 424 req.MigrateConnToRequest.ConnID, req.MigrateConnToRequest.DB, len(req.MigrateConnToRequest.PrepareStmts)) 425 for _, stmt := range req.MigrateConnToRequest.PrepareStmts { 426 logutil.Infof("migrated prepare stmt on conn %d, %s, %s", req.MigrateConnToRequest.ConnID, stmt.Name, stmt.SQL) 427 } 428 resp.MigrateConnToResponse = &query.MigrateConnToResponse{ 429 Success: true, 430 } 431 return nil 432 }