github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/pkg/streamer/hub.go (about)

     1  // Copyright 2019 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 streamer
    15  
    16  import (
    17  	"path/filepath"
    18  	"strings"
    19  	"sync"
    20  
    21  	"github.com/pingcap/tiflow/dm/pkg/terror"
    22  	"github.com/pingcap/tiflow/dm/pkg/utils"
    23  )
    24  
    25  var (
    26  	readerHub *ReaderHub // singleton instance
    27  	once      sync.Once
    28  )
    29  
    30  // RelayLogInfo represents information for relay log.
    31  type RelayLogInfo struct {
    32  	TaskName     string
    33  	SubDir       string
    34  	SubDirSuffix int
    35  	Filename     string
    36  }
    37  
    38  // Earlier checks whether this relay log file is earlier than the other.
    39  func (info *RelayLogInfo) Earlier(other *RelayLogInfo) bool {
    40  	if info.SubDirSuffix < other.SubDirSuffix {
    41  		return true
    42  	} else if info.SubDirSuffix > other.SubDirSuffix {
    43  		return false
    44  	}
    45  	return strings.Compare(info.Filename, other.Filename) < 0
    46  }
    47  
    48  // String implements Stringer.String.
    49  func (info *RelayLogInfo) String() string {
    50  	return filepath.Join(info.SubDir, info.Filename)
    51  }
    52  
    53  // relayLogInfoHub holds information for all active relay logs.
    54  type relayLogInfoHub struct {
    55  	mu   sync.RWMutex
    56  	logs map[string]RelayLogInfo
    57  }
    58  
    59  func newRelayLogInfoHub() *relayLogInfoHub {
    60  	return &relayLogInfoHub{
    61  		logs: map[string]RelayLogInfo{},
    62  	}
    63  }
    64  
    65  func (h *relayLogInfoHub) update(taskName, subDir, filename string) error {
    66  	_, suffix, err := utils.ParseRelaySubDir(subDir)
    67  	if err != nil {
    68  		return err
    69  	}
    70  	if !utils.VerifyFilename(filename) {
    71  		return terror.ErrBinlogInvalidFilename.Generatef("binlog filename %s not valid", filename)
    72  	}
    73  	h.mu.Lock()
    74  	defer h.mu.Unlock()
    75  	h.logs[taskName] = RelayLogInfo{
    76  		TaskName:     taskName,
    77  		SubDir:       subDir,
    78  		SubDirSuffix: suffix,
    79  		Filename:     filename,
    80  	}
    81  	return nil
    82  }
    83  
    84  func (h *relayLogInfoHub) remove(taskName string) {
    85  	h.mu.Lock()
    86  	defer h.mu.Unlock()
    87  	delete(h.logs, taskName)
    88  }
    89  
    90  func (h *relayLogInfoHub) earliest() (taskName string, earliest *RelayLogInfo) {
    91  	h.mu.RLock()
    92  	defer h.mu.RUnlock()
    93  	for name, info := range h.logs {
    94  		var isEarlier bool
    95  		if earliest == nil {
    96  			isEarlier = true
    97  		} else if info.Earlier(earliest) {
    98  			isEarlier = true
    99  		}
   100  		if isEarlier {
   101  			taskName = name
   102  			clone := info
   103  			earliest = &clone
   104  		}
   105  	}
   106  	return
   107  }
   108  
   109  // ReaderHub holds information for all active Readers.
   110  type ReaderHub struct {
   111  	rlih *relayLogInfoHub
   112  }
   113  
   114  // GetReaderHub gets singleton instance of ReaderHub.
   115  func GetReaderHub() *ReaderHub {
   116  	once.Do(func() {
   117  		readerHub = &ReaderHub{
   118  			rlih: newRelayLogInfoHub(),
   119  		}
   120  	})
   121  	return readerHub
   122  }
   123  
   124  // UpdateActiveRelayLog updates active relay log for taskName.
   125  func (h *ReaderHub) UpdateActiveRelayLog(taskName, subDir, filename string) error {
   126  	return h.rlih.update(taskName, subDir, filename)
   127  }
   128  
   129  // RemoveActiveRelayLog removes active relay log for taskName.
   130  func (h *ReaderHub) RemoveActiveRelayLog(taskName string) {
   131  	h.rlih.remove(taskName)
   132  }
   133  
   134  // EarliestActiveRelayLog implements RelayOperator.EarliestActiveRelayLog.
   135  func (h *ReaderHub) EarliestActiveRelayLog() *RelayLogInfo {
   136  	_, rli := h.rlih.earliest()
   137  	return rli
   138  }