Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions cookbook/templates/replication-operations.gotxt
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,21 @@ fi

sandbox_dir=$SANDBOX_HOME/rsandbox_$(echo $version | tr '.' '_' )

# Version-aware SQL commands
sortable_version=$(echo "$version" | awk -F. '{printf "%03d%03d%03d", $1, $2, $3}')
minimum_version_binary_log="008002000"
minimum_version_replica="008000022"

show_master_cmd="SHOW MASTER STATUS"
if [[ "v$sortable_version" > "v$minimum_version_binary_log" ]] || [[ "v$sortable_version" == "v$minimum_version_binary_log" ]]; then
show_master_cmd="SHOW BINARY LOG STATUS"
fi

header "Running a simple command with the master in the sandbox." \
"Notice the usage of the '-e', as if we were using the 'mysql' client"
"Notice the usage of the '-e', as if we were using the 'mysql' client"

(set -x
$sandbox_dir/m -e 'SHOW MASTER STATUS'
$sandbox_dir/m -e "$show_master_cmd"
Comment on lines 33 to +34
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sortable_version is computed inside the first ( ... ) subshell, so it won’t be available in the later subshell at lines 61-65. That makes the if [[ "v$sortable_version" ... ]] check effectively compare an empty value and will pick the wrong branch on newer MySQL versions. Move the sortable_version=... computation outside the subshells (once, near the top) so it can be reused reliably.

Copilot uses AI. Check for mistakes.
)

header "Creating a table in the master"
Expand Down Expand Up @@ -54,7 +64,12 @@ header "Checking the status of all slaves"
run $sandbox_dir/check_slaves

header "Running a multiple query in all slaves"
(set -x
$sandbox_dir/use_all_slaves "STOP SLAVE; SET GLOBAL slave_parallel_workers=3; START SLAVE;show processlist "
)

if [[ "v$sortable_version" > "v$minimum_version_replica" ]] || [[ "v$sortable_version" == "v$minimum_version_replica" ]]; then
(set -x
$sandbox_dir/use_all_slaves "STOP REPLICA; SET GLOBAL replica_parallel_workers=3; START REPLICA;show processlist "
)
else
(set -x
$sandbox_dir/use_all_slaves "STOP SLAVE; SET GLOBAL slave_parallel_workers=3; START SLAVE;show processlist "
)
Comment on lines +67 to +74
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

fd -t f "replication-operations.gotxt" --exec cat -n {} \; | head -100

Repository: ProxySQL/dbdeployer

Length of output: 2815


🌐 Web query:

MySQL 8.0.22 START REPLICA STOP REPLICA release notes

💡 Result:

In MySQL 8.0.22 release notes, the statements START SLAVE, STOP SLAVE, SHOW SLAVE STATUS, SHOW SLAVE HOSTS, and RESET SLAVE are deprecated. New aliases START REPLICA, STOP REPLICA, SHOW REPLICA STATUS, SHOW REPLICAS, and RESET REPLICA are introduced as replacements. These new statements function identically to the old ones, with only terminology changes to use "replica" instead of "slave". The old statements still work but emit deprecation warnings. Corresponding status variables like Com_slave_start are aliased to Com_replica_start.

Citations:


🌐 Web query:

MySQL replica_parallel_workers version 8.0.26 availability

💡 Result:

Yes, the replica_parallel_workers system variable is available in MySQL 8.0.26. It was introduced in this version as the replacement for the deprecated slave_parallel_workers variable. In MySQL 8.0.26, the default value is 0 (single-threaded replication by default). The variable enables multithreaded replication on replicas, setting the number of parallel applier worker threads (plus a coordinator thread). Values range from 0 to 1024, and it is dynamic (can be changed at runtime). For multi-channel replication, the setting applies per channel. From MySQL 8.0.27 onward, the default changed to 4.

Citations:


Gate replica_parallel_workers separately from START/STOP REPLICA.

START REPLICA/STOP REPLICA are available from MySQL 8.0.22, but replica_parallel_workers only exists from MySQL 8.0.26. On 8.0.22–8.0.25 this branch will switch to the new statement names correctly and then fail on SET GLOBAL replica_parallel_workers=3.

Suggested fix
 minimum_version_binary_log="008002000"
 minimum_version_replica="008000022"
+minimum_version_replica_parallel_workers="008000026"
@@
 if [[ "v$sortable_version" > "v$minimum_version_replica" ]] || [[ "v$sortable_version" == "v$minimum_version_replica" ]]; then
