diff --git a/expected/backup_from_standby.out b/expected/backup_from_standby.out index 4fcf052e..8914b6bb 100644 --- a/expected/backup_from_standby.out +++ b/expected/backup_from_standby.out @@ -12,3 +12,26 @@ 0 0 0 + +###### BACKUP COMMAND FROM STANDBY SERVER TEST-0003 ###### +0 +0 +0 + +###### must be primary even if the recovery target is latest ###### + pg_is_in_recovery +------------------- + f +(1 row) + +###### BACKUP COMMAND FROM STANDBY SERVER TEST-0004 ###### +0 +0 +0 + +###### must be standby and synchronized with the primary server ###### + status +----------- + streaming +(1 row) + diff --git a/restore.c b/restore.c index a54adfb6..deb13769 100644 --- a/restore.c +++ b/restore.c @@ -29,6 +29,7 @@ static void add_recovery_related_options(const char *target_time, TimeLineID target_tli, bool target_tli_latest); static void create_recovery_signal(void); +static void remove_standby_signal(void); static pgRecoveryTarget *checkIfCreateRecoveryConf(const char *target_time, const char *target_xid, @@ -378,6 +379,12 @@ do_restore(const char *target_time, /* Create recovery.signal file */ create_recovery_signal(); + /* + * Remove if standby.signal file exists because pg_rman doesn’t treat + * the backup as restoring on standby automatically now. + */ + remove_standby_signal(); + /* release catalog lock */ catalog_unlock(); @@ -799,6 +806,38 @@ create_recovery_signal(void) } } +static void +remove_standby_signal(void) +{ + struct stat stat_buf; + char path[MAXPGPATH]; + + if (verbose && !check) + printf(_("----------------------------------------\n")); + + elog(INFO, _("removing standby.signal if exists to restore as primary")); + + if (!check) + { + snprintf(path, lengthof(path), "%s/standby.signal", pgdata); + + if (stat(path, &stat_buf) == 0) + { + if (remove(path)) + { + ereport(ERROR, + (errcode(ERROR_SYSTEM), + errmsg("could not remove \"%s\": %s", path, + strerror(errno)))); + } + ereport(INFO, + (errmsg("removed standby.signal"), + errhint("if you want to start as standby, additional manual" + "setups to make standby.signal and so on are required"))); + } + } +} + static void backup_online_files(bool re_recovery) { diff --git a/sql/backup_from_standby.sh b/sql/backup_from_standby.sh index 5c7e2e1b..53712fcb 100644 --- a/sql/backup_from_standby.sh +++ b/sql/backup_from_standby.sh @@ -150,17 +150,43 @@ EOF pg_ctl -D ${SBYDATA_PATH} start -w -t 600 > /dev/null 2>&1 } +function load_with_pgbench +{ + pgbench -p ${TEST_PGPORT} -T ${DURATION} -d pgbench > /dev/null 2>&1 +} + +function full_backup_from_standby +{ + pg_rman backup -B ${BACKUP_PATH} -b full -Z -p ${TEST_PGPORT} -d postgres -D ${SBYDATA_PATH} --standby-host=localhost --standby-port=${TEST_SBYPGPORT} --quiet;echo $? + pg_rman validate -B ${BACKUP_PATH} --quiet; echo $? +} + +function incremental_backup_from_standby +{ + pg_rman backup -B ${BACKUP_PATH} -b incremental -Z -p ${TEST_PGPORT} -d postgres -D ${SBYDATA_PATH} --standby-host=localhost --standby-port=${TEST_SBYPGPORT} --quiet;echo $? + pg_rman validate -B ${BACKUP_PATH} --quiet; echo $? +} + +function get_database_data_from_primary +{ + psql -p ${TEST_PGPORT} --no-psqlrc -d pgbench -c "SELECT * FROM pgbench_branches;" +} + +function get_database_data_from_standby +{ + psql -p ${TEST_SBYPGPORT} --no-psqlrc -d pgbench -c "SELECT * FROM pgbench_branches;" +} + init_backup setup_standby init_catalog echo '###### BACKUP COMMAND FROM STANDBY SERVER TEST-0001 ######' echo '###### full backup mode ######' -pgbench -p ${TEST_PGPORT} -T ${DURATION} -d pgbench > /dev/null 2>&1 -psql -p ${TEST_PGPORT} --no-psqlrc -d pgbench -c "SELECT * FROM pgbench_branches;" > ${TEST_BASE}/TEST-0001-before.out -pg_rman backup -B ${BACKUP_PATH} -b full -Z -p ${TEST_PGPORT} -d postgres -D ${SBYDATA_PATH} --standby-host=localhost --standby-port=${TEST_SBYPGPORT} --quiet;echo $? -pg_rman validate -B ${BACKUP_PATH} --quiet; echo $? +load_with_pgbench +get_database_data_from_primary > ${TEST_BASE}/TEST-0001-before.out +full_backup_from_standby TARGET_XID=`psql -p ${TEST_PGPORT} --no-psqlrc -d pgbench -tAq -c "INSERT INTO pgbench_history VALUES (1) RETURNING(xmin);"` -pgbench -p ${TEST_PGPORT} -T ${DURATION} -d pgbench > /dev/null 2>&1 +load_with_pgbench pg_ctl stop -m immediate -D ${PGDATA_PATH} > /dev/null 2>&1 cp ${PGDATA_PATH}/postgresql.conf ${TEST_BASE}/postgresql.conf sleep 1 @@ -173,7 +199,7 @@ ${BACKUP_RESTORE_COMMAND} ${BACKUP_TARGET_XID_COMMAND} EOF pg_ctl start -w -t 600 -D ${PGDATA_PATH} > /dev/null 2>&1 -psql -p ${TEST_PGPORT} --no-psqlrc -d pgbench -c "SELECT * FROM pgbench_branches;" > ${TEST_BASE}/TEST-0001-after.out +get_database_data_from_primary > ${TEST_BASE}/TEST-0001-after.out diff ${TEST_BASE}/TEST-0001-before.out ${TEST_BASE}/TEST-0001-after.out echo '' @@ -182,15 +208,13 @@ setup_standby init_catalog echo '###### BACKUP COMMAND FROM STANDBY SERVER TEST-0002 ######' echo '###### full + incremental backup mode ######' -pgbench -p ${TEST_PGPORT} -d pgbench > /dev/null 2>&1 -pg_rman backup -B ${BACKUP_PATH} -b full -Z -p ${TEST_PGPORT} -d postgres -D ${SBYDATA_PATH} --standby-host=localhost --standby-port=${TEST_SBYPGPORT} --quiet;echo $? -pg_rman validate -B ${BACKUP_PATH} --quiet; echo $? -pgbench -p ${TEST_PGPORT} -T ${DURATION} -d pgbench > /dev/null 2>&1 -pg_rman backup -B ${BACKUP_PATH} -b incremental -Z -p ${TEST_PGPORT} -d postgres -D ${SBYDATA_PATH} --standby-host=localhost --standby-port=${TEST_SBYPGPORT} --quiet;echo $? -pg_rman validate -B ${BACKUP_PATH} --quiet; echo $? -psql -p ${TEST_PGPORT} --no-psqlrc -d pgbench -c "SELECT * FROM pgbench_branches;" > ${TEST_BASE}/TEST-0002-before.out +load_with_pgbench +full_backup_from_standby +load_with_pgbench +incremental_backup_from_standby +get_database_data_from_primary > ${TEST_BASE}/TEST-0002-before.out TARGET_XID=`psql -p ${TEST_PGPORT} --no-psqlrc -d pgbench -tAq -c "INSERT INTO pgbench_history VALUES (1) RETURNING(xmin);"` -pgbench -p ${TEST_PGPORT} -T ${DURATION} pgbench > /dev/null 2>&1 +load_with_pgbench pg_ctl stop -m immediate -D ${PGDATA_PATH} > /dev/null 2>&1 cp ${PGDATA_PATH}/postgresql.conf ${TEST_BASE}/postgresql.conf sleep 1 @@ -203,9 +227,51 @@ ${BACKUP_RESTORE_COMMAND} ${BACKUP_TARGET_XID_COMMAND} EOF pg_ctl start -w -t 600 -D ${PGDATA_PATH} > /dev/null 2>&1 -psql -p ${TEST_PGPORT} --no-psqlrc -d pgbench -c "SELECT * FROM pgbench_branches;" > ${TEST_BASE}/TEST-0002-after.out +get_database_data_from_primary > ${TEST_BASE}/TEST-0002-after.out diff ${TEST_BASE}/TEST-0002-before.out ${TEST_BASE}/TEST-0002-after.out +echo '' + +# check to start as primary (stand-alone) if the recovery target is latest +init_backup +setup_standby +init_catalog +echo '###### BACKUP COMMAND FROM STANDBY SERVER TEST-0003 ######' +load_with_pgbench +get_database_data_from_primary > ${TEST_BASE}/TEST-0003-before.out +full_backup_from_standby +# Don't load_with_pgbench again. It makes the *.out result difference because +# restoring to the latest point using archived wal including the one generated +# by the second load. +pg_ctl stop -m immediate -D ${PGDATA_PATH} > /dev/null 2>&1 +pg_rman restore -B ${BACKUP_PATH} -D ${PGDATA_PATH} --quiet;echo $? +sed -i -e "s/^port = .*$/port = ${TEST_PGPORT}/" ${PGDATA_PATH}/postgresql.conf +pg_ctl start -w -t 600 -D ${PGDATA_PATH} > /dev/null 2>&1 +get_database_data_from_primary > ${TEST_BASE}/TEST-0003-after.out +diff ${TEST_BASE}/TEST-0003-before.out ${TEST_BASE}/TEST-0003-after.out +echo '' +echo '###### must be primary even if the recovery target is latest ######' +sleep 3 # wait until finishing recovery +psql -p ${TEST_PGPORT} --no-psqlrc -d pgbench -c "SELECT pg_is_in_recovery();" +# check to start as standby if a user configure it manually +init_backup +setup_standby +init_catalog +echo '###### BACKUP COMMAND FROM STANDBY SERVER TEST-0004 ######' +load_with_pgbench +full_backup_from_standby +load_with_pgbench # this data will be replicated after restoring +get_database_data_from_primary > ${TEST_BASE}/TEST-0004-before.out +pg_ctl stop -m immediate -D ${SBYDATA_PATH} > /dev/null 2>&1 +pg_rman restore -B ${BACKUP_PATH} -D ${SBYDATA_PATH} --quiet;echo $? +touch ${SBYDATA_PATH}/standby.signal # configure for standby server +pg_ctl start -w -t 600 -D ${SBYDATA_PATH} > /dev/null 2>&1 +echo '' +echo '###### must be standby and synchronized with the primary server ######' +sleep 3 # wait until finishing to sync +psql -p ${TEST_SBYPGPORT} --no-psqlrc -d pgbench -c "SELECT status FROM pg_stat_wal_receiver;" +get_database_data_from_standby > ${TEST_BASE}/TEST-0004-after.out +diff ${TEST_BASE}/TEST-0004-before.out ${TEST_BASE}/TEST-0004-after.out # clean up the temporal test data pg_ctl stop -m immediate -D ${PGDATA_PATH} > /dev/null 2>&1