Fix pg_rewind when pg_xlog is a symlink.
pg_xlog is often a symlink, typically to a different filesystem. Don't get confused and comlain about by that, and just always pretend that it's a normal directory, even if it's really a symlink. Also add a test case for this. Backpatch to 9.5.
This commit is contained in:
parent
69b7a35c9a
commit
0e42397f42
@ -13,16 +13,18 @@ package RewindTest;
|
|||||||
#
|
#
|
||||||
# 2. setup_cluster - creates a PostgreSQL cluster that runs as the master
|
# 2. setup_cluster - creates a PostgreSQL cluster that runs as the master
|
||||||
#
|
#
|
||||||
# 3. create_standby - runs pg_basebackup to initialize a standby server, and
|
# 3. start_master - starts the master server
|
||||||
|
#
|
||||||
|
# 4. create_standby - runs pg_basebackup to initialize a standby server, and
|
||||||
# sets it up to follow the master.
|
# sets it up to follow the master.
|
||||||
#
|
#
|
||||||
# 4. promote_standby - runs "pg_ctl promote" to promote the standby server.
|
# 5. promote_standby - runs "pg_ctl promote" to promote the standby server.
|
||||||
# The old master keeps running.
|
# The old master keeps running.
|
||||||
#
|
#
|
||||||
# 5. run_pg_rewind - stops the old master (if it's still running) and runs
|
# 6. run_pg_rewind - stops the old master (if it's still running) and runs
|
||||||
# pg_rewind to synchronize it with the now-promoted standby server.
|
# pg_rewind to synchronize it with the now-promoted standby server.
|
||||||
#
|
#
|
||||||
# 6. clean_rewind_test - stops both servers used in the test, if they're
|
# 7. clean_rewind_test - stops both servers used in the test, if they're
|
||||||
# still running.
|
# still running.
|
||||||
#
|
#
|
||||||
# The test script can use the helper functions master_psql and standby_psql
|
# The test script can use the helper functions master_psql and standby_psql
|
||||||
@ -56,6 +58,7 @@ our @EXPORT = qw(
|
|||||||
|
|
||||||
init_rewind_test
|
init_rewind_test
|
||||||
setup_cluster
|
setup_cluster
|
||||||
|
start_master
|
||||||
create_standby
|
create_standby
|
||||||
promote_standby
|
promote_standby
|
||||||
run_pg_rewind
|
run_pg_rewind
|
||||||
@ -182,7 +185,10 @@ max_connections = 10
|
|||||||
|
|
||||||
# Accept replication connections on master
|
# Accept replication connections on master
|
||||||
configure_hba_for_replication $test_master_datadir;
|
configure_hba_for_replication $test_master_datadir;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub start_master
|
||||||
|
{
|
||||||
system_or_bail('pg_ctl' , '-w',
|
system_or_bail('pg_ctl' , '-w',
|
||||||
'-D' , $test_master_datadir,
|
'-D' , $test_master_datadir,
|
||||||
'-l', "$log_path/master.log",
|
'-l', "$log_path/master.log",
|
||||||
|
@ -78,6 +78,14 @@ process_source_file(const char *path, file_type_t type, size_t newsize,
|
|||||||
strcmp(path, "postmaster.opts") == 0)
|
strcmp(path, "postmaster.opts") == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pretend that pg_xlog is a directory, even if it's really a symlink.
|
||||||
|
* We don't want to mess with the symlink itself, nor complain if it's a
|
||||||
|
* symlink in source but not in target or vice versa.
|
||||||
|
*/
|
||||||
|
if (strcmp(path, "pg_xlog") == 0 && type == FILE_TYPE_SYMLINK)
|
||||||
|
type = FILE_TYPE_DIRECTORY;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip temporary files, .../pgsql_tmp/... and .../pgsql_tmp.* in source.
|
* Skip temporary files, .../pgsql_tmp/... and .../pgsql_tmp.* in source.
|
||||||
* This has the effect that all temporary files in the destination will be
|
* This has the effect that all temporary files in the destination will be
|
||||||
@ -112,7 +120,7 @@ process_source_file(const char *path, file_type_t type, size_t newsize,
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case FILE_TYPE_DIRECTORY:
|
case FILE_TYPE_DIRECTORY:
|
||||||
if (exists && !S_ISDIR(statbuf.st_mode))
|
if (exists && !S_ISDIR(statbuf.st_mode) && strcmp(path, "pg_xlog") != 0)
|
||||||
{
|
{
|
||||||
/* it's a directory in source, but not in target. Strange.. */
|
/* it's a directory in source, but not in target. Strange.. */
|
||||||
pg_fatal("\"%s\" is not a directory\n", localpath);
|
pg_fatal("\"%s\" is not a directory\n", localpath);
|
||||||
@ -285,6 +293,12 @@ process_target_file(const char *path, file_type_t type, size_t oldsize,
|
|||||||
strcmp(path, "postmaster.opts") == 0)
|
strcmp(path, "postmaster.opts") == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like in process_source_file, pretend that xlog is always a directory.
|
||||||
|
*/
|
||||||
|
if (strcmp(path, "pg_xlog") == 0 && type == FILE_TYPE_SYMLINK)
|
||||||
|
type = FILE_TYPE_DIRECTORY;
|
||||||
|
|
||||||
key.path = (char *) path;
|
key.path = (char *) path;
|
||||||
key_ptr = &key;
|
key_ptr = &key;
|
||||||
exists = (bsearch(&key_ptr, map->array, map->narray, sizeof(file_entry_t *),
|
exists = (bsearch(&key_ptr, map->array, map->narray, sizeof(file_entry_t *),
|
||||||
|
@ -10,6 +10,7 @@ sub run_test
|
|||||||
my $test_mode = shift;
|
my $test_mode = shift;
|
||||||
|
|
||||||
RewindTest::setup_cluster();
|
RewindTest::setup_cluster();
|
||||||
|
RewindTest::start_master();
|
||||||
|
|
||||||
# Create a test table and insert a row in master.
|
# Create a test table and insert a row in master.
|
||||||
master_psql("CREATE TABLE tbl1 (d text)");
|
master_psql("CREATE TABLE tbl1 (d text)");
|
||||||
|
@ -10,6 +10,7 @@ sub run_test
|
|||||||
my $test_mode = shift;
|
my $test_mode = shift;
|
||||||
|
|
||||||
RewindTest::setup_cluster();
|
RewindTest::setup_cluster();
|
||||||
|
RewindTest::start_master();
|
||||||
|
|
||||||
# Create a database in master.
|
# Create a database in master.
|
||||||
master_psql('CREATE DATABASE inmaster');
|
master_psql('CREATE DATABASE inmaster');
|
||||||
|
@ -15,6 +15,7 @@ sub run_test
|
|||||||
my $test_mode = shift;
|
my $test_mode = shift;
|
||||||
|
|
||||||
RewindTest::setup_cluster();
|
RewindTest::setup_cluster();
|
||||||
|
RewindTest::start_master();
|
||||||
|
|
||||||
my $test_master_datadir = $RewindTest::test_master_datadir;
|
my $test_master_datadir = $RewindTest::test_master_datadir;
|
||||||
|
|
||||||
|
79
src/bin/pg_rewind/t/004_pg_xlog_symlink.pl
Normal file
79
src/bin/pg_rewind/t/004_pg_xlog_symlink.pl
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#
|
||||||
|
# Test pg_rewind when the target's pg_xlog directory is a symlink.
|
||||||
|
#
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use File::Copy;
|
||||||
|
use File::Path qw(remove_tree);
|
||||||
|
use TestLib;
|
||||||
|
use Test::More;
|
||||||
|
if ($windows_os)
|
||||||
|
{
|
||||||
|
plan skip_all => 'symlinks not supported on Windows';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plan tests => 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
use RewindTest;
|
||||||
|
|
||||||
|
sub run_test
|
||||||
|
{
|
||||||
|
my $test_mode = shift;
|
||||||
|
|
||||||
|
my $master_xlogdir = "$tmp_check/xlog_master";
|
||||||
|
|
||||||
|
remove_tree($master_xlogdir);
|
||||||
|
RewindTest::setup_cluster();
|
||||||
|
|
||||||
|
# turn pg_xlog into a symlink
|
||||||
|
print("moving $test_master_datadir/pg_xlog to $master_xlogdir\n");
|
||||||
|
move("$test_master_datadir/pg_xlog", $master_xlogdir) or die;
|
||||||
|
symlink($master_xlogdir, "$test_master_datadir/pg_xlog") or die;
|
||||||
|
|
||||||
|
RewindTest::start_master();
|
||||||
|
|
||||||
|
# Create a test table and insert a row in master.
|
||||||
|
master_psql("CREATE TABLE tbl1 (d text)");
|
||||||
|
master_psql("INSERT INTO tbl1 VALUES ('in master')");
|
||||||
|
|
||||||
|
master_psql("CHECKPOINT");
|
||||||
|
|
||||||
|
RewindTest::create_standby();
|
||||||
|
|
||||||
|
# Insert additional data on master that will be replicated to standby
|
||||||
|
master_psql("INSERT INTO tbl1 values ('in master, before promotion')");
|
||||||
|
|
||||||
|
master_psql('CHECKPOINT');
|
||||||
|
|
||||||
|
RewindTest::promote_standby();
|
||||||
|
|
||||||
|
# Insert a row in the old master. This causes the master and standby
|
||||||
|
# to have "diverged", it's no longer possible to just apply the
|
||||||
|
# standy's logs over master directory - you need to rewind.
|
||||||
|
master_psql("INSERT INTO tbl1 VALUES ('in master, after promotion')");
|
||||||
|
|
||||||
|
# Also insert a new row in the standby, which won't be present in the
|
||||||
|
# old master.
|
||||||
|
standby_psql("INSERT INTO tbl1 VALUES ('in standby, after promotion')");
|
||||||
|
|
||||||
|
RewindTest::run_pg_rewind($test_mode);
|
||||||
|
|
||||||
|
check_query(
|
||||||
|
'SELECT * FROM tbl1',
|
||||||
|
qq(in master
|
||||||
|
in master, before promotion
|
||||||
|
in standby, after promotion
|
||||||
|
),
|
||||||
|
'table content');
|
||||||
|
|
||||||
|
RewindTest::clean_rewind_test();
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run the test in both modes
|
||||||
|
run_test('local');
|
||||||
|
run_test('remote');
|
||||||
|
|
||||||
|
exit(0);
|
Loading…
x
Reference in New Issue
Block a user