diff --git a/.github/workflows/replica-tests.yml b/.github/workflows/replica-tests.yml index 5a9bfb7f7..d418efd02 100644 --- a/.github/workflows/replica-tests.yml +++ b/.github/workflows/replica-tests.yml @@ -10,7 +10,7 @@ jobs: strategy: fail-fast: false matrix: - image: ['mysql/mysql-server:5.7.41','mysql:8.0.41','mysql:8.4.3','percona/percona-server:8.0.41-32'] + image: ['mysql:5.7.41','mysql:8.0.41','mysql:8.4.3','percona/percona-server:8.0.41-32'] env: TEST_MYSQL_IMAGE: ${{ matrix.image }} diff --git a/localtests/docker-compose.yml b/localtests/docker-compose.yml deleted file mode 100644 index 0ec3ca943..000000000 --- a/localtests/docker-compose.yml +++ /dev/null @@ -1,29 +0,0 @@ -services: - mysql-primary: - image: $TEST_MYSQL_IMAGE - container_name: mysql-primary - command: --server-id=1 --log-bin=mysql-bin --binlog-format=row --gtid-mode=ON --enforce-gtid-consistency=ON --character-set-server=utf8mb4 $MYSQL_NATIVE_PASSWORD_FLAG - environment: - MYSQL_ROOT_PASSWORD: opensesame - MYSQL_ROOT_HOST: '%' - MYSQL_DATABASE: test - MYSQL_TCP_PORT: 3307 - INIT_ROCKSDB: 1 # for percona-server - ports: - - '3307:3307' - expose: - - '3307' - mysql-replica: - image: $TEST_MYSQL_IMAGE - container_name: mysql-replica - command: --server-id=2 --log-bin=mysql-bin --binlog-format=row --gtid-mode=ON --enforce-gtid-consistency=ON --log-slave-updates=ON --character-set-server=utf8mb4 $MYSQL_NATIVE_PASSWORD_FLAG - environment: - MYSQL_ROOT_PASSWORD: opensesame - MYSQL_ROOT_HOST: '%' - MYSQL_DATABASE: test - MYSQL_TCP_PORT: 3308 - INIT_ROCKSDB: 1 # for percona-server - ports: - - '3308:3308' - expose: - - '3308' diff --git a/localtests/test.sh b/localtests/test.sh index d918d473b..a9f4a82a5 100755 --- a/localtests/test.sh +++ b/localtests/test.sh @@ -79,9 +79,6 @@ verify_master_and_replica() { echo "gtid_mode on master is ${current_gtid_mode} with enforce_gtid_consistency=${current_enforce_gtid_consistency}" echo "server_uuid on master is ${current_master_server_uuid}, replica is ${current_replica_server_uuid}" - echo "Gracefully sleeping for 3 seconds while replica is setting up..." - sleep 3 - if [ "$(gh-ost-test-mysql-replica -e "select 1" -ss)" != "1" ]; then echo "Cannot verify gh-ost-test-mysql-replica" exit 1 @@ -94,6 +91,19 @@ verify_master_and_replica() { [ "$replica_host" == "$(hostname)" ] && replica_host="127.0.0.1" echo "# replica verified at $replica_host:$replica_port" + # Detect the server version once; no need to re-query it per test. + # Cache replica_terminology and seconds_behind_source values to avoid later checks. + mysql_version="$(gh-ost-test-mysql-replica -s -s -e "select @@version")" + mysql_version_comment="$(gh-ost-test-mysql-master -s -s -e "select @@version_comment")" + if [[ $mysql_version =~ "8.4" ]]; then + replica_terminology="replica" + seconds_behind_source="Seconds_Behind_Source" + else + replica_terminology="slave" + seconds_behind_source="Seconds_Behind_Master" + fi + echo "# detected version ${mysql_version} (${mysql_version_comment}); using '${replica_terminology}' terminology" + if [ "$docker" = true ]; then master_host="0.0.0.0" master_port="3307" @@ -113,27 +123,35 @@ echo_dot() { echo -n "." } -start_replication() { - mysql_version="$(gh-ost-test-mysql-replica -e "select @@version")" - if [[ $mysql_version =~ "8.4" ]]; then - seconds_behind_source="Seconds_Behind_Source" - replica_terminology="replica" +# Block until the replica has applied everything committed on the master so far. +# Used after seeding a test's schema/data on the master so gh-ost (which +# inspects the replica) never sees a stale table. Returns immediately when +# there is no lag; waits up to 10s otherwise. +# Relies on GTID (gtid_mode=ON); falls back to a short sleep if GTID is unavailable. +wait_replica_caught_up() { + local master_gtid + master_gtid="$(gh-ost-test-mysql-master -s -s -e "select @@global.gtid_executed" 2>/dev/null)" + if [ -n "$master_gtid" ]; then + gh-ost-test-mysql-replica -s -s -e "do WAIT_FOR_EXECUTED_GTID_SET('${master_gtid}', 10)" >/dev/null 2>&1 else - seconds_behind_source="Seconds_Behind_Master" - replica_terminology="slave" + sleep 1 fi +} + +start_replication() { + # replica_terminology / seconds_behind_source are detected once in verify_master_and_replica. gh-ost-test-mysql-replica -e "stop $replica_terminology; start $replica_terminology;" num_attempts=0 while gh-ost-test-mysql-replica -e "show $replica_terminology status\G" | grep $seconds_behind_source | grep -q NULL; do ((num_attempts = num_attempts + 1)) - if [ $num_attempts -gt 10 ]; then + if [ $num_attempts -gt 50 ]; then echo echo "ERROR replication failure" exit 1 fi echo_dot - sleep 1 + sleep 0.2 done } @@ -156,7 +174,7 @@ build_ghost_command() { --skip-metadata-lock-check \ --initially-drop-old-table \ --initially-drop-ghost-table \ - --throttle-query='select timestampdiff(second, min(last_update), now()) < 5 from _${table_name}_ghc' \ + --throttle-query='select timestampdiff(second, min(last_update), now()) < ${THROTTLE_SECONDS:-2} from _${table_name}_ghc' \ --throttle-flag-file=$throttle_flag_file \ --serve-socket-file=/tmp/gh-ost.test.sock \ --initially-drop-socket-file \ @@ -255,8 +273,6 @@ test_single() { if [ -f $tests_path/$test_name/ignore_versions ]; then ignore_versions=$(cat $tests_path/$test_name/ignore_versions) - mysql_version=$(gh-ost-test-mysql-master -s -s -e "select @@version") - mysql_version_comment=$(gh-ost-test-mysql-master -s -s -e "select @@version_comment") if echo "$mysql_version" | egrep -q "^${ignore_versions}"; then echo -n "Skipping: $test_name" return 0 @@ -322,9 +338,9 @@ test_single() { if [ -f $tests_path/$test_name/order_by ]; then order_by="order by $(cat $tests_path/$test_name/order_by)" fi - # graceful sleep for replica to catch up + echo_dot - sleep 1 + wait_replica_caught_up table_name="gh_ost_test" ghost_table_name="_gh_ost_test_gho" @@ -473,7 +489,11 @@ build_binary() { test_all() { build_binary test_dirs=$(find "$tests_path" -mindepth 1 -maxdepth 1 ! -path . -type d | grep "$test_pattern" | sort) - while read -r test_dir; do + # Read the test list on FD 3, not stdin: the mysql wrappers may run + # `docker exec -i`, which attaches and drains stdin. On stdin (FD 0) the + # first such call inside the loop would swallow the remaining test-dir + # lines, ending the loop after a single test. + while read -r test_dir <&3; do test_name=$(basename "$test_dir") local test_start_time=$(date +%s) if ! test_single "$test_name"; then @@ -489,13 +509,10 @@ test_all() { echo echo "+ pass (${test_duration}s)" fi - mysql_version="$(gh-ost-test-mysql-replica -e "select @@version")" - replica_terminology="slave" - if [[ $mysql_version =~ "8.4" ]]; then - replica_terminology="replica" - fi - gh-ost-test-mysql-replica -e "start $replica_terminology" - done <<<"$test_dirs" + # No need to restart replication here: each test stops it + # (gh-ost --test-on-replica) and start_replication restarts it at the + # next test's start. + done 3<<<"$test_dirs" } verify_master_and_replica diff --git a/script/.env b/script/.env new file mode 100644 index 000000000..f81ff5cd2 --- /dev/null +++ b/script/.env @@ -0,0 +1,3 @@ +MYSQL_ROOT_PASSWORD=opensesame +MYSQL_ROOT_HOST=% +MYSQL_DATABASE=test diff --git a/script/docker-compose.toxiproxy.yml b/script/docker-compose.toxiproxy.yml new file mode 100644 index 000000000..cd70d3903 --- /dev/null +++ b/script/docker-compose.toxiproxy.yml @@ -0,0 +1,7 @@ +services: + mysql-toxiproxy: + image: "ghcr.io/shopify/toxiproxy:latest" + container_name: mysql-toxiproxy + ports: + - '8474:8474' + - '23308:23308' diff --git a/script/docker-compose.yml b/script/docker-compose.yml new file mode 100644 index 000000000..ae2222127 --- /dev/null +++ b/script/docker-compose.yml @@ -0,0 +1,36 @@ +services: + mysql-primary: + image: $TEST_MYSQL_IMAGE + container_name: mysql-primary + command: --server-id=1 + init: true + env_file: + - .env + environment: + - MYSQL_TCP_PORT=3307 + volumes: + - $CONF_PATH/create_user.sql:/docker-entrypoint-initdb.d/create_user.sql:ro + - $CONF_PATH/common.cnf:$MYSQL_CONFD/common.cnf:ro + healthcheck: + test: "mysql -h 127.0.0.1 -uroot -p$MYSQL_ROOT_PASSWORD -e 'select 1;' || exit 1" + interval: 5s + # Generous first-boot window: emulated amd64 5.7 on arm64 can take 60s+ to + # init a fresh datadir. Health failures during start_period don't count, so + # `up --wait` won't abort before the server is reachable. + start_period: 120s + retries: 10 + ports: + - '3307:3307' + mysql-replica: + extends: mysql-primary + container_name: mysql-replica + command: --server-id=2 + # Volumes (create_user.sql, common.cnf) are inherited from mysql-primary. + # Replication is NOT configured here (i.e. at boot) intentionally: + # docker-gh-ost-replica-tests::setup applies start_replication.sql once + # both servers are up and listening, so the primary is reachable and + # replica connects on the first try instead of racing the primary's boot. + environment: + - MYSQL_TCP_PORT=3308 + ports: !override + - '3308:3308' diff --git a/script/docker-gh-ost-replica-tests b/script/docker-gh-ost-replica-tests index e267d4f89..e7c45f467 100755 --- a/script/docker-gh-ost-replica-tests +++ b/script/docker-gh-ost-replica-tests @@ -12,8 +12,7 @@ # Flags: # -t use a toxiproxy for replica connection to simulate dropped connections -set -e -toxiproxy=false +set -euo pipefail GH_OST_ROOT=$(git rev-parse --show-toplevel) if [[ ":$PATH:" != *":$GH_OST_ROOT:"* ]]; then @@ -35,22 +34,6 @@ poll_mysql() { return 0 } -mysql-source() { - if [[ $TEST_MYSQL_IMAGE =~ "mysql:8.4" ]]; then - gh-ost-test-mysql-master --ssl-mode=required "$@" - else - gh-ost-test-mysql-master "$@" - fi -} - -mysql-replica() { - if [[ $TEST_MYSQL_IMAGE =~ "mysql:8.4" ]]; then - gh-ost-test-mysql-replica --ssl-mode=required "$@" - else - gh-ost-test-mysql-replica "$@" - fi -} - create_toxiproxy() { curl --fail -X POST http://localhost:8474/proxies \ -H "Content-Type: application/json" \ @@ -68,54 +51,29 @@ create_toxiproxy() { } setup() { - [ -z "$TEST_MYSQL_IMAGE" ] && TEST_MYSQL_IMAGE="mysql:8.0.41" - - echo "Starting MySQL $TEST_MYSQL_IMAGE containers..." - compose_file="$GH_OST_ROOT/localtests/docker-compose.yml" - MYSQL_SHA2_RSA_KEYS_FLAG="" - MYSQL_PASSWORD_HASHING_ALGORITHM="mysql_native_password" - if [[ $TEST_MYSQL_IMAGE =~ "mysql:8.4" ]]; then - MYSQL_PASSWORD_HASHING_ALGORITHM="caching_sha2_password" - MYSQL_SHA2_RSA_KEYS_FLAG="--caching-sha2-password-auto-generate-rsa-keys=ON" - fi - (TEST_MYSQL_IMAGE="$TEST_MYSQL_IMAGE" MYSQL_SHA2_RSA_KEYS_FLAG="$MYSQL_SHA2_RSA_KEYS_FLAG" envsubst <"$compose_file") >"$compose_file.tmp" - if [ "$toxiproxy" = true ]; then - echo "Starting toxiproxy container..." - cat <>"$compose_file.tmp" - mysql-toxiproxy: - image: "ghcr.io/shopify/toxiproxy:latest" - container_name: mysql-toxiproxy - ports: - - '8474:8474' - - '23308:23308' - expose: - - '23308' - - '8474' -EOF + echo "Starting $TEST_MYSQL_IMAGE with toxiproxy..." + else + echo "Starting $TEST_MYSQL_IMAGE..." fi - docker compose -f "$compose_file.tmp" up -d --wait + # docker compose makes sure that both servers are + # - initialized with correct my.cnf and listening + # - have users with correct permissions created + docker compose up --wait echo "Waiting for MySQL..." poll_mysql "master" || exit 1 poll_mysql "replica" || exit 1 - echo -n "Setting up replication..." - mysql-source -e "create user if not exists 'repl'@'%' identified with $MYSQL_PASSWORD_HASHING_ALGORITHM by 'repl';" - mysql-source -e "grant replication slave on *.* to 'repl'@'%'; flush privileges;" - mysql-source -e "create user if not exists 'gh-ost'@'%' identified with $MYSQL_PASSWORD_HASHING_ALGORITHM by 'gh-ost';" - mysql-source -e "grant all on *.* to 'gh-ost'@'%';" - - sleep 1 - if [[ $TEST_MYSQL_IMAGE =~ "mysql:8.4" ]]; then - mysql-replica -e "change replication source to source_host='mysql-primary', source_port=3307, source_user='repl', source_password='repl', source_auto_position=1, source_ssl=1;" - mysql-replica -e "start replica;" - else - mysql-replica -e "change master to master_host='mysql-primary', master_port=3307, master_user='repl', master_password='repl', master_auto_position=1;" - mysql-replica -e "start slave;" + # Configure replication now that both servers are reachable, + # so the replica's IO thread connects on the first try. + echo "Starting replication..." + if ! gh-ost-test-mysql-replica < "$CONF_PATH/start_replication.sql"; then + echo " ❌ failed to start replication" + exit 1 fi - echo "OK" + echo " ✔ replication OK" if [ "$toxiproxy" = true ]; then echo "Creating toxiproxy..." @@ -124,30 +82,75 @@ EOF fi } +status() { + docker compose ps +} + teardown() { - echo "Stopping containers..." - docker stop mysql-replica - docker stop mysql-primary - docker stop mysql-toxiproxy 2>/dev/null || true - echo "Removing containers..." - docker rm mysql-replica - docker rm mysql-primary - docker rm mysql-toxiproxy 2>/dev/null || true + echo "Stopping and deleting containers..." + # -v also removes the anonymous /var/lib/mysql data volumes + # (the image declares VOLUME). Without -v these just pile up + # as dangling ~200MB volumes across runs. + # --remove-orphans: in case previous run used toxiproxy, we want to tear it down too. + docker compose down -v --remove-orphans } -main() { - local cmd="$1" - local tflag= - if [[ "$2" == "-t" ]]; then - toxiproxy=true +compose_setup() { + # export TEST_MYSQL_IMAGE so it's parsed in docker-compose.yml + export TEST_MYSQL_IMAGE="${TEST_MYSQL_IMAGE:-mysql:8.0.41}" + [[ "${2:-}" == "-t" ]] && toxiproxy=true || toxiproxy=false + + local compose_path="$GH_OST_ROOT/script" + # COMPOSE_FILE env var is recognised by docker compose and can contain multiple files + export COMPOSE_FILE="$compose_path/docker-compose.yml" + if [ "$toxiproxy" = true ]; then + COMPOSE_FILE="${COMPOSE_FILE}:$compose_path/docker-compose.toxiproxy.yml" + fi + + # Per-version config lives in docker/- (e.g. mysql-8.0) + # Derive from the image repo basename and from the tag, + # so registry/repo prefixes like percona/percona-server:8.0.41-32 resolve correctly. + local repo tag flavor major_minor + repo="${TEST_MYSQL_IMAGE%%:*}" + tag="${TEST_MYSQL_IMAGE##*:}" + flavor="${repo##*/}" + major_minor="$(echo "$tag" | cut -d. -f1-2)" + export CONF_PATH="$compose_path/docker/${flavor}-${major_minor}" + if [[ ! -d "$CONF_PATH" ]]; then + echo "No config dir for image '$TEST_MYSQL_IMAGE' (expected $CONF_PATH)" >&2 + exit 1 + fi + + # Per-flavor knobs, with defaults. Each flavor dir may override these in an + # optional flavor.env (e.g. Percona reads config from /etc/my.cnf.d). + # Keeps this script flavor-agnostic. + export MYSQL_CONFD=/etc/mysql/conf.d # where the server reads common.cnf + if [[ -f "$CONF_PATH/flavor.env" ]]; then + # shellcheck disable=SC1091 + source "$CONF_PATH/flavor.env" fi +} + +usage() { + echo "Usage: $(basename "$0") up|down|status|run [-t]" >&2 + exit 1 +} + +main() { + local cmd="${1:-}" + [[ -z "$cmd" ]] && usage + compose_setup "$@" if [[ "$cmd" == "up" ]]; then setup elif [[ "$cmd" == "down" ]]; then teardown + elif [[ "$cmd" == "status" ]]; then + status elif [[ "$cmd" == "run" ]]; then shift 1 "$GH_OST_ROOT/localtests/test.sh" -d "$@" + else + usage fi } diff --git a/script/docker/mysql-5.7/common.cnf b/script/docker/mysql-5.7/common.cnf new file mode 100644 index 000000000..528860adb --- /dev/null +++ b/script/docker/mysql-5.7/common.cnf @@ -0,0 +1,10 @@ +[mysqld] +gtid-mode=ON +enforce-gtid-consistency=ON +character-set-server=utf8mb4 +# MySQL 5.7 has the binary log off by default and gtid-mode=ON additionally +# requires log-bin + log-slave-updates (8.0 enables all of these for free). +# gh-ost tails ROW events from the replica's own binlog under --test-on-replica. +log-bin=mysql-bin +binlog-format=ROW +log-slave-updates=ON diff --git a/script/docker/mysql-5.7/create_user.sql b/script/docker/mysql-5.7/create_user.sql new file mode 100644 index 000000000..853d5828b --- /dev/null +++ b/script/docker/mysql-5.7/create_user.sql @@ -0,0 +1,4 @@ +create user if not exists 'repl'@'%' identified with mysql_native_password by 'repl'; +grant replication slave on *.* to 'repl'@'%'; flush privileges; +create user if not exists 'gh-ost'@'%' identified with mysql_native_password by 'gh-ost'; +grant all on *.* to 'gh-ost'@'%'; diff --git a/script/docker/mysql-5.7/flavor.env b/script/docker/mysql-5.7/flavor.env new file mode 100644 index 000000000..86c6c4b07 --- /dev/null +++ b/script/docker/mysql-5.7/flavor.env @@ -0,0 +1,2 @@ +# MySQL 5.7 only publishes amd64 images; emulate on other arches (e.g. arm64). +export DOCKER_DEFAULT_PLATFORM="${DOCKER_DEFAULT_PLATFORM:-linux/amd64}" diff --git a/script/docker/mysql-5.7/start_replication.sql b/script/docker/mysql-5.7/start_replication.sql new file mode 100644 index 000000000..54aa3a213 --- /dev/null +++ b/script/docker/mysql-5.7/start_replication.sql @@ -0,0 +1,2 @@ +change master to master_host='mysql-primary', master_port=3307, master_user='repl', master_password='repl', master_auto_position=1; +start slave; diff --git a/script/docker/mysql-8.0/common.cnf b/script/docker/mysql-8.0/common.cnf new file mode 100644 index 000000000..9fe03bad8 --- /dev/null +++ b/script/docker/mysql-8.0/common.cnf @@ -0,0 +1,8 @@ +[mysqld] +gtid-mode=ON +enforce-gtid-consistency=ON +character-set-server=utf8mb4 +# Use the legacy auth plugin (as on 5.7 and master) so clients connect over +# plain TCP without TLS. 8.0 defaults to caching_sha2_password, which forces a +# secure transport. Covers root too (created by the entrypoint). +default-authentication-plugin=mysql_native_password diff --git a/script/docker/mysql-8.0/create_user.sql b/script/docker/mysql-8.0/create_user.sql new file mode 100644 index 000000000..1ce384f27 --- /dev/null +++ b/script/docker/mysql-8.0/create_user.sql @@ -0,0 +1,5 @@ +create user if not exists 'repl'@'%' identified with mysql_native_password by 'repl'; +grant replication slave on *.* to 'repl'@'%'; flush privileges; +create user if not exists 'gh-ost'@'%' identified with mysql_native_password by 'gh-ost'; +grant all on *.* to 'gh-ost'@'%'; + diff --git a/script/docker/mysql-8.0/start_replication.sql b/script/docker/mysql-8.0/start_replication.sql new file mode 100644 index 000000000..cbf3ef2a1 --- /dev/null +++ b/script/docker/mysql-8.0/start_replication.sql @@ -0,0 +1,3 @@ +change replication source to source_host='mysql-primary', source_port=3307, source_user='repl', source_password='repl', source_auto_position=1; +start replica; + diff --git a/script/docker/mysql-8.4/common.cnf b/script/docker/mysql-8.4/common.cnf new file mode 100644 index 000000000..c4f063cc6 --- /dev/null +++ b/script/docker/mysql-8.4/common.cnf @@ -0,0 +1,4 @@ +[mysqld] +gtid-mode=ON +enforce-gtid-consistency=ON +character-set-server=utf8mb4 diff --git a/script/docker/mysql-8.4/create_user.sql b/script/docker/mysql-8.4/create_user.sql new file mode 100644 index 000000000..57145463f --- /dev/null +++ b/script/docker/mysql-8.4/create_user.sql @@ -0,0 +1,5 @@ +create user if not exists 'repl'@'%' identified with caching_sha2_password by 'repl'; +grant replication slave on *.* to 'repl'@'%'; flush privileges; +create user if not exists 'gh-ost'@'%' identified with caching_sha2_password by 'gh-ost'; +grant all on *.* to 'gh-ost'@'%'; + diff --git a/script/docker/mysql-8.4/start_replication.sql b/script/docker/mysql-8.4/start_replication.sql new file mode 100644 index 000000000..89f39cc32 --- /dev/null +++ b/script/docker/mysql-8.4/start_replication.sql @@ -0,0 +1,3 @@ +change replication source to source_host='mysql-primary', source_port=3307, source_user='repl', source_password='repl', source_auto_position=1, source_ssl=1; +start replica; + diff --git a/script/docker/percona-server-8.0/common.cnf b/script/docker/percona-server-8.0/common.cnf new file mode 100644 index 000000000..9fe03bad8 --- /dev/null +++ b/script/docker/percona-server-8.0/common.cnf @@ -0,0 +1,8 @@ +[mysqld] +gtid-mode=ON +enforce-gtid-consistency=ON +character-set-server=utf8mb4 +# Use the legacy auth plugin (as on 5.7 and master) so clients connect over +# plain TCP without TLS. 8.0 defaults to caching_sha2_password, which forces a +# secure transport. Covers root too (created by the entrypoint). +default-authentication-plugin=mysql_native_password diff --git a/script/docker/percona-server-8.0/create_user.sql b/script/docker/percona-server-8.0/create_user.sql new file mode 100644 index 000000000..1ce384f27 --- /dev/null +++ b/script/docker/percona-server-8.0/create_user.sql @@ -0,0 +1,5 @@ +create user if not exists 'repl'@'%' identified with mysql_native_password by 'repl'; +grant replication slave on *.* to 'repl'@'%'; flush privileges; +create user if not exists 'gh-ost'@'%' identified with mysql_native_password by 'gh-ost'; +grant all on *.* to 'gh-ost'@'%'; + diff --git a/script/docker/percona-server-8.0/flavor.env b/script/docker/percona-server-8.0/flavor.env new file mode 100644 index 000000000..26d07866f --- /dev/null +++ b/script/docker/percona-server-8.0/flavor.env @@ -0,0 +1,3 @@ +# The Percona Server image reads server config from /etc/my.cnf.d, not the +# /etc/mysql/conf.d path the official MySQL image !includedir's. +export MYSQL_CONFD=/etc/my.cnf.d diff --git a/script/docker/percona-server-8.0/start_replication.sql b/script/docker/percona-server-8.0/start_replication.sql new file mode 100644 index 000000000..cbf3ef2a1 --- /dev/null +++ b/script/docker/percona-server-8.0/start_replication.sql @@ -0,0 +1,3 @@ +change replication source to source_host='mysql-primary', source_port=3307, source_user='repl', source_password='repl', source_auto_position=1; +start replica; + diff --git a/script/gh-ost-test-mysql-master b/script/gh-ost-test-mysql-master index d517ca77b..5a3042220 100755 --- a/script/gh-ost-test-mysql-master +++ b/script/gh-ost-test-mysql-master @@ -1,6 +1,16 @@ #!/bin/bash # # This executes a command on the mysql-primary docker container created -# from localtests/docker-compose.yml. It's used by localtests/test.sh. - -MYSQL_PWD=opensesame mysql -uroot -h0.0.0.0 -P3307 "$@" +# from script/docker-compose.yml. It's used by localtests/test.sh. +# +# Prefer the host's native mysql client over the published port (faster: +# ~0.03s/call vs ~0.08s for docker exec). Fall back to `docker exec` when no +# client is on PATH. Set GH_OST_TEST_USE_DOCKER=1 to force docker exec. +# +# -h 127.0.0.1 forces a TCP connection instead of the unix socket. +if [[ -z "${GH_OST_TEST_USE_DOCKER:-}" ]] && command -v mysql >/dev/null 2>&1; then + MYSQL_PWD=opensesame mysql -uroot -h 127.0.0.1 -P 3307 "$@" +else + # -i forwards stdin so callers can pipe SQL in (e.g. < create.sql). + docker exec -i -e MYSQL_PWD=opensesame mysql-primary mysql -uroot -h 127.0.0.1 "$@" +fi diff --git a/script/gh-ost-test-mysql-replica b/script/gh-ost-test-mysql-replica index ae2646bf3..5e8735dbb 100755 --- a/script/gh-ost-test-mysql-replica +++ b/script/gh-ost-test-mysql-replica @@ -1,6 +1,16 @@ #!/bin/bash # # This executes a command on the mysql-replica docker container created -# from localtests/docker-compose.yml. It's used by localtests/test.sh. - -MYSQL_PWD=opensesame mysql -uroot -h0.0.0.0 -P3308 "$@" +# from script/docker-compose.yml. It's used by localtests/test.sh. +# +# Prefer the host's native mysql client over the published port (faster: +# ~0.03s/call vs ~0.08s for docker exec). Fall back to `docker exec` when no +# client is on PATH. Set GH_OST_TEST_USE_DOCKER=1 to force docker exec. +# +# -h 127.0.0.1 forces a TCP connection instead of the unix socket. +if [[ -z "${GH_OST_TEST_USE_DOCKER:-}" ]] && command -v mysql >/dev/null 2>&1; then + MYSQL_PWD=opensesame mysql -uroot -h 127.0.0.1 -P 3308 "$@" +else + # -i forwards stdin so callers can pipe SQL in (e.g. < create.sql). + docker exec -i -e MYSQL_PWD=opensesame mysql-replica mysql -uroot -h 127.0.0.1 "$@" +fi