1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-11-06 08:49:29 +02:00

The backup command is implemented entirely in C.

For the most part this is a direct migration of the Perl code into C except as noted below.

A backup can now be initiated from a linked directory.  The link will not be stored in the manifest or recreated on restore.  If a link or directory does not already exist in the restore location then a directory will be created.

The logic for creating backup labels has been improved and it should no longer be possible to get a backup label earlier than the latest backup even with timezone changes or clock skew.  This has never been an issue in the field that we know of, but we found it in testing.

For online backups all times are fetched from the PostgreSQL primary host (before only copy start was).  This doesn't affect backup integrity but it does prevent clock skew between hosts affecting backup duration reporting.

Archive copy now works as expected when the archive and backup have different compression settings, i.e. when one is compressed and the other is not.  This was a long-standing bug in the Perl code.

Resume will now work even if hardlink settings have been changed.

Reviewed by Cynthia Shang.
This commit is contained in:
David Steele
2019-12-13 17:14:26 -05:00
parent e206093beb
commit 1f2ce45e6b
22 changed files with 4061 additions and 4864 deletions

View File

@@ -1,511 +0,0 @@
####################################################################################################################################
# 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()'))
{
#---------------------------------------------------------------------------------------------------------------------------
# Create backup path so manifest can be saved
storageRepo->pathCreate(storageRepo()->pathGet(STORAGE_REPO_BACKUP . "/$strBackupLabel"));
($lSizeCurrent, $lManifestSaveCurrent) = backupManifestUpdate(
$oBackupManifest,
$strHost,
$iLocalId,
$self->{strPgControl},
$strRepoPgControl,
$lPgControlSize,
undef,
false,
BACKUP_FILE_COPY,
8192,
8192,
$strPgControlHash,
undef,
16785408,
0,
167854,
0);
# 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->testResult(sub {storageRepo()->exists("$strBackupPath/" . FILE_MANIFEST)}, false, "backup.manifest missing");
$self->testResult(
sub {storageRepo()->exists("$strBackupPath/" . FILE_MANIFEST . INI_COPY_EXT)}, false, "backup.manifest.copy missing");
#---------------------------------------------------------------------------------------------------------------------------
# No prior checksum, no compression, no page checksum, no extra, no delta, no hasReference
($lSizeCurrent, $lManifestSaveCurrent) = backupManifestUpdate(
$oBackupManifest,
$strHost,
$iLocalId,
$strFileDb,
$strRepoFile,
$lFileSize,
$strFileHash,
false,
BACKUP_FILE_COPY,
16777216,
16777216,
'1c7e00fd09b9dd11fc2966590b3e3274645dd031',
undef,
16785408,
8192,
167854,
8192);
# 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->testResult(
sub {storageRepo()->exists("$strBackupPath/" . FILE_MANIFEST)}, false, 'backup.manifest.copy missing in repo');
#---------------------------------------------------------------------------------------------------------------------------
# Set up page checksum result
$rResultExtra = {'valid' => true,'align' => true};
($lSizeCurrent, $lManifestSaveCurrent) = backupManifestUpdate(
$oBackupManifest,
$strHost,
$iLocalId,
$strFileDb,
$strRepoFile,
$lFileSize,
$strFileHash,
true,
BACKUP_FILE_COPY,
16777216,
3646899,
'1c7e00fd09b9dd11fc2966590b3e3274645dd031',
$rResultExtra,
16785408,
16785408,
167854,
0);
# 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");
# 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 - skip file");
#---------------------------------------------------------------------------------------------------------------------------
# Removed db file is removed from manifest
($lSizeCurrent, $lManifestSaveCurrent) = backupManifestUpdate(
$oBackupManifest,
$strHost,
$iLocalId,
"$strFileDb.1",
"$strRepoFile.1",
$lFileSize,
$strFileHash,
false,
BACKUP_FILE_SKIP,
undef,
undef,
undef,
undef,
16785408,
33562624,
167854,
0);
$self->testResult(sub {$oBackupManifest->test(MANIFEST_SECTION_TARGET_FILE, "$strRepoFile.1")},
false, " $strRepoFile.1 section removed from manifest");
# Add back the section
$oBackupManifest->set(MANIFEST_SECTION_TARGET_FILE, "$strRepoFile.1");
# Code coverage for code path when 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,
BACKUP_FILE_SKIP,
undef,
undef,
undef,
undef,
16785408,
50339840,
167854,
0);
$self->testResult(sub {$oBackupManifest->test(MANIFEST_SECTION_TARGET_FILE, "$strRepoFile.1")},
false, " $strRepoFile.1 section removed from manifest on undef host");
#---------------------------------------------------------------------------------------------------------------------------
# Has reference - Code path to ensure reference is removed
($lSizeCurrent, $lManifestSaveCurrent) = backupManifestUpdate(
$oBackupManifest,
$strHost,
$iLocalId,
$strFileDb,
$strRepoFile,
$lFileSize,
$strFileHash,
false,
BACKUP_FILE_COPY,
16777216,
16777216,
'1c7e00fd09b9dd11fc2966590b3e3274645dd031',
undef,
16785408,
67117056,
167854,
0);
# 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
# 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,
BACKUP_FILE_NOOP,
16777216,
undef,
'1c7e00fd09b9dd11fc2966590b3e3274645dd031',
undef,
16785408,
83894272,
$lManifestSaveSize,
0);
$self->testResult(($lSizeCurrent ==$lSizeCurrentAfter && $lManifestSaveCurrent == $lManifestSaveCurrentAfter),
true, ' running counts updated');
}
################################################################################################################################
# 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;
$rResultExtra = undef;
$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");
#---------------------------------------------------------------------------------------------------------------------------
# Checksum 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->{valid} = 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, "align flag should have been set for misaligned page");
$rResultExtra->{align} = 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, "align flag should have been set for misaligned page");
$rResultExtra->{align} = 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;

