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 }