From 54924e1fee38e331cec9d6e00085dd791d28ff31 Mon Sep 17 00:00:00 2001 From: Rene Cannao Date: Mon, 23 Mar 2026 23:01:31 +0000 Subject: [PATCH] fix: MySQL 8.4+ replication compatibility (SHOW BINARY LOG STATUS, CHANGE REPLICATION SOURCE TO) Use version-aware SQL commands for replication setup and monitoring: - SHOW MASTER STATUS -> SHOW BINARY LOG STATUS (8.2+) - SHOW SLAVE STATUS -> SHOW REPLICA STATUS (8.0.22+) - CHANGE MASTER TO -> CHANGE REPLICATION SOURCE TO (8.0.23+) - START/STOP/RESET SLAVE -> START/STOP/RESET REPLICA (8.0.22+) - master_pos_wait() -> source_pos_wait() (8.0.22+) - GET_MASTER_PUBLIC_KEY -> GET_SOURCE_PUBLIC_KEY (8.0.23+) --- globals/globals.go | 3 + sandbox/multi-source-replication.go | 24 ++++++ sandbox/replication.go | 81 ++++++++++++++++++- .../replication/check_multi_source.gotxt | 4 +- .../templates/replication/check_slaves.gotxt | 4 +- .../templates/replication/init_slaves.gotxt | 4 +- .../templates/replication/multi_source.gotxt | 8 +- .../replication/test_replication.gotxt | 10 +-- 8 files changed, 121 insertions(+), 17 deletions(-) diff --git a/globals/globals.go b/globals/globals.go index 79f93a82..9ac017f0 100644 --- a/globals/globals.go +++ b/globals/globals.go @@ -416,6 +416,9 @@ var ( MinimumRootAuthVersion = NumericVersion{10, 4, 3} MinimumAdminAddressVersion = NumericVersion{8, 0, 14} MinimumMySQLShellEmbed = NumericVersion{8, 0, 4} + MinimumShowReplicaStatusVersion = NumericVersion{8, 0, 22} + MinimumChangeReplicationSourceVersion = NumericVersion{8, 0, 23} + MinimumShowBinaryLogStatusVersion = NumericVersion{8, 2, 0} ) const ( diff --git a/sandbox/multi-source-replication.go b/sandbox/multi-source-replication.go index 526e862f..e1bfc9b2 100644 --- a/sandbox/multi-source-replication.go +++ b/sandbox/multi-source-replication.go @@ -182,6 +182,18 @@ func CreateAllMastersReplication(sandboxDef SandboxDef, origin string, nodes int data["RplPassword"] = sandboxDef.RplPassword data["NodeLabel"] = defaults.Defaults().NodePrefix data["ChangeMasterExtra"] = setChangeMasterProperties("", sandboxDef.ChangeMasterOptions, logger) + replCmds := replicationCommands(sandboxDef.Version) + data["ShowMasterStatus"] = replCmds["ShowMasterStatus"] + data["ShowSlaveStatus"] = replCmds["ShowSlaveStatus"] + data["ChangeMasterTo"] = replCmds["ChangeMasterTo"] + data["StartReplica"] = replCmds["StartReplica"] + data["StopReplica"] = replCmds["StopReplica"] + data["ResetReplica"] = replCmds["ResetReplica"] + data["MasterPosWaitFunc"] = replCmds["MasterPosWaitFunc"] + data["MasterHostParam"] = replCmds["MasterHostParam"] + data["MasterPortParam"] = replCmds["MasterPortParam"] + data["MasterUserParam"] = replCmds["MasterUserParam"] + data["MasterPasswordParam"] = replCmds["MasterPasswordParam"] logger.Printf("Writing master and slave scripts in %s\n", sandboxDef.SandboxDir) for _, node := range slaveList { data["Node"] = node @@ -407,6 +419,18 @@ func CreateFanInReplication(sandboxDef SandboxDef, origin string, nodes int, mas data["NodeLabel"] = defaults.Defaults().NodePrefix data["ChangeMasterExtra"] = setChangeMasterProperties("", sandboxDef.ChangeMasterOptions, logger) data["MasterIp"] = masterIp + replCmds := replicationCommands(sandboxDef.Version) + data["ShowMasterStatus"] = replCmds["ShowMasterStatus"] + data["ShowSlaveStatus"] = replCmds["ShowSlaveStatus"] + data["ChangeMasterTo"] = replCmds["ChangeMasterTo"] + data["StartReplica"] = replCmds["StartReplica"] + data["StopReplica"] = replCmds["StopReplica"] + data["ResetReplica"] = replCmds["ResetReplica"] + data["MasterPosWaitFunc"] = replCmds["MasterPosWaitFunc"] + data["MasterHostParam"] = replCmds["MasterHostParam"] + data["MasterPortParam"] = replCmds["MasterPortParam"] + data["MasterUserParam"] = replCmds["MasterUserParam"] + data["MasterPasswordParam"] = replCmds["MasterPasswordParam"] logger.Printf("Writing master and slave scripts in %s\n", sandboxDef.SandboxDir) for _, slave := range slist { data["Node"] = slave diff --git a/sandbox/replication.go b/sandbox/replication.go index 694335f8..ed62e9f7 100644 --- a/sandbox/replication.go +++ b/sandbox/replication.go @@ -29,6 +29,47 @@ import ( "github.com/pkg/errors" ) +func replicationCommands(version string) map[string]string { + cmds := map[string]string{ + "ShowMasterStatus": "show master status", + "ShowSlaveStatus": "show slave status", + "ChangeMasterTo": "CHANGE MASTER TO", + "StartReplica": "START SLAVE", + "StopReplica": "STOP SLAVE", + "ResetReplica": "RESET SLAVE", + "MasterPosWaitFunc": "master_pos_wait", + "MasterHostParam": "master_host", + "MasterPortParam": "master_port", + "MasterUserParam": "master_user", + "MasterPasswordParam": "master_password", + } + + useReplicaStatus, _ := common.GreaterOrEqualVersion(version, globals.MinimumShowReplicaStatusVersion) + if useReplicaStatus { + cmds["ShowSlaveStatus"] = "show replica status" + cmds["StartReplica"] = "START REPLICA" + cmds["StopReplica"] = "STOP REPLICA" + cmds["ResetReplica"] = "RESET REPLICA" + cmds["MasterPosWaitFunc"] = "source_pos_wait" + } + + useChangeSource, _ := common.GreaterOrEqualVersion(version, globals.MinimumChangeReplicationSourceVersion) + if useChangeSource { + cmds["ChangeMasterTo"] = "CHANGE REPLICATION SOURCE TO" + cmds["MasterHostParam"] = "source_host" + cmds["MasterPortParam"] = "source_port" + cmds["MasterUserParam"] = "source_user" + cmds["MasterPasswordParam"] = "source_password" + } + + useBinaryLogStatus, _ := common.GreaterOrEqualVersion(version, globals.MinimumShowBinaryLogStatusVersion) + if useBinaryLogStatus { + cmds["ShowMasterStatus"] = "show binary log status" + } + + return cmds +} + type Slave struct { Node int Port int @@ -188,7 +229,12 @@ func CreateMasterSlaveReplication(sandboxDef SandboxDef, origin string, nodes in } if isMinimumNativeAuthPlugin { if !sandboxDef.NativeAuthPlugin { - sandboxDef.ChangeMasterOptions = append(sandboxDef.ChangeMasterOptions, "GET_MASTER_PUBLIC_KEY=1") + useNewSourceSyntax, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumChangeReplicationSourceVersion) + if useNewSourceSyntax { + sandboxDef.ChangeMasterOptions = append(sandboxDef.ChangeMasterOptions, "GET_SOURCE_PUBLIC_KEY=1") + } else { + sandboxDef.ChangeMasterOptions = append(sandboxDef.ChangeMasterOptions, "GET_MASTER_PUBLIC_KEY=1") + } } } slaves := nodes - 1 @@ -199,6 +245,7 @@ func CreateMasterSlaveReplication(sandboxDef SandboxDef, origin string, nodes in timestamp := time.Now() changeMasterExtra = setChangeMasterProperties(changeMasterExtra, sandboxDef.ChangeMasterOptions, logger) + replCmds := replicationCommands(sandboxDef.Version) var data = common.StringMap{ "ShellPath": sandboxDef.ShellPath, "Copyright": globals.ShellScriptCopyright, @@ -216,6 +263,17 @@ func CreateMasterSlaveReplication(sandboxDef SandboxDef, origin string, nodes in "ChangeMasterExtra": changeMasterExtra, "MasterAutoPosition": masterAutoPosition, "Slaves": []common.StringMap{}, + "ShowMasterStatus": replCmds["ShowMasterStatus"], + "ShowSlaveStatus": replCmds["ShowSlaveStatus"], + "ChangeMasterTo": replCmds["ChangeMasterTo"], + "StartReplica": replCmds["StartReplica"], + "StopReplica": replCmds["StopReplica"], + "ResetReplica": replCmds["ResetReplica"], + "MasterPosWaitFunc": replCmds["MasterPosWaitFunc"], + "MasterHostParam": replCmds["MasterHostParam"], + "MasterPortParam": replCmds["MasterPortParam"], + "MasterUserParam": replCmds["MasterUserParam"], + "MasterPasswordParam": replCmds["MasterPasswordParam"], } logger.Printf("Defining replication data: %v\n", stringMapToJson(data)) @@ -308,7 +366,17 @@ func CreateMasterSlaveReplication(sandboxDef SandboxDef, origin string, nodes in "ChangeMasterExtra": changeMasterExtra, "MasterAutoPosition": masterAutoPosition, "RplUser": sandboxDef.RplUser, - "RplPassword": sandboxDef.RplPassword}) + "RplPassword": sandboxDef.RplPassword, + "ChangeMasterTo": replCmds["ChangeMasterTo"], + "StartReplica": replCmds["StartReplica"], + "ShowSlaveStatus": replCmds["ShowSlaveStatus"], + "ShowMasterStatus": replCmds["ShowMasterStatus"], + "MasterHostParam": replCmds["MasterHostParam"], + "MasterPortParam": replCmds["MasterPortParam"], + "MasterUserParam": replCmds["MasterUserParam"], + "MasterPasswordParam": replCmds["MasterPasswordParam"], + "MasterPosWaitFunc": replCmds["MasterPosWaitFunc"], + }) sandboxDef.LoadGrants = false sandboxDef.Prompt = fmt.Sprintf("%s%d", slaveLabel, i) sandboxDef.DirName = fmt.Sprintf("%s%d", nodeLabel, i) @@ -369,6 +437,15 @@ func CreateMasterSlaveReplication(sandboxDef SandboxDef, origin string, nodes in "MasterAutoPosition": masterAutoPosition, "SlaveAbbr": slaveAbbr, "SandboxDir": sandboxDef.SandboxDir, + "ChangeMasterTo": replCmds["ChangeMasterTo"], + "StartReplica": replCmds["StartReplica"], + "ShowSlaveStatus": replCmds["ShowSlaveStatus"], + "ShowMasterStatus": replCmds["ShowMasterStatus"], + "MasterHostParam": replCmds["MasterHostParam"], + "MasterPortParam": replCmds["MasterPortParam"], + "MasterUserParam": replCmds["MasterUserParam"], + "MasterPasswordParam": replCmds["MasterPasswordParam"], + "MasterPosWaitFunc": replCmds["MasterPosWaitFunc"], } logger.Printf("Defining replication node data: %v\n", stringMapToJson(dataSlave)) logger.Printf("Create slave script %d\n", i) diff --git a/sandbox/templates/replication/check_multi_source.gotxt b/sandbox/templates/replication/check_multi_source.gotxt index 3634b4f4..d69880d9 100644 --- a/sandbox/templates/replication/check_multi_source.gotxt +++ b/sandbox/templates/replication/check_multi_source.gotxt @@ -12,7 +12,7 @@ do port=$($SBDIR/{{.NodeLabel}}$M/use -BN -e "show variables like 'port'") server_id=$($SBDIR/{{.NodeLabel}}$M/use -BN -e "show variables like 'server_id'") echo "$port - $server_id" - $SBDIR/{{.NodeLabel}}$M/use -e 'show master status\G' | grep "File\|Position\|Executed" + $SBDIR/{{.NodeLabel}}$M/use -e '{{.ShowMasterStatus}}\G' | grep "File\|Position\|Executed" done for S in $SLAVES do @@ -20,5 +20,5 @@ do port=$($SBDIR/{{.NodeLabel}}$S/use -BN -e "show variables like 'port'") server_id=$($SBDIR/{{.NodeLabel}}$S/use -BN -e "show variables like 'server_id'") echo "$port - $server_id" - $SBDIR/{{.NodeLabel}}$S/use -e 'show slave status\G' | grep "\(Running:\|Master_Log_Pos\|\ $master_status +$MASTER -e '{{.ShowMasterStatus}}\G' > $master_status master_binlog=$(grep 'File:' $master_status | awk '{print $2}' ) master_pos=$(grep 'Position:' $master_status | awk '{print $2}' ) echo "# {{.MasterLabel}} log: $master_binlog - Position: $master_pos - Rows: $MASTER_RECS" @@ -98,7 +98,7 @@ do then sleep 3 else - S_READY=$($SLAVE -BN -e "select master_pos_wait('$master_binlog', $master_pos,60)") + S_READY=$($SLAVE -BN -e "select {{.MasterPosWaitFunc}}('$master_binlog', $master_pos,60)") # master_pos_wait can return 0 or a positive number for successful replication # Any result that is not NULL or -1 is acceptable if [ "$S_READY" != "-1" -a "$S_READY" != "NULL" ] @@ -109,10 +109,10 @@ do fi if [ -f initialize_{{.SlaveLabel}}s ] then - $SLAVE -e 'show slave status\G' > $slave_status - IO_RUNNING=$(grep -w Slave_IO_Running $slave_status | awk '{print $2}') + $SLAVE -e '{{.ShowSlaveStatus}}\G' > $slave_status + IO_RUNNING=$(grep -E -w "Slave_IO_Running|Replica_IO_Running" $slave_status | awk '{print $2}') ok_equal $IO_RUNNING Yes "{{.SlaveLabel}} #$SLAVE_N IO thread is running" - SQL_RUNNING=$(grep -w Slave_IO_Running $slave_status | awk '{print $2}') + SQL_RUNNING=$(grep -E -w "Slave_SQL_Running|Replica_SQL_Running" $slave_status | awk '{print $2}') ok_equal $SQL_RUNNING Yes "{{.SlaveLabel}} #$SLAVE_N SQL thread is running" rm -f $slave_status fi