github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/pkg/ha/subtask.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 ha
    15  
    16  import (
    17  	"context"
    18  
    19  	"github.com/pingcap/tiflow/dm/common"
    20  	"github.com/pingcap/tiflow/dm/config"
    21  	"github.com/pingcap/tiflow/dm/pkg/etcdutil"
    22  	"github.com/pingcap/tiflow/dm/pkg/terror"
    23  	clientv3 "go.etcd.io/etcd/client/v3"
    24  )
    25  
    26  // GetSubTaskCfg gets the subtask config of the specified source and task name.
    27  // if the config for the source not exist, return with `err == nil` and `revision=0`.
    28  // if task name is "", will return all the subtaskConfigs as a map{taskName: subtaskConfig} of the source
    29  // if task name if given, will return a map{taskName: subtaskConfig} whose length is 1.
    30  func GetSubTaskCfg(cli *clientv3.Client, source, task string, rev int64) (map[string]config.SubTaskConfig, int64, error) {
    31  	ctx, cancel := context.WithTimeout(cli.Ctx(), etcdutil.DefaultRequestTimeout)
    32  	defer cancel()
    33  
    34  	var (
    35  		tsm  = make(map[string]config.SubTaskConfig)
    36  		resp *clientv3.GetResponse
    37  		err  error
    38  	)
    39  	if task != "" {
    40  		resp, err = cli.Get(ctx, common.UpstreamSubTaskKeyAdapter.Encode(source, task), clientv3.WithRev(rev))
    41  	} else {
    42  		resp, err = cli.Get(ctx, common.UpstreamSubTaskKeyAdapter.Encode(source), clientv3.WithPrefix(), clientv3.WithRev(rev))
    43  	}
    44  
    45  	if err != nil {
    46  		return tsm, 0, terror.ErrHAFailTxnOperation.Delegate(err, "fail to get subtask config, source: %s, task: %s", source, task)
    47  	}
    48  
    49  	cfgs, err := subTaskCfgFromResp(source, task, resp)
    50  	if err != nil {
    51  		return tsm, 0, err
    52  	}
    53  	tsm = cfgs[source]
    54  
    55  	return tsm, resp.Header.Revision, nil
    56  }
    57  
    58  // GetAllSubTaskCfg gets all subtask configs.
    59  // k/v: source ID -> task name -> subtask config.
    60  func GetAllSubTaskCfg(cli *clientv3.Client) (map[string]map[string]config.SubTaskConfig, int64, error) {
    61  	ctx, cancel := context.WithTimeout(cli.Ctx(), etcdutil.DefaultRequestTimeout)
    62  	defer cancel()
    63  
    64  	resp, err := cli.Get(ctx, common.UpstreamSubTaskKeyAdapter.Path(), clientv3.WithPrefix())
    65  	if err != nil {
    66  		return nil, 0, terror.ErrHAFailTxnOperation.Delegate(err, "fail to get all subtask configs")
    67  	}
    68  
    69  	cfgs, err := subTaskCfgFromResp("", "", resp)
    70  	if err != nil {
    71  		return nil, 0, err
    72  	}
    73  
    74  	return cfgs, resp.Header.Revision, nil
    75  }
    76  
    77  // putSubTaskCfgOp returns a PUT etcd operation for the subtask config.
    78  func putSubTaskCfgOp(cfgs ...config.SubTaskConfig) ([]clientv3.Op, error) {
    79  	ops := make([]clientv3.Op, 0, len(cfgs))
    80  	for _, cfg := range cfgs {
    81  		value, err := cfg.Toml()
    82  		if err != nil {
    83  			return ops, err
    84  		}
    85  		key := common.UpstreamSubTaskKeyAdapter.Encode(cfg.SourceID, cfg.Name)
    86  		ops = append(ops, clientv3.OpPut(key, value))
    87  	}
    88  	return ops, nil
    89  }
    90  
    91  // deleteSubTaskCfgOp returns a DELETE etcd operation for the subtask config.
    92  func deleteSubTaskCfgOp(cfgs ...config.SubTaskConfig) []clientv3.Op {
    93  	ops := make([]clientv3.Op, 0, len(cfgs))
    94  	for _, cfg := range cfgs {
    95  		ops = append(ops, clientv3.OpDelete(common.UpstreamSubTaskKeyAdapter.Encode(cfg.SourceID, cfg.Name)))
    96  	}
    97  	return ops
    98  }
    99  
   100  func putValidatorStageOps(stages ...Stage) ([]clientv3.Op, error) {
   101  	ops := make([]clientv3.Op, 0, len(stages))
   102  	for _, stage := range stages {
   103  		key := common.StageValidatorKeyAdapter.Encode(stage.Source, stage.Task)
   104  		value, err := stage.toJSON()
   105  		if err != nil {
   106  			return nil, err
   107  		}
   108  		ops = append(ops, clientv3.OpPut(key, value))
   109  	}
   110  	return ops, nil
   111  }
   112  
   113  func deleteValidatorStageOps(stages ...Stage) []clientv3.Op {
   114  	ops := make([]clientv3.Op, 0, len(stages))
   115  	for _, stage := range stages {
   116  		key := common.StageValidatorKeyAdapter.Encode(stage.Source, stage.Task)
   117  		ops = append(ops, clientv3.OpDelete(key))
   118  	}
   119  	return ops
   120  }
   121  
   122  func subTaskCfgFromResp(source, task string, resp *clientv3.GetResponse) (map[string]map[string]config.SubTaskConfig, error) {
   123  	cfgs := make(map[string]map[string]config.SubTaskConfig)
   124  	if source != "" {
   125  		cfgs[source] = make(map[string]config.SubTaskConfig) // avoid cfgs[source] is nil
   126  	}
   127  
   128  	if resp.Count == 0 {
   129  		return cfgs, nil
   130  	} else if source != "" && task != "" && resp.Count > 1 {
   131  		// this should not happen.
   132  		return cfgs, terror.ErrConfigMoreThanOne.Generate(resp.Count, "config", "(source: "+source+", task: "+task+")")
   133  	}
   134  
   135  	for _, kvs := range resp.Kvs {
   136  		cfg := config.SubTaskConfig{}
   137  		err := cfg.Decode(string(kvs.Value), true)
   138  		if err != nil {
   139  			return cfgs, err
   140  		}
   141  		if _, ok := cfgs[cfg.SourceID]; !ok {
   142  			cfgs[cfg.SourceID] = make(map[string]config.SubTaskConfig)
   143  		}
   144  		cfgs[cfg.SourceID][cfg.Name] = cfg
   145  	}
   146  
   147  	return cfgs, nil
   148  }