You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-12-07 23:03:24 +02:00
The local command for restore is implemented entirely in C.
This is just the part of restore run by the local helper processes, not the entire command. Even so, various optimizations in the code (like pipelining and optimizations for zero-length files) should make the restore command faster on object stores.
This commit is contained in:
@@ -25,156 +25,6 @@ use pgBackRest::Storage::Filter::Gzip;
|
||||
use pgBackRest::Storage::Filter::Sha;
|
||||
use pgBackRest::Storage::Helper;
|
||||
|
||||
####################################################################################################################################
|
||||
# restoreFile
|
||||
#
|
||||
# Restores a single file.
|
||||
####################################################################################################################################
|
||||
sub restoreFile
|
||||
{
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strDbFile,
|
||||
$lSize,
|
||||
$lModificationTime,
|
||||
$strChecksum,
|
||||
$bZero,
|
||||
$bForce, # Force flag
|
||||
$strRepoFile,
|
||||
$strReference,
|
||||
$strMode,
|
||||
$strUser,
|
||||
$strGroup,
|
||||
$lCopyTimeStart, # Backup start time - used for size/timestamp deltas
|
||||
$bDelta, # Is restore a delta?
|
||||
$strBackupPath, # Backup path
|
||||
$bSourceCompressed, # Is the source compressed?
|
||||
$strCipherPass, # Passphrase to decrypt the repo file (undefined if repo not encrypted)
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '::restoreFile', \@_,
|
||||
{name => 'strDbFile', trace => true},
|
||||
{name => 'lSize', trace => true},
|
||||
{name => 'lModificationTime', trace => true},
|
||||
{name => 'strChecksum', required => false, trace => true},
|
||||
{name => 'bZero', required => false, default => false, trace => true},
|
||||
{name => 'bForce', trace => true},
|
||||
{name => 'strRepoFile', trace => true},
|
||||
{name => 'strReference', required => false, trace => true},
|
||||
{name => 'strMode', trace => true},
|
||||
{name => 'strUser', trace => true},
|
||||
{name => 'strGroup', trace => true},
|
||||
{name => 'lCopyTimeStart', trace => true},
|
||||
{name => 'bDelta', trace => true},
|
||||
{name => 'strBackupPath', trace => true},
|
||||
{name => 'bSourceCompressed', trace => true},
|
||||
{name => 'strCipherPass', required => false, trace => true},
|
||||
);
|
||||
|
||||
# Does the file need to be copied?
|
||||
my $oStorageDb = storageDb();
|
||||
my $bCopy = true;
|
||||
|
||||
# Zero file if requested
|
||||
if ($bZero)
|
||||
{
|
||||
$bCopy = false;
|
||||
|
||||
my $oDestinationFileIo = $oStorageDb->openWrite(
|
||||
$strDbFile, {strMode => $strMode, strUser => $strUser, strGroup => $strGroup, lTimestamp => $lModificationTime});
|
||||
$oDestinationFileIo->open();
|
||||
|
||||
# Now truncate to the original size. This will create a sparse file which is very efficient for this use case.
|
||||
truncate($oDestinationFileIo->handle(), $lSize);
|
||||
|
||||
$oDestinationFileIo->close();
|
||||
}
|
||||
# Perform delta if requested
|
||||
elsif ($bDelta)
|
||||
{
|
||||
my $oStat = $oStorageDb->info($strDbFile, {bIgnoreMissing => true});
|
||||
|
||||
# Do the delta if the file exists and is not a link or the link destination exists
|
||||
if (defined($oStat) &&
|
||||
(!S_ISLNK($oStat->mode) ||
|
||||
$oStorageDb->exists(
|
||||
$oStorageDb->pathAbsolute(dirname($strDbFile), $oStorageDb->{oDriver}->linkDestination($strDbFile)))))
|
||||
{
|
||||
# If force then use size/timestamp delta
|
||||
if ($bForce)
|
||||
{
|
||||
# Make sure that timestamp/size are equal and that timestamp is before the copy start time of the backup
|
||||
if (defined($oStat) && $oStat->size == $lSize &&
|
||||
$oStat->mtime == $lModificationTime && $oStat->mtime < $lCopyTimeStart)
|
||||
{
|
||||
$bCopy = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
my ($strActualChecksum, $lActualSize) = $oStorageDb->hashSize($strDbFile);
|
||||
|
||||
if ($lActualSize == $lSize && ($lSize == 0 || $strActualChecksum eq $strChecksum))
|
||||
{
|
||||
# Even if hash is the same set the time back to backup time. This helps with unit testing, but also
|
||||
# presents a pristine version of the database after restore.
|
||||
utime($lModificationTime, $lModificationTime, $strDbFile)
|
||||
or confess &log(ERROR, "unable to set time for ${strDbFile}");
|
||||
|
||||
$bCopy = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Copy file from repository to database
|
||||
if ($bCopy)
|
||||
{
|
||||
# Add sha filter
|
||||
my $rhyFilter = [{strClass => STORAGE_FILTER_SHA}];
|
||||
|
||||
# Add compression
|
||||
if ($bSourceCompressed)
|
||||
{
|
||||
unshift(@{$rhyFilter}, {strClass => STORAGE_FILTER_GZIP, rxyParam => [{strCompressType => STORAGE_DECOMPRESS}]});
|
||||
}
|
||||
|
||||
# Open destination file
|
||||
my $oDestinationFileIo = $oStorageDb->openWrite(
|
||||
$strDbFile,
|
||||
{strMode => $strMode, strUser => $strUser, strGroup => $strGroup, lTimestamp => $lModificationTime,
|
||||
rhyFilter => $rhyFilter});
|
||||
|
||||
# Copy file
|
||||
storageRepo()->copy(
|
||||
storageRepo()->openRead(
|
||||
STORAGE_REPO_BACKUP . qw(/) . (defined($strReference) ? $strReference : $strBackupPath) .
|
||||
"/${strRepoFile}" . ($bSourceCompressed ? qw{.} . COMPRESS_EXT : ''),
|
||||
{bProtocolCompress => !$bSourceCompressed && $lSize != 0, strCipherPass => $strCipherPass}),
|
||||
$oDestinationFileIo);
|
||||
|
||||
# Validate checksum
|
||||
if ($oDestinationFileIo->result(COMMON_IO_HANDLE) != 0 && $oDestinationFileIo->result(STORAGE_FILTER_SHA) ne $strChecksum)
|
||||
{
|
||||
confess &log(ERROR,
|
||||
"error restoring ${strDbFile}: actual checksum '" . $oDestinationFileIo->digest() .
|
||||
"' does not match expected checksum ${strChecksum}", ERROR_CHECKSUM);
|
||||
}
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'bCopy', value => $bCopy, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(restoreFile);
|
||||
|
||||
####################################################################################################################################
|
||||
# restoreLog
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user