Skip to content

Commit 615b695

Browse files
committed
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.
1 parent 2b917a5 commit 615b695

File tree

6 files changed

+98
-5
lines changed

6 files changed

+98
-5
lines changed

src/bin/pg_rewind/RewindTest.pm

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,18 @@ package RewindTest;
1313
#
1414
# 2. setup_cluster - creates a PostgreSQL cluster that runs as the master
1515
#
16-
# 3. create_standby - runs pg_basebackup to initialize a standby server, and
16+
# 3. start_master - starts the master server
17+
#
18+
# 4. create_standby - runs pg_basebackup to initialize a standby server, and
1719
# sets it up to follow the master.
1820
#
19-
# 4. promote_standby - runs "pg_ctl promote" to promote the standby server.
21+
# 5. promote_standby - runs "pg_ctl promote" to promote the standby server.
2022
# The old master keeps running.
2123
#
22-
# 5. run_pg_rewind - stops the old master (if it's still running) and runs
24+
# 6. run_pg_rewind - stops the old master (if it's still running) and runs
2325
# pg_rewind to synchronize it with the now-promoted standby server.
2426
#
25-
# 6. clean_rewind_test - stops both servers used in the test, if they're
27+
# 7. clean_rewind_test - stops both servers used in the test, if they're
2628
# still running.
2729
#
2830
# The test script can use the helper functions master_psql and standby_psql
@@ -56,6 +58,7 @@ our @EXPORT = qw(
5658
5759
init_rewind_test
5860
setup_cluster
61+
start_master
5962
create_standby
6063
promote_standby
6164
run_pg_rewind
@@ -189,7 +192,10 @@ max_connections = 10
189192
"$test_master_datadir/pg_hba.conf", qq(
190193
local replication all trust
191194
));
195+
}
192196

197+
sub start_master
198+
{
193199
system_or_bail('pg_ctl' , '-w',
194200
'-D' , $test_master_datadir,
195201
'-l', "$log_path/master.log",

src/bin/pg_rewind/filemap.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ process_source_file(const char *path, file_type_t type, size_t newsize,
7878
strcmp(path, "postmaster.opts") == 0)
7979
return;
8080

81+
/*
82+
* Pretend that pg_xlog is a directory, even if it's really a symlink.
83+
* We don't want to mess with the symlink itself, nor complain if it's a
84+
* symlink in source but not in target or vice versa.
85+
*/
86+
if (strcmp(path, "pg_xlog") == 0 && type == FILE_TYPE_SYMLINK)
87+
type = FILE_TYPE_DIRECTORY;
88+
8189
/*
8290
* Skip temporary files, .../pgsql_tmp/... and .../pgsql_tmp.* in source.
8391
* 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,
112120
switch (type)
113121
{
114122
case FILE_TYPE_DIRECTORY:
115-
if (exists && !S_ISDIR(statbuf.st_mode))
123+
if (exists && !S_ISDIR(statbuf.st_mode) && strcmp(path, "pg_xlog") != 0)
116124
{
117125
/* it's a directory in source, but not in target. Strange.. */
118126
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,
285293
strcmp(path, "postmaster.opts") == 0)
286294
return;
287295

296+
/*
297+
* Like in process_source_file, pretend that xlog is always a directory.
298+
*/
299+
if (strcmp(path, "pg_xlog") == 0 && type == FILE_TYPE_SYMLINK)
300+
type = FILE_TYPE_DIRECTORY;
301+
288302
key.path = (char *) path;
289303
key_ptr = &key;
290304
exists = (bsearch(&key_ptr, map->array, map->narray, sizeof(file_entry_t *),

src/bin/pg_rewind/t/001_basic.pl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ sub run_test
1010
my $test_mode = shift;
1111

1212
RewindTest::setup_cluster();
13+
RewindTest::start_master();
1314

1415
# Create a test table and insert a row in master.
1516
master_psql("CREATE TABLE tbl1 (d text)");

src/bin/pg_rewind/t/002_databases.pl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ sub run_test
1010
my $test_mode = shift;
1111

1212
RewindTest::setup_cluster();
13+
RewindTest::start_master();
1314

1415
# Create a database in master.
1516
master_psql('CREATE DATABASE inmaster');

src/bin/pg_rewind/t/003_extrafiles.pl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ sub run_test
1515
my $test_mode = shift;
1616

1717
RewindTest::setup_cluster();
18+
RewindTest::start_master();
1819

1920
my $test_master_datadir = $RewindTest::test_master_datadir;
2021

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#
2+
# Test pg_rewind when the target's pg_xlog directory is a symlink.
3+
#
4+
use strict;
5+
use warnings;
6+
use File::Copy;
7+
use File::Path qw(remove_tree);
8+
use TestLib;
9+
use Test::More tests => 4;
10+
11+
use RewindTest;
12+
13+
sub run_test
14+
{
15+
my $test_mode = shift;
16+
17+
my $master_xlogdir = "$tmp_check/xlog_master";
18+
19+
remove_tree($master_xlogdir);
20+
RewindTest::setup_cluster();
21+
22+
# turn pg_xlog into a symlink
23+
print("moving $test_master_datadir/pg_xlog to $master_xlogdir\n");
24+
move("$test_master_datadir/pg_xlog", $master_xlogdir) or die;
25+
symlink($master_xlogdir, "$test_master_datadir/pg_xlog") or die;
26+
27+
RewindTest::start_master();
28+
29+
# Create a test table and insert a row in master.
30+
master_psql("CREATE TABLE tbl1 (d text)");
31+
master_psql("INSERT INTO tbl1 VALUES ('in master')");
32+
33+
master_psql("CHECKPOINT");
34+
35+
RewindTest::create_standby();
36+
37+
# Insert additional data on master that will be replicated to standby
38+
master_psql("INSERT INTO tbl1 values ('in master, before promotion')");
39+
40+
master_psql('CHECKPOINT');
41+
42+
RewindTest::promote_standby();
43+
44+
# Insert a row in the old master. This causes the master and standby
45+
# to have "diverged", it's no longer possible to just apply the
46+
# standy's logs over master directory - you need to rewind.
47+
master_psql("INSERT INTO tbl1 VALUES ('in master, after promotion')");
48+
49+
# Also insert a new row in the standby, which won't be present in the
50+
# old master.
51+
standby_psql("INSERT INTO tbl1 VALUES ('in standby, after promotion')");
52+
53+
RewindTest::run_pg_rewind($test_mode);
54+
55+
check_query(
56+
'SELECT * FROM tbl1',
57+
qq(in master
58+
in master, before promotion
59+
in standby, after promotion
60+
),
61+
'table content');
62+
63+
RewindTest::clean_rewind_test();
64+
}
65+
66+
# Run the test in both modes
67+
run_test('local');
68+
run_test('remote');
69+
70+
exit(0);

0 commit comments

Comments
 (0)