mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-14 10:13:05 +02:00
d038b9a029
PostgreSQL 11 introduces configurable WAL segment sizes, from 1MB to 1GB. There are two areas that needed to be updated to support this: building the archive-get queue and checking that WAL has been archived after a backup. Both operations require the WAL segment size to properly build a list. Checking the archive after a backup is still implemented in Perl and has an active database connection, so just get the WAL segment size from the database. The archive-get command does not have a connection to the database, so get the WAL segment size from pg_control instead. This requires a deeper inspection of pg_control than has been done in the past, so it seemed best to copy the relevant data structures from each version of PostgreSQL and build a generic interface layer to address them. While this approach is a bit verbose, it has the advantage of being relatively simple, and can easily be updated for new versions of PostgreSQL. Since the integration tests generate pg_control files for testing, teach Perl how to generate files with the correct offsets for both 32-bit and 64-bit architectures.
692 lines
33 KiB
Perl
692 lines
33 KiB
Perl
####################################################################################################################################
|
|
# Tests for Backup File module
|
|
####################################################################################################################################
|
|
package pgBackRestTest::Module::Backup::BackupFileUnitPerlTest;
|
|
use parent 'pgBackRestTest::Env::HostEnvTest';
|
|
|
|
####################################################################################################################################
|
|
# Perl includes
|
|
####################################################################################################################################
|
|
use strict;
|
|
use warnings FATAL => qw(all);
|
|
use Carp qw(confess);
|
|
|
|
use File::Basename qw(dirname);
|
|
use Storable qw(dclone);
|
|
|
|
use pgBackRest::Backup::File;
|
|
use pgBackRest::Common::Exception;
|
|
use pgBackRest::Common::Ini;
|
|
use pgBackRest::Common::Log;
|
|
use pgBackRest::Common::String;
|
|
use pgBackRest::Common::Wait;
|
|
use pgBackRest::Config::Config;
|
|
use pgBackRest::DbVersion;
|
|
use pgBackRest::Manifest;
|
|
use pgBackRest::Protocol::Helper;
|
|
use pgBackRest::Protocol::Storage::Helper;
|
|
use pgBackRest::Storage::Helper;
|
|
|
|
use pgBackRestTest::Common::ExecuteTest;
|
|
use pgBackRestTest::Common::RunTest;
|
|
use pgBackRestTest::Env::Host::HostBackupTest;
|
|
|
|
####################################################################################################################################
|
|
# initModule
|
|
####################################################################################################################################
|
|
sub initModule
|
|
{
|
|
my $self = shift;
|
|
|
|
$self->{strDbPath} = $self->testPath() . '/db';
|
|
$self->{strRepoPath} = $self->testPath() . '/repo';
|
|
$self->{strBackupPath} = "$self->{strRepoPath}/backup/" . $self->stanza();
|
|
$self->{strPgControl} = $self->{strDbPath} . '/' . DB_FILE_PGCONTROL;
|
|
|
|
# Create backup path
|
|
storageTest()->pathCreate($self->{strBackupPath}, {bIgnoreExists => true, bCreateParent => true});
|
|
|
|
# Generate pg_control file
|
|
storageTest()->pathCreate($self->{strDbPath} . '/' . DB_PATH_GLOBAL, {bCreateParent => true});
|
|
$self->controlGenerate($self->{strDbPath}, PG_VERSION_94);
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# run
|
|
####################################################################################################################################
|
|
sub run
|
|
{
|
|
my $self = shift;
|
|
|
|
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
|
|
$self->optionTestSet(CFGOPT_PG_PATH, $self->{strDbPath});
|
|
$self->optionTestSet(CFGOPT_REPO_PATH, $self->{strRepoPath});
|
|
$self->optionTestSet(CFGOPT_LOG_PATH, $self->testPath());
|
|
|
|
$self->optionTestSetBool(CFGOPT_ONLINE, false);
|
|
|
|
$self->optionTestSet(CFGOPT_DB_TIMEOUT, 5);
|
|
$self->optionTestSet(CFGOPT_PROTOCOL_TIMEOUT, 6);
|
|
$self->optionTestSet(CFGOPT_COMPRESS_LEVEL, 3);
|
|
|
|
$self->configTestLoad(CFGCMD_BACKUP);
|
|
|
|
# Repo
|
|
my $strRepoBackupPath = storageRepo()->pathGet(STORAGE_REPO_BACKUP);
|
|
my $strBackupLabel = "20180724-182750F";
|
|
|
|
# File
|
|
my $strFileName = "12345";
|
|
my $strFileDb = $self->{strDbPath} . "/$strFileName";
|
|
my $strFileHash = '1c7e00fd09b9dd11fc2966590b3e3274645dd031';
|
|
my $strFileRepo = storageRepo()->pathGet(
|
|
STORAGE_REPO_BACKUP . "/$strBackupLabel/" . MANIFEST_TARGET_PGDATA . "/$strFileName");
|
|
my $strRepoFile = MANIFEST_TARGET_PGDATA . "/$strFileName";
|
|
my $strRepoPgControl = MANIFEST_FILE_PGCONTROL;
|
|
my $strPgControlRepo = storageRepo()->pathGet(STORAGE_REPO_BACKUP . "/$strBackupLabel/$strRepoPgControl");
|
|
my $strPgControlHash =
|
|
$self->archBits() == 32 ? '8107e546c59c72a8c1818fc3610d7cc1e5623660' : '4c77c900f7af0d9ab13fa9982051a42e0b637f6c';
|
|
|
|
# Copy file to db path
|
|
executeTest('cp ' . $self->dataPath() . "/filecopy.archive2.bin ${strFileDb}");
|
|
|
|
# Get size and data info for the files in the db path
|
|
my $hManifest = storageDb()->manifest($self->{strDbPath});
|
|
my $lFileSize = $hManifest->{$strFileName}{size} + 0;
|
|
my $lFileTime = $hManifest->{$strFileName}{modification_time} + 0;
|
|
my $lPgControlSize = $hManifest->{&DB_FILE_PGCONTROL}{size} + 0;
|
|
my $lPgControlTime = $hManifest->{&DB_FILE_PGCONTROL}{modification_time} + 0;
|
|
|
|
my $lRepoFileCompressSize = 3646899;
|
|
|
|
my $strBackupPath = $self->{strBackupPath} . "/$strBackupLabel";
|
|
my $strHost = "host";
|
|
my $iLocalId = 1;
|
|
|
|
# Initialize the manifest
|
|
my $oBackupManifest = new pgBackRest::Manifest("$strBackupPath/" . FILE_MANIFEST,
|
|
{bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => 201409291});
|
|
$oBackupManifest->build(storageDb(), $self->{strDbPath}, undef, true, false);
|
|
|
|
# Set the initial size values for backupManifestUpdate - running size and size for when to save the file
|
|
my $lSizeCurrent = 0;
|
|
my $lSizeTotal = 16785408;
|
|
my $lManifestSaveCurrent = 0;
|
|
my $lManifestSaveSize = int($lSizeTotal / 100);
|
|
|
|
# Result variables
|
|
my $iResultCopyResult;
|
|
my $lResultCopySize;
|
|
my $lResultRepoSize;
|
|
my $strResultCopyChecksum;
|
|
my $rResultExtra;
|
|
|
|
################################################################################################################################
|
|
if ($self->begin('backupFile(), backupManifestUpdate()'))
|
|
{
|
|
#---------------------------------------------------------------------------------------------------------------------------
|
|
# Copy pg_control and confirm manifestUpdate does not save the manifest yet
|
|
($iResultCopyResult, $lResultCopySize, $lResultRepoSize, $strResultCopyChecksum, $rResultExtra) =
|
|
backupFile($self->{strPgControl}, MANIFEST_FILE_PGCONTROL, $lPgControlSize, undef, false, $strBackupLabel, false,
|
|
cfgOption(CFGOPT_COMPRESS_LEVEL), $lPgControlTime, true, undef, false, false, undef);
|
|
|
|
$self->testResult(sub {storageTest()->exists($strPgControlRepo)}, true, 'pg_control file exists in repo');
|
|
|
|
$self->testResult(($iResultCopyResult == BACKUP_FILE_COPY && $strResultCopyChecksum eq $strPgControlHash &&
|
|
$lResultCopySize == $lPgControlSize && $lResultRepoSize == $lPgControlSize), true,
|
|
'pg_control file copied to repo successfully');
|
|
|
|
($lSizeCurrent, $lManifestSaveCurrent) = backupManifestUpdate(
|
|
$oBackupManifest,
|
|
$strHost,
|
|
$iLocalId,
|
|
$self->{strPgControl},
|
|
$strRepoPgControl,
|
|
$lPgControlSize,
|
|
undef,
|
|
false,
|
|
$iResultCopyResult,
|
|
$lResultCopySize,
|
|
$lResultRepoSize,
|
|
$strResultCopyChecksum,
|
|
$rResultExtra,
|
|
$lSizeTotal,
|
|
$lSizeCurrent,
|
|
$lManifestSaveSize,
|
|
$lManifestSaveCurrent);
|
|
|
|
# Accumulators should be same size as pg_control
|
|
$self->testResult(($lSizeCurrent == $lPgControlSize && $lManifestSaveCurrent == $lPgControlSize), true,
|
|
"file size in repo and repo size equal pg_control size");
|
|
|
|
$self->testResult(sub {$oBackupManifest->test(MANIFEST_SECTION_TARGET_FILE, MANIFEST_FILE_PGCONTROL,
|
|
MANIFEST_SUBKEY_CHECKSUM, $strPgControlHash)}, true, "manifest updated for pg_control");
|
|
|
|
# Neither backup.manifest nor backup.manifest.copy written because size threshold not met
|
|
$self->testException(sub {storageRepo()->openRead("$strBackupPath/" . FILE_MANIFEST . INI_COPY_EXT)}, ERROR_FILE_MISSING,
|
|
"unable to open '$strBackupPath/" . FILE_MANIFEST . INI_COPY_EXT . "': No such file or directory");
|
|
$self->testException(sub {storageRepo()->openRead("$strBackupPath/" . FILE_MANIFEST)}, ERROR_FILE_MISSING,
|
|
"unable to open '$strBackupPath/" . FILE_MANIFEST . "': No such file or directory");
|
|
|
|
#---------------------------------------------------------------------------------------------------------------------------
|
|
# No prior checksum, no compression, no page checksum, no extra, no delta, no hasReference
|
|
($iResultCopyResult, $lResultCopySize, $lResultRepoSize, $strResultCopyChecksum, $rResultExtra) =
|
|
backupFile($strFileDb, $strRepoFile, $lFileSize, undef, false, $strBackupLabel, false,
|
|
cfgOption(CFGOPT_COMPRESS_LEVEL), $lFileTime, true, undef, false, false, undef);
|
|
|
|
$self->testResult(sub {storageTest()->exists($strFileRepo)}, true, 'non-compressed file exists in repo');
|
|
|
|
$self->testResult(($iResultCopyResult == BACKUP_FILE_COPY && $strResultCopyChecksum eq $strFileHash &&
|
|
$lResultCopySize == $lFileSize && $lResultRepoSize == $lFileSize), true,
|
|
'file copied to repo successfully');
|
|
|
|
$self->testException(sub {storageRepo()->openRead("$strFileRepo.gz")}, ERROR_FILE_MISSING,
|
|
"unable to open '$strFileRepo.gz': No such file or directory");
|
|
|
|
($lSizeCurrent, $lManifestSaveCurrent) = backupManifestUpdate(
|
|
$oBackupManifest,
|
|
$strHost,
|
|
$iLocalId,
|
|
$strFileDb,
|
|
$strRepoFile,
|
|
$lFileSize,
|
|
$strFileHash,
|
|
false,
|
|
$iResultCopyResult,
|
|
$lResultCopySize,
|
|
$lResultRepoSize,
|
|
$strResultCopyChecksum,
|
|
$rResultExtra,
|
|
$lSizeTotal,
|
|
$lSizeCurrent,
|
|
$lManifestSaveSize,
|
|
$lManifestSaveCurrent);
|
|
|
|
# Accumulator includes size of pg_control and file. Manifest saved so ManifestSaveCurrent returns to 0
|
|
$self->testResult(($lSizeCurrent == ($lPgControlSize + $lFileSize) && $lManifestSaveCurrent == 0), true,
|
|
"repo size increased and ManifestSaveCurrent returns to 0");
|
|
|
|
$self->testResult(sub {$oBackupManifest->test(MANIFEST_SECTION_TARGET_FILE, $strRepoFile,
|
|
MANIFEST_SUBKEY_CHECKSUM, $strFileHash)}, true, "manifest updated for $strRepoFile");
|
|
|
|
# Backup.manifest not written but backup.manifest.copy written because size threshold met
|
|
$self->testResult(sub {storageTest()->exists("$strBackupPath/" . FILE_MANIFEST . INI_COPY_EXT)}, true,
|
|
'backup.manifest.copy exists in repo');
|
|
$self->testException(sub {storageRepo()->openRead("$strBackupPath/" . FILE_MANIFEST)}, ERROR_FILE_MISSING,
|
|
"unable to open '$strBackupPath/" . FILE_MANIFEST . "': No such file or directory");
|
|
|
|
storageTest()->remove($strFileRepo);
|
|
storageTest()->remove($strPgControlRepo);
|
|
|
|
#---------------------------------------------------------------------------------------------------------------------------
|
|
# No prior checksum, yes compression, yes page checksum, no extra, no delta, no hasReference
|
|
$self->testException(sub {backupFile($strFileDb, $strRepoFile, $lFileSize, undef, true,
|
|
$strBackupLabel, true, cfgOption(CFGOPT_COMPRESS_LEVEL), $lFileTime, true, undef, false, false, undef)}, ERROR_ASSERT,
|
|
"iWalId is required in Backup::Filter::PageChecksum->new");
|
|
|
|
# Build the lsn start parameter to pass to the extra function
|
|
my $hStartLsnParam =
|
|
{
|
|
iWalId => 0xFFFF,
|
|
iWalOffset => 0xFFFF,
|
|
};
|
|
|
|
#---------------------------------------------------------------------------------------------------------------------------
|
|
# No prior checksum, yes compression, yes page checksum, yes extra, no delta, no hasReference
|
|
($iResultCopyResult, $lResultCopySize, $lResultRepoSize, $strResultCopyChecksum, $rResultExtra) =
|
|
backupFile($strFileDb, $strRepoFile, $lFileSize, undef, true, $strBackupLabel, true,
|
|
cfgOption(CFGOPT_COMPRESS_LEVEL), $lFileTime, true, $hStartLsnParam, false, false, undef);
|
|
|
|
$self->testResult(sub {storageTest()->exists("$strFileRepo.gz")}, true, 'compressed file exists in repo');
|
|
|
|
$self->testResult(($iResultCopyResult == BACKUP_FILE_COPY && $strResultCopyChecksum eq $strFileHash &&
|
|
$lResultRepoSize == $lRepoFileCompressSize && $rResultExtra->{bValid}), true, 'file copied to repo successfully');
|
|
|
|
# Only the compressed version of the file exists
|
|
$self->testException(sub {storageRepo()->openRead("$strFileRepo")}, ERROR_FILE_MISSING,
|
|
"unable to open '$strFileRepo': No such file or directory");
|
|
|
|
($lSizeCurrent, $lManifestSaveCurrent) = backupManifestUpdate(
|
|
$oBackupManifest,
|
|
$strHost,
|
|
$iLocalId,
|
|
$strFileDb,
|
|
$strRepoFile,
|
|
$lFileSize,
|
|
$strFileHash,
|
|
true,
|
|
$iResultCopyResult,
|
|
$lResultCopySize,
|
|
$lResultRepoSize,
|
|
$strResultCopyChecksum,
|
|
$rResultExtra,
|
|
$lSizeTotal,
|
|
$lSizeCurrent,
|
|
$lManifestSaveSize,
|
|
$lManifestSaveCurrent);
|
|
|
|
# File is compressed in repo so make sure repo-size added to manifest
|
|
$self->testResult(sub {$oBackupManifest->test(
|
|
MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_REPO_SIZE, $lResultRepoSize)},
|
|
true, "repo-size set");
|
|
$self->testResult(sub {$oBackupManifest->test(
|
|
MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_CHECKSUM_PAGE, $rResultExtra->{bValid})},
|
|
true, "checksum page set");
|
|
|
|
# Save the compressed file for later test
|
|
executeTest('mv ' . "$strFileRepo.gz $strFileRepo.gz.SAVE");
|
|
|
|
#---------------------------------------------------------------------------------------------------------------------------
|
|
# Add a segment number for bChecksumPage code coverage
|
|
executeTest('cp ' . "$strFileDb $strFileDb.1");
|
|
|
|
# No prior checksum, no compression, yes page checksum, yes extra, no delta, no hasReference
|
|
($iResultCopyResult, $lResultCopySize, $lResultRepoSize, $strResultCopyChecksum, $rResultExtra) =
|
|
backupFile("$strFileDb.1", "$strRepoFile.1", $lFileSize, undef, true, $strBackupLabel, false,
|
|
cfgOption(CFGOPT_COMPRESS_LEVEL), $lFileTime, true, $hStartLsnParam, false, false, undef);
|
|
|
|
$self->testResult(sub {storageTest()->exists("$strFileRepo.1")}, true, 'non-compressed segment file exists in repo');
|
|
|
|
$self->testResult(($iResultCopyResult == BACKUP_FILE_COPY && $strResultCopyChecksum eq $strFileHash &&
|
|
$lResultRepoSize == $lFileSize && $rResultExtra->{bValid}), true, 'segment file copied to repo successfully');
|
|
|
|
# Set a section in the manifest to ensure it is removed in the next test
|
|
$oBackupManifest->set(
|
|
MANIFEST_SECTION_TARGET_FILE, "$strRepoFile.1", MANIFEST_SUBKEY_CHECKSUM, $strResultCopyChecksum);
|
|
|
|
$self->testResult(sub {$oBackupManifest->test(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . "/$strFileName.1")},
|
|
true, MANIFEST_TARGET_PGDATA . "/$strFileName.1 section exists in manifest");
|
|
|
|
#---------------------------------------------------------------------------------------------------------------------------
|
|
# Remove the db file and try to back it up
|
|
storageTest()->remove("$strFileDb.1");
|
|
|
|
# No prior checksum, no compression, no page checksum, no extra, No delta, no hasReference, no db file
|
|
($iResultCopyResult, $lResultCopySize, $lResultRepoSize, $strResultCopyChecksum, $rResultExtra) =
|
|
backupFile("$strFileDb.1", "$strRepoFile.1", $lFileSize, undef, false, $strBackupLabel,
|
|
false, cfgOption(CFGOPT_COMPRESS_LEVEL), $lFileTime, true, undef, false, false, undef);
|
|
|
|
$self->testResult(($iResultCopyResult == BACKUP_FILE_SKIP && !defined($strResultCopyChecksum) &&
|
|
!defined($lResultRepoSize) && !defined($lResultCopySize)), true, "db file missing - $strRepoFile.1 file skipped");
|
|
|
|
# Delta not set so file still exists in repo
|
|
$self->testResult(sub {storageTest()->exists("$strFileRepo.1")}, true, ' delta not set - file exists in repo');
|
|
|
|
($lSizeCurrent, $lManifestSaveCurrent) = backupManifestUpdate(
|
|
$oBackupManifest,
|
|
$strHost,
|
|
$iLocalId,
|
|
"$strFileDb.1",
|
|
"$strRepoFile.1",
|
|
$lFileSize,
|
|
$strFileHash,
|
|
false,
|
|
$iResultCopyResult,
|
|
$lResultCopySize,
|
|
$lResultRepoSize,
|
|
$strResultCopyChecksum,
|
|
$rResultExtra,
|
|
$lSizeTotal,
|
|
$lSizeCurrent,
|
|
$lManifestSaveSize,
|
|
$lManifestSaveCurrent);
|
|
|
|
$self->testResult(sub {$oBackupManifest->test(MANIFEST_SECTION_TARGET_FILE, "$strRepoFile.1")},
|
|
false, " $strRepoFile.1 section removed from manifest");
|
|
|
|
# Yes prior checksum, no compression, no page checksum, no extra, yes delta, no hasReference, no db file
|
|
($iResultCopyResult, $lResultCopySize, $lResultRepoSize, $strResultCopyChecksum, $rResultExtra) =
|
|
backupFile("$strFileDb.1", MANIFEST_TARGET_PGDATA . "/$strFileName.1", $lFileSize, $strFileHash, false, $strBackupLabel,
|
|
false, cfgOption(CFGOPT_COMPRESS_LEVEL), $lFileTime, true, undef, true, false, undef);
|
|
|
|
$self->testResult(($iResultCopyResult == BACKUP_FILE_SKIP && !defined($strResultCopyChecksum) &&
|
|
!defined($lResultRepoSize)), true, "db file missing - delta $strRepoFile.1 file skipped");
|
|
|
|
$self->testResult(sub {storageTest()->exists("$strFileRepo.1")}, false, ' delta set - file removed from repo');
|
|
|
|
# Code path for host not defined for logged message of skipped file
|
|
($lSizeCurrent, $lManifestSaveCurrent) = backupManifestUpdate(
|
|
$oBackupManifest,
|
|
undef,
|
|
$iLocalId,
|
|
"$strFileDb.1",
|
|
MANIFEST_TARGET_PGDATA . "/$strFileName.1",
|
|
$lFileSize,
|
|
$strFileHash,
|
|
false,
|
|
$iResultCopyResult,
|
|
$lResultCopySize,
|
|
$lResultRepoSize,
|
|
$strResultCopyChecksum,
|
|
$rResultExtra,
|
|
$lSizeTotal,
|
|
$lSizeCurrent,
|
|
$lManifestSaveSize,
|
|
$lManifestSaveCurrent);
|
|
|
|
# Yes prior checksum, no compression, no page checksum, no extra, yes delta, no hasReference, no db file,
|
|
# do not ignoreMissing
|
|
$self->testException(sub {backupFile("$strFileDb.1", "$strRepoFile.1", $lFileSize, $strFileHash,
|
|
false, $strBackupLabel, false, cfgOption(CFGOPT_COMPRESS_LEVEL), $lFileTime, false, undef, true, false, undef)},
|
|
ERROR_FILE_MISSING, "unable to open '$strFileDb.1': No such file or directory");
|
|
|
|
#---------------------------------------------------------------------------------------------------------------------------
|
|
# Restore the compressed file
|
|
executeTest('mv ' . "$strFileRepo.gz.SAVE $strFileRepo.gz");
|
|
|
|
# Yes prior checksum, yes compression, no page checksum, no extra, yes delta, no hasReference
|
|
($iResultCopyResult, $lResultCopySize, $lResultRepoSize, $strResultCopyChecksum, $rResultExtra) =
|
|
backupFile($strFileDb, $strRepoFile, $lFileSize, $strFileHash, false, $strBackupLabel,
|
|
true, cfgOption(CFGOPT_COMPRESS_LEVEL), $lFileTime, true, undef, true, false, undef);
|
|
|
|
$self->testResult(($iResultCopyResult == BACKUP_FILE_CHECKSUM && $strResultCopyChecksum eq $strFileHash &&
|
|
$lResultCopySize == $lFileSize), true, 'db checksum and repo same - no copy file');
|
|
|
|
#---------------------------------------------------------------------------------------------------------------------------
|
|
# DB Checksum mismatch
|
|
storageTest()->remove("$strFileRepo", {bIgnoreMissing => true});
|
|
# Save the compressed file for later test
|
|
executeTest('mv ' . "$strFileRepo.gz $strFileRepo.gz.SAVE");
|
|
|
|
# Yes prior checksum, no compression, no page checksum, no extra, yes delta, no hasReference
|
|
($iResultCopyResult, $lResultCopySize, $lResultRepoSize, $strResultCopyChecksum, $rResultExtra) =
|
|
backupFile($strFileDb, $strRepoFile, $lFileSize, $strFileHash . "ff", false,
|
|
$strBackupLabel, false, cfgOption(CFGOPT_COMPRESS_LEVEL), $lFileTime, true, undef, true, false, undef);
|
|
|
|
$self->testResult(($iResultCopyResult == BACKUP_FILE_COPY && $strResultCopyChecksum eq $strFileHash &&
|
|
$lResultCopySize == $lFileSize && $lResultRepoSize == $lFileSize), true, 'db checksum mismatch - copy file');
|
|
|
|
#---------------------------------------------------------------------------------------------------------------------------
|
|
# DB file size mismatch
|
|
# Yes prior checksum, no compression, no page checksum, no extra, yes delta, no hasReference
|
|
($iResultCopyResult, $lResultCopySize, $lResultRepoSize, $strResultCopyChecksum, $rResultExtra) =
|
|
backupFile($strFileDb, $strRepoFile, $lFileSize + 1, $strFileHash, false, $strBackupLabel, false,
|
|
cfgOption(CFGOPT_COMPRESS_LEVEL), $lFileTime, true, undef, true, false, undef);
|
|
|
|
$self->testResult(($iResultCopyResult == BACKUP_FILE_COPY && $strResultCopyChecksum eq $strFileHash &&
|
|
$lResultCopySize == $lFileSize && $lResultRepoSize == $lFileSize), true, 'db file size mismatch - copy file');
|
|
|
|
#---------------------------------------------------------------------------------------------------------------------------
|
|
# Repo mismatch
|
|
|
|
# Restore the compressed file as if non-compressed so checksum won't match
|
|
executeTest('cp ' . "$strFileRepo.gz.SAVE $strFileRepo");
|
|
|
|
# Yes prior checksum, no compression, no page checksum, no extra, yes delta, no hasReference
|
|
($iResultCopyResult, $lResultCopySize, $lResultRepoSize, $strResultCopyChecksum, $rResultExtra) =
|
|
backupFile($strFileDb, $strRepoFile, $lFileSize, $strFileHash, false, $strBackupLabel, false,
|
|
cfgOption(CFGOPT_COMPRESS_LEVEL), $lFileTime, true, undef, true, false, undef);
|
|
|
|
$self->testResult(($iResultCopyResult == BACKUP_FILE_RECOPY && $strResultCopyChecksum eq $strFileHash &&
|
|
$lResultCopySize == $lFileSize && $lResultRepoSize == $lFileSize), true, 'repo checksum mismatch - recopy file');
|
|
|
|
# Restore the compressed file
|
|
executeTest('mv ' . "$strFileRepo.gz.SAVE $strFileRepo.gz");
|
|
|
|
# Yes prior checksum, yes compression, no page checksum, no extra, no delta, no hasReference
|
|
($iResultCopyResult, $lResultCopySize, $lResultRepoSize, $strResultCopyChecksum, $rResultExtra) =
|
|
backupFile($strFileDb, $strRepoFile, $lFileSize + 1, $strFileHash, false,
|
|
$strBackupLabel, true, cfgOption(CFGOPT_COMPRESS_LEVEL), $lFileTime, true, undef, false, false, undef);
|
|
|
|
$self->testResult(($iResultCopyResult == BACKUP_FILE_RECOPY && $strResultCopyChecksum eq $strFileHash &&
|
|
$lResultCopySize == $lFileSize), true, 'repo size mismatch - recopy file');
|
|
|
|
#---------------------------------------------------------------------------------------------------------------------------
|
|
# Has reference
|
|
# Set a reference in the manifest to ensure it is removed after backupManifestUpdate
|
|
$oBackupManifest->set(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_REFERENCE, BOGUS);
|
|
|
|
$self->testResult(sub {$oBackupManifest->test(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_REFERENCE,
|
|
BOGUS)}, true, "$strRepoFile reference section exists in manifest");
|
|
|
|
# Yes prior checksum, no compression, no page checksum, no extra, yes delta, yes hasReference
|
|
($iResultCopyResult, $lResultCopySize, $lResultRepoSize, $strResultCopyChecksum, $rResultExtra) =
|
|
backupFile($strFileDb, $strRepoFile, $lFileSize + 1, $strFileHash, false,
|
|
$strBackupLabel, false, cfgOption(CFGOPT_COMPRESS_LEVEL), $lFileTime, true, undef, true, true, undef);
|
|
|
|
$self->testResult(($iResultCopyResult == BACKUP_FILE_COPY && $strResultCopyChecksum eq $strFileHash &&
|
|
$lResultCopySize == $lFileSize && $lResultRepoSize == $lFileSize), true, 'db file size mismatch has reference - copy');
|
|
|
|
# Code path to ensure reference is removed
|
|
($lSizeCurrent, $lManifestSaveCurrent) = backupManifestUpdate(
|
|
$oBackupManifest,
|
|
$strHost,
|
|
$iLocalId,
|
|
$strFileDb,
|
|
$strRepoFile,
|
|
$lFileSize,
|
|
$strFileHash,
|
|
false,
|
|
$iResultCopyResult,
|
|
$lResultCopySize,
|
|
$lResultRepoSize,
|
|
$strResultCopyChecksum,
|
|
$rResultExtra,
|
|
$lSizeTotal,
|
|
$lSizeCurrent,
|
|
$lManifestSaveSize,
|
|
$lManifestSaveCurrent);
|
|
|
|
# Confirm reference to prior backup removed
|
|
$self->testResult(sub {$oBackupManifest->test(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . "/$strFileName.",
|
|
MANIFEST_SUBKEY_REFERENCE)},
|
|
false, "reference to prior backup in manifest removed");
|
|
|
|
#---------------------------------------------------------------------------------------------------------------------------
|
|
# BACKUP_FILE_NOOP
|
|
# Yes prior checksum, no compression, no page checksum, no extra, yes delta, yes hasReference
|
|
($iResultCopyResult, $lResultCopySize, $lResultRepoSize, $strResultCopyChecksum, $rResultExtra) =
|
|
backupFile($strFileDb, $strRepoFile, $lFileSize, $strFileHash, false,
|
|
$strBackupLabel, false, cfgOption(CFGOPT_COMPRESS_LEVEL), $lFileTime, true, undef, true, true, undef);
|
|
|
|
$self->testResult(($iResultCopyResult == BACKUP_FILE_NOOP && $strResultCopyChecksum eq $strFileHash &&
|
|
$lResultCopySize == $lFileSize), true, 'db file same has reference - noop');
|
|
|
|
# Calculate running counts
|
|
my $lSizeCurrentAfter = $lSizeCurrent + $lFileSize;
|
|
my $lManifestSaveCurrentAfter = $lManifestSaveCurrent + $lFileSize;
|
|
|
|
# Increase manifest save size, so manifest will not be saved so counts can be tested
|
|
$lManifestSaveSize = $lFileSize * 2;
|
|
|
|
($lSizeCurrent, $lManifestSaveCurrent) = backupManifestUpdate(
|
|
$oBackupManifest,
|
|
$strHost,
|
|
$iLocalId,
|
|
$strFileDb,
|
|
$strRepoFile,
|
|
$lFileSize,
|
|
$strFileHash,
|
|
false,
|
|
$iResultCopyResult,
|
|
$lResultCopySize,
|
|
$lResultRepoSize,
|
|
$strResultCopyChecksum,
|
|
$rResultExtra,
|
|
$lSizeTotal,
|
|
$lSizeCurrent,
|
|
$lManifestSaveSize,
|
|
$lManifestSaveCurrent);
|
|
|
|
$self->testResult(($lSizeCurrent ==$lSizeCurrentAfter && $lManifestSaveCurrent == $lManifestSaveCurrentAfter),
|
|
true, ' running counts updated');
|
|
|
|
#---------------------------------------------------------------------------------------------------------------------------
|
|
# Remove file from repo. No reference so should hard error since this means sometime between the building of the manifest
|
|
# for the aborted backup, the file went missing from the aborted backup dir.
|
|
storageTest()->remove("$strFileRepo", {bIgnoreMissing => true});
|
|
|
|
$self->testException(sub {backupFile($strFileDb, $strRepoFile, $lFileSize, $strFileHash,
|
|
false, $strBackupLabel, false, cfgOption(CFGOPT_COMPRESS_LEVEL), $lFileTime, true, undef, true, false, undef)},
|
|
ERROR_FILE_MISSING, "unable to open '$strFileRepo': No such file or directory");
|
|
}
|
|
|
|
################################################################################################################################
|
|
# This section for for code coverage that is not covered in the above tests
|
|
if ($self->begin('backupManifestUpdate()'))
|
|
{
|
|
$oBackupManifest = new pgBackRest::Manifest("$strBackupPath/" . FILE_MANIFEST,
|
|
{bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => 201409291});
|
|
|
|
#---------------------------------------------------------------------------------------------------------------------------
|
|
# Check BACKUP_FILE_RECOPY warning
|
|
$iResultCopyResult = BACKUP_FILE_RECOPY;
|
|
$lResultCopySize = 0;
|
|
$lResultRepoSize = $lResultCopySize + 1;
|
|
$strResultCopyChecksum = $strFileHash;
|
|
$lSizeCurrent = 0;
|
|
$lManifestSaveSize = $lFileSize * 2;
|
|
$lManifestSaveCurrent = 0;
|
|
|
|
$self->testResult(sub {backupManifestUpdate(
|
|
$oBackupManifest,
|
|
undef,
|
|
$iLocalId,
|
|
$strFileDb,
|
|
$strRepoFile,
|
|
$lFileSize,
|
|
$strFileHash,
|
|
false,
|
|
$iResultCopyResult,
|
|
$lResultCopySize,
|
|
$lResultRepoSize,
|
|
$strResultCopyChecksum,
|
|
$rResultExtra,
|
|
$lSizeTotal,
|
|
$lSizeCurrent,
|
|
$lManifestSaveSize,
|
|
$lManifestSaveCurrent)}, "($lFileSize, $lFileSize)",
|
|
'backup file recopy warning', {strLogExpect =>
|
|
"WARN: resumed backup file $strRepoFile does not have expected checksum $strFileHash. The file will be recopied and" .
|
|
" backup will continue but this may be an issue unless the resumed backup path in the repository is known to be" .
|
|
" corrupted.\n" .
|
|
"NOTE: this does not indicate a problem with the PostgreSQL page checksums."});
|
|
|
|
# Check size code paths
|
|
$self->testResult(
|
|
$oBackupManifest->test(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_SIZE, $lResultCopySize),
|
|
true, " copy size set");
|
|
$self->testResult(
|
|
$oBackupManifest->test(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_REPO_SIZE, $lResultRepoSize),
|
|
true, " repo size set");
|
|
$self->testResult(
|
|
$oBackupManifest->test(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_CHECKSUM, $strResultCopyChecksum),
|
|
false, " checksum not set since copy size 0");
|
|
|
|
#---------------------------------------------------------------------------------------------------------------------------
|
|
# Checkum page exception
|
|
$iResultCopyResult = BACKUP_FILE_COPY;
|
|
|
|
$self->testException(sub {backupManifestUpdate(
|
|
$oBackupManifest,
|
|
$strHost,
|
|
$iLocalId,
|
|
$strFileDb,
|
|
$strRepoFile,
|
|
$lFileSize,
|
|
$strFileHash,
|
|
true,
|
|
$iResultCopyResult,
|
|
$lResultCopySize,
|
|
$lResultRepoSize,
|
|
$strResultCopyChecksum,
|
|
$rResultExtra,
|
|
$lSizeTotal,
|
|
$lSizeCurrent,
|
|
$lManifestSaveSize,
|
|
$lManifestSaveCurrent)},
|
|
ERROR_ASSERT, "$strFileDb should have calculated page checksums");
|
|
|
|
$rResultExtra->{bValid} = false;
|
|
$self->testException(sub {backupManifestUpdate(
|
|
$oBackupManifest,
|
|
$strHost,
|
|
$iLocalId,
|
|
$strFileDb,
|
|
$strRepoFile,
|
|
$lFileSize,
|
|
$strFileHash,
|
|
true,
|
|
$iResultCopyResult,
|
|
$lResultCopySize + 1,
|
|
$lResultRepoSize,
|
|
$strResultCopyChecksum,
|
|
$rResultExtra,
|
|
$lSizeTotal,
|
|
$lSizeCurrent,
|
|
$lManifestSaveSize,
|
|
$lManifestSaveCurrent)},
|
|
ERROR_ASSERT, "bAlign flag should have been set for misaligned page");
|
|
|
|
$rResultExtra->{bAlign} = true;
|
|
$self->testException(sub {backupManifestUpdate(
|
|
$oBackupManifest,
|
|
$strHost,
|
|
$iLocalId,
|
|
$strFileDb,
|
|
$strRepoFile,
|
|
$lFileSize,
|
|
$strFileHash,
|
|
true,
|
|
$iResultCopyResult,
|
|
$lResultCopySize + 1,
|
|
$lResultRepoSize,
|
|
$strResultCopyChecksum,
|
|
$rResultExtra,
|
|
$lSizeTotal,
|
|
$lSizeCurrent,
|
|
$lManifestSaveSize,
|
|
$lManifestSaveCurrent)},
|
|
ERROR_ASSERT, "bAlign flag should have been set for misaligned page");
|
|
|
|
$rResultExtra->{bAlign} = false;
|
|
$self->testResult(sub {backupManifestUpdate(
|
|
$oBackupManifest,
|
|
$strHost,
|
|
$iLocalId,
|
|
$strFileDb,
|
|
$strRepoFile,
|
|
$lFileSize,
|
|
$strFileHash,
|
|
true,
|
|
$iResultCopyResult,
|
|
$lResultCopySize + 1,
|
|
$lResultRepoSize,
|
|
$strResultCopyChecksum,
|
|
$rResultExtra,
|
|
$lSizeTotal,
|
|
$lSizeCurrent,
|
|
$lManifestSaveSize,
|
|
$lManifestSaveCurrent)},
|
|
"($lFileSize, $lFileSize)",
|
|
'page misalignment warning - host defined', {strLogExpect =>
|
|
"WARN: page misalignment in file $strHost:$strFileDb: file size " . ($lResultCopySize + 1) .
|
|
" is not divisible by page size " . PG_PAGE_SIZE});
|
|
|
|
$self->testResult(sub {backupManifestUpdate(
|
|
$oBackupManifest,
|
|
undef,
|
|
$iLocalId,
|
|
$strFileDb,
|
|
$strRepoFile,
|
|
$lFileSize,
|
|
$strFileHash,
|
|
true,
|
|
$iResultCopyResult,
|
|
$lResultCopySize + 1,
|
|
$lResultRepoSize,
|
|
$strResultCopyChecksum,
|
|
$rResultExtra,
|
|
$lSizeTotal,
|
|
$lSizeCurrent,
|
|
$lManifestSaveSize,
|
|
$lManifestSaveCurrent)},
|
|
"($lFileSize, $lFileSize)",
|
|
'page misalignment warning - host not defined', {strLogExpect =>
|
|
"WARN: page misalignment in file $strFileDb: file size " . ($lResultCopySize + 1) .
|
|
" is not divisible by page size " . PG_PAGE_SIZE});
|
|
}
|
|
}
|
|
|
|
1;
|