github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/txnutil/gc/gc_service.go (about)

     1  // Copyright 2021 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  
    20  	"github.com/pingcap/errors"
    21  	"github.com/pingcap/log"
    22  	"github.com/pingcap/tiflow/cdc/model"
    23  	cerrors "github.com/pingcap/tiflow/pkg/errors"
    24  	"github.com/pingcap/tiflow/pkg/retry"
    25  	pd "github.com/tikv/pd/client"
    26  	"go.uber.org/zap"
    27  )
    28  
    29  const (
    30  	// EnsureGCServiceCreating is a tag of GC service id for changefeed creation
    31  	EnsureGCServiceCreating = "-creating-"
    32  	// EnsureGCServiceResuming is a tag of GC service id for changefeed resumption
    33  	EnsureGCServiceResuming = "-resuming-"
    34  	// EnsureGCServiceInitializing is a tag of GC service id for changefeed initialization
    35  	EnsureGCServiceInitializing = "-initializing-"
    36  )
    37  
    38  // EnsureChangefeedStartTsSafety checks if the startTs less than the minimum of
    39  // service GC safepoint and this function will update the service GC to startTs
    40  func EnsureChangefeedStartTsSafety(
    41  	ctx context.Context, pdCli pd.Client,
    42  	gcServiceIDPrefix string,
    43  	changefeedID model.ChangeFeedID,
    44  	TTL int64, startTs uint64,
    45  ) error {
    46  	minServiceGCTs, err := SetServiceGCSafepoint(
    47  		ctx, pdCli,
    48  		gcServiceIDPrefix+changefeedID.Namespace+"_"+changefeedID.ID,
    49  		TTL, startTs)
    50  	if err != nil {
    51  		return errors.Trace(err)
    52  	}
    53  	// startTs should be greater than or equal to minServiceGCTs + 1, otherwise gcManager
    54  	// would return a ErrSnapshotLostByGC even though the changefeed would appear to be successfully
    55  	// created/resumed. See issue #6350 for more detail.
    56  	if startTs > 0 && startTs < minServiceGCTs+1 {
    57  		return cerrors.ErrStartTsBeforeGC.GenWithStackByArgs(startTs, minServiceGCTs)
    58  	}
    59  	return nil
    60  }
    61  
    62  // UndoEnsureChangefeedStartTsSafety cleans the service GC safepoint of a changefeed
    63  // if something goes wrong after successfully calling EnsureChangefeedStartTsSafety().
    64  func UndoEnsureChangefeedStartTsSafety(
    65  	ctx context.Context, pdCli pd.Client,
    66  	gcServiceIDPrefix string,
    67  	changefeedID model.ChangeFeedID,
    68  ) error {
    69  	err := RemoveServiceGCSafepoint(
    70  		ctx,
    71  		pdCli,
    72  		gcServiceIDPrefix+changefeedID.Namespace+"_"+changefeedID.ID)
    73  	if err != nil {
    74  		return errors.Trace(err)
    75  	}
    76  
    77  	return nil
    78  }
    79  
    80  // PD leader switch may happen, so just gcServiceMaxRetries it.
    81  // The default PD election timeout is 3 seconds. Triple the timeout as
    82  // retry time to make sure PD leader can be elected during retry.
    83  const (
    84  	gcServiceBackoffDelay = 1000 // 1s
    85  	gcServiceMaxRetries   = 9
    86  )
    87  
    88  // SetServiceGCSafepoint set a service safepoint to PD.
    89  func SetServiceGCSafepoint(
    90  	ctx context.Context, pdCli pd.Client, serviceID string, TTL int64, safePoint uint64,
    91  ) (minServiceGCTs uint64, err error) {
    92  	err = retry.Do(ctx,
    93  		func() error {
    94  			var err1 error
    95  			minServiceGCTs, err1 = pdCli.UpdateServiceGCSafePoint(ctx, serviceID, TTL, safePoint)
    96  			if err1 != nil {
    97  				log.Warn("Set GC safepoint failed, retry later", zap.Error(err1))
    98  			}
    99  			return err1
   100  		},
   101  		retry.WithBackoffBaseDelay(gcServiceBackoffDelay),
   102  		retry.WithMaxTries(gcServiceMaxRetries),
   103  		retry.WithIsRetryableErr(cerrors.IsRetryableError))
   104  	return
   105  }
   106  
   107  // RemoveServiceGCSafepoint removes a service safepoint from PD.
   108  func RemoveServiceGCSafepoint(ctx context.Context, pdCli pd.Client, serviceID string) error {
   109  	// Set TTL to 0 second to delete the service safe point.
   110  	TTL := 0
   111  	return retry.Do(ctx,
   112  		func() error {
   113  			_, err := pdCli.UpdateServiceGCSafePoint(ctx, serviceID, int64(TTL), math.MaxUint64)
   114  			if err != nil {
   115  				log.Warn("Remove GC safepoint failed, retry later", zap.Error(err))
   116  			}
   117  			return err
   118  		},
   119  		retry.WithBackoffBaseDelay(gcServiceBackoffDelay), // 1s
   120  		retry.WithMaxTries(gcServiceMaxRetries),
   121  		retry.WithIsRetryableErr(cerrors.IsRetryableError))
   122  }