Skip to content

Add checks in pg_rewind to abort if backup_label file is found in #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/bin/pg_rewind/file_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,23 @@ sync_target_dir(void)
sync_pgdata(datadir_target, PG_VERSION_NUM, sync_method);
}

/*
* Check if a file is present using the stat function. Return 'true'
* if present and 'false' if not.
*/
bool
is_file_present(const char *datadir, const char *path)
{
struct stat s;
char fullpath[MAXPGPATH];

snprintf(fullpath, sizeof(fullpath), "%s/%s", datadir, path);

if (stat(fullpath, &s) < 0)
return false;

return true;
}

/*
* Read a file into memory. The file to be read is <datadir>/<path>.
Expand Down
2 changes: 1 addition & 1 deletion src/bin/pg_rewind/file_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ extern void truncate_target_file(const char *path, off_t newsize);
extern void create_target(file_entry_t *entry);
extern void remove_target(file_entry_t *entry);
extern void sync_target_dir(void);

extern bool is_file_present(const char *datadir, const char *path);
extern char *slurpFile(const char *datadir, const char *path, size_t *filesize);

typedef void (*process_file_callback_t) (const char *path, file_type_t type, size_t size, const char *link_target);
Expand Down
22 changes: 22 additions & 0 deletions src/bin/pg_rewind/libpq_source.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ static void appendArrayEscapedString(StringInfo buf, const char *str);
static void process_queued_fetch_requests(libpq_source *src);

/* public interface functions */
static bool libpq_is_file_present(rewind_source *source, const char *path);
static void libpq_traverse_files(rewind_source *source,
process_file_callback_t callback);
static void libpq_queue_fetch_file(rewind_source *source, const char *path, size_t len);
Expand All @@ -87,6 +88,7 @@ init_libpq_source(PGconn *conn)

src = pg_malloc0(sizeof(libpq_source));

src->common.is_file_present = libpq_is_file_present;
src->common.traverse_files = libpq_traverse_files;
src->common.fetch_file = libpq_fetch_file;
src->common.queue_fetch_file = libpq_queue_fetch_file;
Expand Down Expand Up @@ -627,6 +629,26 @@ appendArrayEscapedString(StringInfo buf, const char *str)
appendStringInfoCharMacro(buf, '\"');
}

/*
* Check if a file is present using the connection to the
* database.
*/
static bool
libpq_is_file_present(rewind_source *source, const char *path)
{
PGconn *conn = ((libpq_source *) source)->conn;
PGresult *res;
const char *paramValues[1];

paramValues[0] = path;
res = PQexecParams(conn, "SELECT pg_stat_file($1)",
1, NULL, paramValues, NULL, NULL, 1);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
return false;

return true;
}

/*
* Fetch a single file as a malloc'd buffer.
*/
Expand Down
14 changes: 14 additions & 0 deletions src/bin/pg_rewind/local_source.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ typedef struct
const char *datadir; /* path to the source data directory */
} local_source;

static bool local_is_file_present(rewind_source *source, const char *path);
static void local_traverse_files(rewind_source *source,
process_file_callback_t callback);
static char *local_fetch_file(rewind_source *source, const char *path,
Expand All @@ -43,6 +44,7 @@ init_local_source(const char *datadir)

src = pg_malloc0(sizeof(local_source));

src->common.is_file_present = local_is_file_present;
src->common.traverse_files = local_traverse_files;
src->common.fetch_file = local_fetch_file;
src->common.queue_fetch_file = local_queue_fetch_file;
Expand All @@ -62,6 +64,18 @@ local_traverse_files(rewind_source *source, process_file_callback_t callback)
traverse_datadir(((local_source *) source)->datadir, callback);
}

/*
* Check if a file is present. It calls the file_ops is_file_present
* to check.
*/
static bool
local_is_file_present(rewind_source *source, const char *path)
{
const char *datadir = ((local_source *) source)->datadir;

return is_file_present(datadir, path);
}

