diff --git a/cmd/single.go b/cmd/single.go index d79ca79..3cff3f6 100644 --- a/cmd/single.go +++ b/cmd/single.go @@ -400,7 +400,13 @@ func fillSandboxDefinition(cmd *cobra.Command, args []string, usingImport bool) common.ErrCheckExitf(err, 1, globals.ErrWhileComparingVersions) if isMinimumGtid { sd.GtidOptions = sandbox.SingleTemplates[templateName].Contents - sd.ReplCrashSafeOptions = sandbox.SingleTemplates[globals.TmplReplCrashSafeOptions].Contents + // Use 8.4+ crash-safe options template (no deprecated master-info-repository) + crashSafeTmpl := globals.TmplReplCrashSafeOptions + isMySQL84, _ := common.GreaterOrEqualVersion(sd.Version, globals.MinimumResetBinaryLogsVersion) + if isMySQL84 { + crashSafeTmpl = globals.TmplReplCrashSafeOptions84 + } + sd.ReplCrashSafeOptions = sandbox.SingleTemplates[crashSafeTmpl].Contents sd.ReplOptions = sandbox.SingleTemplates[globals.TmplReplicationOptions].Contents if sd.ServerId == 0 { sd.PortAsServerId = true @@ -418,7 +424,13 @@ func fillSandboxDefinition(cmd *cobra.Command, args []string, usingImport bool) isMinimumCrashSafe, err := common.HasCapability(sd.Flavor, common.CrashSafe, sd.Version) common.ErrCheckExitf(err, 1, globals.ErrWhileComparingVersions) if isMinimumCrashSafe { - sd.ReplCrashSafeOptions = sandbox.SingleTemplates[globals.TmplReplCrashSafeOptions].Contents + // Use 8.4+ crash-safe options template (no deprecated master-info-repository) + crashSafeTmpl := globals.TmplReplCrashSafeOptions + isMySQL84, _ := common.GreaterOrEqualVersion(sd.Version, globals.MinimumResetBinaryLogsVersion) + if isMySQL84 { + crashSafeTmpl = globals.TmplReplCrashSafeOptions84 + } + sd.ReplCrashSafeOptions = sandbox.SingleTemplates[crashSafeTmpl].Contents } else { common.Exitf(1, globals.ErrOptionRequiresVersion, globals.ReplCrashSafeLabel, common.IntSliceToDottedString(globals.MinimumCrashSafeVersion)) } diff --git a/globals/template_names.go b/globals/template_names.go index 6212a27..d54d1a4 100644 --- a/globals/template_names.go +++ b/globals/template_names.go @@ -165,7 +165,13 @@ const ( TmplTidbMyCnf = "tidb_my_cnf" // group - TmplInitNodes = "init_nodes" - TmplCheckNodes = "check_nodes" - TmplGroupReplOptions = "group_repl_options" + TmplInitNodes = "init_nodes" + TmplCheckNodes = "check_nodes" + TmplGroupReplOptions = "group_repl_options" + TmplInitNodes84 = "init_nodes84" + TmplGroupReplOptions84 = "group_repl_options84" + + // MySQL 8.4+ specific templates + TmplInitSlaves84 = "init_slaves_84" + TmplReplCrashSafeOptions84 = "repl_crash_safe_options84" ) diff --git a/sandbox/group_replication.go b/sandbox/group_replication.go index 67c120d..52a0da8 100644 --- a/sandbox/group_replication.go +++ b/sandbox/group_replication.go @@ -288,6 +288,13 @@ func CreateGroupReplication(sandboxDef SandboxDef, origin string, nodes int, mas sbItem.LogDirectory = common.DirName(sandboxDef.LogFileName) } + // Select version-appropriate templates for group replication init + initNodesTmpl := globals.TmplInitNodes + isMySQL84, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumResetBinaryLogsVersion) + if isMySQL84 { + initNodesTmpl = globals.TmplInitNodes84 + } + for i := 1; i <= nodes; i++ { groupPort := baseGroupPort + i sandboxDef.Port = basePort + i @@ -338,18 +345,24 @@ func CreateGroupReplication(sandboxDef SandboxDef, origin string, nodes int, mas // Version-aware options for group replication useReplicaUpdates, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumShowReplicaStatusVersion) useNoWriteSetExtraction, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumNoWriteSetExtractionVersion) + // Use 8.4+ group replication options template when applicable + useMySQL84GroupOptions, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumResetBinaryLogsVersion) replicationData := common.StringMap{ - "BasePort": basePortText, - "GroupSeeds": connectionString, - "LocalAddresses": fmt.Sprintf("%s:%d", masterIp, groupPort), - "PrimaryMode": singlePrimaryMode, - "UseReplicaUpdates": useReplicaUpdates, - "SkipWriteSetExtraction": useNoWriteSetExtraction, + "BasePort": basePortText, + "GroupSeeds": connectionString, + "LocalAddresses": fmt.Sprintf("%s:%d", masterIp, groupPort), + "PrimaryMode": singlePrimaryMode, + "UseReplicaUpdates": useReplicaUpdates, + "SkipWriteSetExtraction": useNoWriteSetExtraction, } + groupReplOptionsTmpl := globals.TmplGroupReplOptions + if useMySQL84GroupOptions { + groupReplOptionsTmpl = globals.TmplGroupReplOptions84 + } replOptionsText, err := common.SafeTemplateFill("group_replication", - GroupTemplates[globals.TmplGroupReplOptions].Contents, replicationData) + GroupTemplates[groupReplOptionsTmpl].Contents, replicationData) if err != nil { return err } @@ -360,8 +373,10 @@ func CreateGroupReplication(sandboxDef SandboxDef, origin string, nodes int, mas sandboxDef.ReplOptions += fmt.Sprintf("\n%s\n", SingleTemplates[globals.TmplGtidOptions57].Contents) // master-info-repository and relay-log-info-repository removed in 8.4+ - skipCrashSafeOpts, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumResetBinaryLogsVersion) - if !skipCrashSafeOpts { + if useMySQL84GroupOptions { + // relay-log-recovery is still valid; use the 8.4-specific template + sandboxDef.ReplOptions += fmt.Sprintf("\n%s\n", SingleTemplates[globals.TmplReplCrashSafeOptions84].Contents) + } else { sandboxDef.ReplOptions += fmt.Sprintf("\n%s\n", SingleTemplates[globals.TmplReplCrashSafeOptions].Contents) } @@ -487,7 +502,7 @@ func CreateGroupReplication(sandboxDef SandboxDef, origin string, nodes int, mas data: data, sandboxDir: sandboxDef.SandboxDir, scripts: []ScriptDef{ - {globals.ScriptInitializeNodes, globals.TmplInitNodes, true}, + {globals.ScriptInitializeNodes, initNodesTmpl, true}, {globals.ScriptCheckNodes, globals.TmplCheckNodes, true}, }, } diff --git a/sandbox/group_templates.go b/sandbox/group_templates.go index 3c1775b..f77e6ce 100644 --- a/sandbox/group_templates.go +++ b/sandbox/group_templates.go @@ -30,18 +30,29 @@ var ( //go:embed templates/group/init_nodes.gotxt initNodesTemplate string + //go:embed templates/group/init_nodes84.gotxt + initNodes84Template string + //go:embed templates/group/check_nodes.gotxt checkNodesTemplate string //go:embed templates/group/group_repl_options.gotxt groupReplOptionsTemplate string + //go:embed templates/group/group_repl_options84.gotxt + groupReplOptions84Template string + GroupTemplates = TemplateCollection{ globals.TmplInitNodes: TemplateDesc{ Description: "Initialize group replication after deployment", Notes: "", Contents: initNodesTemplate, }, + globals.TmplInitNodes84: TemplateDesc{ + Description: "Initialize group replication after deployment (MySQL 8.4+ syntax)", + Notes: "Uses CHANGE REPLICATION SOURCE TO syntax", + Contents: initNodes84Template, + }, globals.TmplCheckNodes: TemplateDesc{ Description: "Checks the status of group replication", Notes: "", @@ -52,5 +63,10 @@ var ( Notes: "", Contents: groupReplOptionsTemplate, }, + globals.TmplGroupReplOptions84: TemplateDesc{ + Description: "replication options for Group replication node (MySQL 8.4+)", + Notes: "Excludes transaction_write_set_extraction removed in 8.4", + Contents: groupReplOptions84Template, + }, } ) diff --git a/sandbox/multi-source-replication.go b/sandbox/multi-source-replication.go index ddd7dde..c598e74 100644 --- a/sandbox/multi-source-replication.go +++ b/sandbox/multi-source-replication.go @@ -113,8 +113,11 @@ func CreateAllMastersReplication(sandboxDef SandboxDef, origin string, nodes int } sandboxDef.GtidOptions = SingleTemplates[globals.TmplGtidOptions57].Contents - skipCrashSafeOpts, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumResetBinaryLogsVersion) - if !skipCrashSafeOpts { + isMySQL84allMasters, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumResetBinaryLogsVersion) + if isMySQL84allMasters { + // relay-log-recovery is still valid; use 8.4-specific template (no deprecated master-info-repository) + sandboxDef.ReplCrashSafeOptions = SingleTemplates[globals.TmplReplCrashSafeOptions84].Contents + } else { sandboxDef.ReplCrashSafeOptions = SingleTemplates[globals.TmplReplCrashSafeOptions].Contents } if sandboxDef.DirName == "" { @@ -325,8 +328,11 @@ func CreateFanInReplication(sandboxDef SandboxDef, origin string, nodes int, mas slaveList = globals.SlaveListValue } sandboxDef.GtidOptions = SingleTemplates[globals.TmplGtidOptions57].Contents - skipCrashSafe2, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumResetBinaryLogsVersion) - if !skipCrashSafe2 { + isMySQL84fanIn, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumResetBinaryLogsVersion) + if isMySQL84fanIn { + // relay-log-recovery is still valid; use 8.4-specific template (no deprecated master-info-repository) + sandboxDef.ReplCrashSafeOptions = SingleTemplates[globals.TmplReplCrashSafeOptions84].Contents + } else { sandboxDef.ReplCrashSafeOptions = SingleTemplates[globals.TmplReplCrashSafeOptions].Contents } if sandboxDef.DirName == "" { diff --git a/sandbox/pxc_replication.go b/sandbox/pxc_replication.go index 24c5646..e949dd5 100644 --- a/sandbox/pxc_replication.go +++ b/sandbox/pxc_replication.go @@ -328,8 +328,11 @@ func CreatePxcReplication(sandboxDef SandboxDef, origin string, nodes int, maste sandboxDef.ReplOptions += fmt.Sprintf("\n%s\n", SingleTemplates[globals.TmplGtidOptions57].Contents) // master-info-repository and relay-log-info-repository removed in 8.4+ - skipCrashSafeOpts, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumResetBinaryLogsVersion) - if !skipCrashSafeOpts { + isMySQL84pxc, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumResetBinaryLogsVersion) + if isMySQL84pxc { + // relay-log-recovery is still valid; use 8.4-specific template (no deprecated master-info-repository) + sandboxDef.ReplOptions += fmt.Sprintf("\n%s\n", SingleTemplates[globals.TmplReplCrashSafeOptions84].Contents) + } else { sandboxDef.ReplOptions += fmt.Sprintf("\n%s\n", SingleTemplates[globals.TmplReplCrashSafeOptions].Contents) } // 8.0.11 diff --git a/sandbox/repl_templates.go b/sandbox/repl_templates.go index 93f71eb..8611c3e 100644 --- a/sandbox/repl_templates.go +++ b/sandbox/repl_templates.go @@ -30,6 +30,9 @@ var ( //go:embed templates/replication/init_slaves.gotxt initSlavesTemplate string + //go:embed templates/replication/init_slaves_84.gotxt + initSlaves84Template string + //go:embed templates/replication/semi_sync_start.gotxt semiSyncStartTemplate string @@ -135,6 +138,11 @@ var ( Notes: "Can also be run after calling './clear_all'", Contents: initSlavesTemplate, }, + globals.TmplInitSlaves84: TemplateDesc{ + Description: "Initialize slaves after deployment (MySQL 8.4+ syntax)", + Notes: "Uses CHANGE REPLICATION SOURCE TO and SOURCE_AUTO_POSITION", + Contents: initSlaves84Template, + }, globals.TmplSemiSyncStart: TemplateDesc{ Description: "Starts semi synch replication ", Notes: "", diff --git a/sandbox/replication.go b/sandbox/replication.go index 5c6d7a6..b43e3f4 100644 --- a/sandbox/replication.go +++ b/sandbox/replication.go @@ -224,8 +224,14 @@ func CreateMasterSlaveReplication(sandboxDef SandboxDef, origin string, nodes in changeMasterExtra := "" masterAutoPosition := "" if sandboxDef.GtidOptions != "" { - masterAutoPosition += ", MASTER_AUTO_POSITION=1" - logger.Printf("Adding MASTER_AUTO_POSITION to slaves setup\n") + useSourceAutoPosition, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumChangeReplicationSourceVersion) + if useSourceAutoPosition { + masterAutoPosition = ", SOURCE_AUTO_POSITION=1" + logger.Printf("Adding SOURCE_AUTO_POSITION to slaves setup\n") + } else { + masterAutoPosition = ", MASTER_AUTO_POSITION=1" + logger.Printf("Adding MASTER_AUTO_POSITION to slaves setup\n") + } } // 8.0.11 // isMinimumNativeAuthPlugin, err := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumNativeAuthPluginVersion) @@ -497,6 +503,13 @@ func CreateMasterSlaveReplication(sandboxDef SandboxDef, origin string, nodes in execAllSlaves := "exec_all_" + slavePlural execAllMasters := "exec_all_" + masterPlural + // Select the appropriate init_slaves template based on MySQL version + initSlavesTemplate := globals.TmplInitSlaves + useNewSourceSyntax, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumChangeReplicationSourceVersion) + if useNewSourceSyntax { + initSlavesTemplate = globals.TmplInitSlaves84 + } + sb := ScriptBatch{ tc: ReplicationTemplates, logger: logger, @@ -515,7 +528,7 @@ func CreateMasterSlaveReplication(sandboxDef SandboxDef, origin string, nodes in {globals.ScriptMetadataAll, globals.TmplMetadataAll, true}, {useAllSlaves, globals.TmplUseAllSlaves, true}, {useAllMasters, globals.TmplUseAllMasters, true}, - {initializeSlaves, globals.TmplInitSlaves, true}, + {initializeSlaves, initSlavesTemplate, true}, {checkSlaves, globals.TmplCheckSlaves, true}, {masterAbbr, globals.TmplMaster, true}, {execAllSlaves, globals.TmplExecAllSlaves, true}, diff --git a/sandbox/templates.go b/sandbox/templates.go index 2795d9a..6f70b24 100644 --- a/sandbox/templates.go +++ b/sandbox/templates.go @@ -128,6 +128,9 @@ var ( //go:embed templates/single/repl_crash_safe_options.gotxt replCrashSafeOptions string + //go:embed templates/single/repl_crash_safe_options84.gotxt + replCrashSafeOptions84 string + //go:embed templates/single/gtid_options_56.gotxt gtidOptions56 string @@ -218,6 +221,11 @@ var ( Notes: "", Contents: replCrashSafeOptions, }, + globals.TmplReplCrashSafeOptions84: TemplateDesc{ + Description: "Replication crash safe options for MySQL 8.4+", + Notes: "Excludes master-info-repository and relay-log-info-repository removed in 8.4", + Contents: replCrashSafeOptions84, + }, globals.TmplExposeDdTables: TemplateDesc{ Description: "Commands needed to enable data dictionary table usage", Notes: "", diff --git a/sandbox/templates/group/group_repl_options84.gotxt b/sandbox/templates/group/group_repl_options84.gotxt new file mode 100644 index 0000000..695703f --- /dev/null +++ b/sandbox/templates/group/group_repl_options84.gotxt @@ -0,0 +1,14 @@ + +# After customization, these options are added to my.sandbox.cnf +# MySQL 8.4+ group replication options (transaction_write_set_extraction removed) +binlog_checksum=NONE +log_replica_updates=ON +plugin-load-add=group_replication.so +group_replication=FORCE_PLUS_PERMANENT +group_replication_start_on_boot=OFF +group_replication_bootstrap_group=OFF +report-host=127.0.0.1 +loose-group_replication_group_name="{{.BasePort}}-bbbb-cccc-dddd-eeeeeeeeeeee" +loose-group-replication-local-address={{.LocalAddresses}} +loose-group-replication-group-seeds={{.GroupSeeds}} +loose-group-replication-single-primary-mode={{.PrimaryMode}} diff --git a/sandbox/templates/group/init_nodes84.gotxt b/sandbox/templates/group/init_nodes84.gotxt new file mode 100644 index 0000000..0282b54 --- /dev/null +++ b/sandbox/templates/group/init_nodes84.gotxt @@ -0,0 +1,31 @@ +#!{{.ShellPath}} +{{.Copyright}} +# Generated by dbdeployer {{.AppVersion}} using {{.TemplateName}} on {{.DateTime}} +# Uses MySQL 8.4+ replication syntax (CHANGE REPLICATION SOURCE TO) +multi_sb={{.SandboxDir}} +# workaround for Bug#89959 +{{range .Nodes}} +{{.SandboxDir}}/{{.NodeLabel}}{{.Node}}/use -h {{.MasterIp}} -u {{.RplUser}} -p{{.RplPassword}} -e 'set @a=1' +{{end}} +[ -z "$SLEEP_TIME" ] && SLEEP_TIME=1 +{{range .Nodes}} + user_cmd='{{.ResetMasterCmd}};' + user_cmd="$user_cmd {{.ChangeMasterTo}} {{.MasterUserParam}}='rsandbox', {{.MasterPasswordParam}}='rsandbox' {{.ChangeMasterExtra}} FOR CHANNEL 'group_replication_recovery';" + echo "# Node {{.Node}} # $user_cmd" + $multi_sb/{{.NodeLabel}}{{.Node}}/use -u root -e "$user_cmd" +{{end}} +echo "" + +BEFORE_START_CMD="SET GLOBAL group_replication_bootstrap_group=ON;" +START_CMD="START GROUP_REPLICATION;" +AFTER_START_CMD="SET GLOBAL group_replication_bootstrap_group=OFF;" +echo "# Node 1 # $BEFORE_START_CMD" +$multi_sb/n1 -e "$BEFORE_START_CMD" +{{ range .Nodes}} + echo "# Node {{.Node}} # $START_CMD" + $multi_sb/n{{.Node}} -e "$START_CMD" + sleep $SLEEP_TIME +{{end}} +echo "# Node 1 # $AFTER_START_CMD" +$multi_sb/n1 -e "$AFTER_START_CMD" +$multi_sb/check_nodes diff --git a/sandbox/templates/replication/init_slaves_84.gotxt b/sandbox/templates/replication/init_slaves_84.gotxt new file mode 100644 index 0000000..0e6ce75 --- /dev/null +++ b/sandbox/templates/replication/init_slaves_84.gotxt @@ -0,0 +1,32 @@ +#!{{.ShellPath}} +{{.Copyright}} +# Generated by dbdeployer {{.AppVersion}} using {{.TemplateName}} on {{.DateTime}} + +# Don't use directly. +# This script is called by 'start_all' when needed +# Uses MySQL 8.4+ replication syntax (CHANGE REPLICATION SOURCE TO) +SBDIR={{.SandboxDir}} +cd "$SBDIR" +# workaround for Bug#89959 +$SBDIR/{{.MasterLabel}}/use -h {{.MasterIp}} -u {{.RplUser}} -p{{.RplPassword}} -e 'set @a=1' +if [ ! -f needs_initialization ] +then + # First run: root is running without password + export NOPASSWORD=1 +fi + +{{ range .Slaves }} +echo "initializing {{.SlaveLabel}} {{.Node}}" +echo '{{.ChangeMasterTo}} {{.MasterHostParam}}="{{.MasterIp}}", {{.MasterPortParam}}={{.MasterPort}}, {{.MasterUserParam}}="{{.RplUser}}", {{.MasterPasswordParam}}="{{.RplPassword}}" {{.MasterAutoPosition}} {{.ChangeMasterExtra}}' | $SBDIR/{{.NodeLabel}}{{.Node}}/use -u root +$SBDIR/{{.NodeLabel}}{{.Node}}/use -u root -e '{{.StartReplica}}' +{{end}} +if [ -x ./post_initialization ] +then + unset NOPASSWORD + ./post_initialization > post_initialization.log 2>&1 + exit_code=$? + if [ "$exit_code" == "0" ] + then +rm -f ./post_initialization + fi +fi diff --git a/sandbox/templates/single/repl_crash_safe_options84.gotxt b/sandbox/templates/single/repl_crash_safe_options84.gotxt new file mode 100644 index 0000000..fade40e --- /dev/null +++ b/sandbox/templates/single/repl_crash_safe_options84.gotxt @@ -0,0 +1,4 @@ + +# replication crash-safe options for MySQL 8.4+ +# master-info-repository and relay-log-info-repository are removed in 8.4 +relay-log-recovery=on