github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/cdc/model/owner.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 model 15 16 import ( 17 "encoding/json" 18 "fmt" 19 20 "github.com/pingcap/errors" 21 timodel "github.com/pingcap/tidb/pkg/parser/model" 22 "github.com/pingcap/tiflow/cdc/processor/tablepb" 23 cerror "github.com/pingcap/tiflow/pkg/errors" 24 ) 25 26 // AdminJobType represents for admin job type, both used in owner and processor 27 type AdminJobType int 28 29 // AdminJob holds an admin job 30 type AdminJob struct { 31 CfID ChangeFeedID 32 Type AdminJobType 33 Error *RunningError 34 OverwriteCheckpointTs uint64 35 } 36 37 // All AdminJob types 38 const ( 39 AdminNone AdminJobType = iota 40 AdminStop 41 AdminResume 42 AdminRemove 43 AdminFinish 44 ) 45 46 // String implements fmt.Stringer interface. 47 func (t AdminJobType) String() string { 48 switch t { 49 case AdminNone: 50 return "noop" 51 case AdminStop: 52 return "stop changefeed" 53 case AdminResume: 54 return "resume changefeed" 55 case AdminRemove: 56 return "remove changefeed" 57 case AdminFinish: 58 return "finish changefeed" 59 } 60 return "unknown" 61 } 62 63 // IsStopState returns whether changefeed is in stop state with give admin job 64 func (t AdminJobType) IsStopState() bool { 65 switch t { 66 case AdminStop, AdminRemove, AdminFinish: 67 return true 68 } 69 return false 70 } 71 72 // DDLJobEntry is the DDL job entry. 73 type DDLJobEntry struct { 74 Job *timodel.Job 75 OpType OpType 76 CRTs uint64 77 } 78 79 // TaskPosition records the process information of a capture 80 type TaskPosition struct { 81 // The maximum event CommitTs that has been synchronized. This is updated by corresponding processor. 82 // 83 // Deprecated: only used in API. TODO: remove API usage. 84 CheckPointTs uint64 `json:"checkpoint-ts"` 85 // The event that satisfies CommitTs <= ResolvedTs can be synchronized. This is updated by corresponding processor. 86 // 87 // Deprecated: only used in API. TODO: remove API usage. 88 ResolvedTs uint64 `json:"resolved-ts"` 89 // The count of events were synchronized. This is updated by corresponding processor. 90 // 91 // Deprecated: only used in API. TODO: remove API usage. 92 Count uint64 `json:"count"` 93 94 // Error when changefeed error happens 95 Error *RunningError `json:"error"` 96 // Warning when module error happens 97 Warning *RunningError `json:"warning"` 98 } 99 100 // Marshal returns the json marshal format of a TaskStatus 101 func (tp *TaskPosition) Marshal() (string, error) { 102 data, err := json.Marshal(tp) 103 return string(data), cerror.WrapError(cerror.ErrMarshalFailed, err) 104 } 105 106 // Unmarshal unmarshals into *TaskStatus from json marshal byte slice 107 func (tp *TaskPosition) Unmarshal(data []byte) error { 108 err := json.Unmarshal(data, tp) 109 return errors.Annotatef( 110 cerror.WrapError(cerror.ErrUnmarshalFailed, err), "Unmarshal data: %v", data) 111 } 112 113 // String implements fmt.Stringer interface. 114 func (tp *TaskPosition) String() string { 115 data, _ := tp.Marshal() 116 return data 117 } 118 119 // Clone returns a deep clone of TaskPosition 120 func (tp *TaskPosition) Clone() *TaskPosition { 121 ret := &TaskPosition{ 122 CheckPointTs: tp.CheckPointTs, 123 ResolvedTs: tp.ResolvedTs, 124 Count: tp.Count, 125 } 126 if tp.Error != nil { 127 ret.Error = &RunningError{ 128 Time: tp.Error.Time, 129 Addr: tp.Error.Addr, 130 Code: tp.Error.Code, 131 Message: tp.Error.Message, 132 } 133 } 134 if tp.Warning != nil { 135 ret.Warning = &RunningError{ 136 Time: tp.Warning.Time, 137 Addr: tp.Warning.Addr, 138 Code: tp.Warning.Code, 139 Message: tp.Warning.Message, 140 } 141 } 142 return ret 143 } 144 145 // All TableOperation flags 146 const ( 147 // Move means after the delete operation, the table will be re added. 148 // This field is necessary since we must persist enough information to 149 // restore complete table operation in case of processor or owner crashes. 150 OperFlagMoveTable uint64 = 1 << iota 151 ) 152 153 // All TableOperation status 154 const ( 155 OperDispatched uint64 = iota 156 OperProcessed 157 OperFinished 158 ) 159 160 // TableOperation records the current information of a table migration 161 type TableOperation struct { 162 Delete bool `json:"delete"` 163 Flag uint64 `json:"flag,omitempty"` 164 // if the operation is a delete operation, BoundaryTs is checkpoint ts 165 // if the operation is an add operation, BoundaryTs is start ts 166 BoundaryTs uint64 `json:"boundary_ts"` 167 Status uint64 `json:"status,omitempty"` 168 } 169 170 // TableProcessed returns whether the table has been processed by processor 171 func (o *TableOperation) TableProcessed() bool { 172 return o.Status == OperProcessed || o.Status == OperFinished 173 } 174 175 // TableApplied returns whether the table has finished the startup procedure. 176 // Returns true if table has been processed by processor and resolved ts reaches global resolved ts. 177 func (o *TableOperation) TableApplied() bool { 178 return o.Status == OperFinished 179 } 180 181 // Clone returns a deep-clone of the struct 182 func (o *TableOperation) Clone() *TableOperation { 183 if o == nil { 184 return nil 185 } 186 clone := *o 187 return &clone 188 } 189 190 // TableReplicaInfo records the table replica info 191 type TableReplicaInfo struct { 192 StartTs Ts `json:"start-ts"` 193 } 194 195 // Clone clones a TableReplicaInfo 196 func (i *TableReplicaInfo) Clone() *TableReplicaInfo { 197 if i == nil { 198 return nil 199 } 200 clone := *i 201 return &clone 202 } 203 204 // TaskStatus records the task information of a capture. 205 // 206 // Deprecated: only used in API. TODO: remove API usage. 207 type TaskStatus struct { 208 Tables map[TableID]*TableReplicaInfo `json:"tables"` 209 Operation map[TableID]*TableOperation `json:"operation"` 210 AdminJobType AdminJobType `json:"admin-job-type"` 211 ModRevision int64 `json:"-"` 212 } 213 214 // String implements fmt.Stringer interface. 215 func (ts *TaskStatus) String() string { 216 data, _ := ts.Marshal() 217 return data 218 } 219 220 // Marshal returns the json marshal format of a TaskStatus 221 func (ts *TaskStatus) Marshal() (string, error) { 222 data, err := json.Marshal(ts) 223 return string(data), cerror.WrapError(cerror.ErrMarshalFailed, err) 224 } 225 226 // Unmarshal unmarshals into *TaskStatus from json marshal byte slice 227 func (ts *TaskStatus) Unmarshal(data []byte) error { 228 err := json.Unmarshal(data, ts) 229 return errors.Annotatef( 230 cerror.WrapError(cerror.ErrUnmarshalFailed, err), "Unmarshal data: %v", data) 231 } 232 233 // Clone returns a deep-clone of the struct 234 func (ts *TaskStatus) Clone() *TaskStatus { 235 clone := *ts 236 tables := make(map[TableID]*TableReplicaInfo, len(ts.Tables)) 237 for tableID, table := range ts.Tables { 238 tables[tableID] = table.Clone() 239 } 240 clone.Tables = tables 241 operation := make(map[TableID]*TableOperation, len(ts.Operation)) 242 for tableID, opt := range ts.Operation { 243 operation[tableID] = opt.Clone() 244 } 245 clone.Operation = operation 246 return &clone 247 } 248 249 // TableID is the ID of the table 250 type TableID = tablepb.TableID 251 252 // Ts is the timestamp with a logical count 253 type Ts = tablepb.Ts 254 255 // ProcessorsInfos maps from capture IDs to TaskStatus 256 type ProcessorsInfos map[CaptureID]*TaskStatus 257 258 // String implements fmt.Stringer interface. 259 func (p ProcessorsInfos) String() string { 260 s := "{" 261 for id, sinfo := range p { 262 s += fmt.Sprintf("%s: %+v,", id, *sinfo) 263 } 264 265 s += "}" 266 267 return s 268 } 269 270 // ChangeFeedStatus stores information about a ChangeFeed 271 // It is stored in etcd. 272 type ChangeFeedStatus struct { 273 CheckpointTs uint64 `json:"checkpoint-ts"` 274 // minTableBarrierTs is the minimum commitTs of all DDL events and is only 275 // used to check whether there is a pending DDL job at the checkpointTs when 276 // initializing the changefeed. 277 MinTableBarrierTs uint64 `json:"min-table-barrier-ts"` 278 // TODO: remove this filed after we don't use ChangeFeedStatus to 279 // control processor. This is too ambiguous. 280 AdminJobType AdminJobType `json:"admin-job-type"` 281 } 282 283 // Marshal returns json encoded string of ChangeFeedStatus, only contains necessary fields stored in storage 284 func (status *ChangeFeedStatus) Marshal() (string, error) { 285 data, err := json.Marshal(status) 286 return string(data), cerror.WrapError(cerror.ErrMarshalFailed, err) 287 } 288 289 // Unmarshal unmarshals into *ChangeFeedStatus from json marshal byte slice 290 func (status *ChangeFeedStatus) Unmarshal(data []byte) error { 291 err := json.Unmarshal(data, status) 292 return errors.Annotatef( 293 cerror.WrapError(cerror.ErrUnmarshalFailed, err), "Unmarshal data: %v", data) 294 } 295 296 // ProcInfoSnap holds most important replication information of a processor 297 type ProcInfoSnap struct { 298 CfID ChangeFeedID `json:"changefeed-id"` 299 CaptureID string `json:"capture-id"` 300 }