#
# 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.
#
-# 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.
#
-# 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.
#
-# 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.
#
# The test script can use the helper functions master_psql and standby_psql
init_rewind_test
setup_cluster
+ start_master
create_standby
promote_standby
run_pg_rewind
# Accept replication connections on master
configure_hba_for_replication $test_master_datadir;
+}
+sub start_master
+{
system_or_bail('pg_ctl' , '-w',
'-D' , $test_master_datadir,
'-l', "$log_path/master.log",
strcmp(path, "postmaster.opts") == 0)
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.
* This has the effect that all temporary files in the destination will be
switch (type)
{
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.. */
pg_fatal("\"%s\" is not a directory\n", localpath);
strcmp(path, "postmaster.opts") == 0)
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_ptr = &key;
exists = (bsearch(&key_ptr, map->array, map->narray, sizeof(file_entry_t *),
my $test_mode = shift;
RewindTest::setup_cluster();
+ RewindTest::start_master();
# Create a test table and insert a row in master.
master_psql("CREATE TABLE tbl1 (d text)");
my $test_mode = shift;
RewindTest::setup_cluster();
+ RewindTest::start_master();
# Create a database in master.
master_psql('CREATE DATABASE inmaster');
my $test_mode = shift;
RewindTest::setup_cluster();
+ RewindTest::start_master();
my $test_master_datadir = $RewindTest::test_master_datadir;
--- /dev/null
+#
+# 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);