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
|
|
|
|
|
|
|
use threads;
|
|
|
|
use Thread::Queue;
|
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
|
|
|
|
|
|
|
use lib dirname($0);
|
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;
|
2015-08-29 20:20:46 +02:00
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# Operation constants
|
|
|
|
####################################################################################################################################
|
|
|
|
use constant OP_BACKUP_FILE => 'BackupFile';
|
|
|
|
|
|
|
|
use constant OP_BACKUP_FILE_BACKUP_FILE => OP_BACKUP_FILE . '::backupFile';
|
|
|
|
use constant OP_BACKUP_FILE_BACKUP_MANIFEST_UPDATE => OP_BACKUP_FILE . '::backupManifestUpdate';
|
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
|
2015-08-29 20:20:46 +02:00
|
|
|
$bDestinationCompress, # Compress destination file
|
|
|
|
$strChecksum, # File checksum to be checked
|
|
|
|
$lModificationTime, # File modification time
|
|
|
|
$lSizeFile, # File size
|
|
|
|
$lSizeTotal, # Total size of the files to be copied
|
|
|
|
$lSizeCurrent, # Size of files copied so far
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
OP_BACKUP_FILE_BACKUP_FILE, \@_,
|
|
|
|
{name => 'oFile', trace => true},
|
2016-04-15 04:50:02 +02:00
|
|
|
{name => 'strDbFile', trace => true},
|
|
|
|
{name => 'strRepoFile', trace => true},
|
2015-08-29 20:20:46 +02:00
|
|
|
{name => 'bDestinationCompress', trace => true},
|
|
|
|
{name => 'strChecksum', required => false, trace => true},
|
|
|
|
{name => 'lModificationTime', trace => true},
|
|
|
|
{name => 'lSizeFile', trace => true},
|
2016-02-15 03:42:11 +02:00
|
|
|
{name => 'lSizeTotal', default => 0, trace => true},
|
|
|
|
{name => 'lSizeCurrent', required => false, trace => true}
|
2015-08-29 20:20:46 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
my $bCopyResult = true; # Copy result
|
|
|
|
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
|
|
|
|
|
|
|
# Add the size of the current file to keep track of percent complete
|
|
|
|
$lSizeCurrent += $lSizeFile;
|
|
|
|
|
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-04-15 04:50:02 +02:00
|
|
|
&log(WARN, "resumed backup file ${strRepoFile} should have checksum ${strChecksum} but " .
|
2015-05-07 02:24:34 +02:00
|
|
|
"actually has checksum ${strCopyChecksum}. 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-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)
|
|
|
|
($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
|
|
|
|
true, # 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-04-15 04:50:02 +02:00
|
|
|
&log(DETAIL, "skip file removed by database: " . $strDbFile);
|
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.
|
|
|
|
if ($bCopyResult)
|
|
|
|
{
|
|
|
|
$lRepoSize = (fileStat($oFile->pathGet(PATH_BACKUP_TMP, $strFileOp)))->size;
|
|
|
|
}
|
|
|
|
|
2015-05-07 02:24:34 +02:00
|
|
|
# Ouput log
|
2015-08-29 20:20:46 +02:00
|
|
|
if ($bCopyResult)
|
|
|
|
{
|
2016-04-15 04:50:02 +02:00
|
|
|
&log($bCopy ? INFO : DETAIL,
|
|
|
|
(defined($strChecksum) && !$bCopy ? 'checksum resumed file' : 'backup file') .
|
|
|
|
" ${strDbFile} (" . fileSizeFormat($lCopySize) .
|
|
|
|
($lSizeTotal > 0 ? ', ' . int($lSizeCurrent * 100 / $lSizeTotal) . '%' : '') . ')' .
|
|
|
|
($lCopySize != 0 ? " checksum ${strCopyChecksum}" : ''));
|
2015-08-29 20:20:46 +02:00
|
|
|
}
|
2015-04-07 13:34:37 +02:00
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'bCopyResult', value => $bCopyResult, trace => true},
|
|
|
|
{name => 'lSizeCurrent', value => $lSizeCurrent, trace => true},
|
|
|
|
{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,
|
|
|
|
$strFile,
|
|
|
|
$bCopied,
|
|
|
|
$lSize,
|
2016-04-15 04:50:02 +02:00
|
|
|
$lRepoSize,
|
2015-08-29 20:20:46 +02:00
|
|
|
$strChecksum,
|
|
|
|
$lManifestSaveSize,
|
|
|
|
$lManifestSaveCurrent
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
OP_BACKUP_FILE_BACKUP_MANIFEST_UPDATE, \@_,
|
|
|
|
{name => 'oManifest', trace => true},
|
|
|
|
{name => 'strFile', trace => true},
|
|
|
|
{name => 'bCopied', trace => true},
|
|
|
|
{name => 'lSize', required => false, trace => true},
|
2016-04-15 04:50:02 +02:00
|
|
|
{name => 'lRepoSize', required => false, trace => true},
|
2015-08-29 20:20:46 +02:00
|
|
|
{name => 'strChecksum', required => false, trace => true},
|
2016-02-15 03:42:11 +02:00
|
|
|
{name => 'lManifestSaveSize', required => false, trace => true},
|
|
|
|
{name => 'lManifestSaveCurrent', required => false, trace => true}
|
2015-08-29 20:20:46 +02:00
|
|
|
);
|
2015-04-11 21:02:04 +02:00
|
|
|
|
|
|
|
# If copy was successful store the checksum and size
|
|
|
|
if ($bCopied)
|
|
|
|
{
|
2016-04-15 04:50:02 +02:00
|
|
|
$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_SIZE, $lSize);
|
|
|
|
|
|
|
|
if ($lRepoSize != $lSize)
|
|
|
|
{
|
|
|
|
$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_REPO_SIZE, $lRepoSize);
|
|
|
|
}
|
2015-04-11 21:02:04 +02:00
|
|
|
|
|
|
|
if ($lSize > 0)
|
|
|
|
{
|
2016-04-15 04:50:02 +02:00
|
|
|
$oManifest->set(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_CHECKSUM, $strChecksum);
|
2015-04-11 21:02:04 +02:00
|
|
|
}
|
2015-05-07 02:24:34 +02:00
|
|
|
|
|
|
|
# Determine whether to save the manifest
|
2016-02-15 03:42:11 +02:00
|
|
|
if (defined($lManifestSaveSize))
|
2015-05-07 02:24:34 +02:00
|
|
|
{
|
2016-02-15 03:42:11 +02:00
|
|
|
$lManifestSaveCurrent += $lSize;
|
|
|
|
|
|
|
|
if ($lManifestSaveCurrent >= $lManifestSaveSize)
|
|
|
|
{
|
|
|
|
$oManifest->save();
|
|
|
|
logDebugMisc
|
|
|
|
(
|
|
|
|
$strOperation, 'save manifest',
|
|
|
|
{name => 'lManifestSaveSize', value => $lManifestSaveSize},
|
|
|
|
{name => 'lManifestSaveCurrent', value => $lManifestSaveCurrent}
|
|
|
|
);
|
|
|
|
|
|
|
|
$lManifestSaveCurrent = 0;
|
|
|
|
}
|
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
|
|
|
|
else
|
|
|
|
{
|
2016-04-15 04:50:02 +02:00
|
|
|
$oManifest->remove(MANIFEST_SECTION_TARGET_FILE, $strFile);
|
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,
|
|
|
|
{name => 'lManifestSaveCurrent', value => $lManifestSaveCurrent, trace => true}
|
|
|
|
);
|
2015-04-11 21:02:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
push @EXPORT, qw(backupManifestUpdate);
|
|
|
|
|
2015-04-07 13:34:37 +02:00
|
|
|
1;
|