+    parallel_workers_var="slave_parallel_workers"
+    if [[ "v$sortable_version" > "v$minimum_version_replica_parallel_workers" ]] || [[ "v$sortable_version" == "v$minimum_version_replica_parallel_workers" ]]; then
+        parallel_workers_var="replica_parallel_workers"
+    fi
     (set -x
-    $sandbox_dir/use_all_slaves "STOP REPLICA; SET GLOBAL replica_parallel_workers=3; START REPLICA;show processlist "
+    $sandbox_dir/use_all_slaves "STOP REPLICA; SET GLOBAL ${parallel_workers_var}=3; START REPLICA;show processlist "
     )
 else
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [[ "v$sortable_version" > "v$minimum_version_replica" ]] || [[ "v$sortable_version" == "v$minimum_version_replica" ]]; then
(set -x
$sandbox_dir/use_all_slaves "STOP REPLICA; SET GLOBAL replica_parallel_workers=3; START REPLICA;show processlist "
)
else
(set -x
$sandbox_dir/use_all_slaves "STOP SLAVE; SET GLOBAL slave_parallel_workers=3; START SLAVE;show processlist "
)
if [[ "v$sortable_version" > "v$minimum_version_replica" ]] || [[ "v$sortable_version" == "v$minimum_version_replica" ]]; then
parallel_workers_var="slave_parallel_workers"
if [[ "v$sortable_version" > "v$minimum_version_replica_parallel_workers" ]] || [[ "v$sortable_version" == "v$minimum_version_replica_parallel_workers" ]]; then
parallel_workers_var="replica_parallel_workers"
fi
(set -x
$sandbox_dir/use_all_slaves "STOP REPLICA; SET GLOBAL ${parallel_workers_var}=3; START REPLICA;show processlist "
)
else
(set -x
$sandbox_dir/use_all_slaves "STOP SLAVE; SET GLOBAL slave_parallel_workers=3; START SLAVE;show processlist "
)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cookbook/templates/replication-operations.gotxt` around lines 67 - 74, The
code switches to START/STOP REPLICA for MySQL >= 8.0.22 but unconditionally
tries to SET GLOBAL replica_parallel_workers (which exists only from 8.0.26),
causing failures on 8.0.22–8.0.25; update the logic around
sandbox_dir/use_all_slaves so that the SET GLOBAL replica_parallel_workers=3 is
executed only when sortable_version >= the 8.0.26 threshold (introduce a new
minimum_version_replica_parallel constant or variable) and otherwise skip that
SET or use the older slave_parallel_workers name when appropriate; keep the
START/STOP REPLICA vs START/STOP SLAVE switch unchanged, but gate the
replica_parallel_workers assignment behind the new version check (referencing
sortable_version, minimum_version_replica, minimum_version_replica_parallel,
START REPLICA/STOP REPLICA, replica_parallel_workers, slave_parallel_workers,
and sandbox_dir/use_all_slaves).

fi
8 changes: 8 additions & 0 deletions sandbox/sandbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,14 @@ func createSingleSandbox(sandboxDef SandboxDef) (execList []concurrent.Execution
"HistoryDir": sandboxDef.HistoryDir,
}

// Use version-appropriate replication syntax for connection info
replCmds := replicationCommands(sandboxDef.Version)
data["ChangeMasterTo"] = replCmds["ChangeMasterTo"]
data["MasterHostParam"] = replCmds["MasterHostParam"]
data["MasterPortParam"] = replCmds["MasterPortParam"]
data["MasterUserParam"] = replCmds["MasterUserParam"]
data["MasterPasswordParam"] = replCmds["MasterPasswordParam"]

if sandboxDef.TaskUser != "" {
if sandboxDef.TaskUserRole == "" {
return emptyExecutionList, fmt.Errorf("task user defined but task role is empty")
Expand Down
8 changes: 4 additions & 4 deletions sandbox/templates/single/connection_info_sql.gotxt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

CHANGE MASTER TO master_host="{{.SbHost}}",
master_port={{.Port}},
master_user="{{.RplUser}}",
master_password="{{.RplPassword}}"
{{.ChangeMasterTo}} {{.MasterHostParam}}="{{.SbHost}}",
{{.MasterPortParam}}={{.Port}},
{{.MasterUserParam}}="{{.RplUser}}",
{{.MasterPasswordParam}}="{{.RplPassword}}"
Comment on lines +2 to +5
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

connection.sql is consumed by replicate_from on the slave side, but this template now renders the statement keyword (CHANGE MASTER TO vs CHANGE REPLICATION SOURCE TO) and parameter names (master_* vs source_*) at sandbox generation time (i.e., based on the master sandbox’s version). For cross-version replication (slave newer than master), this can generate syntax that is invalid on the slave. Consider keeping this file version-neutral (values only) and letting replicate_from construct the correct statement for the slave version.

Copilot uses AI. Check for mistakes.
53 changes: 43 additions & 10 deletions sandbox/templates/single/replicate_from.gotxt
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,15 @@ fi

master_status=/tmp/mstatus$$

$master_use_script -e 'show master status\G' > $master_status
# MySQL 8.2+ renamed SHOW MASTER STATUS to SHOW BINARY LOG STATUS
show_master_status_cmd="show master status"
minimum_version_binary_log="008002000"
if [[ "v$master_sortable_version" > "v$minimum_version_binary_log" ]] || [[ "v$master_sortable_version" == "v$minimum_version_binary_log" ]]
then
show_master_status_cmd="show binary log status"
fi

$master_use_script -e "$show_master_status_cmd\G" > $master_status
binlog_file=$(grep File < $master_status | awk '{print $2}')
binlog_pos=$(grep Position < $master_status | awk '{print $2}')
rm -f $master_status
Expand Down Expand Up @@ -210,21 +218,35 @@ then
exit 1
fi

# MySQL 8.0.23+ renamed CHANGE MASTER TO parameters
minimum_version_change_source="008000023"
auto_position_param="master_auto_position"
log_file_param="master_log_file"
log_pos_param="master_log_pos"
public_key_param="GET_MASTER_PUBLIC_KEY"
if [[ "v$slave_sortable_version" > "v$minimum_version_change_source" ]] || [[ "v$slave_sortable_version" == "v$minimum_version_change_source" ]]
then
auto_position_param="source_auto_position"
log_file_param="source_log_file"
log_pos_param="source_log_pos"
public_key_param="GET_SOURCE_PUBLIC_KEY"
fi

if [ -n "$using_gtid" ]
then
connection_string=$(cat $master_connection ; echo -n ", master_auto_position=1")
else
connection_string=$(cat $master_connection ; echo -n ', master_log_file="'$binlog_file'", master_log_pos='$binlog_pos )
connection_string=$(cat $master_connection ; echo -n ", $auto_position_param=1")
else
connection_string=$(cat $master_connection ; echo -n ", $log_file_param=\"$binlog_file\", $log_pos_param=$binlog_pos" )
if [ -f clone_replication.sql ]
Comment on lines +237 to 240
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

connection_string is built by concatenating the contents of $master_connection (from the master sandbox) with additional options, but the resulting statement is executed on the slave. If master and slave versions differ, $master_connection may contain deprecated/removed syntax/parameter names for the slave (e.g., slave 8.4+). Consider building the full statement in this script based on slave_sortable_version rather than reusing connection.sql from the master.

Copilot uses AI. Check for mistakes.
then
connection_string=$(cat $master_connection ; echo -n ", " ; cat clone_replication.sql)
fi
fi

# If master is 8.0, the slave must be at least 8.0
if [ "$master_short_version" == "8.0" ]
# If master is 8.0+, need public key for caching_sha2_password
if [[ $master_major -ge 8 ]]
then
connection_string="$connection_string, GET_MASTER_PUBLIC_KEY=1"
connection_string="$connection_string, $public_key_param=1"
fi

echo "Connecting to $master_path"
Expand All @@ -236,12 +258,23 @@ if [ -f clone_replication.sql ]
then
rm -f clone_replication.sql
fi
$SBDIR/use -v -e 'start slave'
$SBDIR/use -v -e 'SHOW SLAVE STATUS\G' | grep "\(Running:\|Master_Log_Pos\|\<Master_Log_File\|Retrieved\|Executed\|Auto_Position\)"
# MySQL 8.0.22+ renamed START/STOP/SHOW SLAVE to REPLICA
start_replica_cmd="start slave"
show_replica_cmd="SHOW SLAVE STATUS"
stop_reset_cmd="stop slave; reset slave"
minimum_version_replica="008000022"
if [[ "v$slave_sortable_version" > "v$minimum_version_replica" ]] || [[ "v$slave_sortable_version" == "v$minimum_version_replica" ]]
then
start_replica_cmd="start replica"
show_replica_cmd="SHOW REPLICA STATUS"
stop_reset_cmd="stop replica; reset replica"
fi
$SBDIR/use -v -e "$start_replica_cmd"
$SBDIR/use -v -e "$show_replica_cmd\G" | grep "\(Running:\|Master_Log_Pos\|Source_Log_Pos\|\<Master_Log_File\|\<Source_Log_File\|Retrieved\|Executed\|Auto_Position\)"
date > $active_replication
echo "Connected to $master_path" >> $active_replication
echo "#!{{.ShellPath}}" > $remove_replication
echo "$SBDIR/use -v -e 'stop slave; reset slave'" >> $remove_replication
echo "$SBDIR/use -v -e \"$stop_reset_cmd\"" >> $remove_replication
echo "rm -f $active_replication" >> $remove_replication
chmod +x $remove_replication

Loading