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  }