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

     1  // Copyright 2022 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 utils
    15  
    16  import (
    17  	"fmt"
    18  	"strconv"
    19  	"strings"
    20  
    21  	"github.com/pingcap/tiflow/dm/pkg/log"
    22  	"github.com/pingcap/tiflow/dm/pkg/terror"
    23  	"go.uber.org/zap"
    24  )
    25  
    26  const (
    27  	// the binlog file name format is `base + '.' + seq`.
    28  	binlogFilenameSep = "."
    29  	// PosRelaySubDirSuffixSeparator is used to differ binlog position from multiple
    30  	// (switched) masters, we added a suffix which comes from relay log subdirectory
    31  	// into binlogPos.Name. And we also need support position with RelaySubDirSuffix
    32  	// should always > position without RelaySubDirSuffix, so we can continue from
    33  	// latter to former automatically. convertedPos.BinlogName =
    34  	//   originalPos.BinlogBaseName + PosRelaySubDirSuffixSeparator + RelaySubDirSuffix + binlogFilenameSep + originalPos.BinlogSeq
    35  	// eg. mysql-bin.000003 under folder c6ae5afe-c7a3-11e8-a19d-0242ac130006.000002 => mysql-bin|000002.000003
    36  	// when new relay log subdirectory is created, RelaySubDirSuffix should increase.
    37  	PosRelaySubDirSuffixSeparator = "|"
    38  )
    39  
    40  // Filename represents a binlog filename.
    41  type Filename struct {
    42  	BaseName string
    43  	Seq      string
    44  	SeqInt64 int64
    45  }
    46  
    47  // LessThan checks whether this filename < other filename.
    48  func (f Filename) LessThan(other Filename) bool {
    49  	return f.BaseName == other.BaseName && f.SeqInt64 < other.SeqInt64
    50  }
    51  
    52  // GreaterThanOrEqualTo checks whether this filename >= other filename.
    53  func (f Filename) GreaterThanOrEqualTo(other Filename) bool {
    54  	return f.BaseName == other.BaseName && f.SeqInt64 >= other.SeqInt64
    55  }
    56  
    57  // GreaterThan checks whether this filename > other filename.
    58  func (f Filename) GreaterThan(other Filename) bool {
    59  	return f.BaseName == other.BaseName && f.SeqInt64 > other.SeqInt64
    60  }
    61  
    62  // ParseFilename parses a string representation binlog filename into a `Filename`.
    63  func ParseFilename(filename string) (Filename, error) {
    64  	var fn Filename
    65  	parts := strings.Split(filename, binlogFilenameSep)
    66  	if len(parts) != 2 {
    67  		return fn, terror.Annotatef(terror.ErrBinlogInvalidFilename.Generate(), "filename %s", filename)
    68  	}
    69  
    70  	var (
    71  		seqInt64 int64
    72  		err      error
    73  	)
    74  	if seqInt64, err = strconv.ParseInt(parts[1], 10, 64); err != nil || seqInt64 <= 0 {
    75  		return fn, terror.Annotatef(terror.ErrBinlogInvalidFilename.Generate(), "filename %s", filename)
    76  	}
    77  	fn.BaseName = parts[0]
    78  	fn.Seq = parts[1]
    79  	fn.SeqInt64 = seqInt64
    80  	return fn, nil
    81  }
    82  
    83  // VerifyFilename verifies whether is a valid MySQL/MariaDB binlog filename.
    84  // valid format is `base + '.' + seq`.
    85  func VerifyFilename(filename string) bool {
    86  	if _, err := ParseFilename(filename); err != nil {
    87  		return false
    88  	}
    89  	return true
    90  }
    91  
    92  // GetFilenameIndex returns a int64 index value (seq number) of the filename.
    93  func GetFilenameIndex(filename string) (int64, error) {
    94  	fn, err := ParseFilename(filename)
    95  	if err != nil {
    96  		return 0, err
    97  	}
    98  	return fn.SeqInt64, nil
    99  }
   100  
   101  // ConstructFilename constructs a binlog filename from the basename and seq.
   102  func ConstructFilename(baseName, seq string) string {
   103  	return fmt.Sprintf("%s%s%s", baseName, binlogFilenameSep, seq)
   104  }
   105  
   106  // ConstructFilenameWithUUIDSuffix constructs a binlog filename with UUID suffix.
   107  func ConstructFilenameWithUUIDSuffix(originalName Filename, uuidSuffix string) string {
   108  	return fmt.Sprintf("%s%s%s%s%s", originalName.BaseName, PosRelaySubDirSuffixSeparator, uuidSuffix, binlogFilenameSep, originalName.Seq)
   109  }
   110  
   111  // SplitFilenameWithUUIDSuffix analyzes a binlog filename with UUID suffix.
   112  func SplitFilenameWithUUIDSuffix(filename string) (baseName, uuidSuffix, seq string, err error) {
   113  	items1 := strings.Split(filename, PosRelaySubDirSuffixSeparator)
   114  	if len(items1) != 2 {
   115  		return "", "", "", terror.ErrBinlogInvalidFilenameWithUUIDSuffix.Generate(filename)
   116  	}
   117  
   118  	baseName = items1[0]
   119  	items2 := strings.Split(items1[1], binlogFilenameSep)
   120  
   121  	if len(items2) != 2 {
   122  		return "", "", "", terror.ErrBinlogInvalidFilenameWithUUIDSuffix.Generate(filename)
   123  	}
   124  	uuidSuffix = items2[0]
   125  	seq = items2[1]
   126  	return baseName, uuidSuffix, seq, nil
   127  }
   128  
   129  // ExtractRealName removes relay log uuid suffix if it exists and returns real binlog name.
   130  func ExtractRealName(name string) string {
   131  	if !strings.Contains(name, PosRelaySubDirSuffixSeparator) {
   132  		return name
   133  	}
   134  	baseName, _, seq, err := SplitFilenameWithUUIDSuffix(name)
   135  	if err != nil {
   136  		log.L().Error("failed to split binlog name with uuid suffix", zap.String("name", name), zap.Error(err))
   137  		// nolint:nilerr
   138  		return name
   139  	}
   140  	return ConstructFilename(baseName, seq)
   141  }