2015-04-07 13:34:37 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# BACKUP FILE MODULE
|
|
|
|
####################################################################################################################################
|
2017-05-15 22:01:00 +02:00
|
|
|
package pgBackRest::Backup::File;
|
2015-04-07 13:34:37 +02:00
|
|
|
|
2015-06-14 00:25:49 +02:00
|
|
|
use strict;
|
2015-04-07 13:34:37 +02:00
|
|
|
use warnings FATAL => qw(all);
|
|
|
|
use Carp qw(confess);
|
|
|
|
|
|
|
|
use Exporter qw(import);
|
2015-08-29 20:20:46 +02:00
|
|
|
our @EXPORT = qw();
|
2015-06-14 00:25:49 +02:00
|
|
|
use File::Basename qw(dirname);
|
2016-12-13 01:54:07 +02:00
|
|
|
use Storable qw(dclone);
|
2015-04-07 13:34:37 +02:00
|
|
|
|
2017-06-09 23:51:41 +02:00
|
|
|
use pgBackRest::Backup::Filter::PageChecksum;
|
2016-04-14 15:30:54 +02:00
|
|
|
use pgBackRest::Common::Exception;
|
2017-06-09 23:51:41 +02:00
|
|
|
use pgBackRest::Common::Io::Handle;
|
2016-04-14 15:30:54 +02:00
|
|
|
use pgBackRest::Common::Log;
|
|
|
|
use pgBackRest::Common::String;
|
2017-06-09 23:51:41 +02:00
|
|
|
use pgBackRest::DbVersion;
|
2016-04-14 15:30:54 +02:00
|
|
|
use pgBackRest::Manifest;
|
2017-06-09 23:51:41 +02:00
|
|
|
use pgBackRest::Protocol::Storage::Helper;
|
|
|
|
use pgBackRest::Storage::Base;
|
|
|
|
use pgBackRest::Storage::Filter::Gzip;
|
|
|
|
use pgBackRest::Storage::Filter::Sha;
|
|
|
|
use pgBackRest::Storage::Helper;
|
2016-09-06 15:35:02 +02:00
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# Result constants
|
|
|
|
####################################################################################################################################
|
|
|
|
use constant BACKUP_FILE_CHECKSUM => 0;
|
|
|
|
push @EXPORT, qw(BACKUP_FILE_CHECKSUM);
|
|
|
|
use constant BACKUP_FILE_COPY => 1;
|
|
|
|
push @EXPORT, qw(BACKUP_FILE_COPY);
|
|
|
|
use constant BACKUP_FILE_RECOPY => 2;
|
|
|
|
push @EXPORT, qw(BACKUP_FILE_RECOPY);
|
|
|
|
use constant BACKUP_FILE_SKIP => 3;
|
|
|
|
push @EXPORT, qw(BACKUP_FILE_SKIP);
|
2018-09-19 17:12:45 +02:00
|
|
|
use constant BACKUP_FILE_NOOP => 4;
|
|
|
|
push @EXPORT, qw(BACKUP_FILE_NOOP);
|
2015-08-29 20:20:46 +02:00
|
|
|
|
2015-04-07 13:34:37 +02:00
|
|
|
####################################################################################################################################
|
2015-04-11 21:02:04 +02:00
|
|
|
# backupFile
|
2015-04-07 13:34:37 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
sub backupFile
|
|
|
|
{
|
2015-08-29 20:20:46 +02:00
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
2016-04-15 04:50:02 +02:00
|
|
|
$strDbFile, # Database file to backup
|
|
|
|
$strRepoFile, # Location in the repository to copy to
|
2016-12-04 00:34:51 +02:00
|
|
|
$lSizeFile, # File size
|
2015-08-29 20:20:46 +02:00
|
|
|
$strChecksum, # File checksum to be checked
|
2016-12-13 01:54:07 +02:00
|
|
|
$bChecksumPage, # Should page checksums be calculated?
|
2017-06-09 23:51:41 +02:00
|
|
|
$strBackupLabel, # Label of current backup
|
2017-10-23 00:05:46 +02:00
|
|
|
$bCompress, # Compress destination file
|
|
|
|
$iCompressLevel, # Compress level
|
2015-08-29 20:20:46 +02:00
|
|
|
$lModificationTime, # File modification time
|
2016-08-24 18:39:27 +02:00
|
|
|
$bIgnoreMissing, # Is it OK if the file is missing?
|
2017-01-30 20:59:00 +02:00
|
|
|
$hExtraParam, # Parameter to pass to the extra function
|
2018-09-19 17:12:45 +02:00
|
|
|
$bDelta, # Is the delta option on?
|
|
|
|
$bHasReference, # Does the file exist in the repo in a prior backup in the set?
|
|
|
|
$strCipherPass, # Passphrase to access the repo file (undefined if repo not encrypted). This
|
|
|
|
# parameter must always be last in the parameter list to this function.
|
2015-08-29 20:20:46 +02:00
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
2016-08-11 23:32:28 +02:00
|
|
|
__PACKAGE__ . '::backupFile', \@_,
|
2016-12-04 00:34:51 +02:00
|
|
|
{name => 'strDbFile', trace => true},
|
|
|
|
{name => 'strRepoFile', trace => true},
|
|
|
|
{name => 'lSizeFile', trace => true},
|
|
|
|
{name => 'strChecksum', required => false, trace => true},
|
2016-12-13 01:54:07 +02:00
|
|
|
{name => 'bChecksumPage', trace => true},
|
2017-06-09 23:51:41 +02:00
|
|
|
{name => 'strBackupLabel', trace => true},
|
2017-10-23 00:05:46 +02:00
|
|
|
{name => 'bCompress', trace => true},
|
|
|
|
{name => 'iCompressLevel', trace => true},
|
2016-12-04 00:34:51 +02:00
|
|
|
{name => 'lModificationTime', trace => true},
|
|
|
|
{name => 'bIgnoreMissing', default => true, trace => true},
|
2017-01-30 20:59:00 +02:00
|
|
|
{name => 'hExtraParam', required => false, trace => true},
|
2018-09-19 17:12:45 +02:00
|
|
|
{name => 'bDelta', trace => true},
|
|
|
|
{name => 'bHasReference', trace => true},
|
2017-11-06 19:51:12 +02:00
|
|
|
{name => 'strCipherPass', required => false, trace => true},
|
2015-08-29 20:20:46 +02:00
|
|
|
);
|
|
|
|
|
2017-06-09 23:51:41 +02:00
|
|
|
my $oStorageRepo = storageRepo(); # Repo storage
|
2016-09-06 15:35:02 +02:00
|
|
|
my $iCopyResult = BACKUP_FILE_COPY; # Copy result
|
2015-08-29 20:20:46 +02:00
|
|
|
my $strCopyChecksum; # Copy checksum
|
2016-12-13 01:54:07 +02:00
|
|
|
my $rExtra; # Page checksum result
|
2015-08-29 20:20:46 +02:00
|
|
|
my $lCopySize; # Copy Size
|
2016-04-15 04:50:02 +02:00
|
|
|
my $lRepoSize; # Repo size
|
2015-04-07 13:34:37 +02:00
|
|
|
|
2017-06-09 23:51:41 +02:00
|
|
|
# Add compression suffix if needed
|
2017-10-23 00:05:46 +02:00
|
|
|
my $strFileOp = $strRepoFile . ($bCompress ? '.' . COMPRESS_EXT : '');
|
2017-06-09 23:51:41 +02:00
|
|
|
|
2015-05-07 02:24:34 +02:00
|
|
|
my $bCopy = true;
|
|
|
|
|
2018-09-19 17:12:45 +02:00
|
|
|
# If checksum is defined then the file needs to be checked. If delta option then check the DB and possibly the repo, else just
|
|
|
|
# check the repo.
|
2015-05-07 02:24:34 +02:00
|
|
|
if (defined($strChecksum))
|
2015-04-07 13:34:37 +02:00
|
|
|
{
|
2018-09-19 17:12:45 +02:00
|
|
|
# If delta, then check the DB checksum and possibly the repo. If the checksum does not match in either case then recopy.
|
|
|
|
if ($bDelta)
|
2017-10-23 00:05:46 +02:00
|
|
|
{
|
2018-09-19 17:12:45 +02:00
|
|
|
($strCopyChecksum, $lCopySize) = storageDb()->hashSize($strDbFile, {bIgnoreMissing => $bIgnoreMissing});
|
|
|
|
|
|
|
|
# If the DB file exists, then check the checksum
|
|
|
|
if (defined($strCopyChecksum))
|
|
|
|
{
|
|
|
|
$bCopy = !($strCopyChecksum eq $strChecksum && $lCopySize == $lSizeFile);
|
|
|
|
|
|
|
|
# If the database file checksum and size are same and the file is in a prior backup, then no need to copy. If the
|
|
|
|
# checksum/size do not match, that is OK, just leave the copy result as COPY so the file will be copied to this
|
|
|
|
# backup.
|
|
|
|
if (!$bCopy && $bHasReference)
|
|
|
|
{
|
|
|
|
$iCopyResult = BACKUP_FILE_NOOP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# Else the source file is missing from the database so skip this file
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$iCopyResult = BACKUP_FILE_SKIP;
|
|
|
|
$bCopy = false;
|
|
|
|
}
|
2017-10-23 00:05:46 +02:00
|
|
|
}
|
|
|
|
|
2018-09-19 17:12:45 +02:00
|
|
|
# If this is not a delta backup or it is and the file exists and the checksum from the DB matches, then also test the
|
|
|
|
# checksum of the file in the repo (unless it is in a prior backup) and if the checksum doesn't match, then there may be
|
|
|
|
# corruption in the repo, so recopy
|
|
|
|
if (!$bDelta || !$bHasReference)
|
|
|
|
{
|
|
|
|
# If this is a delta backup and the file is missing from the DB, then remove it from the repo (backupManifestUpdate will
|
|
|
|
# remove it from the manifest)
|
|
|
|
if ($iCopyResult == BACKUP_FILE_SKIP)
|
|
|
|
{
|
|
|
|
$oStorageRepo->remove(STORAGE_REPO_BACKUP . "/${strBackupLabel}/${strFileOp}");
|
|
|
|
}
|
|
|
|
elsif (!$bDelta || !$bCopy)
|
|
|
|
{
|
|
|
|
# Add decompression
|
|
|
|
my $rhyFilter;
|
2017-06-09 23:51:41 +02:00
|
|
|
|
2018-09-19 17:12:45 +02:00
|
|
|
if ($bCompress)
|
|
|
|
{
|
|
|
|
push(@{$rhyFilter}, {strClass => STORAGE_FILTER_GZIP, rxyParam => [{strCompressType => STORAGE_DECOMPRESS}]});
|
|
|
|
}
|
2015-05-07 02:24:34 +02:00
|
|
|
|
2018-09-19 17:12:45 +02:00
|
|
|
# Get the checksum
|
|
|
|
($strCopyChecksum, $lCopySize) = $oStorageRepo->hashSize(
|
|
|
|
$oStorageRepo->openRead(STORAGE_REPO_BACKUP . "/${strBackupLabel}/${strFileOp}",
|
|
|
|
{rhyFilter => $rhyFilter, strCipherPass => $strCipherPass}));
|
|
|
|
|
|
|
|
# Determine if the file needs to be recopied
|
|
|
|
$bCopy = !($strCopyChecksum eq $strChecksum && $lCopySize == $lSizeFile);
|
|
|
|
|
|
|
|
# Set copy result
|
|
|
|
$iCopyResult = $bCopy ? BACKUP_FILE_RECOPY : BACKUP_FILE_CHECKSUM;
|
|
|
|
}
|
|
|
|
}
|
2015-04-07 13:34:37 +02:00
|
|
|
}
|
|
|
|
|
2017-06-09 23:51:41 +02:00
|
|
|
# Copy the file
|
2015-05-07 02:24:34 +02:00
|
|
|
if ($bCopy)
|
|
|
|
{
|
2017-06-09 23:51:41 +02:00
|
|
|
# Add sha filter
|
|
|
|
my $rhyFilter = [{strClass => STORAGE_FILTER_SHA}];
|
|
|
|
|
|
|
|
# Add page checksum filter
|
2017-03-01 21:15:46 +02:00
|
|
|
if ($bChecksumPage)
|
|
|
|
{
|
2017-06-09 23:51:41 +02:00
|
|
|
# Determine which segment no this is by checking for a numeric extension. No extension means segment 0.
|
|
|
|
my $iSegmentNo = ($strDbFile =~ /\.[0-9]+$/) ? substr(($strDbFile =~ m/\.[0-9]+$/g)[0], 1) + 0 : 0;
|
|
|
|
|
|
|
|
push(
|
|
|
|
@{$rhyFilter},
|
|
|
|
{strClass => BACKUP_FILTER_PAGECHECKSUM,
|
|
|
|
rxyParam => [$iSegmentNo, $hExtraParam->{iWalId}, $hExtraParam->{iWalOffset}]});
|
|
|
|
};
|
|
|
|
|
|
|
|
# Add compression
|
2017-10-23 00:05:46 +02:00
|
|
|
if ($bCompress)
|
2017-06-09 23:51:41 +02:00
|
|
|
{
|
2017-10-23 00:05:46 +02:00
|
|
|
push(@{$rhyFilter}, {strClass => STORAGE_FILTER_GZIP, rxyParam => [{iLevel => $iCompressLevel}]});
|
2017-03-01 21:15:46 +02:00
|
|
|
}
|
|
|
|
|
2017-06-09 23:51:41 +02:00
|
|
|
# Open the file
|
2018-09-18 16:18:39 +02:00
|
|
|
my $oSourceFileIo = storageDb()->openRead($strDbFile, {rhyFilter => $rhyFilter, bIgnoreMissing => $bIgnoreMissing});
|
2017-06-09 23:51:41 +02:00
|
|
|
|
|
|
|
# If source file exists
|
|
|
|
if (defined($oSourceFileIo))
|
|
|
|
{
|
|
|
|
# Copy the file
|
|
|
|
$oStorageRepo->copy(
|
|
|
|
$oSourceFileIo,
|
|
|
|
$oStorageRepo->openWrite(
|
|
|
|
STORAGE_REPO_BACKUP . "/${strBackupLabel}/${strFileOp}",
|
2017-11-06 19:51:12 +02:00
|
|
|
{bPathCreate => true, bProtocolCompress => !$bCompress, strCipherPass => $strCipherPass}));
|
2017-06-09 23:51:41 +02:00
|
|
|
|
|
|
|
# Get sha checksum and size
|
|
|
|
$strCopyChecksum = $oSourceFileIo->result(STORAGE_FILTER_SHA);
|
|
|
|
$lCopySize = $oSourceFileIo->result(COMMON_IO_HANDLE);
|
|
|
|
|
|
|
|
# Get results of page checksum validation
|
|
|
|
$rExtra = $bChecksumPage ? $oSourceFileIo->result(BACKUP_FILTER_PAGECHECKSUM) : undef;
|
|
|
|
}
|
|
|
|
# Else if source file is missing the database removed it
|
|
|
|
else
|
2015-04-07 13:34:37 +02:00
|
|
|
{
|
2016-09-06 15:35:02 +02:00
|
|
|
$iCopyResult = BACKUP_FILE_SKIP;
|
2015-04-07 13:34:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-15 04:50:02 +02:00
|
|
|
# If file was copied or checksum'd then get size in repo. This has to be checked after the file is at rest because filesystem
|
|
|
|
# compression may affect the actual repo size and this cannot be calculated in stream.
|
2016-09-06 15:35:02 +02:00
|
|
|
if ($iCopyResult == BACKUP_FILE_COPY || $iCopyResult == BACKUP_FILE_RECOPY || $iCopyResult == BACKUP_FILE_CHECKSUM)
|
2016-04-15 04:50:02 +02:00
|
|
|
{
|
2017-06-09 23:51:41 +02:00
|
|
|
$lRepoSize = ($oStorageRepo->info(STORAGE_REPO_BACKUP . "/${strBackupLabel}/${strFileOp}"))->size();
|
2016-04-15 04:50:02 +02:00
|
|
|
}
|
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
2016-09-06 15:35:02 +02:00
|
|
|
{name => 'iCopyResult', value => $iCopyResult, trace => true},
|
2015-08-29 20:20:46 +02:00
|
|
|
{name => 'lCopySize', value => $lCopySize, trace => true},
|
2016-04-15 04:50:02 +02:00
|
|
|
{name => 'lRepoSize', value => $lRepoSize, trace => true},
|
2016-12-13 01:54:07 +02:00
|
|
|
{name => 'strCopyChecksum', value => $strCopyChecksum, trace => true},
|
|
|
|
{name => 'rExtra', value => $rExtra, trace => true},
|
2015-08-29 20:20:46 +02:00
|
|
|
);
|
2015-04-07 13:34:37 +02:00
|
|
|
}
|
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
push @EXPORT, qw(backupFile);
|
2015-04-07 13:34:37 +02:00
|
|
|
|
2015-04-11 21:02:04 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# backupManifestUpdate
|
|
|
|
####################################################################################################################################
|
|
|
|
sub backupManifestUpdate
|
|
|
|
{
|
2015-08-29 20:20:46 +02:00
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$oManifest,
|
2016-09-06 15:35:02 +02:00
|
|
|
$strHost,
|
2016-09-14 23:37:07 +02:00
|
|
|
$iLocalId,
|
2016-09-06 15:35:02 +02:00
|
|
|
$strDbFile,
|
2016-12-04 00:34:51 +02:00
|
|
|
$strRepoFile,
|
2015-08-29 20:20:46 +02:00
|
|
|
$lSize,
|
2016-12-04 00:34:51 +02:00
|
|
|
$strChecksum,
|
2016-12-13 01:54:07 +02:00
|
|
|
$bChecksumPage,
|
2016-12-04 00:34:51 +02:00
|
|
|
$iCopyResult,
|
2016-09-06 15:35:02 +02:00
|
|
|
$lSizeCopy,
|
|
|
|
$lSizeRepo,
|
2016-12-04 00:34:51 +02:00
|
|
|
$strChecksumCopy,
|
2016-12-13 01:54:07 +02:00
|
|
|
$rExtra,
|
2016-09-06 15:35:02 +02:00
|
|
|
$lSizeTotal,
|
|
|
|
$lSizeCurrent,
|
2015-08-29 20:20:46 +02:00
|
|
|
$lManifestSaveSize,
|
|
|
|
$lManifestSaveCurrent
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
2016-08-11 23:32:28 +02:00
|
|
|
__PACKAGE__ . '::backupManifestUpdate', \@_,
|
2015-08-29 20:20:46 +02:00
|
|
|
{name => 'oManifest', trace => true},
|
2016-09-06 15:35:02 +02:00
|
|
|
{name => 'strHost', required => false, trace => true},
|
2016-09-14 23:37:07 +02:00
|
|
|
{name => 'iLocalId', required => false, trace => true},
|
2016-12-04 00:34:51 +02:00
|
|
|
|
|
|
|
# Parameters to backupFile()
|
2016-09-06 15:35:02 +02:00
|
|
|
{name => 'strDbFile', trace => true},
|
2016-12-04 00:34:51 +02:00
|
|
|
{name => 'strRepoFile', trace => true},
|
2015-08-29 20:20:46 +02:00
|
|
|
{name => 'lSize', required => false, trace => true},
|
2016-12-04 00:34:51 +02:00
|
|
|
{name => 'strChecksum', required => false, trace => true},
|
2016-12-13 01:54:07 +02:00
|
|
|
{name => 'bChecksumPage', trace => true},
|
2016-12-04 00:34:51 +02:00
|
|
|
|
|
|
|
# Results from backupFile()
|
|
|
|
{name => 'iCopyResult', trace => true},
|
2016-09-06 15:35:02 +02:00
|
|
|
{name => 'lSizeCopy', required => false, trace => true},
|
|
|
|
{name => 'lSizeRepo', required => false, trace => true},
|
2016-12-04 00:34:51 +02:00
|
|
|
{name => 'strChecksumCopy', required => false, trace => true},
|
2016-12-13 01:54:07 +02:00
|
|
|
{name => 'rExtra', required => false, trace => true},
|
2016-12-04 00:34:51 +02:00
|
|
|
|
|
|
|
# Accumulators
|
2016-09-06 15:35:02 +02:00
|
|
|
{name => 'lSizeTotal', trace => true},
|
|
|
|
{name => 'lSizeCurrent', trace => true},
|
|
|
|
{name => 'lManifestSaveSize', trace => true},
|
|
|
|
{name => 'lManifestSaveCurrent', trace => true}
|
2015-08-29 20:20:46 +02:00
|
|
|
);
|
2015-04-11 21:02:04 +02:00
|
|
|
|
2016-09-06 15:35:02 +02:00
|
|
|
# Increment current backup progress
|
|
|
|
$lSizeCurrent += $lSize;
|
|
|
|
|
2018-09-19 17:12:45 +02:00
|
|
|
# If the file is in a prior backup and nothing changed, then nothing needs to be done
|
|
|
|
if ($iCopyResult == BACKUP_FILE_NOOP)
|
2015-04-11 21:02:04 +02:00
|
|
|
{
|
2018-09-19 17:12:45 +02:00
|
|
|
# File copy was not needed so just restore the size and checksum to the manifest
|
2016-09-06 15:35:02 +02:00
|
|
|
$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_SIZE, $lSizeCopy);
|
2018-09-19 17:12:45 +02:00
|
|
|
$oManifest->set(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_CHECKSUM, $strChecksumCopy);
|
2015-04-11 21:02:04 +02:00
|
|
|
|
2018-09-19 17:12:45 +02:00
|
|
|
&log(DETAIL,
|
|
|
|
'match file from prior backup ' . (defined($strHost) ? "${strHost}:" : '') . "${strDbFile} (" .
|
|
|
|
fileSizeFormat($lSizeCopy) . ', ' . int($lSizeCurrent * 100 / $lSizeTotal) . '%)' .
|
|
|
|
($lSizeCopy != 0 ? " checksum ${strChecksumCopy}" : ''),
|
|
|
|
undef, undef, undef, $iLocalId);
|
|
|
|
}
|
|
|
|
# Else process the results
|
|
|
|
else
|
|
|
|
{
|
|
|
|
# Log invalid checksum
|
|
|
|
if ($iCopyResult == BACKUP_FILE_RECOPY)
|
2015-04-11 21:02:04 +02:00
|
|
|
{
|
2018-09-19 17:12:45 +02:00
|
|
|
&log(
|
|
|
|
WARN,
|
|
|
|
"resumed backup file ${strRepoFile} does not have expected checksum ${strChecksum}. 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.");
|
2015-04-11 21:02:04 +02:00
|
|
|
}
|
2015-05-07 02:24:34 +02:00
|
|
|
|
2018-09-19 17:12:45 +02:00
|
|
|
# If copy was successful store the checksum and size
|
|
|
|
if ($iCopyResult == BACKUP_FILE_COPY || $iCopyResult == BACKUP_FILE_RECOPY || $iCopyResult == BACKUP_FILE_CHECKSUM)
|
2015-05-07 02:24:34 +02:00
|
|
|
{
|
2018-09-19 17:12:45 +02:00
|
|
|
# Log copy or checksum
|
|
|
|
&log($iCopyResult == BACKUP_FILE_CHECKSUM ? DETAIL : INFO,
|
|
|
|
($iCopyResult == BACKUP_FILE_CHECKSUM ?
|
|
|
|
'checksum resumed file ' : 'backup file ' . (defined($strHost) ? "${strHost}:" : '')) .
|
|
|
|
"${strDbFile} (" . fileSizeFormat($lSizeCopy) .
|
|
|
|
', ' . int($lSizeCurrent * 100 / $lSizeTotal) . '%)' .
|
|
|
|
($lSizeCopy != 0 ? " checksum ${strChecksumCopy}" : ''), undef, undef, undef, $iLocalId);
|
2016-12-13 01:54:07 +02:00
|
|
|
|
2018-09-19 17:12:45 +02:00
|
|
|
$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_SIZE, $lSizeCopy);
|
|
|
|
|
|
|
|
if ($lSizeRepo != $lSizeCopy)
|
2016-12-13 01:54:07 +02:00
|
|
|
{
|
2018-09-19 17:12:45 +02:00
|
|
|
$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_REPO_SIZE, $lSizeRepo);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($lSizeCopy > 0)
|
|
|
|
{
|
|
|
|
$oManifest->set(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_CHECKSUM, $strChecksumCopy);
|
|
|
|
}
|
2016-12-13 01:54:07 +02:00
|
|
|
|
2018-09-19 17:12:45 +02:00
|
|
|
# If the file was copied, then remove any reference to the file's existence in a prior backup.
|
|
|
|
if ($iCopyResult == BACKUP_FILE_COPY || $iCopyResult == BACKUP_FILE_RECOPY)
|
|
|
|
{
|
|
|
|
$oManifest->remove(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_REFERENCE);
|
|
|
|
}
|
|
|
|
|
|
|
|
# If the file had page checksums calculated during the copy
|
|
|
|
if ($bChecksumPage)
|
|
|
|
{
|
|
|
|
# The valid flag should be set
|
|
|
|
if (defined($rExtra->{bValid}))
|
2016-12-13 01:54:07 +02:00
|
|
|
{
|
2018-09-19 17:12:45 +02:00
|
|
|
# Store the valid flag
|
|
|
|
$oManifest->boolSet(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_CHECKSUM_PAGE, $rExtra->{bValid});
|
2016-12-13 01:54:07 +02:00
|
|
|
|
2018-09-19 17:12:45 +02:00
|
|
|
# If the page was not valid
|
|
|
|
if (!$rExtra->{bValid})
|
2016-12-13 01:54:07 +02:00
|
|
|
{
|
2018-09-19 17:12:45 +02:00
|
|
|
# Check for a page misalignment
|
|
|
|
if ($lSizeCopy % PG_PAGE_SIZE != 0)
|
|
|
|
{
|
|
|
|
# Make sure the align flag was set, otherwise there is a bug
|
|
|
|
if (!defined($rExtra->{bAlign}) || $rExtra->{bAlign})
|
|
|
|
{
|
|
|
|
confess &log(ASSERT, 'bAlign flag should have been set for misaligned page');
|
|
|
|
}
|
2016-12-13 01:54:07 +02:00
|
|
|
|
2018-09-19 17:12:45 +02:00
|
|
|
# Emit a warning so the user knows something is amiss
|
|
|
|
&log(WARN,
|
|
|
|
'page misalignment in file ' . (defined($strHost) ? "${strHost}:" : '') .
|
|
|
|
"${strDbFile}: file size ${lSizeCopy} is not divisible by page size " . PG_PAGE_SIZE);
|
|
|
|
}
|
|
|
|
# Else process the page check errors
|
|
|
|
else
|
2016-12-13 01:54:07 +02:00
|
|
|
{
|
2018-09-19 17:12:45 +02:00
|
|
|
$oManifest->set(
|
|
|
|
MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR,
|
|
|
|
dclone($rExtra->{iyPageError}));
|
2016-12-13 01:54:07 +02:00
|
|
|
|
2018-09-19 17:12:45 +02:00
|
|
|
# Build a pretty list of the page errors
|
|
|
|
my $strPageError;
|
|
|
|
my $iPageErrorTotal = 0;
|
|
|
|
|
|
|
|
foreach my $iyPage (@{$rExtra->{iyPageError}})
|
2016-12-13 01:54:07 +02:00
|
|
|
{
|
2018-09-19 17:12:45 +02:00
|
|
|
$strPageError .= (defined($strPageError) ? ', ' : '');
|
|
|
|
|
|
|
|
# If a range of pages
|
|
|
|
if (ref($iyPage))
|
|
|
|
{
|
|
|
|
$strPageError .= $$iyPage[0] . '-' . $$iyPage[1];
|
|
|
|
$iPageErrorTotal += ($$iyPage[1] - $$iyPage[0]) + 1;
|
|
|
|
}
|
|
|
|
# Else a single page
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$strPageError .= $iyPage;
|
|
|
|
$iPageErrorTotal += 1;
|
|
|
|
}
|
2016-12-13 01:54:07 +02:00
|
|
|
}
|
2018-09-19 17:12:45 +02:00
|
|
|
|
|
|
|
# There should be at least one page in the error list
|
|
|
|
if ($iPageErrorTotal == 0)
|
2016-12-13 01:54:07 +02:00
|
|
|
{
|
2018-09-19 17:12:45 +02:00
|
|
|
confess &log(ASSERT, 'page checksum error list should have at least one entry');
|
2016-12-13 01:54:07 +02:00
|
|
|
}
|
|
|
|
|
2018-09-19 17:12:45 +02:00
|
|
|
# Emit a warning so the user knows something is amiss
|
|
|
|
&log(WARN,
|
|
|
|
'invalid page checksum' . ($iPageErrorTotal > 1 ? 's' : '') .
|
|
|
|
' found in file ' . (defined($strHost) ? "${strHost}:" : '') . "${strDbFile} at page" .
|
|
|
|
($iPageErrorTotal > 1 ? 's' : '') . " ${strPageError}");
|
2016-12-13 01:54:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-09-19 17:12:45 +02:00
|
|
|
# If it's not set that's a bug in the code
|
|
|
|
elsif (!$oManifest->test(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_CHECKSUM_PAGE))
|
|
|
|
{
|
|
|
|
confess &log(ASSERT, "${strDbFile} should have calculated page checksums");
|
|
|
|
}
|
2016-12-13 01:54:07 +02:00
|
|
|
}
|
|
|
|
}
|
2018-09-19 17:12:45 +02:00
|
|
|
# Else the file was removed during backup so remove from manifest
|
|
|
|
elsif ($iCopyResult == BACKUP_FILE_SKIP)
|
|
|
|
{
|
|
|
|
&log(DETAIL, 'skip file removed by database ' . (defined($strHost) ? "${strHost}:" : '') . $strDbFile);
|
|
|
|
$oManifest->remove(MANIFEST_SECTION_TARGET_FILE, $strRepoFile);
|
|
|
|
}
|
2016-09-06 15:35:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# Determine whether to save the manifest
|
|
|
|
$lManifestSaveCurrent += $lSize;
|
|
|
|
|
|
|
|
if ($lManifestSaveCurrent >= $lManifestSaveSize)
|
|
|
|
{
|
2017-06-09 23:51:41 +02:00
|
|
|
$oManifest->saveCopy();
|
|
|
|
|
2016-09-06 15:35:02 +02:00
|
|
|
logDebugMisc
|
|
|
|
(
|
|
|
|
$strOperation, 'save manifest',
|
|
|
|
{name => 'lManifestSaveSize', value => $lManifestSaveSize},
|
|
|
|
{name => 'lManifestSaveCurrent', value => $lManifestSaveCurrent}
|
|
|
|
);
|
|
|
|
|
|
|
|
$lManifestSaveCurrent = 0;
|
2015-04-11 21:02:04 +02:00
|
|
|
}
|
2015-05-07 02:24:34 +02:00
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
2016-09-06 15:35:02 +02:00
|
|
|
{name => 'lSizeCurrent', value => $lSizeCurrent, trace => true},
|
|
|
|
{name => 'lManifestSaveCurrent', value => $lManifestSaveCurrent, trace => true},
|
2015-08-29 20:20:46 +02:00
|
|
|
);
|
2015-04-11 21:02:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
push @EXPORT, qw(backupManifestUpdate);
|
|
|
|
|
2015-04-07 13:34:37 +02:00
|
|
|
1;
|