github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/txnutil/gc/gc_service_test.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 gc
    15  
    16  import (
    17  	"context"
    18  	"math"
    19  	"testing"
    20  
    21  	"github.com/pingcap/errors"
    22  	"github.com/pingcap/tiflow/cdc/model"
    23  	"github.com/stretchr/testify/require"
    24  	pd "github.com/tikv/pd/client"
    25  )
    26  
    27  func TestCheckSafetyOfStartTs(t *testing.T) {
    28  	t.Parallel()
    29  
    30  	pdCli := &mockPdClientForServiceGCSafePoint{serviceSafePoint: make(map[string]uint64)}
    31  
    32  	ctx := context.Background()
    33  
    34  	TTL := int64(1)
    35  	// assume no pd leader switch
    36  	pdCli.UpdateServiceGCSafePoint(ctx, "service1", 10, 60) //nolint:errcheck
    37  	err := EnsureChangefeedStartTsSafety(ctx, pdCli,
    38  		"ticdc-creating-",
    39  		model.DefaultChangeFeedID("changefeed1"), TTL, 50)
    40  	require.Equal(t,
    41  		"[CDC:ErrStartTsBeforeGC]fail to create or maintain changefeed "+
    42  			"because start-ts 50 is earlier than or equal to GC safepoint at 60", err.Error())
    43  	pdCli.UpdateServiceGCSafePoint(ctx, "service2", 10, 80) //nolint:errcheck
    44  	pdCli.UpdateServiceGCSafePoint(ctx, "service3", 10, 70) //nolint:errcheck
    45  	err = EnsureChangefeedStartTsSafety(ctx, pdCli,
    46  		"ticdc-creating-",
    47  		model.DefaultChangeFeedID("changefeed2"), TTL, 65)
    48  	require.Nil(t, err)
    49  	require.Equal(t, pdCli.serviceSafePoint, map[string]uint64{
    50  		"service1":                           60,
    51  		"service2":                           80,
    52  		"service3":                           70,
    53  		"ticdc-creating-default_changefeed2": 65,
    54  	})
    55  	err = UndoEnsureChangefeedStartTsSafety(ctx, pdCli,
    56  		"ticdc-creating-",
    57  		model.DefaultChangeFeedID("changefeed2"))
    58  	require.Nil(t, err)
    59  	require.Equal(t, pdCli.serviceSafePoint, map[string]uint64{
    60  		"service1":                           60,
    61  		"service2":                           80,
    62  		"service3":                           70,
    63  		"ticdc-creating-default_changefeed2": math.MaxUint64,
    64  	})
    65  
    66  	pdCli.enableLeaderSwitch = true
    67  
    68  	pdCli.retryThreshold = 1
    69  	pdCli.retryCount = 0
    70  	err = EnsureChangefeedStartTsSafety(ctx, pdCli,
    71  		"ticdc-creating-",
    72  		model.DefaultChangeFeedID("changefeed2"), TTL, 65)
    73  	require.Nil(t, err)
    74  
    75  	pdCli.retryThreshold = gcServiceMaxRetries + 1
    76  	pdCli.retryCount = 0
    77  	err = EnsureChangefeedStartTsSafety(ctx, pdCli,
    78  		"ticdc-creating-",
    79  		model.DefaultChangeFeedID("changefeed2"), TTL, 65)
    80  	require.NotNil(t, err)
    81  	require.Equal(t, err.Error(),
    82  		"[CDC:ErrReachMaxTry]reach maximum try: 9, error: not pd leader: not pd leader")
    83  
    84  	pdCli.retryThreshold = 3
    85  	pdCli.retryCount = 0
    86  	err = EnsureChangefeedStartTsSafety(ctx, pdCli,
    87  		"ticdc-creating-",
    88  		model.DefaultChangeFeedID("changefeed1"), TTL, 50)
    89  	require.Equal(t, err.Error(),
    90  		"[CDC:ErrStartTsBeforeGC]fail to create or maintain changefeed "+
    91  			"because start-ts 50 is earlier than or equal to GC safepoint at 60")
    92  }
    93  
    94  type mockPdClientForServiceGCSafePoint struct {
    95  	pd.Client
    96  	serviceSafePoint   map[string]uint64
    97  	enableLeaderSwitch bool
    98  	retryCount         int
    99  	retryThreshold     int
   100  }
   101  
   102  func (m *mockPdClientForServiceGCSafePoint) UpdateServiceGCSafePoint(ctx context.Context, serviceID string, ttl int64, safePoint uint64) (uint64, error) {
   103  	defer func() { m.retryCount++ }()
   104  	minSafePoint := uint64(math.MaxUint64)
   105  	if m.enableLeaderSwitch && m.retryCount < m.retryThreshold {
   106  		// simulate pd leader switch error
   107  		return minSafePoint, errors.New("not pd leader")
   108  	}
   109  
   110  	for _, safePoint := range m.serviceSafePoint {
   111  		if minSafePoint > safePoint {
   112  			minSafePoint = safePoint
   113  		}
   114  	}
   115  	if safePoint < minSafePoint && len(m.serviceSafePoint) != 0 {
   116  		return minSafePoint, nil
   117  	}
   118  	m.serviceSafePoint[serviceID] = safePoint
   119  	return minSafePoint, nil
   120  }