1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-14 10:13:05 +02:00
pgbackrest/lib/BackRest/BackupFile.pm
David Steele 1afbab010f v0.75: New repository format, info command and experimental 9.5 support
* IMPORTANT NOTE: This flag day release breaks compatibility with older versions of PgBackRest.  The manifest format, on-disk structure, and the binary names have all changed.  You must create a new repository to hold backups for this version of PgBackRest and keep your older repository for a time in case you need to do a restore.  The `pg_backrest.conf` file has not changed but you'll need to change any references to `pg_backrest.pl` in cron (or elsewhere) to `pg_backrest` (without the `.pl` extension).

* Add info command.

* More efficient file ordering for backup.  Files are copied in descending size order so a single thread does not end up copying a large file at the end.  This had already been implemented for restore.

* Logging now uses unbuffered output.  This should make log files that are being written by multiple threads less chaotic.  Suggested by Michael Renner.

* Experimental support for PostgreSQL 9.5.  This may break when the control version or WAL magic changes but will be updated in each release.
2015-06-14 20:59:32 -04:00

141 lines
5.4 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);
use File::Basename qw(dirname);
use lib dirname($0);
use BackRest::Exception;
use BackRest::File;
use BackRest::Manifest;
use BackRest::Utility;
####################################################################################################################################
# backupFile
####################################################################################################################################
sub backupFile
{
my $oFile = shift; # File object
my $strSourceFile = shift; # Source file to backup
my $strDestinationFile = shift; # Destination backup file
my $bDestinationCompress = shift; # Compress destination file
my $strChecksum = shift; # File checksum to be checked
my $lModificationTime = shift; # File modification time
my $lSizeFile = shift; # File size
my $lSizeTotal = shift; # Total size of the files to be copied
my $lSizeCurrent = shift; # Size of files copied so far
my $bCopyResult; # 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->hash_size(PATH_BACKUP_TMP, $strDestinationFile);
$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);
return false, $lSizeCurrent, undef, undef;
}
}
# Ouput log
&log(INFO, (defined($strChecksum) && !$bCopy ? 'checksum resumed file' : 'backup file') .
" $strSourceFile (" . file_size_format($lCopySize) .
($lSizeTotal > 0 ? ', ' . int($lSizeCurrent * 100 / $lSizeTotal) . '%' : '') . ')' .
($lCopySize != 0 ? " checksum ${strCopyChecksum}" : ''));
return true, $lSizeCurrent, $lCopySize, $strCopyChecksum;
}
our @EXPORT = qw(backupFile);
####################################################################################################################################
# backupManifestUpdate
####################################################################################################################################
sub backupManifestUpdate
{
my $oManifest = shift;
my $strSection = shift;
my $strFile = shift;
my $bCopied = shift;
my $lSize = shift;
my $strChecksum = shift;
my $lManifestSaveSize = shift;
my $lManifestSaveCurrent = shift;
# 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();
&log(DEBUG, 'manifest saved');
$lManifestSaveCurrent = 0;
}
}
# Else the file was removed during backup so remove from manifest
else
{
$oManifest->remove($strSection, $strFile);
}
return $lManifestSaveCurrent;
}
push @EXPORT, qw(backupManifestUpdate);
1;