github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/relay/file.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 relay 15 16 import ( 17 "os" 18 "path/filepath" 19 20 "github.com/pingcap/tiflow/dm/pkg/binlog" 21 "github.com/pingcap/tiflow/dm/pkg/log" 22 "github.com/pingcap/tiflow/dm/pkg/terror" 23 "github.com/pingcap/tiflow/dm/pkg/utils" 24 "go.uber.org/zap" 25 ) 26 27 // FileCmp is a compare condition used when collecting binlog files. 28 type FileCmp uint8 29 30 // FileCmpLess represents a < FileCmp condition, others are similar. 31 const ( 32 FileCmpLess FileCmp = iota + 1 33 FileCmpLessEqual 34 FileCmpEqual 35 FileCmpBiggerEqual 36 FileCmpBigger 37 ) 38 39 // EventNotifier notifies whether there is new binlog event written to the file. 40 type EventNotifier interface { 41 // Notified returns a channel used to check whether there is new binlog event written to the file 42 Notified() chan interface{} 43 } 44 45 // CollectAllBinlogFiles collects all valid binlog files in dir, and returns filenames in binlog ascending order. 46 func CollectAllBinlogFiles(dir string) ([]string, error) { 47 if dir == "" { 48 return nil, terror.ErrEmptyRelayDir.Generate() 49 } 50 return binlog.ReadSortedBinlogFromDir(dir) 51 } 52 53 // CollectBinlogFilesCmp collects valid binlog files with a compare condition. 54 func CollectBinlogFilesCmp(dir, baseFile string, cmp FileCmp) ([]string, error) { 55 if dir == "" { 56 return nil, terror.ErrEmptyRelayDir.Generate() 57 } 58 59 if bp := filepath.Join(dir, baseFile); !utils.IsFileExists(bp) { 60 return nil, terror.ErrBaseFileNotFound.Generate(baseFile, dir) 61 } 62 63 bf, err := utils.ParseFilename(baseFile) 64 if err != nil { 65 return nil, terror.Annotatef(err, "filename %s", baseFile) 66 } 67 68 allFiles, err := CollectAllBinlogFiles(dir) 69 if err != nil { 70 return nil, err 71 } 72 73 results := make([]string, 0, len(allFiles)) 74 for _, f := range allFiles { 75 // we have parse f in `CollectAllBinlogFiles`, may be we can refine this 76 parsed, err := utils.ParseFilename(f) 77 if err != nil || parsed.BaseName != bf.BaseName { 78 log.L().Warn("collecting binlog file, ignore invalid file", zap.String("file", f), log.ShortError(err)) 79 continue 80 } 81 switch cmp { 82 case FileCmpBigger: 83 if !parsed.GreaterThan(bf) { 84 log.L().Debug("ignore older or equal binlog file", zap.String("file", f), zap.String("directory", dir)) 85 continue 86 } 87 case FileCmpBiggerEqual: 88 if !parsed.GreaterThanOrEqualTo(bf) { 89 log.L().Debug("ignore older binlog file", zap.String("file", f), zap.String("directory", dir)) 90 continue 91 } 92 case FileCmpLess: 93 if !parsed.LessThan(bf) { 94 log.L().Debug("ignore newer or equal binlog file", zap.String("file", f), zap.String("directory", dir)) 95 continue 96 } 97 default: 98 return nil, terror.ErrBinFileCmpCondNotSupport.Generate(cmp) 99 } 100 101 results = append(results, f) 102 } 103 104 return results, nil 105 } 106 107 // getFirstBinlogName gets the first binlog file in relay sub directory. 108 func getFirstBinlogName(baseDir, uuid string) (string, error) { 109 subDir := filepath.Join(baseDir, uuid) 110 files, err := binlog.ReadSortedBinlogFromDir(subDir) 111 if err != nil { 112 return "", terror.Annotatef(err, "get binlog file for dir %s", subDir) 113 } 114 115 if len(files) == 0 { 116 return "", terror.ErrBinlogFilesNotFound.Generate(subDir) 117 } 118 return files[0], nil 119 } 120 121 // fileSizeUpdated checks whether the file's size has updated 122 // return 123 // 124 // 0: not updated 125 // 1: update to larger 126 // -1: update to smaller, only happens in special case, for example we change 127 // relay.meta manually and start task before relay log catches up. 128 func fileSizeUpdated(path string, latestSize int64) (int, error) { 129 fi, err := os.Stat(path) 130 if err != nil { 131 return 0, terror.ErrGetRelayLogStat.Delegate(err, path) 132 } 133 curSize := fi.Size() 134 switch { 135 case curSize == latestSize: 136 return 0, nil 137 case curSize > latestSize: 138 log.L().Debug("size of relay log file has been changed", zap.String("file", path), 139 zap.Int64("old size", latestSize), zap.Int64("size", curSize)) 140 return 1, nil 141 default: 142 log.L().Error("size of relay log file has been changed", zap.String("file", path), 143 zap.Int64("old size", latestSize), zap.Int64("size", curSize)) 144 return -1, nil 145 } 146 }