You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2026-05-22 10:15:16 +02:00
Retry reads of pg_control until checksum is valid.
On certain file systems (e.g. ext4) pg_control may appear torn if there is a concurrent write while reading the file. To prevent an invalid read, retry until the checksum matches the control data. Special handling is required for the pg-version-force feature since the offset of the checksum is not known. In this case, scan from the default position to the end of the data looking for a checksum match. This is a bit imprecise, but better than nothing, and the chance of a random collision in the control data seems very remote considering the ratio of data size (< 512 bytes) to checksum size (4 bytes). This was discovered and a possible solution proposed for PostgreSQL in [1]. The proposed solution may work for backup, but pgBackRest needs to be able to read pg_control reliably outside of backup. So no matter what fix is adopted for PostgreSQL, pgBackRest need retries. Further adjustment may be required as the PostgreSQL fix evolves. [1] https://www.postgresql.org/message-id/20221123014224.xisi44byq3cf5psi%40awork3.anarazel.de
This commit is contained in:
@@ -271,48 +271,6 @@ sub dbCatalogVersion
|
||||
return $hCatalogVersion->{$strPgVersion};
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Get database control version for the db version
|
||||
####################################################################################################################################
|
||||
sub dbControlVersion
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strPgVersion,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->dbControlVersion', \@_,
|
||||
{name => 'strPgVersion', trace => true},
|
||||
);
|
||||
|
||||
my $hControlVersion =
|
||||
{
|
||||
&PG_VERSION_93 => 937,
|
||||
&PG_VERSION_94 => 942,
|
||||
&PG_VERSION_95 => 942,
|
||||
&PG_VERSION_96 => 960,
|
||||
&PG_VERSION_10 => 1002,
|
||||
&PG_VERSION_11 => 1100,
|
||||
&PG_VERSION_12 => 1201,
|
||||
&PG_VERSION_13 => 1300,
|
||||
&PG_VERSION_14 => 1300,
|
||||
&PG_VERSION_15 => 1300,
|
||||
&PG_VERSION_16 => 1300,
|
||||
};
|
||||
|
||||
if (!defined($hControlVersion->{$strPgVersion}))
|
||||
{
|
||||
confess &log(ASSERT, "no control version defined for pg version ${strPgVersion}");
|
||||
}
|
||||
|
||||
return $hControlVersion->{$strPgVersion};
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Generate control file content
|
||||
####################################################################################################################################
|
||||
@@ -332,48 +290,97 @@ sub controlGenerateContent
|
||||
{name => 'strPgVersion', trace => true},
|
||||
);
|
||||
|
||||
my $tControlContent = pack('Q', $self->dbSysId($strPgVersion));
|
||||
$tControlContent .= pack('L', $self->dbControlVersion($strPgVersion));
|
||||
$tControlContent .= pack('L', $self->dbCatalogVersion($strPgVersion));
|
||||
|
||||
# Offset to page size by architecture bits and version
|
||||
my $rhOffsetToPageSize =
|
||||
my $hControlContent =
|
||||
{
|
||||
32 =>
|
||||
{
|
||||
'9.3' => 180 - length($tControlContent),
|
||||
'9.4' => 188 - length($tControlContent),
|
||||
'9.5' => 200 - length($tControlContent),
|
||||
'9.6' => 200 - length($tControlContent),
|
||||
'10' => 200 - length($tControlContent),
|
||||
'11' => 192 - length($tControlContent),
|
||||
'12' => 196 - length($tControlContent),
|
||||
'13' => 196 - length($tControlContent),
|
||||
&PG_VERSION_93 =>
|
||||
"5d0064a7b3b6e00da903000009b0ff0b00000000000000000000000001000000000000000000000000000000000000000000000001000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"00000000000000000000000000200000000000000000000000000001000000000000000000000000000000000000000043d77e50",
|
||||
&PG_VERSION_94 =>
|
||||
"5e0064a7b3b6e00dae0300000b43010c00000000000000000000000001000000000000000000000000000000000000000000000001000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000002000000000000000000000000000010000000000000000000000000000000000000000" .
|
||||
"000000006b0756c8",
|
||||
&PG_VERSION_95 =>
|
||||
"5f0064a7b3b6e00dae030000a3cc020c00000000000000000000000001000000000000000000000000000000000000000000000001000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000010000000000000000" .
|
||||
"000000000000000000000000000000003bfe413a",
|
||||
&PG_VERSION_96 =>
|
||||
"600064a7b3b6e00dc0030000c34b040c00000000000000000000000001000000000000000000000000000000000000000000000001000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000010000000000000000" .
|
||||
"000000000000000000000000000000005d135da6",
|
||||
&PG_VERSION_10 =>
|
||||
"640064a7b3b6e00dea030000cbce050c00000000000000000000000001000000000000000000000000000000000000000000000001000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000010000000000000000" .
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8556c34",
|
||||
},
|
||||
|
||||
64 =>
|
||||
{
|
||||
'9.3' => 192 - length($tControlContent),
|
||||
'9.4' => 200 - length($tControlContent),
|
||||
'9.5' => 216 - length($tControlContent),
|
||||
'9.6' => 216 - length($tControlContent),
|
||||
'10' => 216 - length($tControlContent),
|
||||
'11' => 208 - length($tControlContent),
|
||||
'12' => 212 - length($tControlContent),
|
||||
'13' => 212 - length($tControlContent),
|
||||
&PG_VERSION_93 =>
|
||||
"5d0064a7b3b6e00da903000009b0ff0b00000000000000000000000000000000010000000000000000000000000000000000000000000000" .
|
||||
"0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000020000000000000000000000000000100000000000000000000000000000000" .
|
||||
"0000000003fff8cc",
|
||||
&PG_VERSION_94 =>
|
||||
"5e0064a7b3b6e00dae0300000b43010c00000000000000000000000000000000010000000000000000000000000000000000000000000000" .
|
||||
"0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000010000000000000000" .
|
||||
"00000000000000000000000000000000ee6cf996",
|
||||
&PG_VERSION_95 =>
|
||||
"5f0064a7b3b6e00dae030000a3cc020c00000000000000000000000000000000010000000000000000000000000000000000000000000000" .
|
||||
"0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000" .
|
||||
"0000000000000001000000000000000000000000000000000000000000000000381ec2de",
|
||||
&PG_VERSION_96 =>
|
||||
"600064a7b3b6e00dc0030000c34b040c00000000000000000000000000000000010000000000000000000000000000000000000000000000" .
|
||||
"0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000" .
|
||||
"00000000000000010000000000000000000000000000000000000000000000002d96a4c0",
|
||||
&PG_VERSION_10 =>
|
||||
"640064a7b3b6e00dea030000cbce050c00000000000000000000000000000000010000000000000000000000000000000000000000000000" .
|
||||
"0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000" .
|
||||
"0000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" .
|
||||
"00000000000000008d543cdf",
|
||||
},
|
||||
};
|
||||
|
||||
# Fill up to page size and set page size
|
||||
$tControlContent .= ('C' x $rhOffsetToPageSize->{$self->archBits()}{$strPgVersion});
|
||||
$tControlContent .= pack('L', 8192);
|
||||
my $strControlContent = $hControlContent->{$self->archBits()}{$strPgVersion};
|
||||
|
||||
if (!defined($strControlContent))
|
||||
{
|
||||
confess &log(ASSERT, "no control content defined for pg version ${strPgVersion}");
|
||||
}
|
||||
|
||||
my $tControlContent = '';
|
||||
|
||||
for (my $iIdx = 0; $iIdx < length($strControlContent) / 2; $iIdx++)
|
||||
{
|
||||
my $iChar = hex(substr($strControlContent, $iIdx * 2, 2));
|
||||
$tControlContent .= pack('C', $iChar);
|
||||
}
|
||||
|
||||
# Fill up to wal segment size and set wal segment size
|
||||
$tControlContent .= ('C' x 8);
|
||||
$tControlContent .= pack('L', 16 * 1024 * 1024);
|
||||
|
||||
# Pad bytes
|
||||
$tControlContent .= ('C' x (8192 - length($tControlContent)));
|
||||
for (my $iIdx = length($tControlContent); $iIdx < 8192; $iIdx++)
|
||||
{
|
||||
$tControlContent .= pack('C', 0);
|
||||
}
|
||||
|
||||
return \$tControlContent;
|
||||
}
|
||||
|
||||
@@ -372,7 +372,7 @@ sub run
|
||||
|
||||
$oHostDbPrimary->manifestFileCreate(
|
||||
\%oManifest, MANIFEST_TARGET_PGDATA, DB_FILE_PGCONTROL, '[replaceme]',
|
||||
$self->archBits() == 32 ? '8107e546c59c72a8c1818fc3610d7cc1e5623660' : '4c77c900f7af0d9ab13fa9982051a42e0b637f6c',
|
||||
$self->archBits() == 32 ? '59331420592064afff045f352de3a1ce53b0dd21' : 'e8bd9ef18a0b58f89aed7e98a1c32119f03727ee',
|
||||
$lTime - 100, undef, true);
|
||||
|
||||
# Copy pg_control
|
||||
|
||||
Reference in New Issue
Block a user