github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cdc/owner/feed_state_manager_test.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 owner 15 16 import ( 17 "github.com/pingcap/check" 18 "github.com/pingcap/ticdc/cdc/model" 19 "github.com/pingcap/ticdc/pkg/config" 20 cdcContext "github.com/pingcap/ticdc/pkg/context" 21 "github.com/pingcap/ticdc/pkg/orchestrator" 22 "github.com/pingcap/ticdc/pkg/util/testleak" 23 ) 24 25 var _ = check.Suite(&feedStateManagerSuite{}) 26 27 type feedStateManagerSuite struct { 28 } 29 30 func (s *feedStateManagerSuite) TestHandleJob(c *check.C) { 31 defer testleak.AfterTest(c)() 32 ctx := cdcContext.NewBackendContext4Test(true) 33 manager := new(feedStateManager) 34 state := model.NewChangefeedReactorState(ctx.ChangefeedVars().ID) 35 tester := orchestrator.NewReactorStateTester(c, state, nil) 36 state.PatchInfo(func(info *model.ChangeFeedInfo) (*model.ChangeFeedInfo, bool, error) { 37 c.Assert(info, check.IsNil) 38 return &model.ChangeFeedInfo{SinkURI: "123", Config: &config.ReplicaConfig{}}, true, nil 39 }) 40 state.PatchStatus(func(status *model.ChangeFeedStatus) (*model.ChangeFeedStatus, bool, error) { 41 c.Assert(status, check.IsNil) 42 return &model.ChangeFeedStatus{}, true, nil 43 }) 44 tester.MustApplyPatches() 45 manager.Tick(state) 46 tester.MustApplyPatches() 47 c.Assert(manager.ShouldRunning(), check.IsTrue) 48 49 // an admin job which of changefeed is not match 50 manager.PushAdminJob(&model.AdminJob{ 51 CfID: "fake-changefeed-id", 52 Type: model.AdminStop, 53 }) 54 manager.Tick(state) 55 tester.MustApplyPatches() 56 c.Assert(manager.ShouldRunning(), check.IsTrue) 57 58 // a running can not be resume 59 manager.PushAdminJob(&model.AdminJob{ 60 CfID: ctx.ChangefeedVars().ID, 61 Type: model.AdminResume, 62 }) 63 manager.Tick(state) 64 tester.MustApplyPatches() 65 c.Assert(manager.ShouldRunning(), check.IsTrue) 66 67 // stop a changefeed 68 manager.PushAdminJob(&model.AdminJob{ 69 CfID: ctx.ChangefeedVars().ID, 70 Type: model.AdminStop, 71 }) 72 manager.Tick(state) 73 tester.MustApplyPatches() 74 c.Assert(manager.ShouldRunning(), check.IsFalse) 75 c.Assert(state.Info.State, check.Equals, model.StateStopped) 76 c.Assert(state.Info.AdminJobType, check.Equals, model.AdminStop) 77 c.Assert(state.Status.AdminJobType, check.Equals, model.AdminStop) 78 79 // resume a changefeed 80 manager.PushAdminJob(&model.AdminJob{ 81 CfID: ctx.ChangefeedVars().ID, 82 Type: model.AdminResume, 83 }) 84 manager.Tick(state) 85 tester.MustApplyPatches() 86 c.Assert(manager.ShouldRunning(), check.IsTrue) 87 c.Assert(state.Info.State, check.Equals, model.StateNormal) 88 c.Assert(state.Info.AdminJobType, check.Equals, model.AdminNone) 89 c.Assert(state.Status.AdminJobType, check.Equals, model.AdminNone) 90 91 // remove a changefeed 92 manager.PushAdminJob(&model.AdminJob{ 93 CfID: ctx.ChangefeedVars().ID, 94 Type: model.AdminRemove, 95 }) 96 manager.Tick(state) 97 tester.MustApplyPatches() 98 c.Assert(manager.ShouldRunning(), check.IsFalse) 99 c.Assert(state.Exist(), check.IsFalse) 100 } 101 102 func (s *feedStateManagerSuite) TestMarkFinished(c *check.C) { 103 defer testleak.AfterTest(c)() 104 ctx := cdcContext.NewBackendContext4Test(true) 105 manager := new(feedStateManager) 106 state := model.NewChangefeedReactorState(ctx.ChangefeedVars().ID) 107 tester := orchestrator.NewReactorStateTester(c, state, nil) 108 state.PatchInfo(func(info *model.ChangeFeedInfo) (*model.ChangeFeedInfo, bool, error) { 109 c.Assert(info, check.IsNil) 110 return &model.ChangeFeedInfo{SinkURI: "123", Config: &config.ReplicaConfig{}}, true, nil 111 }) 112 state.PatchStatus(func(status *model.ChangeFeedStatus) (*model.ChangeFeedStatus, bool, error) { 113 c.Assert(status, check.IsNil) 114 return &model.ChangeFeedStatus{}, true, nil 115 }) 116 tester.MustApplyPatches() 117 manager.Tick(state) 118 tester.MustApplyPatches() 119 c.Assert(manager.ShouldRunning(), check.IsTrue) 120 121 manager.MarkFinished() 122 manager.Tick(state) 123 tester.MustApplyPatches() 124 c.Assert(manager.ShouldRunning(), check.IsFalse) 125 c.Assert(state.Info.State, check.Equals, model.StateFinished) 126 c.Assert(state.Info.AdminJobType, check.Equals, model.AdminFinish) 127 c.Assert(state.Status.AdminJobType, check.Equals, model.AdminFinish) 128 } 129 130 func (s *feedStateManagerSuite) TestCleanUpInfos(c *check.C) { 131 defer testleak.AfterTest(c)() 132 ctx := cdcContext.NewBackendContext4Test(true) 133 manager := new(feedStateManager) 134 state := model.NewChangefeedReactorState(ctx.ChangefeedVars().ID) 135 tester := orchestrator.NewReactorStateTester(c, state, nil) 136 state.PatchInfo(func(info *model.ChangeFeedInfo) (*model.ChangeFeedInfo, bool, error) { 137 c.Assert(info, check.IsNil) 138 return &model.ChangeFeedInfo{SinkURI: "123", Config: &config.ReplicaConfig{}}, true, nil 139 }) 140 state.PatchStatus(func(status *model.ChangeFeedStatus) (*model.ChangeFeedStatus, bool, error) { 141 c.Assert(status, check.IsNil) 142 return &model.ChangeFeedStatus{}, true, nil 143 }) 144 state.PatchTaskStatus(ctx.GlobalVars().CaptureInfo.ID, func(status *model.TaskStatus) (*model.TaskStatus, bool, error) { 145 return &model.TaskStatus{}, true, nil 146 }) 147 state.PatchTaskPosition(ctx.GlobalVars().CaptureInfo.ID, func(position *model.TaskPosition) (*model.TaskPosition, bool, error) { 148 return &model.TaskPosition{}, true, nil 149 }) 150 state.PatchTaskWorkload(ctx.GlobalVars().CaptureInfo.ID, func(workload model.TaskWorkload) (model.TaskWorkload, bool, error) { 151 return model.TaskWorkload{}, true, nil 152 }) 153 tester.MustApplyPatches() 154 c.Assert(state.TaskStatuses, check.HasKey, ctx.GlobalVars().CaptureInfo.ID) 155 c.Assert(state.TaskPositions, check.HasKey, ctx.GlobalVars().CaptureInfo.ID) 156 c.Assert(state.Workloads, check.HasKey, ctx.GlobalVars().CaptureInfo.ID) 157 manager.Tick(state) 158 tester.MustApplyPatches() 159 c.Assert(manager.ShouldRunning(), check.IsTrue) 160 161 manager.MarkFinished() 162 manager.Tick(state) 163 tester.MustApplyPatches() 164 c.Assert(manager.ShouldRunning(), check.IsFalse) 165 c.Assert(state.Info.State, check.Equals, model.StateFinished) 166 c.Assert(state.Info.AdminJobType, check.Equals, model.AdminFinish) 167 c.Assert(state.Status.AdminJobType, check.Equals, model.AdminFinish) 168 c.Assert(state.TaskStatuses, check.Not(check.HasKey), ctx.GlobalVars().CaptureInfo.ID) 169 c.Assert(state.TaskPositions, check.Not(check.HasKey), ctx.GlobalVars().CaptureInfo.ID) 170 c.Assert(state.Workloads, check.Not(check.HasKey), ctx.GlobalVars().CaptureInfo.ID) 171 } 172 173 func (s *feedStateManagerSuite) TestHandleError(c *check.C) { 174 defer testleak.AfterTest(c)() 175 ctx := cdcContext.NewBackendContext4Test(true) 176 manager := new(feedStateManager) 177 state := model.NewChangefeedReactorState(ctx.ChangefeedVars().ID) 178 tester := orchestrator.NewReactorStateTester(c, state, nil) 179 state.PatchInfo(func(info *model.ChangeFeedInfo) (*model.ChangeFeedInfo, bool, error) { 180 c.Assert(info, check.IsNil) 181 return &model.ChangeFeedInfo{SinkURI: "123", Config: &config.ReplicaConfig{}}, true, nil 182 }) 183 state.PatchStatus(func(status *model.ChangeFeedStatus) (*model.ChangeFeedStatus, bool, error) { 184 c.Assert(status, check.IsNil) 185 return &model.ChangeFeedStatus{}, true, nil 186 }) 187 state.PatchTaskStatus(ctx.GlobalVars().CaptureInfo.ID, func(status *model.TaskStatus) (*model.TaskStatus, bool, error) { 188 return &model.TaskStatus{}, true, nil 189 }) 190 state.PatchTaskPosition(ctx.GlobalVars().CaptureInfo.ID, func(position *model.TaskPosition) (*model.TaskPosition, bool, error) { 191 return &model.TaskPosition{Error: &model.RunningError{ 192 Addr: ctx.GlobalVars().CaptureInfo.AdvertiseAddr, 193 Code: "[CDC:ErrEtcdSessionDone]", 194 Message: "fake error for test", 195 }}, true, nil 196 }) 197 state.PatchTaskWorkload(ctx.GlobalVars().CaptureInfo.ID, func(workload model.TaskWorkload) (model.TaskWorkload, bool, error) { 198 return model.TaskWorkload{}, true, nil 199 }) 200 tester.MustApplyPatches() 201 manager.Tick(state) 202 tester.MustApplyPatches() 203 c.Assert(manager.ShouldRunning(), check.IsTrue) 204 // error reported by processor in task position should be cleaned 205 c.Assert(state.TaskPositions[ctx.GlobalVars().CaptureInfo.ID].Error, check.IsNil) 206 207 // throw error more than history threshold to turn feed state into error 208 for i := 0; i < model.ErrorHistoryThreshold; i++ { 209 state.PatchTaskPosition(ctx.GlobalVars().CaptureInfo.ID, func(position *model.TaskPosition) (*model.TaskPosition, bool, error) { 210 return &model.TaskPosition{Error: &model.RunningError{ 211 Addr: ctx.GlobalVars().CaptureInfo.AdvertiseAddr, 212 Code: "[CDC:ErrEtcdSessionDone]", 213 Message: "fake error for test", 214 }}, true, nil 215 }) 216 tester.MustApplyPatches() 217 manager.Tick(state) 218 tester.MustApplyPatches() 219 } 220 c.Assert(manager.ShouldRunning(), check.IsFalse) 221 c.Assert(state.Info.State, check.Equals, model.StateError) 222 c.Assert(state.Info.AdminJobType, check.Equals, model.AdminStop) 223 c.Assert(state.Status.AdminJobType, check.Equals, model.AdminStop) 224 } 225 226 func (s *feedStateManagerSuite) TestChangefeedStatusNotExist(c *check.C) { 227 defer testleak.AfterTest(c)() 228 ctx := cdcContext.NewBackendContext4Test(true) 229 manager := new(feedStateManager) 230 state := model.NewChangefeedReactorState(ctx.ChangefeedVars().ID) 231 tester := orchestrator.NewReactorStateTester(c, state, map[string]string{ 232 "/tidb/cdc/capture/d563bfc0-f406-4f34-bc7d-6dc2e35a44e5": `{"id":"d563bfc0-f406-4f34-bc7d-6dc2e35a44e5","address":"172.16.6.147:8300","version":"v5.0.0-master-dirty"}`, 233 "/tidb/cdc/changefeed/info/" + ctx.ChangefeedVars().ID: `{"sink-uri":"blackhole:///","opts":{},"create-time":"2021-06-05T00:44:15.065939487+08:00","start-ts":425381670108266496,"target-ts":0,"admin-job-type":1,"sort-engine":"unified","config":{"case-sensitive":true,"enable-old-value":true,"force-replicate":false,"check-gc-safe-point":true,"filter":{"rules":["*.*"],"ignore-txn-start-ts":null},"mounter":{"worker-num":16},"sink":{"dispatchers":null,"protocol":"default"},"cyclic-replication":{"enable":false,"replica-id":0,"filter-replica-ids":null,"id-buckets":0,"sync-ddl":false},"scheduler":{"type":"table-number","polling-time":-1}},"state":"failed","history":[],"error":{"addr":"172.16.6.147:8300","code":"CDC:ErrSnapshotLostByGC","message":"[CDC:ErrSnapshotLostByGC]fail to create or maintain changefeed due to snapshot loss caused by GC. checkpoint-ts 425381670108266496 is earlier than GC safepoint at 0"},"sync-point-enabled":false,"sync-point-interval":600000000000,"creator-version":"v5.0.0-master-dirty"}`, 234 "/tidb/cdc/owner/156579d017f84a68": "d563bfc0-f406-4f34-bc7d-6dc2e35a44e5", 235 }) 236 manager.Tick(state) 237 c.Assert(manager.ShouldRunning(), check.IsFalse) 238 tester.MustApplyPatches() 239 240 manager.PushAdminJob(&model.AdminJob{ 241 CfID: ctx.ChangefeedVars().ID, 242 Type: model.AdminRemove, 243 Opts: &model.AdminJobOption{ForceRemove: true}, 244 }) 245 manager.Tick(state) 246 c.Assert(manager.ShouldRunning(), check.IsFalse) 247 tester.MustApplyPatches() 248 c.Assert(state.Info, check.IsNil) 249 c.Assert(state.Exist(), check.IsFalse) 250 }