static char *
local_fetch_file(rewind_source *source, const char *path, size_t *filesize)
{
Expand Down
6 changes: 5 additions & 1 deletion src/bin/pg_rewind/pg_rewind.c
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,11 @@ perform_rewind(filemap_t *filemap, rewind_source *source,
static void
sanityChecks(void)
{
/* TODO Check that there's no backup_label in either cluster */
if (source->is_file_present(source, "backup_label"))
pg_fatal("The backup_label file is present in source cluster");

if (is_file_present(datadir_target, "backup_label"))
pg_fatal("The backup_label file is present in target cluster");

/* Check system_identifier match */
if (ControlFile_target.system_identifier != ControlFile_source.system_identifier)
Expand Down
5 changes: 5 additions & 0 deletions src/bin/pg_rewind/rewind_source.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@

typedef struct rewind_source
{
/*
* Check if a file is present. Return true if present, false otherwise.
*/
bool (*is_file_present) (struct rewind_source *, const char *path);

/*
* Traverse all files in the source data directory, and call 'callback' on
* each file.
Expand Down
46 changes: 43 additions & 3 deletions src/bin/pg_rewind/t/001_basic.pl
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,54 @@ sub run_test
standby_psql(
"INSERT INTO space_tbl VALUES ('in standby, after promotion')");

my $primary_pgdata = $node_primary->data_dir;
my $standby_pgdata = $node_standby->data_dir;

# Create mock backup_label in both standby and primary
# and ensure pg rewind errors
$node_primary->create_mock_backup_label;
$node_standby->create_mock_backup_label;
command_fails(
[
'pg_rewind', '--debug',
'--source-pgdata', $standby_pgdata,
'--target-pgdata', $primary_pgdata,
'--no-sync', '--dry-run'
],
'pg_rewind with unexpected backup_label on primary & standby');

# Remove the backup file in primary and check if pg_rewind
# errors because of the backup label in standby.
$node_primary->rm_mock_backup_label;
command_fails(
[
'pg_rewind', '--debug',
'--source-pgdata', $standby_pgdata,
'--target-pgdata', $primary_pgdata,
'--no-sync', '--dry-run'
],
'pg_rewind with unexpected backup_label on standby');
$node_standby->rm_mock_backup_label;

# Add back the primary backup_file and confirm the pg_rewind
# does not start.
$node_primary->create_mock_backup_label;
command_fails(
[
'pg_rewind', '--debug',
'--source-pgdata', $standby_pgdata,
'--target-pgdata', $primary_pgdata,
'--no-sync', '--dry-run'
],
'pg_rewind with unexpected backup_label on primary');
$node_primary->rm_mock_backup_label;

# Before running pg_rewind, do a couple of extra tests with several
# option combinations. As the code paths taken by those tests
# do not change for the "local" and "remote" modes, just run them
# in "local" mode for simplicity's sake.
if ($test_mode eq 'local')
{
my $primary_pgdata = $node_primary->data_dir;
my $standby_pgdata = $node_standby->data_dir;

# First check that pg_rewind fails if the target cluster is
# not stopped as it fails to start up for the forced recovery
Expand Down Expand Up @@ -141,7 +181,7 @@ sub run_test
# with --dry-run mode. If anything gets generated in the data
# folder, the follow-up run of pg_rewind will most likely fail,
# so keep this test as the last one of this subset.
$node_standby->stop;
$node_standby->stop;
command_ok(
[
'pg_rewind', '--debug',
Expand Down
31 changes: 31 additions & 0 deletions src/test/perl/PostgreSQL/Test/Cluster.pm
Original file line number Diff line number Diff line change
Expand Up @@ -3090,6 +3090,37 @@ sub pg_recvlogical_upto

=pod

=item $node->create_mock_backup_label(self)

Create a mock backup_label file to simulate a real life scenario
where pg_rewind is attempted on a cluster with backup_label.

=cut

sub create_mock_backup_label
{
my ($self) = @_;
my $label_file = $self->data_dir . "/backup_label";
system("touch $label_file")
}

=pod

=item $node->create_mock_backup_label(self)

Remove the mock backup_label file from the cluster.

=cut

sub rm_mock_backup_label
{
my ($self) = @_;
my $label_file = $self->data_dir . "/backup_label";
unlink($label_file)
}

=pod

=item $node->corrupt_page_checksum(self, file, page_offset)

Intentionally corrupt the checksum field of one page in a file.
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy