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  }