github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cdc/owner_operator.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 cdc 15 16 import ( 17 "context" 18 "sync" 19 20 tidbkv "github.com/pingcap/tidb/kv" 21 22 "github.com/pingcap/errors" 23 timodel "github.com/pingcap/parser/model" 24 "github.com/pingcap/ticdc/cdc/entry" 25 "github.com/pingcap/ticdc/cdc/kv" 26 "github.com/pingcap/ticdc/cdc/model" 27 "github.com/pingcap/ticdc/cdc/puller" 28 "github.com/pingcap/ticdc/pkg/regionspan" 29 "github.com/pingcap/ticdc/pkg/util" 30 pd "github.com/tikv/pd/client" 31 "golang.org/x/sync/errgroup" 32 ) 33 34 // TODO: add tests 35 type ddlHandler struct { 36 puller puller.Puller 37 resolvedTS uint64 38 ddlJobs []*timodel.Job 39 40 mu sync.Mutex 41 wg *errgroup.Group 42 cancel func() 43 } 44 45 func newDDLHandler(pdCli pd.Client, grpcPool kv.GrpcPool, kvStorage tidbkv.Storage, checkpointTS uint64) *ddlHandler { 46 // TODO: context should be passed from outter caller 47 ctx, cancel := context.WithCancel(context.Background()) 48 plr := puller.NewPuller(ctx, pdCli, grpcPool, kvStorage, checkpointTS, []regionspan.Span{regionspan.GetDDLSpan(), regionspan.GetAddIndexDDLSpan()}, false) 49 h := &ddlHandler{ 50 puller: plr, 51 cancel: cancel, 52 } 53 // Set it up so that one failed goroutine cancels all others sharing the same ctx 54 errg, ctx := errgroup.WithContext(ctx) 55 ctx = util.PutTableInfoInCtx(ctx, -1, "") 56 57 // FIXME: user of ddlHandler can't know error happen. 58 errg.Go(func() error { 59 return plr.Run(ctx) 60 }) 61 62 rawDDLCh := puller.SortOutput(ctx, plr.Output()) 63 64 errg.Go(func() error { 65 for { 66 select { 67 case <-ctx.Done(): 68 return ctx.Err() 69 case e := <-rawDDLCh: 70 if e == nil { 71 continue 72 } 73 err := h.receiveDDL(e) 74 if err != nil { 75 return errors.Trace(err) 76 } 77 } 78 } 79 }) 80 h.wg = errg 81 return h 82 } 83 84 func (h *ddlHandler) receiveDDL(rawDDL *model.RawKVEntry) error { 85 if rawDDL.OpType == model.OpTypeResolved { 86 h.mu.Lock() 87 h.resolvedTS = rawDDL.CRTs 88 h.mu.Unlock() 89 return nil 90 } 91 job, err := entry.UnmarshalDDL(rawDDL) 92 if err != nil { 93 return errors.Trace(err) 94 } 95 if job == nil { 96 return nil 97 } 98 99 h.mu.Lock() 100 defer h.mu.Unlock() 101 h.ddlJobs = append(h.ddlJobs, job) 102 return nil 103 } 104 105 var _ OwnerDDLHandler = &ddlHandler{} 106 107 // PullDDL implements `roles.OwnerDDLHandler` interface. 108 func (h *ddlHandler) PullDDL() (uint64, []*timodel.Job, error) { 109 h.mu.Lock() 110 defer h.mu.Unlock() 111 result := h.ddlJobs 112 h.ddlJobs = nil 113 return h.resolvedTS, result, nil 114 } 115 116 func (h *ddlHandler) Close() error { 117 h.cancel() 118 err := h.wg.Wait() 119 return errors.Trace(err) 120 }