github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/pkg/shardddl/pessimism/keeper.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 pessimism
    15  
    16  import (
    17  	"sync"
    18  
    19  	"github.com/pingcap/tiflow/dm/master/metrics"
    20  	"github.com/pingcap/tiflow/dm/pkg/utils"
    21  )
    22  
    23  // LockKeeper used to keep and handle DDL lock conveniently.
    24  // The lock information do not need to be persistent, and can be re-constructed from the shard DDL info.
    25  type LockKeeper struct {
    26  	mu    sync.RWMutex
    27  	locks map[string]*Lock // lockID -> Lock
    28  }
    29  
    30  // NewLockKeeper creates a new LockKeeper instance.
    31  func NewLockKeeper() *LockKeeper {
    32  	return &LockKeeper{
    33  		locks: make(map[string]*Lock),
    34  	}
    35  }
    36  
    37  // TrySync tries to sync the lock.
    38  func (lk *LockKeeper) TrySync(info Info, sources []string) (string, bool, int, error) {
    39  	var (
    40  		lockID = genDDLLockID(info)
    41  		l      *Lock
    42  		ok     bool
    43  	)
    44  
    45  	lk.mu.Lock()
    46  	defer lk.mu.Unlock()
    47  
    48  	if l, ok = lk.locks[lockID]; !ok {
    49  		lk.locks[lockID] = NewLock(lockID, info.Task, info.Source, info.DDLs, sources)
    50  		l = lk.locks[lockID]
    51  	}
    52  
    53  	synced, remain, err := l.TrySync(info.Source, info.DDLs, sources)
    54  	return lockID, synced, remain, err
    55  }
    56  
    57  // RemoveLock removes a lock.
    58  func (lk *LockKeeper) RemoveLock(lockID string) bool {
    59  	lk.mu.Lock()
    60  	defer lk.mu.Unlock()
    61  
    62  	_, ok := lk.locks[lockID]
    63  	delete(lk.locks, lockID)
    64  	metrics.RemoveDDLPending(utils.ExtractTaskFromLockID(lockID))
    65  	return ok
    66  }
    67  
    68  // RemoveLockByInfo removes a lock through given info.
    69  func (lk *LockKeeper) RemoveLockByInfo(info Info) bool {
    70  	lockID := genDDLLockID(info)
    71  	return lk.RemoveLock(lockID)
    72  }
    73  
    74  // FindLock finds a lock.
    75  func (lk *LockKeeper) FindLock(lockID string) *Lock {
    76  	lk.mu.RLock()
    77  	defer lk.mu.RUnlock()
    78  
    79  	return lk.locks[lockID]
    80  }
    81  
    82  // Locks return a copy of all Locks.
    83  func (lk *LockKeeper) Locks() map[string]*Lock {
    84  	lk.mu.RLock()
    85  	defer lk.mu.RUnlock()
    86  
    87  	locks := make(map[string]*Lock, len(lk.locks))
    88  	for k, v := range lk.locks {
    89  		locks[k] = v
    90  	}
    91  	return locks
    92  }
    93  
    94  // Clear clears all Locks.
    95  func (lk *LockKeeper) Clear() {
    96  	lk.mu.Lock()
    97  	defer lk.mu.Unlock()
    98  
    99  	lk.locks = make(map[string]*Lock)
   100  }
   101  
   102  // genDDLLockID generates DDL lock ID from its info.
   103  func genDDLLockID(info Info) string {
   104  	return utils.GenDDLLockID(info.Task, info.Schema, info.Table)
   105  }