github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/pkg/v1workermeta/meta.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 v1workermeta
    15  
    16  import (
    17  	"github.com/golang/protobuf/proto"
    18  	"github.com/pingcap/tiflow/dm/pb"
    19  	"github.com/pingcap/tiflow/dm/pkg/terror"
    20  	"github.com/syndtr/goleveldb/leveldb"
    21  	"github.com/syndtr/goleveldb/leveldb/util"
    22  )
    23  
    24  // meta stores metadata of tasks.
    25  type meta struct {
    26  	tasks map[string]*pb.V1SubTaskMeta
    27  }
    28  
    29  // newMeta returns a meta object.
    30  func newMeta(db *leveldb.DB) (*meta, error) {
    31  	tasks, err := loadTaskMetas(db)
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  
    36  	return &meta{
    37  		tasks: tasks,
    38  	}, nil
    39  }
    40  
    41  // TasksMeta returns meta of all tasks.
    42  func (meta *meta) TasksMeta() map[string]*pb.V1SubTaskMeta {
    43  	tasks := make(map[string]*pb.V1SubTaskMeta, len(meta.tasks))
    44  	for name, task := range meta.tasks {
    45  		tasks[name] = proto.Clone(task).(*pb.V1SubTaskMeta)
    46  	}
    47  	return tasks
    48  }
    49  
    50  // taskMetaPrefix is prefix of task meta key.
    51  var taskMetaPrefix = []byte("!DM!TaskMeta")
    52  
    53  // encodeTaskMetaKey encodes take name into a task meta key.
    54  func encodeTaskMetaKey(name string) []byte {
    55  	key := append([]byte{}, taskMetaPrefix...)
    56  	return append(key, name...)
    57  }
    58  
    59  // loadTaskMetas loads all task metas from kv db.
    60  func loadTaskMetas(db *leveldb.DB) (map[string]*pb.V1SubTaskMeta, error) {
    61  	if db == nil {
    62  		return nil, terror.ErrWorkerLogInvalidHandler.Generate()
    63  	}
    64  
    65  	var (
    66  		tasks = make(map[string]*pb.V1SubTaskMeta)
    67  		err   error
    68  	)
    69  
    70  	iter := db.NewIterator(util.BytesPrefix(taskMetaPrefix), nil)
    71  	for iter.Next() {
    72  		taskBytes := iter.Value()
    73  		task := &pb.V1SubTaskMeta{}
    74  		err = task.Unmarshal(taskBytes)
    75  		if err != nil {
    76  			iter.Release()
    77  			return nil, terror.ErrWorkerLogUnmarshalTaskMeta.Delegate(err, taskBytes)
    78  		}
    79  
    80  		tasks[task.Name] = task
    81  	}
    82  	iter.Release()
    83  
    84  	err = iter.Error()
    85  	if err != nil {
    86  		return nil, terror.ErrWorkerLogFetchTaskFromMeta.Delegate(err, taskMetaPrefix)
    87  	}
    88  
    89  	return tasks, nil
    90  }
    91  
    92  // setTaskMeta saves task meta into kv db.
    93  // it's used for testing.
    94  func setTaskMeta(db *leveldb.DB, task *pb.V1SubTaskMeta) error {
    95  	if db == nil {
    96  		return terror.ErrWorkerLogInvalidHandler.Generate()
    97  	}
    98  
    99  	err := verifyTaskMeta(task)
   100  	if err != nil {
   101  		return terror.Annotatef(err, "verify task meta %+v", task)
   102  	}
   103  
   104  	taskBytes, err := task.Marshal()
   105  	if err != nil {
   106  		return terror.ErrWorkerLogMarshalTask.Delegate(err, task)
   107  	}
   108  
   109  	err = db.Put(encodeTaskMetaKey(task.Name), taskBytes, nil)
   110  	if err != nil {
   111  		return terror.ErrWorkerLogSaveTaskMeta.Delegate(err, task.Name)
   112  	}
   113  
   114  	return nil
   115  }
   116  
   117  // deleteTaskMeta deletes task meta from kv DB.
   118  // it's used for testing.
   119  func deleteTaskMeta(db *leveldb.DB, name string) error {
   120  	if db == nil {
   121  		return terror.ErrWorkerLogInvalidHandler.Generate()
   122  	}
   123  
   124  	err := db.Delete(encodeTaskMetaKey(name), nil)
   125  	if err != nil {
   126  		return terror.ErrWorkerLogDeleteTaskMeta.Delegate(err, name)
   127  	}
   128  
   129  	return nil
   130  }
   131  
   132  // verifyTaskMeta verifies legality of take meta.
   133  // it's used for testing.
   134  func verifyTaskMeta(task *pb.V1SubTaskMeta) error {
   135  	if task == nil {
   136  		return terror.ErrWorkerLogVerifyTaskMeta.New("empty task not valid")
   137  	}
   138  
   139  	if len(task.Name) == 0 {
   140  		return terror.ErrWorkerLogVerifyTaskMeta.New("empty task name not valid")
   141  	}
   142  
   143  	if len(task.Task) == 0 {
   144  		return terror.ErrWorkerLogVerifyTaskMeta.New("empty task config not valid")
   145  	}
   146  
   147  	if task.Stage == pb.Stage_InvalidStage {
   148  		return terror.ErrWorkerLogVerifyTaskMeta.Generatef("stage %s not valid", task.Stage)
   149  	}
   150  
   151  	if task.Op == pb.TaskOp_InvalidOp {
   152  		return terror.ErrWorkerLogVerifyTaskMeta.Generatef("task operation %s not valid", task.Op)
   153  	}
   154  
   155  	return nil
   156  }