View File

@@ -1,409 +0,0 @@
####################################################################################################################################
# Tests for Backup module
####################################################################################################################################
package pgBackRestTest::Module::Backup::BackupUnitPerlTest;
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::Backup;
use pgBackRest::Backup::Common;
use pgBackRest::Common::Exception;
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::ContainerTest;
use pgBackRestTest::Common::ExecuteTest;
use pgBackRestTest::Common::FileTest;
use pgBackRestTest::Common::RunTest;
use pgBackRestTest::Env::Host::HostBackupTest;
####################################################################################################################################
# run
####################################################################################################################################
sub run
{
my $self = shift;
################################################################################################################################
if ($self->begin('backupRegExpGet()'))
{
# Expected results matrix
my $hExpected = {};
$hExpected->{&false}{&false}{&true}{&false} = '[0-9]{8}\-[0-9]{6}F\_[0-9]{8}\-[0-9]{6}I';
$hExpected->{&false}{&false}{&true}{&true} = '^[0-9]{8}\-[0-9]{6}F\_[0-9]{8}\-[0-9]{6}I$';
$hExpected->{&false}{&true}{&false}{&false} = '[0-9]{8}\-[0-9]{6}F\_[0-9]{8}\-[0-9]{6}D';
$hExpected->{&false}{&true}{&false}{&true} = '^[0-9]{8}\-[0-9]{6}F\_[0-9]{8}\-[0-9]{6}D$';
$hExpected->{&false}{&true}{&true}{&false} = '[0-9]{8}\-[0-9]{6}F\_[0-9]{8}\-[0-9]{6}(D|I)';
$hExpected->{&false}{&true}{&true}{&true} = '^[0-9]{8}\-[0-9]{6}F\_[0-9]{8}\-[0-9]{6}(D|I)$';
$hExpected->{&true}{&false}{&false}{&false} = '[0-9]{8}\-[0-9]{6}F';
$hExpected->{&true}{&false}{&false}{&true} = '^[0-9]{8}\-[0-9]{6}F$';
$hExpected->{&true}{&false}{&true}{&false} = '[0-9]{8}\-[0-9]{6}F(\_[0-9]{8}\-[0-9]{6}I){0,1}';
$hExpected->{&true}{&false}{&true}{&true} = '^[0-9]{8}\-[0-9]{6}F(\_[0-9]{8}\-[0-9]{6}I){0,1}$';
$hExpected->{&true}{&true}{&false}{&false} = '[0-9]{8}\-[0-9]{6}F(\_[0-9]{8}\-[0-9]{6}D){0,1}';
$hExpected->{&true}{&true}{&false}{&true} = '^[0-9]{8}\-[0-9]{6}F(\_[0-9]{8}\-[0-9]{6}D){0,1}$';
$hExpected->{&true}{&true}{&true}{&false} = '[0-9]{8}\-[0-9]{6}F(\_[0-9]{8}\-[0-9]{6}(D|I)){0,1}';
$hExpected->{&true}{&true}{&true}{&true} = '^[0-9]{8}\-[0-9]{6}F(\_[0-9]{8}\-[0-9]{6}(D|I)){0,1}$';
# Iterate though all possible combinations
for (my $bFull = false; $bFull <= true; $bFull++)
{
for (my $bDiff = false; $bDiff <= true; $bDiff++)
{
for (my $bIncr = false; $bIncr <= true; $bIncr++)
{
for (my $bAnchor = false; $bAnchor <= true; $bAnchor++)
{
# Make sure that an assertion is thrown if no types are requested
if (!($bFull || $bDiff || $bIncr))
{
$self->testException(
sub {backupRegExpGet($bFull, $bDiff, $bIncr, $bAnchor)},
ERROR_ASSERT, 'at least one backup type must be selected');
}
# Else make sure the returned value is correct
else
{
$self->testResult(
sub {backupRegExpGet($bFull, $bDiff, $bIncr, $bAnchor)}, $hExpected->{$bFull}{$bDiff}{$bIncr}{$bAnchor},
"expression full $bFull, diff $bDiff, incr $bIncr, anchor $bAnchor = " .
$hExpected->{$bFull}{$bDiff}{$bIncr}{$bAnchor});
}
}
}
}
}
}
################################################################################################################################
if ($self->begin('backupLabelFormat()'))
{
my $strBackupLabelFull = timestampFileFormat(undef, 1482000000) . 'F';
$self->testResult(sub {backupLabelFormat(CFGOPTVAL_BACKUP_TYPE_FULL, undef, 1482000000)}, $strBackupLabelFull,
'full backup label');
#---------------------------------------------------------------------------------------------------------------------------
$self->testException(
sub {backupLabelFormat(CFGOPTVAL_BACKUP_TYPE_FULL, $strBackupLabelFull, 1482000000)},
ERROR_ASSERT, "strBackupLabelLast must not be defined when strType = 'full'");
#---------------------------------------------------------------------------------------------------------------------------
my $strBackupLabelDiff = "${strBackupLabelFull}_" . timestampFileFormat(undef, 1482000400) . 'D';
$self->testResult(
sub {backupLabelFormat(CFGOPTVAL_BACKUP_TYPE_DIFF, $strBackupLabelFull, 1482000400)}, $strBackupLabelDiff,
'diff backup label');
#---------------------------------------------------------------------------------------------------------------------------
$self->testException(
sub {backupLabelFormat(CFGOPTVAL_BACKUP_TYPE_DIFF, undef, 1482000400)},
ERROR_ASSERT, "strBackupLabelLast must be defined when strType = 'diff'");
#---------------------------------------------------------------------------------------------------------------------------
$self->testResult(
sub {backupLabelFormat(CFGOPTVAL_BACKUP_TYPE_INCR, $strBackupLabelDiff, 1482000800)},
"${strBackupLabelFull}_" . timestampFileFormat(undef, 1482000800) . 'I',
'incremental backup label');
}
################################################################################################################################
if ($self->begin('backupLabel()'))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_REPO_PATH, $self->testPath() . '/repo');
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
#---------------------------------------------------------------------------------------------------------------------------
my $lTime = time();
my $strFullLabel = backupLabelFormat(CFGOPTVAL_BACKUP_TYPE_FULL, undef, $lTime);
storageRepo()->pathCreate(STORAGE_REPO_BACKUP . "/${strFullLabel}", {bCreateParent => true});
my $strNewFullLabel = backupLabel(storageRepo(), CFGOPTVAL_BACKUP_TYPE_FULL, undef, $lTime);
$self->testResult(sub {$strFullLabel ne $strNewFullLabel}, true, 'new full label <> existing full backup dir');
#---------------------------------------------------------------------------------------------------------------------------
executeTest('rmdir ' . storageRepo()->pathGet(STORAGE_REPO_BACKUP . "/${strFullLabel}"));
storageRepo()->pathCreate(
STORAGE_REPO_BACKUP . qw(/) . PATH_BACKUP_HISTORY . '/' . timestampFormat('%4d', $lTime), {bCreateParent => true});
storageRepo()->put(
STORAGE_REPO_BACKUP . qw{/} . PATH_BACKUP_HISTORY . '/' . timestampFormat('%4d', $lTime) .
"/${strFullLabel}.manifest." . COMPRESS_EXT);
$strNewFullLabel = backupLabel(storageRepo(), CFGOPTVAL_BACKUP_TYPE_FULL, undef, $lTime);
$self->testResult(sub {$strFullLabel ne $strNewFullLabel}, true, 'new full label <> existing full history file');
#---------------------------------------------------------------------------------------------------------------------------
$lTime = time() + 1000;
$strFullLabel = backupLabelFormat(CFGOPTVAL_BACKUP_TYPE_FULL, undef, $lTime);
$strNewFullLabel = backupLabel(storageRepo(), CFGOPTVAL_BACKUP_TYPE_FULL, undef, $lTime);
$self->testResult(sub {$strFullLabel eq $strNewFullLabel}, true, 'new full label in future');
#---------------------------------------------------------------------------------------------------------------------------
$lTime = time();
$strFullLabel = backupLabelFormat(CFGOPTVAL_BACKUP_TYPE_FULL, undef, $lTime);
my $strDiffLabel = backupLabelFormat(CFGOPTVAL_BACKUP_TYPE_DIFF, $strFullLabel, $lTime);
storageRepo()->pathCreate(STORAGE_REPO_BACKUP . "/${strDiffLabel}", {bCreateParent => true});
my $strNewDiffLabel = backupLabel(storageRepo(), CFGOPTVAL_BACKUP_TYPE_DIFF, $strFullLabel, $lTime);
$self->testResult(sub {$strDiffLabel ne $strNewDiffLabel}, true, 'new diff label <> existing diff backup dir');
#---------------------------------------------------------------------------------------------------------------------------
executeTest('rmdir ' . storageRepo()->pathGet(STORAGE_REPO_BACKUP . "/${strDiffLabel}"));
storageRepo()->pathCreate(
STORAGE_REPO_BACKUP . qw(/) . PATH_BACKUP_HISTORY . '/' . timestampFormat('%4d', $lTime),
{bIgnoreExists => true, bCreateParent => true});
storageRepo()->put(
STORAGE_REPO_BACKUP . qw{/} . PATH_BACKUP_HISTORY . '/' . timestampFormat('%4d', $lTime) .
"/${strDiffLabel}.manifest." . COMPRESS_EXT);
$strNewDiffLabel = backupLabel(storageRepo(), CFGOPTVAL_BACKUP_TYPE_DIFF, $strFullLabel, $lTime);
$self->testResult(sub {$strDiffLabel ne $strNewDiffLabel}, true, 'new full label <> existing diff history file');
#---------------------------------------------------------------------------------------------------------------------------
$lTime = time() + 1000;
$strDiffLabel = backupLabelFormat(CFGOPTVAL_BACKUP_TYPE_DIFF, $strFullLabel, $lTime);
$strNewDiffLabel = backupLabel(storageRepo(), CFGOPTVAL_BACKUP_TYPE_DIFF, $strFullLabel, $lTime);
$self->testResult(sub {$strDiffLabel eq $strNewDiffLabel}, true, 'new diff label in future');
}
################################################################################################################################
if ($self->begin('resumeClean()'))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_REPO_PATH, $self->testPath() . '/repo');
$self->optionTestSet(CFGOPT_PG_PATH, $self->testPath() . '/db');
$self->configTestLoad(CFGCMD_BACKUP);
my $lTime = time();
my $strFullLabel = backupLabelFormat(CFGOPTVAL_BACKUP_TYPE_FULL, undef, $lTime);
storageRepo()->pathCreate(STORAGE_REPO_BACKUP . "/${strFullLabel}", {bCreateParent => true});
my $strBackupPath = storageRepo()->pathGet(STORAGE_REPO_BACKUP . "/${strFullLabel}");
my $strBackupManifestFile = "$strBackupPath/" . FILE_MANIFEST;
my $strPath = "path";
my $strSubPath = "$strBackupPath/$strPath";
my $strInManifestNoChecksum = 'in_manifest_no_checksum';
my $strInManifestWithChecksum = 'in_manifest_with_checksum';
my $strInManifestWithReference = 'in_manifest_with_reference';
my $strExpectedManifest = $self->testPath() . '/expected.manifest';
my $strAbortedManifest = $self->testPath() . '/aborted.manifest';
my $oManifest = new pgBackRest::Manifest(
$strBackupManifestFile,
{bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)});
my $oAbortedManifest = new pgBackRest::Manifest(
$strBackupManifestFile,
{bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)});
my $oBackup = new pgBackRest::Backup::Backup();
$oAbortedManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ONLINE, undef, false);
# Compression prior enabled, gzip file exists and not in manifest, dir exists and is in manifest, delta not enabled
#---------------------------------------------------------------------------------------------------------------------------
$oAbortedManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS, undef, true);
storageRepo()->put(storageRepo()->openWrite($strBackupPath . '/' . BOGUS . '.gz',
{strMode => '0750', strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}));
storageRepo()->pathCreate($strSubPath, {bIgnoreExists => true});
my $hDefault = {};
$oManifest->set(MANIFEST_SECTION_TARGET_PATH, $strPath, undef, $hDefault);
$self->testResult(sub {$oBackup->resumeClean(storageRepo(), $strFullLabel, $oManifest, $oAbortedManifest, false, false,
undef, undef)}, false, 'resumeClean, prior compression enabled, delta not enabled');
$self->testResult(sub {!storageRepo()->exists($strBackupPath . '/' . BOGUS . '.gz')}, true, ' gzip file removed');
$self->testResult(sub {storageRepo()->pathExists($strSubPath)}, true, ' path not removed');
# Disable compression
$oAbortedManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS, undef, false);
$oManifest->remove(MANIFEST_SECTION_TARGET_PATH, $strPath);
# Path and files to be removed (not in oManifest)
#---------------------------------------------------------------------------------------------------------------------------
storageRepo()->put(storageRepo()->openWrite($strBackupPath . "/" . FILE_MANIFEST_COPY,
{strMode => '0750', strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}));
storageRepo()->put(storageRepo()->openWrite($strSubPath . "/" . BOGUS,
{strMode => '0750', strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}));
storageRepo()->put(storageRepo()->openWrite($strBackupPath . "/" . BOGUS,
{strMode => '0750', strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}));
$self->testResult(sub {storageRepo()->pathExists($strSubPath) && storageRepo()->exists($strSubPath . "/" . BOGUS) &&
storageRepo()->exists($strBackupPath . "/" . BOGUS)},
true, 'dir and files to be removed exist');
$self->testResult(sub {$oBackup->resumeClean(storageRepo(), $strFullLabel, $oManifest, $oAbortedManifest, false, true,
undef, undef)}, true, 'resumeClean, delta enabled, path and files to remove, manifest copy to remain');
$self->testResult(sub {!storageRepo()->pathExists($strSubPath) && !storageRepo()->exists($strSubPath . "/" . BOGUS)},
true, ' dir removed');
$self->testResult(sub {!storageRepo()->exists($strBackupPath . "/" . BOGUS) &&
storageRepo()->exists($strBackupPath . "/" . FILE_MANIFEST_COPY)}, true,
' file removed, manifest copy remains');
# Online changed, delta enabled
#---------------------------------------------------------------------------------------------------------------------------
$self->testResult(sub {$oBackup->resumeClean(storageRepo(), $strFullLabel, $oManifest, $oAbortedManifest, true, false,
undef, undef)}, true, 'resumeClean, online changed, delta enabled');
# Online does not change, only backup.manifest.copy exists, delta not enabled
#---------------------------------------------------------------------------------------------------------------------------
storageRepo()->put(storageRepo()->openWrite($strBackupPath . '/' . BOGUS,
{strMode => '0750', strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}));
storageRepo()->put(storageRepo()->openWrite($strBackupPath . "/$strInManifestWithReference",
{strMode => '0750', strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}));
storageRepo()->put(storageRepo()->openWrite($strBackupPath . "/$strInManifestNoChecksum",
{strMode => '0750', strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}));
storageRepo()->put(storageRepo()->openWrite($strBackupPath . "/$strInManifestWithChecksum",
{strMode => '0750', strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), 'test');
my ($strHash, $iSize) = storageRepo()->hashSize(storageRepo()->openRead($strBackupPath . "/$strInManifestWithChecksum"));
$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestNoChecksum,
MANIFEST_SUBKEY_SIZE, 0);
$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestNoChecksum,
MANIFEST_SUBKEY_TIMESTAMP, $lTime);
$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_SIZE, $iSize);
$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_TIMESTAMP, $lTime);
$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithReference,
MANIFEST_SUBKEY_SIZE, 0);
$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithReference,
MANIFEST_SUBKEY_TIMESTAMP, $lTime);
$oManifest->set(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithReference,
MANIFEST_SUBKEY_REFERENCE, BOGUS);
$oAbortedManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestNoChecksum,
MANIFEST_SUBKEY_SIZE, 0);
$oAbortedManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestNoChecksum,
MANIFEST_SUBKEY_TIMESTAMP, $lTime);
$oAbortedManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_SIZE, $iSize);
$oAbortedManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_TIMESTAMP, $lTime);
$oAbortedManifest->set(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_CHECKSUM, $strHash);
$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithReference,
MANIFEST_SUBKEY_SIZE, 0);
$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithReference,
MANIFEST_SUBKEY_TIMESTAMP, $lTime);
$oManifest->set(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithReference,
MANIFEST_SUBKEY_REFERENCE, BOGUS);
$self->testResult(sub {$oBackup->resumeClean(storageRepo(), $strFullLabel, $oManifest, $oAbortedManifest, false, false,
undef, undef)}, false, 'resumeClean, online not changed, delta not enabled');
$self->testResult(sub {!storageRepo()->exists($strBackupPath . "/" . BOGUS) &&
!storageRepo()->exists($strBackupPath . "/$strInManifestNoChecksum") &&
!storageRepo()->exists($strBackupPath . "/$strInManifestWithReference") &&
storageRepo()->exists($strBackupPath . "/$strInManifestWithChecksum") &&
storageRepo()->exists($strBackupPath . "/" . FILE_MANIFEST_COPY)}, true,
' file not in manifest or in manifest but no-checksum removed, file in manifest and manifest.copy remains');
$self->testResult(sub {$oManifest->test(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum, MANIFEST_SUBKEY_CHECKSUM,
$strHash)}, true, ' checksum copied to manifest');
# Timestamp in the past for same-sized file with checksum.
#---------------------------------------------------------------------------------------------------------------------------
$oManifest->remove(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum, MANIFEST_SUBKEY_CHECKSUM);
$self->testResult(sub {$oManifest->test(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_CHECKSUM)}, false, 'manifest checksum does not exist');
# Set the timestamp so that the new manifest appears to have a time in the past. This should enable delta.
$oAbortedManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_TIMESTAMP, $lTime + 100);
# Set checksum page for code coverage
$oAbortedManifest->set(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum, MANIFEST_SUBKEY_CHECKSUM_PAGE, false);
$self->testResult(sub {$oBackup->resumeClean(storageRepo(), $strFullLabel, $oManifest, $oAbortedManifest, false, false,
undef, undef)}, true, ' resumeClean, timestamp in past, delta enabled');
$self->testResult(sub {$oManifest->test(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum, MANIFEST_SUBKEY_CHECKSUM,
$strHash) && $oManifest->boolTest(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_CHECKSUM_PAGE, false)}, true, ' checksum copied to manifest');
# Timestamp different for same-sized file with checksum.
#---------------------------------------------------------------------------------------------------------------------------
$oManifest->remove(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum, MANIFEST_SUBKEY_CHECKSUM);
$oAbortedManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_TIMESTAMP, $lTime - 100);
$self->testResult(sub {$oBackup->resumeClean(storageRepo(), $strFullLabel, $oManifest, $oAbortedManifest, false, false,
undef, undef)}, false, 'resumeClean, timestamp different but size the same, delta not enabled');
$self->testResult(sub {$oManifest->test(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_CHECKSUM) && !storageRepo()->exists($strBackupPath . "/$strInManifestWithChecksum")},
false, ' checksum not copied to manifest, file removed');
# Size different, timestamp same for file with checksum.
#---------------------------------------------------------------------------------------------------------------------------
storageRepo()->put(storageRepo()->openWrite($strBackupPath . "/$strInManifestWithChecksum",
{strMode => '0750', strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), 'test');
$oAbortedManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_SIZE, $iSize - 1);
$oAbortedManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_TIMESTAMP, $lTime);
$self->testResult(sub {$oBackup->resumeClean(storageRepo(), $strFullLabel, $oManifest, $oAbortedManifest, false, false,
undef, undef)}, true, 'resumeClean, size different, timestamp same, delta enabled');
$self->testResult(sub {$oManifest->test(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_CHECKSUM) && !storageRepo()->exists($strBackupPath . "/$strInManifestWithChecksum")},
false, ' checksum not copied to manifest, file removed');
# Checksum page error and link to file.
#---------------------------------------------------------------------------------------------------------------------------
storageRepo()->put(storageRepo()->openWrite($strBackupPath . "/$strInManifestWithChecksum",
{strMode => '0750', strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), 'test');
testLinkCreate($strBackupPath . "/testlink", $strBackupPath . "/$strInManifestWithChecksum");
$self->testResult(sub {storageRepo()->exists($strBackupPath . "/testlink")}, true, 'link exists');
$oAbortedManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_SIZE, $iSize);
$oAbortedManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_TIMESTAMP, $lTime);
# Set checksum page for code coverage
$oAbortedManifest->boolSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum, MANIFEST_SUBKEY_CHECKSUM_PAGE, false);
$oAbortedManifest->set(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum, MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR, 'E');
$self->testResult(sub {$oBackup->resumeClean(storageRepo(), $strFullLabel, $oManifest, $oAbortedManifest, false, false,
undef, undef)}, false, ' resumeClean, delta not enabled');
$self->testResult(sub {$oManifest->test(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR, 'E') && !storageRepo()->exists($strBackupPath . "/testlink")},
true, ' checksum page error copied to manifest, link removed');
# Checksum page=true
#---------------------------------------------------------------------------------------------------------------------------
$oAbortedManifest->boolSet(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum, MANIFEST_SUBKEY_CHECKSUM_PAGE, true);
$self->testResult(sub {$oBackup->resumeClean(storageRepo(), $strFullLabel, $oManifest, $oAbortedManifest, false, false,
undef, undef)}, false, ' resumeClean, checksum page = true');
$self->testResult(sub {$oManifest->boolTest(MANIFEST_SECTION_TARGET_FILE, $strInManifestWithChecksum,
MANIFEST_SUBKEY_CHECKSUM_PAGE, true)}, true, ' checksum page set true in manifest');
}
}
1;

