github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cdc/sink/sink.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 sink 15 16 import ( 17 "context" 18 "net/url" 19 "strings" 20 21 "github.com/pingcap/ticdc/cdc/model" 22 "github.com/pingcap/ticdc/cdc/sink/cdclog" 23 "github.com/pingcap/ticdc/pkg/config" 24 cerror "github.com/pingcap/ticdc/pkg/errors" 25 "github.com/pingcap/ticdc/pkg/filter" 26 ) 27 28 // Sink options keys 29 const ( 30 OptChangefeedID = "_changefeed_id" 31 OptCaptureAddr = "_capture_addr" 32 ) 33 34 // Sink is an abstraction for anything that a changefeed may emit into. 35 type Sink interface { 36 Initialize(ctx context.Context, tableInfo []*model.SimpleTableInfo) error 37 38 // EmitRowChangedEvents sends Row Changed Event to Sink 39 // EmitRowChangedEvents may write rows to downstream directly; 40 EmitRowChangedEvents(ctx context.Context, rows ...*model.RowChangedEvent) error 41 42 // EmitDDLEvent sends DDL Event to Sink 43 // EmitDDLEvent should execute DDL to downstream synchronously 44 EmitDDLEvent(ctx context.Context, ddl *model.DDLEvent) error 45 46 // FlushRowChangedEvents flushes each row which of commitTs less than or equal to `resolvedTs` into downstream. 47 // TiCDC guarantees that all of Event which of commitTs less than or equal to `resolvedTs` are sent to Sink through `EmitRowChangedEvents` 48 FlushRowChangedEvents(ctx context.Context, resolvedTs uint64) (uint64, error) 49 50 // EmitCheckpointTs sends CheckpointTs to Sink 51 // TiCDC guarantees that all Events **in the cluster** which of commitTs less than or equal `checkpointTs` are sent to downstream successfully. 52 EmitCheckpointTs(ctx context.Context, ts uint64) error 53 54 // Close closes the Sink 55 Close(ctx context.Context) error 56 57 // Barrier is a synchronous function to wait all events to be flushed in underlying sink 58 // Note once Barrier is called, the resolved ts won't be pushed until the Barrier call returns. 59 Barrier(ctx context.Context) error 60 } 61 62 var sinkIniterMap = make(map[string]sinkInitFunc) 63 64 type sinkInitFunc func(context.Context, model.ChangeFeedID, *url.URL, *filter.Filter, *config.ReplicaConfig, map[string]string, chan error) (Sink, error) 65 66 func init() { 67 // register blackhole sink 68 sinkIniterMap["blackhole"] = func(ctx context.Context, changefeedID model.ChangeFeedID, sinkURI *url.URL, 69 filter *filter.Filter, config *config.ReplicaConfig, opts map[string]string, errCh chan error) (Sink, error) { 70 return newBlackHoleSink(ctx, opts), nil 71 } 72 73 // register mysql sink 74 sinkIniterMap["mysql"] = func(ctx context.Context, changefeedID model.ChangeFeedID, sinkURI *url.URL, 75 filter *filter.Filter, config *config.ReplicaConfig, opts map[string]string, errCh chan error) (Sink, error) { 76 return newMySQLSink(ctx, changefeedID, sinkURI, filter, config, opts) 77 } 78 sinkIniterMap["tidb"] = sinkIniterMap["mysql"] 79 sinkIniterMap["mysql+ssl"] = sinkIniterMap["mysql"] 80 sinkIniterMap["tidb+ssl"] = sinkIniterMap["mysql"] 81 82 // register kafka sink 83 sinkIniterMap["kafka"] = func(ctx context.Context, changefeedID model.ChangeFeedID, sinkURI *url.URL, 84 filter *filter.Filter, config *config.ReplicaConfig, opts map[string]string, errCh chan error) (Sink, error) { 85 return newKafkaSaramaSink(ctx, sinkURI, filter, config, opts, errCh) 86 } 87 sinkIniterMap["kafka+ssl"] = sinkIniterMap["kafka"] 88 89 // register pulsar sink 90 sinkIniterMap["pulsar"] = func(ctx context.Context, changefeedID model.ChangeFeedID, sinkURI *url.URL, 91 filter *filter.Filter, config *config.ReplicaConfig, opts map[string]string, errCh chan error) (Sink, error) { 92 return newPulsarSink(ctx, sinkURI, filter, config, opts, errCh) 93 } 94 sinkIniterMap["pulsar+ssl"] = sinkIniterMap["pulsar"] 95 96 // register local sink 97 sinkIniterMap["local"] = func(ctx context.Context, changefeedID model.ChangeFeedID, sinkURI *url.URL, 98 filter *filter.Filter, config *config.ReplicaConfig, opts map[string]string, errCh chan error) (Sink, error) { 99 return cdclog.NewLocalFileSink(ctx, sinkURI, errCh) 100 } 101 102 // register s3 sink 103 sinkIniterMap["s3"] = func(ctx context.Context, changefeedID model.ChangeFeedID, sinkURI *url.URL, 104 filter *filter.Filter, config *config.ReplicaConfig, opts map[string]string, errCh chan error) (Sink, error) { 105 return cdclog.NewS3Sink(ctx, sinkURI, errCh) 106 } 107 } 108 109 // NewSink creates a new sink with the sink-uri 110 func NewSink(ctx context.Context, changefeedID model.ChangeFeedID, sinkURIStr string, filter *filter.Filter, config *config.ReplicaConfig, opts map[string]string, errCh chan error) (Sink, error) { 111 // parse sinkURI as a URI 112 sinkURI, err := url.Parse(sinkURIStr) 113 if err != nil { 114 return nil, cerror.WrapError(cerror.ErrSinkURIInvalid, err) 115 } 116 if newSink, ok := sinkIniterMap[strings.ToLower(sinkURI.Scheme)]; ok { 117 return newSink(ctx, changefeedID, sinkURI, filter, config, opts, errCh) 118 } 119 return nil, cerror.ErrSinkURIInvalid.GenWithStack("the sink scheme (%s) is not supported", sinkURI.Scheme) 120 }