You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2026-01-06 08:01:21 +03:00
* Fixed an issue where resumed compressed backups were not preserving existing files. * Fixed an issue where resume and incr/diff would not ensure that the prior backup had the same compression and hardlink settings. * Fixed an issue where a cold backup using --no-start-stop could be started on a running PostgreSQL cluster without --force specified. * Fixed an issue where a thread could be started even when none were requested. * Fixed an issue where the pgBackRest version number was not being updated in backup.info and archive.info after an upgrade/downgrade. * Fixed an issue where the info command was throwing an exception when the repository contained no stanzas. Reported by Stephen Frost. * Fixed an issue where the PostgreSQL pg_stop_backup() NOTICEs were being output to stderr. Reported by Stephen Frost. * Renamed recovery-setting option and section to recovery-option to be more consistent with pgBackRest naming conventions. * Command-line help is now extracted from the same XML source that is used for the other documentation and includes much more detail. * Code cleanup and refactoring to standardize on patterns that have evolved over time. * Added dynamic module loading to speed up commands, especially asynchronous archiving. * Expiration tests are now synthetic rather than based on actual backups. This will allow development of more advanced expiration features. * Experimental support for PostgreSQL 9.5 alpha2. This may break when the control version or WAL magic changes in future versions but will be updated in each pgBackRest release to keep pace. All regression tests pass except for --target-resume tests (this functionality has changed in 9.5) and there is no testing yet for .partial WAL segments.
207 lines
8.3 KiB
Perl
207 lines
8.3 KiB
Perl
####################################################################################################################################
|
|
# BACKUP FILE MODULE
|
|
####################################################################################################################################
|
|
package BackRest::BackupFile;
|
|
|
|
use threads;
|
|
use Thread::Queue;
|
|
use strict;
|
|
use warnings FATAL => qw(all);
|
|
use Carp qw(confess);
|
|
|
|
use Exporter qw(import);
|
|
our @EXPORT = qw();
|
|
use File::Basename qw(dirname);
|
|
|
|
use lib dirname($0);
|
|
use BackRest::Common::Exception;
|
|
use BackRest::Common::Log;
|
|
use BackRest::Common::String;
|
|
use BackRest::File;
|
|
use BackRest::Manifest;
|
|
|
|
####################################################################################################################################
|
|
# 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';
|
|
|
|
####################################################################################################################################
|
|
# backupFile
|
|
####################################################################################################################################
|
|
sub backupFile
|
|
{
|
|
# Assign function parameters, defaults, and log debug info
|
|
my
|
|
(
|
|
$strOperation,
|
|
$oFile, # File object
|
|
$strSourceFile, # Source file to backup
|
|
$strDestinationFile, # Destination backup file
|
|
$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},
|
|
{name => 'strSourceFile', trace => true},
|
|
{name => 'strDestinationFile', trace => true},
|
|
{name => 'bDestinationCompress', trace => true},
|
|
{name => 'strChecksum', required => false, trace => true},
|
|
{name => 'lModificationTime', trace => true},
|
|
{name => 'lSizeFile', trace => true},
|
|
{name => 'lSizeTotal', trace => true},
|
|
{name => 'lSizeCurrent', trace => true}
|
|
);
|
|
|
|
my $bCopyResult = true; # Copy result
|
|
my $strCopyChecksum; # Copy checksum
|
|
my $lCopySize; # Copy Size
|
|
|
|
# Add the size of the current file to keep track of percent complete
|
|
$lSizeCurrent += $lSizeFile;
|
|
|
|
# If checksum is defined then the file already exists but needs to be checked
|
|
my $bCopy = true;
|
|
|
|
if (defined($strChecksum))
|
|
{
|
|
($strCopyChecksum, $lCopySize) =
|
|
$oFile->hashSize(PATH_BACKUP_TMP, $strDestinationFile .
|
|
($bDestinationCompress ? '.' . $oFile->{strCompressExtension} : ''), $bDestinationCompress);
|
|
|
|
$bCopy = !($strCopyChecksum eq $strChecksum && $lCopySize == $lSizeFile);
|
|
|
|
if ($bCopy)
|
|
{
|
|
&log(WARN, "resumed backup file ${strDestinationFile} should have checksum ${strChecksum} but " .
|
|
"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.");
|
|
}
|
|
}
|
|
|
|
if ($bCopy)
|
|
{
|
|
# Copy the file from the database to the backup (will return false if the source file is missing)
|
|
($bCopyResult, $strCopyChecksum, $lCopySize) =
|
|
$oFile->copy(PATH_DB_ABSOLUTE, $strSourceFile,
|
|
PATH_BACKUP_TMP, $strDestinationFile .
|
|
($bDestinationCompress ? '.' . $oFile->{strCompressExtension} : ''),
|
|
false, # Source is not compressed since it is the db directory
|
|
$bDestinationCompress, # Destination should be compressed based on backup settings
|
|
true, # Ignore missing files
|
|
$lModificationTime, # Set modification time - this is required for resume
|
|
undef, # Do not set original mode
|
|
true); # Create the destination directory if it does not exist
|
|
|
|
if (!$bCopyResult)
|
|
{
|
|
# If file is missing assume the database removed it (else corruption and nothing we can do!)
|
|
&log(INFO, "skip file removed by database: " . $strSourceFile);
|
|
}
|
|
}
|
|
|
|
# Ouput log
|
|
if ($bCopyResult)
|
|
{
|
|
&log(INFO, (defined($strChecksum) && !$bCopy ? 'checksum resumed file' : 'backup file') .
|
|
" $strSourceFile (" . fileSizeFormat($lCopySize) .
|
|
($lSizeTotal > 0 ? ', ' . int($lSizeCurrent * 100 / $lSizeTotal) . '%' : '') . ')' .
|
|
($lCopySize != 0 ? " checksum ${strCopyChecksum}" : ''));
|
|
}
|
|
|
|
# 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},
|
|
{name => 'strCopyChecksum', value => $strCopyChecksum, trace => true}
|
|
);
|
|
}
|
|
|
|
push @EXPORT, qw(backupFile);
|
|
|
|
####################################################################################################################################
|
|
# backupManifestUpdate
|
|
####################################################################################################################################
|
|
sub backupManifestUpdate
|
|
{
|
|
# Assign function parameters, defaults, and log debug info
|
|
my
|
|
(
|
|
$strOperation,
|
|
$oManifest,
|
|
$strSection,
|
|
$strFile,
|
|
$bCopied,
|
|
$lSize,
|
|
$strChecksum,
|
|
$lManifestSaveSize,
|
|
$lManifestSaveCurrent
|
|
) =
|
|
logDebugParam
|
|
(
|
|
OP_BACKUP_FILE_BACKUP_MANIFEST_UPDATE, \@_,
|
|
{name => 'oManifest', trace => true},
|
|
{name => 'strSection', trace => true},
|
|
{name => 'strFile', trace => true},
|
|
{name => 'bCopied', trace => true},
|
|
{name => 'lSize', required => false, trace => true},
|
|
{name => 'strChecksum', required => false, trace => true},
|
|
{name => 'lManifestSaveSize', trace => true},
|
|
{name => 'lManifestSaveCurrent', trace => true}
|
|
);
|
|
|
|
# If copy was successful store the checksum and size
|
|
if ($bCopied)
|
|
{
|
|
$oManifest->set($strSection, $strFile, MANIFEST_SUBKEY_SIZE, $lSize + 0);
|
|
|
|
if ($lSize > 0)
|
|
{
|
|
$oManifest->set($strSection, $strFile, MANIFEST_SUBKEY_CHECKSUM, $strChecksum);
|
|
}
|
|
|
|
# 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;
|
|
}
|
|
}
|
|
# Else the file was removed during backup so remove from manifest
|
|
else
|
|
{
|
|
$oManifest->remove($strSection, $strFile);
|
|
}
|
|
|
|
# Return from function and log return values if any
|
|
return logDebugReturn
|
|
(
|
|
$strOperation,
|
|
{name => 'lManifestSaveCurrent', value => $lManifestSaveCurrent, trace => true}
|
|
);
|
|
}
|
|
|
|
push @EXPORT, qw(backupManifestUpdate);
|
|
|
|
1;
|