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  }