github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/pkg/etcd/etcdkey.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 etcd
    15  
    16  import (
    17  	"log"
    18  	"strings"
    19  
    20  	cerror "github.com/pingcap/ticdc/pkg/errors"
    21  )
    22  
    23  const (
    24  	etcdKeyBase = "/tidb/cdc"
    25  	ownerKey    = "/owner"
    26  	captureKey  = "/capture"
    27  
    28  	taskKey         = "/task"
    29  	taskWorkloadKey = taskKey + "/workload"
    30  	taskStatusKey   = taskKey + "/status"
    31  	taskPositionKey = taskKey + "/position"
    32  
    33  	changefeedInfoKey = "/changefeed/info"
    34  	jobKey            = "/job"
    35  )
    36  
    37  // CDCKeyType is the type of etcd key
    38  type CDCKeyType = int
    39  
    40  // the types of etcd key
    41  const (
    42  	CDCKeyTypeUnknown CDCKeyType = iota
    43  	CDCKeyTypeOwner
    44  	CDCKeyTypeCapture
    45  	CDCKeyTypeChangefeedInfo
    46  	CDCKeyTypeChangeFeedStatus
    47  	CDCKeyTypeTaskPosition
    48  	CDCKeyTypeTaskStatus
    49  	CDCKeyTypeTaskWorkload
    50  )
    51  
    52  // CDCKey represents a etcd key which is defined by TiCDC
    53  /*
    54   Usage:
    55   we can parse a raw etcd key:
    56   ```
    57   	k := new(CDCKey)
    58   	rawKey := "/tidb/cdc/changefeed/info/test/changefeed"
    59  	err := k.Parse(rawKey)
    60   	c.Assert(k, check.DeepEquals, &CDCKey{
    61  			Tp:           CDCKeyTypeChangefeedInfo,
    62  			ChangefeedID: "test/changefeed",
    63  	})
    64   ```
    65  
    66   and we can generate a raw key from CDCKey
    67   ```
    68   	k := &CDCKey{
    69  			Tp:           CDCKeyTypeChangefeedInfo,
    70  			ChangefeedID: "test/changefeed",
    71  	}
    72   	c.Assert(k.String(), check.Equals, "/tidb/cdc/changefeed/info/test/changefeed")
    73   ```
    74  
    75  */
    76  type CDCKey struct {
    77  	Tp           CDCKeyType
    78  	ChangefeedID string
    79  	CaptureID    string
    80  	OwnerLeaseID string
    81  }
    82  
    83  // Parse parses the given etcd key
    84  func (k *CDCKey) Parse(key string) error {
    85  	if !strings.HasPrefix(key, etcdKeyBase) {
    86  		return cerror.ErrInvalidEtcdKey.GenWithStackByArgs(key)
    87  	}
    88  	key = key[len(etcdKeyBase):]
    89  	switch {
    90  	case strings.HasPrefix(key, ownerKey):
    91  		k.Tp = CDCKeyTypeOwner
    92  		k.CaptureID = ""
    93  		k.ChangefeedID = ""
    94  		key = key[len(ownerKey):]
    95  		if len(key) > 0 {
    96  			key = key[1:]
    97  		}
    98  		k.OwnerLeaseID = key
    99  	case strings.HasPrefix(key, captureKey):
   100  		k.Tp = CDCKeyTypeCapture
   101  		k.CaptureID = key[len(captureKey)+1:]
   102  		k.ChangefeedID = ""
   103  		k.OwnerLeaseID = ""
   104  	case strings.HasPrefix(key, changefeedInfoKey):
   105  		k.Tp = CDCKeyTypeChangefeedInfo
   106  		k.CaptureID = ""
   107  		k.ChangefeedID = key[len(changefeedInfoKey)+1:]
   108  		k.OwnerLeaseID = ""
   109  	case strings.HasPrefix(key, jobKey):
   110  		k.Tp = CDCKeyTypeChangeFeedStatus
   111  		k.CaptureID = ""
   112  		k.ChangefeedID = key[len(jobKey)+1:]
   113  		k.OwnerLeaseID = ""
   114  	case strings.HasPrefix(key, taskStatusKey):
   115  		splitKey := strings.SplitN(key[len(taskStatusKey)+1:], "/", 2)
   116  		if len(splitKey) != 2 {
   117  			return cerror.ErrInvalidEtcdKey.GenWithStackByArgs(key)
   118  		}
   119  		k.Tp = CDCKeyTypeTaskStatus
   120  		k.CaptureID = splitKey[0]
   121  		k.ChangefeedID = splitKey[1]
   122  		k.OwnerLeaseID = ""
   123  	case strings.HasPrefix(key, taskPositionKey):
   124  		splitKey := strings.SplitN(key[len(taskPositionKey)+1:], "/", 2)
   125  		if len(splitKey) != 2 {
   126  			return cerror.ErrInvalidEtcdKey.GenWithStackByArgs(key)
   127  		}
   128  		k.Tp = CDCKeyTypeTaskPosition
   129  		k.CaptureID = splitKey[0]
   130  		k.ChangefeedID = splitKey[1]
   131  		k.OwnerLeaseID = ""
   132  	case strings.HasPrefix(key, taskWorkloadKey):
   133  		splitKey := strings.SplitN(key[len(taskWorkloadKey)+1:], "/", 2)
   134  		if len(splitKey) != 2 {
   135  			return cerror.ErrInvalidEtcdKey.GenWithStackByArgs(key)
   136  		}
   137  		k.Tp = CDCKeyTypeTaskWorkload
   138  		k.CaptureID = splitKey[0]
   139  		k.ChangefeedID = splitKey[1]
   140  		k.OwnerLeaseID = ""
   141  	default:
   142  		return cerror.ErrInvalidEtcdKey.GenWithStackByArgs(key)
   143  	}
   144  	return nil
   145  }
   146  
   147  func (k *CDCKey) String() string {
   148  	switch k.Tp {
   149  	case CDCKeyTypeOwner:
   150  		if len(k.OwnerLeaseID) == 0 {
   151  			return etcdKeyBase + ownerKey
   152  		}
   153  		return etcdKeyBase + ownerKey + "/" + k.OwnerLeaseID
   154  	case CDCKeyTypeCapture:
   155  		return etcdKeyBase + captureKey + "/" + k.CaptureID
   156  	case CDCKeyTypeChangefeedInfo:
   157  		return etcdKeyBase + changefeedInfoKey + "/" + k.ChangefeedID
   158  	case CDCKeyTypeChangeFeedStatus:
   159  		return etcdKeyBase + jobKey + "/" + k.ChangefeedID
   160  	case CDCKeyTypeTaskPosition:
   161  		return etcdKeyBase + taskPositionKey + "/" + k.CaptureID + "/" + k.ChangefeedID
   162  	case CDCKeyTypeTaskStatus:
   163  		return etcdKeyBase + taskStatusKey + "/" + k.CaptureID + "/" + k.ChangefeedID
   164  	case CDCKeyTypeTaskWorkload:
   165  		return etcdKeyBase + taskWorkloadKey + "/" + k.CaptureID + "/" + k.ChangefeedID
   166  	}
   167  	log.Panic("unreachable")
   168  	return ""
   169  }