github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/pkg/context/context.go (about)

     1  // Copyright 2020 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 context
    15  
    16  import (
    17  	"context"
    18  	"log"
    19  	"time"
    20  
    21  	"github.com/pingcap/ticdc/pkg/version"
    22  
    23  	"github.com/pingcap/ticdc/cdc/kv"
    24  	"github.com/pingcap/ticdc/cdc/model"
    25  	"github.com/pingcap/ticdc/pkg/config"
    26  	tidbkv "github.com/pingcap/tidb/kv"
    27  	"github.com/pingcap/tidb/store/tikv/oracle"
    28  	pd "github.com/tikv/pd/client"
    29  	"go.uber.org/zap"
    30  )
    31  
    32  // GlobalVars contains some vars which can be used anywhere in a pipeline
    33  // the lifecycle of vars in the GlobalVars shoule be aligned with the ticdc server process.
    34  // All field in Vars should be READ-ONLY and THREAD-SAFE
    35  type GlobalVars struct {
    36  	PDClient    pd.Client
    37  	KVStorage   tidbkv.Storage
    38  	CaptureInfo *model.CaptureInfo
    39  	EtcdClient  *kv.CDCEtcdClient
    40  	GrpcPool    kv.GrpcPool
    41  }
    42  
    43  // ChangefeedVars contains some vars which can be used anywhere in a pipeline
    44  // the lifecycle of vars in the ChangefeedVars shoule be aligned with the changefeed.
    45  // All field in Vars should be READ-ONLY and THREAD-SAFE
    46  type ChangefeedVars struct {
    47  	ID   model.ChangeFeedID
    48  	Info *model.ChangeFeedInfo
    49  }
    50  
    51  // Context contains Vars(), Done(), Throw(error) and StdContext() context.Context
    52  // Context is used to instead of standard context
    53  type Context interface {
    54  	context.Context
    55  
    56  	// GlobalVars return the `GlobalVars` store by the root context created by `NewContext`
    57  	// Note that the `GlobalVars` should be READ-ONLY and THREAD-SAFE
    58  	// The root node and all its children node share one pointer of `GlobalVars`
    59  	// So any modification of `GlobalVars` will cause all other family nodes to change.
    60  	GlobalVars() *GlobalVars
    61  
    62  	// ChangefeedVars return the `ChangefeedVars` store by the context created by `WithChangefeedVars`
    63  	// Note that the `ChangefeedVars` should be READ-ONLY and THREAD-SAFE
    64  	// The root node and all its children node share one pointer of `ChangefeedVars`
    65  	// So any modification of `ChangefeedVars` will cause all other family nodes to change.
    66  	// ChangefeedVars could be return nil when the `ChangefeedVars` is not set by `WithChangefeedVars`
    67  	ChangefeedVars() *ChangefeedVars
    68  
    69  	// Throw an error to parents nodes
    70  	// we can using `WatchThrow` to listen the errors thrown by children nodes
    71  	Throw(error)
    72  }
    73  
    74  type rootContext struct {
    75  	Context
    76  	globalVars *GlobalVars
    77  }
    78  
    79  // NewContext returns a new pipeline context
    80  func NewContext(stdCtx context.Context, globalVars *GlobalVars) Context {
    81  	ctx := &rootContext{
    82  		globalVars: globalVars,
    83  	}
    84  	return WithStd(ctx, stdCtx)
    85  }
    86  
    87  func (ctx *rootContext) GlobalVars() *GlobalVars {
    88  	return ctx.globalVars
    89  }
    90  
    91  func (ctx *rootContext) ChangefeedVars() *ChangefeedVars {
    92  	return nil
    93  }
    94  
    95  func (ctx *rootContext) Throw(err error) {
    96  	if err == nil {
    97  		return
    98  	}
    99  	// make sure all error has been catched
   100  	log.Panic("an error has escaped, please report a bug", zap.Error(err))
   101  }
   102  
   103  // WithChangefeedVars return a Context with the `ChangefeedVars`
   104  func WithChangefeedVars(ctx Context, changefeedVars *ChangefeedVars) Context {
   105  	return &changefeedVarsContext{
   106  		Context:        ctx,
   107  		changefeedVars: changefeedVars,
   108  	}
   109  }
   110  
   111  type changefeedVarsContext struct {
   112  	Context
   113  	changefeedVars *ChangefeedVars
   114  }
   115  
   116  func (ctx *changefeedVarsContext) ChangefeedVars() *ChangefeedVars {
   117  	return ctx.changefeedVars
   118  }
   119  
   120  type stdContext struct {
   121  	stdCtx context.Context
   122  	Context
   123  }
   124  
   125  func (ctx *stdContext) Deadline() (deadline time.Time, ok bool) {
   126  	return ctx.stdCtx.Deadline()
   127  }
   128  
   129  func (ctx *stdContext) Err() error {
   130  	return ctx.stdCtx.Err()
   131  }
   132  
   133  func (ctx *stdContext) Value(key interface{}) interface{} {
   134  	return ctx.stdCtx.Value(key)
   135  }
   136  
   137  func (ctx *stdContext) Done() <-chan struct{} {
   138  	return ctx.stdCtx.Done()
   139  }
   140  
   141  // WithStd returns a Context with the standard Context
   142  func WithStd(ctx Context, stdCtx context.Context) Context { //revive:disable:context-as-argument
   143  	return &stdContext{
   144  		stdCtx:  stdCtx,
   145  		Context: ctx,
   146  	}
   147  }
   148  
   149  // WithCancel returns a Context with the cancel function
   150  func WithCancel(ctx Context) (Context, context.CancelFunc) {
   151  	stdCtx, cancel := context.WithCancel(ctx)
   152  	return WithStd(ctx, stdCtx), cancel
   153  }
   154  
   155  type throwContext struct {
   156  	Context
   157  	f func(error) error
   158  }
   159  
   160  // WithErrorHandler creates a new context that can watch the Throw function
   161  // if the function `f` specified in WithErrorHandler returns an error,
   162  // the error will be thrown to the parent context.
   163  func WithErrorHandler(ctx Context, f func(error) error) Context {
   164  	return &throwContext{
   165  		Context: ctx,
   166  		f:       f,
   167  	}
   168  }
   169  
   170  func (ctx *throwContext) Throw(err error) {
   171  	if err == nil {
   172  		return
   173  	}
   174  	if err := ctx.f(err); err != nil {
   175  		ctx.Context.Throw(err)
   176  	}
   177  }
   178  
   179  // NewBackendContext4Test returns a new pipeline context for test
   180  func NewBackendContext4Test(withChangefeedVars bool) Context {
   181  	ctx := NewContext(context.Background(), &GlobalVars{
   182  		CaptureInfo: &model.CaptureInfo{
   183  			ID:            "capture-id-test",
   184  			AdvertiseAddr: "127.0.0.1:0000",
   185  			Version:       version.ReleaseVersion,
   186  		},
   187  	})
   188  	if withChangefeedVars {
   189  		ctx = WithChangefeedVars(ctx, &ChangefeedVars{
   190  			ID: "changefeed-id-test",
   191  			Info: &model.ChangeFeedInfo{
   192  				StartTs: oracle.GoTimeToTS(time.Now()),
   193  				Config:  config.GetDefaultReplicaConfig(),
   194  			},
   195  		})
   196  	}
   197  	return ctx
   198  }
   199  
   200  // ZapFieldCapture returns a zap field containing capture address
   201  func ZapFieldCapture(ctx Context) zap.Field {
   202  	return zap.String("capture", ctx.GlobalVars().CaptureInfo.AdvertiseAddr)
   203  }
   204  
   205  // ZapFieldChangefeed returns a zap field containing changefeed id
   206  func ZapFieldChangefeed(ctx Context) zap.Field {
   207  	return zap.String("changefeed", ctx.ChangefeedVars().ID)
   208  }