github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/testing_utils/cdc_state_checker/state.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 main 15 16 import ( 17 "encoding/json" 18 "regexp" 19 20 "go.uber.org/zap" 21 22 "github.com/pingcap/errors" 23 "github.com/pingcap/log" 24 "github.com/pingcap/ticdc/cdc/kv" 25 "github.com/pingcap/ticdc/cdc/model" 26 "github.com/pingcap/ticdc/pkg/orchestrator" 27 "github.com/pingcap/ticdc/pkg/orchestrator/util" 28 ) 29 30 type cdcReactorState struct { 31 Owner model.CaptureID 32 Captures map[model.CaptureID]*model.CaptureInfo 33 ChangefeedStatuses map[model.ChangeFeedID]*model.ChangeFeedStatus 34 TaskPositions map[model.ChangeFeedID]map[model.CaptureID]*model.TaskPosition 35 TaskStatuses map[model.ChangeFeedID]map[model.CaptureID]*model.TaskStatus 36 } 37 38 var ( 39 captureRegex = regexp.MustCompile(regexp.QuoteMeta(kv.CaptureInfoKeyPrefix) + "/(.+)") 40 changefeedRegex = regexp.MustCompile(regexp.QuoteMeta(kv.JobKeyPrefix) + "/(.+)") 41 positionRegex = regexp.MustCompile(regexp.QuoteMeta(kv.TaskPositionKeyPrefix) + "/(.+?)/(.+)") 42 statusRegex = regexp.MustCompile(regexp.QuoteMeta(kv.TaskStatusKeyPrefix) + "/(.+?)/(.+)") 43 ) 44 45 func newCDCReactorState() *cdcReactorState { 46 return &cdcReactorState{ 47 Captures: make(map[model.CaptureID]*model.CaptureInfo), 48 ChangefeedStatuses: make(map[model.ChangeFeedID]*model.ChangeFeedStatus), 49 TaskPositions: make(map[model.ChangeFeedID]map[model.CaptureID]*model.TaskPosition), 50 TaskStatuses: make(map[model.ChangeFeedID]map[model.CaptureID]*model.TaskStatus), 51 } 52 } 53 54 func (s *cdcReactorState) Update(key util.EtcdKey, value []byte, isInit bool) error { 55 if key.String() == kv.CaptureOwnerKey { 56 if value == nil { 57 log.Info("Owner lost", zap.String("old-owner", s.Owner)) 58 return nil 59 } 60 61 log.Info("Owner updated", zap.String("old-owner", s.Owner), 62 zap.ByteString("new-owner", value)) 63 s.Owner = string(value) 64 return nil 65 } 66 67 if matches := captureRegex.FindSubmatch(key.Bytes()); matches != nil { 68 captureID := string(matches[1]) 69 70 if value == nil { 71 log.Info("Capture deleted", 72 zap.String("captureID", captureID), 73 zap.Reflect("old-capture", s.Captures[captureID])) 74 75 delete(s.Captures, captureID) 76 return nil 77 } 78 79 var newCaptureInfo model.CaptureInfo 80 err := json.Unmarshal(value, &newCaptureInfo) 81 if err != nil { 82 return errors.Trace(err) 83 } 84 85 if oldCaptureInfo, ok := s.Captures[captureID]; ok { 86 log.Info("Capture updated", 87 zap.String("captureID", captureID), 88 zap.Reflect("old-capture", oldCaptureInfo), 89 zap.Reflect("new-capture", newCaptureInfo)) 90 } else { 91 log.Info("Capture added", 92 zap.String("captureID", captureID), 93 zap.Reflect("new-capture", newCaptureInfo)) 94 } 95 96 s.Captures[captureID] = &newCaptureInfo 97 return nil 98 } 99 100 if matches := changefeedRegex.FindSubmatch(key.Bytes()); matches != nil { 101 changefeedID := string(matches[1]) 102 103 if value == nil { 104 log.Info("Changefeed deleted", 105 zap.String("changefeedID", changefeedID), 106 zap.Reflect("old-changefeed", s.ChangefeedStatuses)) 107 108 delete(s.ChangefeedStatuses, changefeedID) 109 return nil 110 } 111 112 var newChangefeedStatus model.ChangeFeedStatus 113 err := json.Unmarshal(value, &newChangefeedStatus) 114 if err != nil { 115 return errors.Trace(err) 116 } 117 118 if oldChangefeedInfo, ok := s.ChangefeedStatuses[changefeedID]; ok { 119 log.Info("Changefeed updated", 120 zap.String("changefeedID", changefeedID), 121 zap.Reflect("old-changefeed", oldChangefeedInfo), 122 zap.Reflect("new-changefeed", newChangefeedStatus)) 123 } else { 124 log.Info("Changefeed added", 125 zap.String("changefeedID", changefeedID), 126 zap.Reflect("new-changefeed", newChangefeedStatus)) 127 } 128 129 s.ChangefeedStatuses[changefeedID] = &newChangefeedStatus 130 131 return nil 132 } 133 134 if matches := positionRegex.FindSubmatch(key.Bytes()); matches != nil { 135 captureID := string(matches[1]) 136 changefeedID := string(matches[2]) 137 138 if value == nil { 139 log.Info("Position deleted", 140 zap.String("captureID", captureID), 141 zap.String("changefeedID", changefeedID), 142 zap.Reflect("old-position", s.TaskPositions[changefeedID][captureID])) 143 144 delete(s.TaskPositions[changefeedID], captureID) 145 if len(s.TaskPositions[changefeedID]) == 0 { 146 delete(s.TaskPositions, changefeedID) 147 } 148 149 return nil 150 } 151 152 var newTaskPosition model.TaskPosition 153 err := json.Unmarshal(value, &newTaskPosition) 154 if err != nil { 155 return errors.Trace(err) 156 } 157 158 if _, ok := s.TaskPositions[changefeedID]; !ok { 159 s.TaskPositions[changefeedID] = make(map[model.CaptureID]*model.TaskPosition) 160 } 161 162 if position, ok := s.TaskPositions[changefeedID][captureID]; ok { 163 log.Info("Position updated", 164 zap.String("captureID", captureID), 165 zap.String("changefeedID", changefeedID), 166 zap.Reflect("old-position", position), 167 zap.Reflect("new-position", newTaskPosition)) 168 } else { 169 log.Info("Position created", 170 zap.String("captureID", captureID), 171 zap.String("changefeedID", changefeedID), 172 zap.Reflect("new-position", newTaskPosition)) 173 } 174 175 s.TaskPositions[changefeedID][captureID] = &newTaskPosition 176 177 return nil 178 } 179 180 if matches := statusRegex.FindSubmatch(key.Bytes()); matches != nil { 181 captureID := string(matches[1]) 182 changefeedID := string(matches[2]) 183 184 if value == nil { 185 log.Info("Status deleted", 186 zap.String("captureID", captureID), 187 zap.String("changefeedID", changefeedID), 188 zap.Reflect("old-status", s.TaskStatuses[changefeedID][captureID])) 189 190 delete(s.TaskStatuses[changefeedID], captureID) 191 if len(s.TaskStatuses[changefeedID]) == 0 { 192 delete(s.TaskStatuses, changefeedID) 193 } 194 195 return nil 196 } 197 198 var newTaskStatus model.TaskStatus 199 err := json.Unmarshal(value, &newTaskStatus) 200 if err != nil { 201 return errors.Trace(err) 202 } 203 204 if _, ok := s.TaskStatuses[changefeedID]; !ok { 205 s.TaskStatuses[changefeedID] = make(map[model.CaptureID]*model.TaskStatus) 206 } 207 208 if status, ok := s.TaskStatuses[changefeedID][captureID]; ok { 209 log.Info("Status updated", 210 zap.String("captureID", captureID), 211 zap.String("changefeedID", changefeedID), 212 zap.Reflect("old-status", status), 213 zap.Reflect("new-status", newTaskStatus)) 214 } else { 215 log.Info("Status updated", 216 zap.String("captureID", captureID), 217 zap.String("changefeedID", changefeedID), 218 zap.Reflect("new-status", newTaskStatus)) 219 } 220 221 s.TaskStatuses[changefeedID][captureID] = &newTaskStatus 222 223 return nil 224 } 225 226 log.Debug("Etcd operation ignored", zap.String("key", key.String()), zap.ByteString("value", value)) 227 return nil 228 } 229 230 func (s *cdcReactorState) GetPatches() [][]orchestrator.DataPatch { 231 return nil 232 }