From cd64dc42d1e1b03e57e6ba3d316e4f9dec52a78d Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Fri, 19 Apr 2024 13:30:42 -0400 Subject: [PATCH] pg_combinebackup: Fix incorrect tablespace handling. The previous coding mangled the pathname calculation for incremental files located in user-defined tablespaces. Enhance the test cases to cover such cases, as I should have done originally. Thanks to Andres Freund for alerting me to the lack of test coverage. Discussion: http://postgr.es/m/CA+TgmoYdXTjo9iQeoipTccDpWZzvBNS6EndY2uARM+T4yG_yDg@mail.gmail.com --- src/bin/pg_combinebackup/pg_combinebackup.c | 2 +- src/bin/pg_combinebackup/reconstruct.c | 7 ++-- .../pg_combinebackup/t/002_compare_backups.pl | 32 ++++++++++++++++--- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/bin/pg_combinebackup/pg_combinebackup.c b/src/bin/pg_combinebackup/pg_combinebackup.c index b26c532445..95da1b01bc 100644 --- a/src/bin/pg_combinebackup/pg_combinebackup.c +++ b/src/bin/pg_combinebackup/pg_combinebackup.c @@ -990,7 +990,7 @@ process_directory_recursively(Oid tsoid, /* Reconstruction logic will do the rest. */ reconstruct_from_incremental_file(ifullpath, ofullpath, - relative_path, + manifest_prefix, de->d_name + INCREMENTAL_PREFIX_LENGTH, n_prior_backups, prior_backup_dirs, diff --git a/src/bin/pg_combinebackup/reconstruct.c b/src/bin/pg_combinebackup/reconstruct.c index d481a5c565..c584c63e5d 100644 --- a/src/bin/pg_combinebackup/reconstruct.c +++ b/src/bin/pg_combinebackup/reconstruct.c @@ -75,9 +75,10 @@ static void read_block(rfile *s, off_t off, uint8 *buffer); * output_filename should be the path where the reconstructed file is to be * written. * - * relative_path should be the relative path to the directory containing this - * file. bare_file_name should be the name of the file within that directory, - * without "INCREMENTAL.". + * relative_path should be the path to the directory containing this file, + * relative to the root of the backup (NOT relative to the root of the + * tablespace). bare_file_name should be the name of the file within that + * directory, without "INCREMENTAL.". * * n_prior_backups is the number of prior backups, and prior_backup_dirs is * an array of pathnames where those backups can be found. diff --git a/src/bin/pg_combinebackup/t/002_compare_backups.pl b/src/bin/pg_combinebackup/t/002_compare_backups.pl index 71e9a90d22..1d9764eeac 100644 --- a/src/bin/pg_combinebackup/t/002_compare_backups.pl +++ b/src/bin/pg_combinebackup/t/002_compare_backups.pl @@ -7,11 +7,15 @@ use PostgreSQL::Test::Cluster; use PostgreSQL::Test::Utils; use Test::More; +my $tempdir = PostgreSQL::Test::Utils::tempdir; + # Set up a new database instance. my $primary = PostgreSQL::Test::Cluster->new('primary'); $primary->init(has_archiving => 1, allows_streaming => 1); $primary->append_conf('postgresql.conf', 'summarize_wal = on'); $primary->start; +my $tsprimary = $tempdir . '/ts'; +mkdir($tsprimary) || die "mkdir $tsprimary: $!"; # Create some test tables, each containing one row of data, plus a whole # extra database. @@ -29,24 +33,37 @@ INSERT INTO will_get_dropped VALUES (1, 'initial test row'); CREATE TABLE will_get_rewritten (a int, b text); INSERT INTO will_get_rewritten VALUES (1, 'initial test row'); CREATE DATABASE db_will_get_dropped; +CREATE TABLESPACE ts1 LOCATION '$tsprimary'; +CREATE TABLE will_not_change_in_ts (a int, b text) TABLESPACE ts1; +INSERT INTO will_not_change_in_ts VALUES (1, 'initial test row'); +CREATE TABLE will_change_in_ts (a int, b text) TABLESPACE ts1; +INSERT INTO will_change_in_ts VALUES (1, 'initial test row'); +CREATE TABLE will_get_dropped_in_ts (a int, b text); +INSERT INTO will_get_dropped_in_ts VALUES (1, 'initial test row'); EOM # Take a full backup. my $backup1path = $primary->backup_dir . '/backup1'; +my $tsbackup1path = $tempdir . '/ts1backup'; +mkdir($tsbackup1path) || die "mkdir $tsbackup1path: $!"; $primary->command_ok( - [ 'pg_basebackup', '-D', $backup1path, '--no-sync', '-cfast' ], - "full backup"); + [ 'pg_basebackup', '-D', $backup1path, '--no-sync', '-cfast', + "-T${tsprimary}=${tsbackup1path}" ], "full backup"); # Now make some database changes. $primary->safe_psql('postgres', <backup_dir . '/backup2'; +my $tsbackup2path = $tempdir . '/tsbackup2'; +mkdir($tsbackup2path) || die "mkdir $tsbackup2path: $!"; $primary->command_ok( [ 'pg_basebackup', '-D', $backup2path, '--no-sync', '-cfast', + "-T${tsprimary}=${tsbackup2path}", '--incremental', $backup1path . '/backup_manifest' ], "incremental backup"); @@ -78,9 +98,11 @@ $primary->poll_query_until('postgres', $archive_wait_query) # Perform PITR from the full backup. Disable archive_mode so that the archive # doesn't find out about the new timeline; that way, the later PITR below will # choose the same timeline. +my $tspitr1path = $tempdir . '/tspitr1'; my $pitr1 = PostgreSQL::Test::Cluster->new('pitr1'); $pitr1->init_from_backup($primary, 'backup1', - standby => 1, has_restoring => 1); + standby => 1, has_restoring => 1, + tablespace_map => { $tsbackup1path => $tspitr1path }); $pitr1->append_conf('postgresql.conf', qq{ recovery_target_lsn = '$lsn' recovery_target_action = 'promote' @@ -90,10 +112,12 @@ $pitr1->start(); # Perform PITR to the same LSN from the incremental backup. Use the same # basic configuration as before. +my $tspitr2path = $tempdir . '/tspitr2'; my $pitr2 = PostgreSQL::Test::Cluster->new('pitr2'); $pitr2->init_from_backup($primary, 'backup2', standby => 1, has_restoring => 1, - combine_with_prior => [ 'backup1' ]); + combine_with_prior => [ 'backup1' ], + tablespace_map => { $tsbackup2path => $tspitr2path }); $pitr2->append_conf('postgresql.conf', qq{ recovery_target_lsn = '$lsn' recovery_target_action = 'promote'