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

     1  // Copyright 2021 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 checker
    15  
    16  import (
    17  	"context"
    18  	"database/sql"
    19  	"fmt"
    20  
    21  	toolsutils "github.com/pingcap/tidb-tools/pkg/utils"
    22  	"github.com/pingcap/tidb/pkg/util/dbutil"
    23  	"github.com/pingcap/tiflow/dm/pkg/conn"
    24  )
    25  
    26  // MySQLVersionChecker checks mysql/mariadb/rds,... version.
    27  type MySQLVersionChecker struct {
    28  	db     *sql.DB
    29  	dbinfo *dbutil.DBConfig
    30  }
    31  
    32  // NewMySQLVersionChecker returns a RealChecker.
    33  func NewMySQLVersionChecker(db *sql.DB, dbinfo *dbutil.DBConfig) RealChecker {
    34  	return &MySQLVersionChecker{db: db, dbinfo: dbinfo}
    35  }
    36  
    37  // SupportedVersion defines the MySQL/MariaDB version that DM/syncer supports
    38  // * 5.6.0 <= MySQL Version < 8.1.0.
    39  var SupportedVersion = map[string]struct {
    40  	Min MySQLVersion
    41  	Max MySQLVersion
    42  }{
    43  	"mysql": {
    44  		MySQLVersion{5, 6, 0},
    45  		MySQLVersion{8, 1, 0},
    46  	},
    47  }
    48  
    49  // Check implements the RealChecker interface.
    50  // we only support version >= 5.6.
    51  func (pc *MySQLVersionChecker) Check(ctx context.Context) *Result {
    52  	result := &Result{
    53  		Name:  pc.Name(),
    54  		Desc:  "check whether mysql version is satisfied",
    55  		State: StateWarning,
    56  		Extra: fmt.Sprintf("address of db instance - %s:%d", pc.dbinfo.Host, pc.dbinfo.Port),
    57  	}
    58  
    59  	value, err := dbutil.ShowVersion(ctx, pc.db)
    60  	if err != nil {
    61  		markCheckError(result, err)
    62  		return result
    63  	}
    64  
    65  	err2 := pc.checkVersion(value, result)
    66  	if err2 != nil {
    67  		result.Instruction = err2.Instruction
    68  		err2.Instruction = ""
    69  		result.Errors = append(result.Errors, err2)
    70  	}
    71  	return result
    72  }
    73  
    74  func (pc *MySQLVersionChecker) checkVersion(value string, result *Result) *Error {
    75  	needVersion := SupportedVersion["mysql"]
    76  	if conn.IsMariaDB(value) {
    77  		err := NewWarn("Migrating from MariaDB is still experimental.")
    78  		err.Instruction = "It is recommended that you upgrade MariaDB to 10.1.2 or a later version."
    79  		return err
    80  	}
    81  	if IsTiDBFromVersion(value) {
    82  		err := NewWarn("migration from TiDB not supported")
    83  		err.Instruction = "TiDB is not supported as an upstream database."
    84  		return err
    85  	}
    86  
    87  	version, err := toMySQLVersion(value)
    88  	if err != nil {
    89  		markCheckError(result, err)
    90  		return nil
    91  	}
    92  
    93  	if !version.Ge(needVersion.Min) {
    94  		err := NewWarn("version suggested at least %v but got %v", needVersion.Min, version)
    95  		err.Instruction = "It is recommended that you upgrade the database to the required version before performing data migration. Otherwise data inconsistency or task exceptions might occur."
    96  		return err
    97  	}
    98  
    99  	if !version.Lt(needVersion.Max) {
   100  		err := NewWarn("version suggested earlier than %v but got %v", needVersion.Max, version)
   101  		err.Instruction = "It is recommended that you select a database version that meets the requirements before performing data migration. Otherwise data inconsistency or task exceptions might occur."
   102  		return err
   103  	}
   104  
   105  	result.State = StateSuccess
   106  	return nil
   107  }
   108  
   109  // Name implements the RealChecker interface.
   110  func (pc *MySQLVersionChecker) Name() string {
   111  	return "mysql_version"
   112  }
   113  
   114  /*****************************************************/
   115  
   116  // MySQLServerIDChecker checks mysql/mariadb server ID.
   117  type MySQLServerIDChecker struct {
   118  	db     *sql.DB
   119  	dbinfo *dbutil.DBConfig
   120  }
   121  
   122  // NewMySQLServerIDChecker returns a RealChecker.
   123  func NewMySQLServerIDChecker(db *sql.DB, dbinfo *dbutil.DBConfig) RealChecker {
   124  	return &MySQLServerIDChecker{db: db, dbinfo: dbinfo}
   125  }
   126  
   127  // Check implements the RealChecker interface.
   128  func (pc *MySQLServerIDChecker) Check(ctx context.Context) *Result {
   129  	result := &Result{
   130  		Name:  pc.Name(),
   131  		Desc:  "check whether mysql server_id has been greater than 0",
   132  		State: StateWarning,
   133  		Extra: fmt.Sprintf("address of db instance - %s:%d", pc.dbinfo.Host, pc.dbinfo.Port),
   134  	}
   135  
   136  	serverID, err := dbutil.ShowServerID(ctx, pc.db)
   137  	if err != nil {
   138  		if toolsutils.OriginError(err) != sql.ErrNoRows {
   139  			markCheckError(result, err)
   140  			return result
   141  		}
   142  		result.Errors = append(result.Errors, NewError("server_id not set"))
   143  		result.Instruction = "Set server_id in your database, or errors might happen in master/slave switchover"
   144  		return result
   145  	}
   146  
   147  	if serverID == 0 {
   148  		result.Errors = append(result.Errors, NewError("server_id is 0"))
   149  		result.Instruction = "Set server_id greater than 0, or errors might happen in master/slave switchover"
   150  		return result
   151  	}
   152  	result.State = StateSuccess
   153  	return result
   154  }
   155  
   156  // Name implements the RealChecker interface.
   157  func (pc *MySQLServerIDChecker) Name() string {
   158  	return "mysql_server_id"
   159  }