View File

@@ -1,154 +0,0 @@
####################################################################################################################################
# Archive Common Tests
####################################################################################################################################
package pgBackRestTest::Module::Command::CommandArchiveCommonPerlTest;
use parent 'pgBackRestTest::Env::HostEnvTest';
####################################################################################################################################
# Perl includes
####################################################################################################################################
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use Storable qw(dclone);
use pgBackRest::Archive::Common;
use pgBackRest::Common::Exception;
use pgBackRest::Common::Log;
use pgBackRest::Config::Config;
use pgBackRest::DbVersion;
use pgBackRest::Protocol::Storage::Helper;
use pgBackRestTest::Env::Host::HostBackupTest;
####################################################################################################################################
# run
####################################################################################################################################
sub run
{
my $self = shift;
my $strModule = 'ArchiveCommon';
################################################################################################################################
if ($self->begin("${strModule}::lsnFileRange()"))
{
$self->testResult(sub {lsnFileRange("1/60", "1/60", PG_VERSION_92, 16 * 1024 * 1024)}, "0000000100000000", 'get single');
$self->testResult(
sub {lsnFileRange("1/FD000000", "2/1000000", PG_VERSION_92, 16 * 1024 * 1024)},
"(00000001000000FD, 00000001000000FE, 0000000200000000, 0000000200000001)", 'get range < 9.3');
$self->testResult(
sub {lsnFileRange("1/FD000000", "2/60", PG_VERSION_93, 16 * 1024 * 1024)},
"(00000001000000FD, 00000001000000FE, 00000001000000FF, 0000000200000000)", 'get range >= 9.3');
$self->testResult(
sub {lsnFileRange("A/800", "B/C0000000", PG_VERSION_11, 1024 * 1024 * 1024)},
'(0000000A00000000, 0000000A00000001, 0000000A00000002, 0000000A00000003, 0000000B00000000, 0000000B00000001, ' .
'0000000B00000002, 0000000B00000003)',
'get range >= 11/1GB');
$self->testResult(
sub {lsnFileRange("7/FFEFFFFF", "8/001AAAAA", PG_VERSION_11, 1024 * 1024)},
'(0000000700000FFE, 0000000700000FFF, 0000000800000000, 0000000800000001)', 'get range >= 11/1MB');
}
################################################################################################################################
if ($self->begin("${strModule}::walIsSegment()"))
{
#---------------------------------------------------------------------------------------------------------------------------
$self->testResult(sub {walIsSegment('0000000200ABCDEF0000001')}, false, 'invalid segment');
#---------------------------------------------------------------------------------------------------------------------------
$self->testResult(sub {walIsSegment('0000000200ABCDEF00000001')}, true, 'valid segment');
#---------------------------------------------------------------------------------------------------------------------------
$self->testResult(sub {walIsSegment('000000010000000100000001.partial')}, true, 'valid partial segment');
#---------------------------------------------------------------------------------------------------------------------------
$self->testResult(sub {walIsSegment('00000001.history')}, false, 'valid history file');
#---------------------------------------------------------------------------------------------------------------------------
$self->testResult(sub {walIsSegment('000000020000000100000001.00000028.backup')}, false, 'valid backup file');
}
################################################################################################################################
if ($self->begin("${strModule}::walIsPartial()"))
{
#---------------------------------------------------------------------------------------------------------------------------
my $strWalSegment = '0000000200ABCDEF00000001';
$self->testResult(sub {walIsPartial($strWalSegment)}, false, "${strWalSegment} WAL is not partial");
#---------------------------------------------------------------------------------------------------------------------------
$strWalSegment = $strWalSegment . '.partial';
$self->testResult(sub {walIsPartial($strWalSegment)}, true, "${strWalSegment} WAL is partial");
}
################################################################################################################################
if ($self->begin("${strModule}::walSegmentFind()"))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_REPO_PATH, $self->testPath());
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
my $strArchiveId = '9.4-1';
my $strArchivePath = storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . "/${strArchiveId}");
#---------------------------------------------------------------------------------------------------------------------------
my $strWalSegment = '000000010000000100000001ZZ';
$self->testException(
sub {walSegmentFind(storageRepo(), $strArchiveId, $strWalSegment)}, ERROR_ASSERT,
"${strWalSegment} is not a WAL segment");
#---------------------------------------------------------------------------------------------------------------------------
$strWalSegment = '000000010000000100000001';
$self->testResult(
sub {walSegmentFind(storageRepo(), $strArchiveId, $strWalSegment)}, undef, "${strWalSegment} WAL not found");
#---------------------------------------------------------------------------------------------------------------------------
$self->testException(
sub {walSegmentFind(storageRepo(), $strArchiveId, $strWalSegment, .1)}, ERROR_ARCHIVE_TIMEOUT,
"could not find WAL segment ${strWalSegment} after 0.1 second(s)" .
"\nHINT: is archive_command configured correctly?" .
"\nHINT: use the check command to verify that PostgreSQL is archiving.");
#---------------------------------------------------------------------------------------------------------------------------
my $strWalMajorPath = "${strArchivePath}/" . substr($strWalSegment, 0, 16);
my $strWalSegmentHash = "${strWalSegment}-53aa5d59515aa7288ae02ba414c009aed1ca73ad";
storageRepo()->pathCreate($strWalMajorPath, {bCreateParent => true});
storageRepo()->put("${strWalMajorPath}/${strWalSegmentHash}");
$self->testResult(
sub {walSegmentFind(storageRepo(), $strArchiveId, $strWalSegment)}, $strWalSegmentHash, "${strWalSegment} WAL found");
#---------------------------------------------------------------------------------------------------------------------------
my $strWalSegmentHash2 = "${strWalSegment}-a0b0d38b8aa263e25b8ff52a0a4ba85b6be97f9b.gz";
storageRepo()->put("${strWalMajorPath}/${strWalSegmentHash2}");
$self->testException(
sub {walSegmentFind(storageRepo(), $strArchiveId, $strWalSegment)}, ERROR_ARCHIVE_DUPLICATE,
"duplicates found in archive for WAL segment ${strWalSegment}: ${strWalSegmentHash}, ${strWalSegmentHash2}");
storageRepo()->remove("${strWalMajorPath}/${strWalSegmentHash}");
#---------------------------------------------------------------------------------------------------------------------------
$self->testResult(
sub {walSegmentFind(storageRepo(), $strArchiveId, $strWalSegment)}, $strWalSegmentHash2,
"${strWalSegment} WAL found with compressed extension");
storageRepo()->remove("${strWalMajorPath}/${strWalSegmentHash2}");
#---------------------------------------------------------------------------------------------------------------------------
$strWalSegment = $strWalSegment . '.partial';
$strWalSegmentHash = "${strWalSegment}-996195c807713ef9262170043e7222cb150aef70";
storageRepo()->put("${strWalMajorPath}/${strWalSegmentHash}");
$self->testResult(
sub {walSegmentFind(storageRepo(), $strArchiveId, $strWalSegment)}, $strWalSegmentHash, "${strWalSegment} WAL found");
}
}
1;

