2015-04-07 13:34:37 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# BACKUP FILE MODULE
|
|
|
|
####################################################################################################################################
|
2016-04-14 15:30:54 +02:00
|
|
|
package pgBackRest::BackupFile;
|
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);
|
2015-04-07 13:34:37 +02:00
|
|
|
|
2016-04-14 15:30:54 +02:00
|
|
|
use pgBackRest::Common::Exception;
|
|
|
|
use pgBackRest::Common::Log;
|
|
|
|
use pgBackRest::Common::String;
|
|
|
|
use pgBackRest::File;
|
2016-04-15 04:50:02 +02:00
|
|
|
use pgBackRest::FileCommon;
|
2016-04-14 15:30:54 +02:00
|
|
|
use pgBackRest::Manifest;
|
2016-09-06 15:35:02 +02:00
|
|
|
use pgBackRest::Protocol::Common;
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# 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);
|
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,
|
|
|
|
$oFile, # File object
|
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-04 00:34:51 +02:00
|
|
|
$bDestinationCompress, # Compress destination file
|
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?
|
2015-08-29 20:20:46 +02:00
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
2016-08-11 23:32:28 +02:00
|
|
|
__PACKAGE__ . '::backupFile', \@_,
|
2015-08-29 20:20:46 +02:00
|
|
|
{name => 'oFile', trace => true},
|
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},
|
|
|
|
{name => 'bDestinationCompress', trace => true},
|
|
|
|
{name => 'lModificationTime', trace => true},
|
|
|
|
{name => 'bIgnoreMissing', default => true, trace => true},
|
2015-08-29 20:20:46 +02:00
|
|
|
);
|
|
|
|
|
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
|
|
|
|
my $lCopySize; # Copy Size
|
2016-04-15 04:50:02 +02:00
|
|
|
my $lRepoSize; # Repo size
|
2015-04-07 13:34:37 +02:00
|
|
|
|
2015-05-07 02:24:34 +02:00
|
|
|
# If checksum is defined then the file already exists but needs to be checked
|
|
|
|
my $bCopy = true;
|
|
|
|
|
2016-04-15 04:50:02 +02:00
|
|
|
# Add compression suffix if needed
|
|
|
|
my $strFileOp = $strRepoFile . ($bDestinationCompress ? '.' . $oFile->{strCompressExtension} : '');
|
|
|
|
|
2015-05-07 02:24:34 +02:00
|
|
|
if (defined($strChecksum))
|
2015-04-07 13:34:37 +02:00
|
|
|
{
|
2015-08-29 20:20:46 +02:00
|
|
|
($strCopyChecksum, $lCopySize) =
|
2016-04-15 04:50:02 +02:00
|
|
|
$oFile->hashSize(PATH_BACKUP_TMP, $strFileOp, $bDestinationCompress);
|
2015-05-07 02:24:34 +02:00
|
|
|
|
|
|
|
$bCopy = !($strCopyChecksum eq $strChecksum && $lCopySize == $lSizeFile);
|
|
|
|
|
|
|
|
if ($bCopy)
|
|
|
|
{
|
2016-09-06 15:35:02 +02:00
|
|
|
$iCopyResult = BACKUP_FILE_RECOPY;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$iCopyResult = BACKUP_FILE_CHECKSUM;
|
2015-05-07 02:24:34 +02:00
|
|
|
}
|
2015-04-07 13:34:37 +02:00
|
|
|
}
|
|
|
|
|
2015-05-07 02:24:34 +02:00
|
|
|
if ($bCopy)
|
|
|
|
{
|
2015-04-07 13:34:37 +02:00
|
|
|
# Copy the file from the database to the backup (will return false if the source file is missing)
|
2016-09-06 15:35:02 +02:00
|
|
|
(my $bCopyResult, $strCopyChecksum, $lCopySize) =
|
2016-04-15 04:50:02 +02:00
|
|
|
$oFile->copy(PATH_DB_ABSOLUTE, $strDbFile,
|
|
|
|
PATH_BACKUP_TMP, $strFileOp,
|
2015-04-07 13:34:37 +02:00
|
|
|
false, # Source is not compressed since it is the db directory
|
|
|
|
$bDestinationCompress, # Destination should be compressed based on backup settings
|
2016-08-24 18:39:27 +02:00
|
|
|
$bIgnoreMissing, # Ignore missing files
|
2015-05-07 02:24:34 +02:00
|
|
|
$lModificationTime, # Set modification time - this is required for resume
|
2015-04-07 13:34:37 +02:00
|
|
|
undef, # Do not set original mode
|
|
|
|
true); # Create the destination directory if it does not exist
|
|
|
|
|
2016-04-15 04:50:02 +02:00
|
|
|
# If source file is missing then assume the database removed it (else corruption and nothing we can do!)
|
2015-04-07 13:34:37 +02:00
|
|
|
if (!$bCopyResult)
|
|
|
|
{
|
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
|
|
|
{
|
|
|
|
$lRepoSize = (fileStat($oFile->pathGet(PATH_BACKUP_TMP, $strFileOp)))->size;
|
|
|
|
}
|
|
|
|
|
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},
|
2015-08-29 20:20:46 +02:00
|
|
|
{name => 'strCopyChecksum', value => $strCopyChecksum, trace => true}
|
|
|
|
);
|
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,
|
|
|
|
$iCopyResult,
|
2016-09-06 15:35:02 +02:00
|
|
|
$lSizeCopy,
|
|
|
|
$lSizeRepo,
|
2016-12-04 00:34:51 +02:00
|
|
|
$strChecksumCopy,
|
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},
|
|
|
|
|
|
|
|
# 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},
|
|
|
|
|
|
|
|
# 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;
|
|
|
|
|
|
|
|
# Log invalid checksum
|
|
|
|
if ($iCopyResult == BACKUP_FILE_RECOPY)
|
|
|
|
{
|
|
|
|
&log(
|
|
|
|
WARN,
|
|
|
|
"resumed backup file ${strRepoFile} should have checksum ${strChecksum} but actually has checksum ${strChecksumCopy}." .
|
|
|
|
" The file will be recopied and backup will continue but this may be an issue unless the backup temp path is known to" .
|
|
|
|
" be corrupted.");
|
|
|
|
}
|
|
|
|
|
2015-04-11 21:02:04 +02:00
|
|
|
# If copy was successful store the checksum and size
|
2016-09-06 15:35:02 +02:00
|
|
|
if ($iCopyResult == BACKUP_FILE_COPY || $iCopyResult == BACKUP_FILE_RECOPY || $iCopyResult == BACKUP_FILE_CHECKSUM)
|
2015-04-11 21:02:04 +02:00
|
|
|
{
|
2016-09-06 15:35:02 +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) . '%)' .
|
2016-09-14 23:37:07 +02:00
|
|
|
($lSizeCopy != 0 ? " checksum ${strChecksumCopy}" : ''), undef, undef, undef, $iLocalId);
|
2016-04-15 04:50:02 +02:00
|
|
|
|
2016-09-06 15:35:02 +02:00
|
|
|
$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_SIZE, $lSizeCopy);
|
2015-04-11 21:02:04 +02:00
|
|
|
|
2016-09-06 15:35:02 +02:00
|
|
|
if ($lSizeRepo != $lSizeCopy)
|
2015-04-11 21:02:04 +02:00
|
|
|
{
|
2016-09-06 15:35:02 +02:00
|
|
|
$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_REPO_SIZE, $lSizeRepo);
|
2015-04-11 21:02:04 +02:00
|
|
|
}
|
2015-05-07 02:24:34 +02:00
|
|
|
|
2016-09-06 15:35:02 +02:00
|
|
|
if ($lSizeCopy > 0)
|
2015-05-07 02:24:34 +02:00
|
|
|
{
|
2016-09-06 15:35:02 +02:00
|
|
|
$oManifest->set(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_CHECKSUM, $strChecksumCopy);
|
2015-05-07 02:24:34 +02:00
|
|
|
}
|
2015-04-11 21:02:04 +02:00
|
|
|
}
|
|
|
|
# Else the file was removed during backup so remove from manifest
|
2016-09-06 15:35:02 +02:00
|
|
|
elsif ($iCopyResult == BACKUP_FILE_SKIP)
|
2015-04-11 21:02:04 +02:00
|
|
|
{
|
2016-09-06 15:35:02 +02:00
|
|
|
&log(DETAIL, 'skip file removed by database ' . (defined($strHost) ? "${strHost}:" : '') . $strDbFile);
|
|
|
|
$oManifest->remove(MANIFEST_SECTION_TARGET_FILE, $strRepoFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
# Determine whether to save the manifest
|
|
|
|
$lManifestSaveCurrent += $lSize;
|
|
|
|
|
|
|
|
if ($lManifestSaveCurrent >= $lManifestSaveSize)
|
|
|
|
{
|
|
|
|
$oManifest->save();
|
|
|
|
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;
|