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 }