View File

@@ -516,7 +516,7 @@ sub run
$oHostBackup->backup(
$strType, 'invalid repo',
{oExpectedManifest => \%oManifest, strOptionalParam => '--' . cfgOptionName(CFGOPT_REPO_PATH) . '=/bogus_path',
iExpectedExitStatus => $bS3 ? ERROR_FILE_MISSING : ERROR_PATH_MISSING});
iExpectedExitStatus => ERROR_FILE_MISSING});
# Restore - tests various mode, extra files/paths, missing files/paths
#---------------------------------------------------------------------------------------------------------------------------
@@ -822,7 +822,7 @@ sub run
$oHostBackup->backup(
$strType, '$PGDATA is a substring of valid tblspc excluding / (file missing err expected)',
{oExpectedManifest => \%oManifest, iExpectedExitStatus => ERROR_PATH_MISSING});
{oExpectedManifest => \%oManifest, iExpectedExitStatus => ERROR_FILE_OPEN});
testFileRemove("${strTblSpcPath}/99999");
}

View File

@@ -475,7 +475,7 @@ sub run
my $strStandbyBackup = $oHostBackup->backup(
CFGOPTVAL_BACKUP_TYPE_FULL, 'backup from standby, failure to access at least one standby',
{bStandby => true,
iExpectedExitStatus => ERROR_HOST_CONNECT,
iExpectedExitStatus => ERROR_DB_CONNECT,
strOptionalParam => '--' .
cfgOptionName(cfgOptionIdFromIndex(CFGOPT_PG_HOST, cfgOptionIndexTotal(CFGOPT_PG_PATH))) . '=' . BOGUS});
}
@@ -535,7 +535,9 @@ sub run
$oHostDbMaster->stop();
$oHostBackup->backup(CFGOPTVAL_BACKUP_TYPE_INCR, 'attempt backup when stopped', {iExpectedExitStatus => ERROR_STOP});
$oHostBackup->backup(
CFGOPTVAL_BACKUP_TYPE_INCR, 'attempt backup when stopped',
{iExpectedExitStatus => $oHostBackup == $oHostDbMaster ? ERROR_STOP : ERROR_DB_CONNECT});
$oHostDbMaster->start();
}