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 }