github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/cdc/controller/query.go (about) 1 // Copyright 2023 PingCAP, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package controller 15 16 import ( 17 "context" 18 "sync/atomic" 19 20 "github.com/pingcap/errors" 21 "github.com/pingcap/log" 22 "github.com/pingcap/tiflow/cdc/model" 23 cerror "github.com/pingcap/tiflow/pkg/errors" 24 "go.uber.org/zap" 25 ) 26 27 // QueryType is the type of different queries. 28 type QueryType int32 29 30 const ( 31 // QueryAllChangeFeedSCheckpointTs query all changefeed checkpoint ts. 32 QueryAllChangeFeedSCheckpointTs QueryType = iota 33 // QueryAllChangeFeedInfo is the type of query all changefeed info. 34 QueryAllChangeFeedInfo 35 // QueryCaptures is the type of query captures info. 36 QueryCaptures 37 // QueryExists is the type of query check if a changefeed is exists 38 QueryExists 39 // QueryProcessors is the type of query processor info 40 QueryProcessors 41 ) 42 43 // Query wraps query command and return results. 44 type Query struct { 45 Tp QueryType 46 ChangeFeedID model.ChangeFeedID 47 48 Data interface{} 49 } 50 51 // GetCaptures returns the information about all captures. 52 func (o *controllerImpl) GetCaptures(ctx context.Context) ([]*model.CaptureInfo, error) { 53 query := &Query{ 54 Tp: QueryCaptures, 55 } 56 if err := o.sendQueryToController(ctx, query); err != nil { 57 return nil, errors.Trace(err) 58 } 59 return query.Data.([]*model.CaptureInfo), nil 60 } 61 62 // GetProcessors returns the information about all processors. 63 func (o *controllerImpl) GetProcessors(ctx context.Context) ([]*model.ProcInfoSnap, error) { 64 query := &Query{ 65 Tp: QueryProcessors, 66 } 67 if err := o.sendQueryToController(ctx, query); err != nil { 68 return nil, errors.Trace(err) 69 } 70 return query.Data.([]*model.ProcInfoSnap), nil 71 } 72 73 // GetAllChangeFeedInfo returns all changefeed infos 74 func (o *controllerImpl) GetAllChangeFeedInfo(ctx context.Context) ( 75 map[model.ChangeFeedID]*model.ChangeFeedInfo, error, 76 ) { 77 query := &Query{ 78 Tp: QueryAllChangeFeedInfo, 79 } 80 if err := o.sendQueryToController(ctx, query); err != nil { 81 return nil, errors.Trace(err) 82 } 83 return query.Data.(map[model.ChangeFeedID]*model.ChangeFeedInfo), nil 84 } 85 86 // GetAllChangeFeedCheckpointTs returns all changefeed checkpoints 87 func (o *controllerImpl) GetAllChangeFeedCheckpointTs(ctx context.Context) ( 88 map[model.ChangeFeedID]uint64, error, 89 ) { 90 query := &Query{ 91 Tp: QueryAllChangeFeedSCheckpointTs, 92 } 93 if err := o.sendQueryToController(ctx, query); err != nil { 94 return nil, errors.Trace(err) 95 } 96 return query.Data.(map[model.ChangeFeedID]uint64), nil 97 } 98 99 // IsChangefeedExists returns true if a changefeed is exits 100 func (o *controllerImpl) IsChangefeedExists(ctx context.Context, id model.ChangeFeedID) (bool, error) { 101 query := &Query{ 102 Tp: QueryExists, 103 ChangeFeedID: id, 104 } 105 if err := o.sendQueryToController(ctx, query); err != nil { 106 return false, errors.Trace(err) 107 } 108 return query.Data.(bool), nil 109 } 110 111 // Query queries controller internal information. 112 func (o *controllerImpl) Query(query *Query, done chan<- error) { 113 o.pushControllerJob(&controllerJob{ 114 Tp: controllerJobTypeQuery, 115 query: query, 116 done: done, 117 }) 118 } 119 120 func (o *controllerImpl) pushControllerJob(job *controllerJob) { 121 o.controllerJobQueue.Lock() 122 defer o.controllerJobQueue.Unlock() 123 if atomic.LoadInt32(&o.closed) != 0 { 124 log.Info("reject controller job as controller has been closed", 125 zap.Int("jobType", int(job.Tp))) 126 select { 127 case job.done <- cerror.ErrOwnerNotFound.GenWithStackByArgs(): 128 default: 129 } 130 close(job.done) 131 return 132 } 133 o.controllerJobQueue.queue = append(o.controllerJobQueue.queue, job) 134 } 135 136 func (o *controllerImpl) sendQueryToController(ctx context.Context, query *Query) error { 137 doneCh := make(chan error, 1) 138 o.Query(query, doneCh) 139 140 select { 141 case <-ctx.Done(): 142 return errors.Trace(ctx.Err()) 143 case err := <-doneCh: 144 if err != nil { 145 return errors.Trace(err) 146 } 147 } 148 149 return nil 150 } 151 152 func (o *controllerImpl) takeControllerJobs() []*controllerJob { 153 o.controllerJobQueue.Lock() 154 defer o.controllerJobQueue.Unlock() 155 156 jobs := o.controllerJobQueue.queue 157 o.controllerJobQueue.queue = nil 158 return jobs 159 } 160 161 func (o *controllerImpl) handleJobs(_ context.Context) { 162 jobs := o.takeControllerJobs() 163 for _, job := range jobs { 164 switch job.Tp { 165 case controllerJobTypeQuery: 166 job.done <- o.handleQueries(job.query) 167 } 168 close(job.done) 169 } 170 } 171 172 func (o *controllerImpl) handleQueries(query *Query) error { 173 switch query.Tp { 174 case QueryAllChangeFeedSCheckpointTs: 175 ret := make(map[model.ChangeFeedID]uint64) 176 for cfID, cfReactor := range o.changefeeds { 177 if cfReactor == nil { 178 continue 179 } 180 if cfReactor.Status == nil { 181 continue 182 } 183 ret[cfID] = cfReactor.Status.CheckpointTs 184 } 185 query.Data = ret 186 case QueryAllChangeFeedInfo: 187 ret := map[model.ChangeFeedID]*model.ChangeFeedInfo{} 188 for cfID, cfReactor := range o.changefeeds { 189 if cfReactor.Info == nil { 190 ret[cfID] = &model.ChangeFeedInfo{} 191 continue 192 } 193 var err error 194 ret[cfID], err = cfReactor.Info.Clone() 195 if err != nil { 196 return errors.Trace(err) 197 } 198 } 199 query.Data = ret 200 case QueryCaptures: 201 var ret []*model.CaptureInfo 202 for _, captureInfo := range o.captures { 203 ret = append(ret, &model.CaptureInfo{ 204 ID: captureInfo.ID, 205 AdvertiseAddr: captureInfo.AdvertiseAddr, 206 Version: captureInfo.Version, 207 }) 208 } 209 query.Data = ret 210 case QueryProcessors: 211 var ret []*model.ProcInfoSnap 212 for cfID := range o.changefeeds { 213 for captureID := range o.captures { 214 ret = append(ret, &model.ProcInfoSnap{ 215 CfID: cfID, 216 CaptureID: captureID, 217 }) 218 } 219 } 220 query.Data = ret 221 case QueryExists: 222 _, ok := o.changefeeds[query.ChangeFeedID] 223 query.Data = ok 224 } 225 return nil 226 }