You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-09-16 09:06:18 +02:00
Integration of new Manifest object.
This commit is contained in:
@@ -4,7 +4,7 @@ PgBackRest aims to be a simple backup and restore system that can seamlessly sca
|
||||
|
||||
Instead of relying on traditional backup tools like tar and rsync, PgBackRest implements all backup features internally and features a custom protocol for communicating with remote systems. Removing reliance on tar and rsync allows better solutions to database-specific backup issues. The custom remote protocol limits the types of connections that are required to perform a backup which increases security. Each thread requires only one SSH connection for remote backups.
|
||||
|
||||
A complete list of backrest features:
|
||||
Primary PgBackRest features:
|
||||
|
||||
* Local or remote backup
|
||||
* Multi-threaded backup/restore for performance
|
||||
|
@@ -1389,10 +1389,10 @@ sub backup
|
||||
$oFile->path_create(PATH_BACKUP_CLUSTER, undef, undef, true);
|
||||
|
||||
# Declare the backup manifest
|
||||
my %oBackupManifest;
|
||||
my $oBackupManifest = new BackRest::Manifest();
|
||||
|
||||
${oBackupManifest}{'backup:option'}{'compress'} = $bCompress ? 'y' : 'n';
|
||||
${oBackupManifest}{'backup:option'}{'checksum'} = !$bNoChecksum ? 'y' : 'n';
|
||||
${$oBackupManifest->{oManifest}}{'backup:option'}{'compress'} = $bCompress ? 'y' : 'n';
|
||||
${$oBackupManifest->{oManifest}}{'backup:option'}{'checksum'} = !$bNoChecksum ? 'y' : 'n';
|
||||
|
||||
# Find the previous backup based on the type
|
||||
my $oLastManifest;
|
||||
@@ -1401,16 +1401,15 @@ sub backup
|
||||
|
||||
if (defined($strBackupLastPath))
|
||||
{
|
||||
$oLastManifest = new BackRest::Manifest();
|
||||
ini_load($oFile->path_get(PATH_BACKUP_CLUSTER) . "/${strBackupLastPath}/backup.manifest", $oLastManifest);
|
||||
$oLastManifest = new BackRest::Manifest($oFile->path_get(PATH_BACKUP_CLUSTER) . "/${strBackupLastPath}/backup.manifest");
|
||||
|
||||
if (!defined(${$oLastManifest}{backup}{label}))
|
||||
if (!defined(${$oLastManifest->{oManifest}}{backup}{label}))
|
||||
{
|
||||
confess &log(ERROR, "unable to find label in backup ${strBackupLastPath}");
|
||||
}
|
||||
|
||||
&log(INFO, "last backup label: ${$oLastManifest}{backup}{label}, version ${$oLastManifest}{backup}{version}");
|
||||
${oBackupManifest}{backup}{prior} = ${$oLastManifest}{backup}{label};
|
||||
&log(INFO, "last backup label: ${$oLastManifest->{oManifest}}{backup}{label}, version ${$oLastManifest->{oManifest}}{backup}{version}");
|
||||
${$oBackupManifest->{oManifest}}{backup}{prior} = ${$oLastManifest->{oManifest}}{backup}{label};
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1426,11 +1425,11 @@ sub backup
|
||||
$strType = BACKUP_TYPE_FULL;
|
||||
}
|
||||
|
||||
${oBackupManifest}{backup}{type} = $strType;
|
||||
${$oBackupManifest->{oManifest}}{backup}{type} = $strType;
|
||||
|
||||
if ($strType ne BACKUP_TYPE_FULL)
|
||||
{
|
||||
${oBackupManifest}{'backup:option'}{'hardlink'} = $bHardLink ? 'y' : 'n';
|
||||
${$oBackupManifest->{oManifest}}{'backup:option'}{'hardlink'} = $bHardLink ? 'y' : 'n';
|
||||
}
|
||||
|
||||
# Build backup tmp and config
|
||||
@@ -1438,7 +1437,7 @@ sub backup
|
||||
my $strBackupConfFile = $oFile->path_get(PATH_BACKUP_TMP, 'backup.manifest');
|
||||
|
||||
# Start backup (unless no-start-stop is set)
|
||||
${oBackupManifest}{backup}{'timestamp-start'} = $strTimestampStart;
|
||||
${$oBackupManifest->{oManifest}}{backup}{'timestamp-start'} = $strTimestampStart;
|
||||
my $strArchiveStart;
|
||||
|
||||
if ($bNoStartStop)
|
||||
@@ -1461,12 +1460,12 @@ sub backup
|
||||
}
|
||||
else
|
||||
{
|
||||
($strArchiveStart, ${oBackupManifest}{backup}{'timestamp-db-start'}) = $oDb->backup_start('pg_backrest backup started ' . $strTimestampStart, $bStartFast);
|
||||
${oBackupManifest}{backup}{'archive-start'} = $strArchiveStart;
|
||||
&log(INFO, 'archive start: ' . ${oBackupManifest}{backup}{'archive-start'});
|
||||
($strArchiveStart, ${$oBackupManifest->{oManifest}}{backup}{'timestamp-db-start'}) = $oDb->backup_start('pg_backrest backup started ' . $strTimestampStart, $bStartFast);
|
||||
${$oBackupManifest->{oManifest}}{backup}{'archive-start'} = $strArchiveStart;
|
||||
&log(INFO, 'archive start: ' . ${$oBackupManifest->{oManifest}}{backup}{'archive-start'});
|
||||
}
|
||||
|
||||
${oBackupManifest}{backup}{version} = version_get();
|
||||
${$oBackupManifest->{oManifest}}{backup}{version} = version_get();
|
||||
|
||||
# Build the backup manifest
|
||||
my %oTablespaceMap;
|
||||
@@ -1498,7 +1497,7 @@ sub backup
|
||||
$oDb->tablespace_map_get(\%oTablespaceMap);
|
||||
}
|
||||
|
||||
backup_manifest_build($strDbClusterPath, \%oBackupManifest, $oLastManifest, \%oTablespaceMap);
|
||||
backup_manifest_build($strDbClusterPath, $oBackupManifest->{oManifest}, $oLastManifest, \%oTablespaceMap);
|
||||
&log(TEST, TEST_MANIFEST_BUILD);
|
||||
|
||||
# Check if an aborted backup exists for this stanza
|
||||
@@ -1526,13 +1525,13 @@ sub backup
|
||||
# The backup is usable if between the current backup and the aborted backup:
|
||||
# 1) The version matches
|
||||
# 2) The type of both is full or the types match and prior matches
|
||||
if ($strAbortedVersion eq $oBackupManifest{backup}{version})
|
||||
if ($strAbortedVersion eq ${$oBackupManifest->{oManifest}}{backup}{version})
|
||||
{
|
||||
if ($strAbortedType eq BACKUP_TYPE_FULL && $oBackupManifest{backup}{type} eq BACKUP_TYPE_FULL)
|
||||
if ($strAbortedType eq BACKUP_TYPE_FULL && ${$oBackupManifest->{oManifest}}{backup}{type} eq BACKUP_TYPE_FULL)
|
||||
{
|
||||
$bUsable = true;
|
||||
}
|
||||
elsif ($strAbortedType eq $oBackupManifest{backup}{type} && $strAbortedPrior eq $oBackupManifest{backup}{prior})
|
||||
elsif ($strAbortedType eq ${$oBackupManifest->{oManifest}}{backup}{type} && $strAbortedPrior eq ${$oBackupManifest->{oManifest}}{backup}{prior})
|
||||
{
|
||||
$bUsable = true;
|
||||
}
|
||||
@@ -1545,7 +1544,7 @@ sub backup
|
||||
&log(WARN, 'aborted backup of same type exists, will be cleaned to remove invalid files and resumed');
|
||||
|
||||
# Clean the old backup tmp path
|
||||
backup_tmp_clean(\%oBackupManifest);
|
||||
backup_tmp_clean($oBackupManifest->{oManifest});
|
||||
}
|
||||
# Else remove it
|
||||
else
|
||||
@@ -1571,19 +1570,19 @@ sub backup
|
||||
close($hVersionFile);
|
||||
|
||||
# Save the backup conf file with the manifest
|
||||
ini_save($strBackupConfFile, \%oBackupManifest);
|
||||
ini_save($strBackupConfFile, $oBackupManifest->{oManifest});
|
||||
|
||||
# Perform the backup
|
||||
backup_file($strDbClusterPath, \%oBackupManifest);
|
||||
backup_file($strDbClusterPath, $oBackupManifest->{oManifest});
|
||||
|
||||
# Stop backup (unless no-start-stop is set)
|
||||
my $strArchiveStop;
|
||||
|
||||
if (!$bNoStartStop)
|
||||
{
|
||||
($strArchiveStop, ${oBackupManifest}{backup}{'timestamp-db-stop'}) = $oDb->backup_stop();
|
||||
${oBackupManifest}{backup}{'archive-stop'} = $strArchiveStop;
|
||||
&log(INFO, 'archive stop: ' . ${oBackupManifest}{backup}{'archive-stop'});
|
||||
($strArchiveStop, ${$oBackupManifest->{oManifest}}{backup}{'timestamp-db-stop'}) = $oDb->backup_stop();
|
||||
${$oBackupManifest->{oManifest}}{backup}{'archive-stop'} = $strArchiveStop;
|
||||
&log(INFO, 'archive stop: ' . ${$oBackupManifest->{oManifest}}{backup}{'archive-stop'});
|
||||
}
|
||||
|
||||
# If archive logs are required to complete the backup, then fetch them. This is the default, but can be overridden if the
|
||||
@@ -1592,7 +1591,7 @@ sub backup
|
||||
if ($bArchiveRequired)
|
||||
{
|
||||
# Save the backup conf file second time - before getting archive logs in case that fails
|
||||
ini_save($strBackupConfFile, \%oBackupManifest);
|
||||
ini_save($strBackupConfFile, $oBackupManifest->{oManifest});
|
||||
|
||||
# After the backup has been stopped, need to make a copy of the archive logs need to make the db consistent
|
||||
&log(DEBUG, "retrieving archive logs ${strArchiveStart}:${strArchiveStop}");
|
||||
@@ -1646,11 +1645,11 @@ sub backup
|
||||
}
|
||||
|
||||
# Record timestamp stop in the config
|
||||
${oBackupManifest}{backup}{'timestamp-stop'} = timestamp_string_get();
|
||||
${oBackupManifest}{backup}{label} = $strBackupPath;
|
||||
${$oBackupManifest->{oManifest}}{backup}{'timestamp-stop'} = timestamp_string_get();
|
||||
${$oBackupManifest->{oManifest}}{backup}{label} = $strBackupPath;
|
||||
|
||||
# Save the backup conf file final time
|
||||
ini_save($strBackupConfFile, \%oBackupManifest);
|
||||
ini_save($strBackupConfFile, $oBackupManifest->{oManifest});
|
||||
|
||||
&log(INFO, "new backup label: ${strBackupPath}");
|
||||
|
||||
|
@@ -19,7 +19,7 @@ use Exporter qw(import);
|
||||
our @EXPORT = qw(MANIFEST_SECTION_BACKUP MANIFEST_SECTION_BACKUP_OPTION MANIFEST_SECTION_BACKUP_PATH
|
||||
MANIFEST_SECTION_BACKUP_TABLESPACE
|
||||
|
||||
MANIFEST_KEY_LABEL MANIFEST_KEY_TIMESTAMP_COPY_START
|
||||
MANIFEST_KEY_COMPRESS MANIFEST_KEY_HARDLINK MANIFEST_KEY_LABEL MANIFEST_KEY_TIMESTAMP_COPY_START
|
||||
|
||||
MANIFEST_SUBKEY_CHECKSUM MANIFEST_SUBKEY_DESTINATION MANIFEST_SUBKEY_FUTURE MANIFEST_SUBKEY_GROUP
|
||||
MANIFEST_SUBKEY_LINK MANIFEST_SUBKEY_MODE MANIFEST_SUBKEY_MODIFICATION_TIME MANIFEST_SUBKEY_PATH
|
||||
@@ -35,6 +35,8 @@ use constant
|
||||
MANIFEST_SECTION_BACKUP_PATH => 'backup:path',
|
||||
MANIFEST_SECTION_BACKUP_TABLESPACE => 'backup:tablespace',
|
||||
|
||||
MANIFEST_KEY_COMPRESS => 'compress',
|
||||
MANIFEST_KEY_HARDLINK => 'hardlink',
|
||||
MANIFEST_KEY_LABEL => 'label',
|
||||
MANIFEST_KEY_TIMESTAMP_COPY_START => 'timestamp-copy-start',
|
||||
|
||||
@@ -63,9 +65,34 @@ sub new
|
||||
my $self = {};
|
||||
bless $self, $class;
|
||||
|
||||
# Create the manifest hash
|
||||
$self->{oManifest} = {};
|
||||
|
||||
# Load the manifest if a filename is provided
|
||||
if (defined($strFileName))
|
||||
{
|
||||
ini_load($strFileName, $self->{oManifest});
|
||||
}
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# SAVE
|
||||
#
|
||||
# Save the config file.
|
||||
####################################################################################################################################
|
||||
# sub save
|
||||
# {
|
||||
# my $self = shift;
|
||||
# my $strFileName = shift; # Filename to save manifest to
|
||||
#
|
||||
# # Save the config file
|
||||
# ini_save($strFileName, $self);
|
||||
#
|
||||
# return $self;
|
||||
# }
|
||||
|
||||
####################################################################################################################################
|
||||
# GET
|
||||
#
|
||||
@@ -79,6 +106,8 @@ sub get
|
||||
my $strSubValue = shift;
|
||||
my $bRequired = shift;
|
||||
|
||||
my $oManifest = $self->{oManifest};
|
||||
|
||||
# Section must always be defined
|
||||
if (!defined($strSection))
|
||||
{
|
||||
@@ -89,7 +118,7 @@ sub get
|
||||
$bRequired = defined($bRequired) ? $bRequired : true;
|
||||
|
||||
# Store the result
|
||||
my $oResult;
|
||||
my $oResult = undef;
|
||||
|
||||
if (defined($strSubValue))
|
||||
{
|
||||
@@ -98,21 +127,21 @@ sub get
|
||||
confess &log(ASSERT, 'subvalue requested bu value is not defined');
|
||||
}
|
||||
|
||||
if (defined(${$self}{$strSection}{$strValue}))
|
||||
if (defined(${$oManifest}{$strSection}{$strValue}))
|
||||
{
|
||||
$oResult = ${$self}{$strSection}{$strValue}{$strSubValue};
|
||||
$oResult = ${$oManifest}{$strSection}{$strValue}{$strSubValue};
|
||||
}
|
||||
}
|
||||
elsif (defined($strValue))
|
||||
{
|
||||
if (defined(${$self}{$strSection}))
|
||||
if (defined(${$oManifest}{$strSection}))
|
||||
{
|
||||
$oResult = ${$self}{$strSection}{$strValue};
|
||||
$oResult = ${$oManifest}{$strSection}{$strValue};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oResult = ${$self}{$strSection};
|
||||
$oResult = ${$oManifest}{$strSection};
|
||||
}
|
||||
|
||||
if (!defined($oResult) && $bRequired)
|
||||
@@ -137,16 +166,18 @@ sub set
|
||||
my $strSubKey = shift;
|
||||
my $strValue = shift;
|
||||
|
||||
my $oManifest = $self->{oManifest};
|
||||
|
||||
# Make sure the keys are valid
|
||||
$self->valid($strSection, $strSubKey, $strValue);
|
||||
|
||||
if (defined($strSubKey))
|
||||
{
|
||||
${$self}{$strSection}{$strKey}{$strSubKey} = $strValue;
|
||||
${$oManifest}{$strSection}{$strKey}{$strSubKey} = $strValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
${$self}{$strSection}{$strKey} = $strValue;
|
||||
${$oManifest}{$strSection}{$strKey} = $strValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,6 +245,8 @@ sub keys
|
||||
return sort(keys $self->get($strSection));
|
||||
}
|
||||
|
||||
confess 'nothing was returned';
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
|
@@ -68,7 +68,7 @@ sub new
|
||||
sub manifest_ownership_check
|
||||
{
|
||||
my $self = shift; # Class hash
|
||||
my $oManifest = shift; # Backup manifest
|
||||
my $oManifest = shift; # Backup manifest
|
||||
|
||||
# Create hashes to track valid/invalid users/groups
|
||||
my %oOwnerHash = ();
|
||||
@@ -78,23 +78,25 @@ sub manifest_ownership_check
|
||||
my $strDefaultGroup = getgrgid($();
|
||||
|
||||
my %oFileTypeHash = ('path' => true, 'link' => true, 'file' => true);
|
||||
my %oOwnerTypeHash = ('user' => $strDefaultUser, 'group' => $strDefaultGroup);
|
||||
my %oOwnerTypeHash = (&MANIFEST_SUBKEY_USER => $strDefaultUser, &MANIFEST_SUBKEY_GROUP => $strDefaultGroup);
|
||||
|
||||
# Loop through owner types (user, group)
|
||||
foreach my $strOwnerType (sort (keys %oOwnerTypeHash))
|
||||
{
|
||||
# Loop through all backup paths (base and tablespaces)
|
||||
foreach my $strPathKey (sort(keys ${$oManifest}{'backup:path'}))
|
||||
foreach my $strPathKey ($oManifest->keys(MANIFEST_SECTION_BACKUP_PATH))
|
||||
{
|
||||
# Loop through types (path, link, file)
|
||||
foreach my $strFileType (sort (keys %oFileTypeHash))
|
||||
{
|
||||
my $strSection = "${strPathKey}:${strFileType}";
|
||||
|
||||
# Get users and groups for paths
|
||||
if (defined(${$oManifest}{"${strPathKey}:${strFileType}"}))
|
||||
if ($oManifest->test($strSection))
|
||||
{
|
||||
foreach my $strName (sort (keys ${$oManifest}{"${strPathKey}:${strFileType}"}))
|
||||
foreach my $strName ($oManifest->keys($strSection))
|
||||
{
|
||||
my $strOwner = ${$oManifest}{"${strPathKey}:${strFileType}"}{$strName}{$strOwnerType};
|
||||
my $strOwner = $oManifest->get($strSection, $strName, $strOwnerType);
|
||||
|
||||
# If root then test to see if the user/group is valid
|
||||
if ($< == 0)
|
||||
@@ -118,8 +120,7 @@ sub manifest_ownership_check
|
||||
|
||||
if (!$oOwnerHash{$strOwnerType}{$strOwner})
|
||||
{
|
||||
${$oManifest}{"${strPathKey}:${strFileType}"}{$strName}{$strOwnerType} =
|
||||
$oOwnerTypeHash{$strOwnerType};
|
||||
$oManifest->set($strSection, $strName, $strOwnerType, $oOwnerTypeHash{$strOwnerType});
|
||||
}
|
||||
}
|
||||
# Else set user/group to current user/group
|
||||
@@ -128,11 +129,10 @@ sub manifest_ownership_check
|
||||
if ($strOwner ne $oOwnerTypeHash{$strOwnerType})
|
||||
{
|
||||
$oOwnerHash{$strOwnerType}{$strOwner} = false;
|
||||
${$oManifest}{"${strPathKey}:${strFileType}"}{$strName}{$strOwnerType} =
|
||||
$oOwnerTypeHash{$strOwnerType};
|
||||
$oManifest->set($strSection, $strName, $strOwnerType, $oOwnerTypeHash{$strOwnerType});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,7 +160,6 @@ sub manifest_ownership_check
|
||||
sub manifest_load
|
||||
{
|
||||
my $self = shift; # Class hash
|
||||
my $oManifest = shift; # Backup manifest
|
||||
|
||||
if ($self->{oFile}->exists(PATH_BACKUP_CLUSTER, $self->{strBackupPath}))
|
||||
{
|
||||
@@ -169,20 +168,23 @@ sub manifest_load
|
||||
PATH_DB_ABSOLUTE, $self->{strDbClusterPath} . '/' . FILE_MANIFEST);
|
||||
|
||||
# Load the manifest into a hash
|
||||
ini_load($self->{oFile}->path_get(PATH_DB_ABSOLUTE, $self->{strDbClusterPath} . '/' . FILE_MANIFEST), $oManifest);
|
||||
my $oManifest = new BackRest::Manifest($self->{oFile}->path_get(PATH_DB_ABSOLUTE,
|
||||
$self->{strDbClusterPath} . '/' . FILE_MANIFEST));
|
||||
|
||||
# Remove the manifest now that it is in memory
|
||||
$self->{oFile}->remove(PATH_DB_ABSOLUTE, $self->{strDbClusterPath} . '/' . FILE_MANIFEST);
|
||||
|
||||
# If backup is latest then set it equal to backup label, else verify that requested backup and label match
|
||||
my $strBackupLabel = $oManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_LABEL);
|
||||
|
||||
if ($self->{strBackupPath} eq PATH_LATEST)
|
||||
{
|
||||
$self->{strBackupPath} = ${$oManifest}{'backup'}{label};
|
||||
$self->{strBackupPath} = $strBackupLabel;
|
||||
}
|
||||
elsif ($self->{strBackupPath} ne ${$oManifest}{'backup'}{label})
|
||||
elsif ($self->{strBackupPath} ne $strBackupLabel)
|
||||
{
|
||||
confess &log(ASSERT, "request backup $self->{strBackupPath} and label ${$oManifest}{'backup'}{label} do not match " .
|
||||
" - this indicates some sort of corruption (at the very least paths have been renamed.");
|
||||
confess &log(ASSERT, "request backup $self->{strBackupPath} and label ${strBackupLabel} do not match " .
|
||||
' - this indicates some sort of corruption (at the very least paths have been renamed.');
|
||||
}
|
||||
|
||||
# If tablespaces have been remapped, update the manifest
|
||||
@@ -195,7 +197,7 @@ sub manifest_load
|
||||
if ($strPathKey eq 'base')
|
||||
{
|
||||
&log(INFO, "remapping base to ${strRemapPath}");
|
||||
$oManifest->set(MANIFEST_SECTION_BACKUP_PATH, $strPathKey) = $strRemapPath;
|
||||
$oManifest->set(MANIFEST_SECTION_BACKUP_PATH, $strPathKey, undef, $strRemapPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -223,13 +225,13 @@ sub manifest_load
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
confess &log(ERROR, 'backup ' . $self->{strBackupPath} . ' does not exist');
|
||||
|
||||
$self->manifest_ownership_check($oManifest);
|
||||
|
||||
return $oManifest;
|
||||
}
|
||||
|
||||
$self->manifest_ownership_check($oManifest);
|
||||
confess &log(ERROR, 'backup ' . $self->{strBackupPath} . ' does not exist');
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
@@ -375,12 +377,14 @@ sub build
|
||||
my $oManifest = shift; # Backup manifest
|
||||
|
||||
# Build paths/links in each restore path
|
||||
foreach my $strPathKey ($oManifest->keys(MANIFEST_SECTION_BACKUP_PATH))
|
||||
foreach my $strSectionPathKey ($oManifest->keys(MANIFEST_SECTION_BACKUP_PATH))
|
||||
{
|
||||
my $strPath = $oManifest->get(MANIFEST_SECTION_BACKUP_PATH, $strPathKey);
|
||||
my $strSectionPath = $oManifest->get(MANIFEST_SECTION_BACKUP_PATH, $strSectionPathKey);
|
||||
|
||||
# Create all paths in the manifest that do not already exist
|
||||
foreach my $strName ($oManifest->keys("${strPathKey}:path"))
|
||||
my $strSection = "${strSectionPathKey}:path";
|
||||
|
||||
foreach my $strName ($oManifest->keys($strSection))
|
||||
{
|
||||
# Skip the root path
|
||||
if ($strName eq '.')
|
||||
@@ -389,21 +393,27 @@ sub build
|
||||
}
|
||||
|
||||
# Create the Path
|
||||
if (!$self->{oFile}->exists(PATH_DB_ABSOLUTE, "${strPath}/${strName}"))
|
||||
my $strPath = "${strSectionPath}/${strName}";
|
||||
|
||||
if (!$self->{oFile}->exists(PATH_DB_ABSOLUTE, $strPath))
|
||||
{
|
||||
$self->{oFile}->path_create(PATH_DB_ABSOLUTE, "${strPath}/${strName}",
|
||||
$oManifest->get("${strPathKey}:path", $strName, MANIFEST_SUBKEY_MODE));
|
||||
$self->{oFile}->path_create(PATH_DB_ABSOLUTE, $strPath,
|
||||
$oManifest->get($strSection, $strName, MANIFEST_SUBKEY_MODE));
|
||||
}
|
||||
}
|
||||
|
||||
# Create all links in the manifest that do not already exist
|
||||
foreach my $strName ($oManifest->keys("${strPathKey}:link"))
|
||||
$strSection = "${strSectionPathKey}:link";
|
||||
|
||||
foreach my $strName ($oManifest->keys($strSection))
|
||||
{
|
||||
if (!$self->{oFile}->exists(PATH_DB_ABSOLUTE, "${strPath}/${strName}"))
|
||||
my $strLink = "${strSectionPath}/${strName}";
|
||||
|
||||
if (!$self->{oFile}->exists(PATH_DB_ABSOLUTE, $strLink))
|
||||
{
|
||||
$self->{oFile}->link_create(PATH_DB_ABSOLUTE,
|
||||
$oManifest->get("${strPathKey}:link", $strName, MANIFEST_SUBKEY_DESTINATION),
|
||||
PATH_DB_ABSOLUTE, "${strPath}/${strName}");
|
||||
$oManifest->get($strSection, $strName, MANIFEST_SUBKEY_DESTINATION),
|
||||
PATH_DB_ABSOLUTE, $strLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -428,8 +438,7 @@ sub restore
|
||||
&log(INFO, "Restoring backup set " . $self->{strBackupPath});
|
||||
|
||||
# Make sure the backup path is valid and load the manifest
|
||||
my $oManifest = new BackRest::Manifest();
|
||||
$self->manifest_load($oManifest);
|
||||
my $oManifest = $self->manifest_load();
|
||||
|
||||
# Clean the restore paths
|
||||
$self->clean($oManifest);
|
||||
@@ -440,13 +449,15 @@ sub restore
|
||||
# Assign the files in each path to a thread queue
|
||||
my @oyRestoreQueue;
|
||||
|
||||
foreach my $strPathKey (sort(keys ${$oManifest}{'backup:path'}))
|
||||
foreach my $strPathKey ($oManifest->keys(MANIFEST_SECTION_BACKUP_PATH))
|
||||
{
|
||||
if (defined(${$oManifest}{"${strPathKey}:file"}))
|
||||
my $strSection = "${strPathKey}:file";
|
||||
|
||||
if ($oManifest->test($strSection))
|
||||
{
|
||||
$oyRestoreQueue[@oyRestoreQueue] = Thread::Queue->new();
|
||||
|
||||
foreach my $strName (sort (keys ${$oManifest}{"${strPathKey}:file"}))
|
||||
foreach my $strName ($oManifest->keys($strSection))
|
||||
{
|
||||
$oyRestoreQueue[@oyRestoreQueue - 1]->enqueue("${strPathKey}|${strName}");
|
||||
}
|
||||
@@ -489,7 +500,7 @@ sub restore_thread
|
||||
my $lCopyTimeBegin = $oManifest->epoch(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_COPY_START);
|
||||
|
||||
# Set source compression
|
||||
my $bSourceCompression = ${$oManifest}{'backup:option'}{compress} eq 'y' ? true : false;
|
||||
my $bSourceCompression = $oManifest->get(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS) eq 'y' ? true : false;
|
||||
|
||||
# When a KILL signal is received, immediately abort
|
||||
$SIG{'KILL'} = sub {threads->exit();};
|
||||
@@ -505,26 +516,26 @@ sub restore_thread
|
||||
{
|
||||
my $strSourcePath = (split(/\|/, $strMessage))[0]; # Source path from backup
|
||||
my $strSection = "${strSourcePath}:file"; # Backup section with file info
|
||||
my $strDestinationPath = ${$oManifest}{'backup:path'}{$strSourcePath}; # Destination path stored in manifest
|
||||
my $strDestinationPath = $oManifest->get(MANIFEST_SECTION_BACKUP_PATH, # Destination path stored in manifest
|
||||
$strSourcePath);
|
||||
$strSourcePath =~ s/\:/\//g; # Replace : with / in source path
|
||||
my $strName = (split(/\|/, $strMessage))[1]; # Name of file to be restored
|
||||
|
||||
# If the file is a reference to a previous backup and hardlinks are off, then fetch it from that backup
|
||||
my $strReference = defined(${$oManifest}{'backup:option'}{hardlink}) && ${$oManifest}{'backup:option'}{hardlink} eq 'y' ? undef :
|
||||
${$oManifest}{$strSection}{$strName}{reference};
|
||||
my $strReference = $oManifest->test(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_HARDLINK, undef, 'y') ? undef :
|
||||
$oManifest->get($strSection, $strName, MANIFEST_SUBKEY_REFERENCE, false);
|
||||
|
||||
# Generate destination file name
|
||||
my $strDestinationFile = $oFileThread->path_get(PATH_DB_ABSOLUTE, "${strDestinationPath}/${strName}");
|
||||
|
||||
# If checksum is set the destination file already exists, try a checksum before copying
|
||||
my $strChecksum = ${$oManifest}{$strSection}{$strName}{checksum};
|
||||
|
||||
if ($oFileThread->exists(PATH_DB_ABSOLUTE, $strDestinationFile))
|
||||
{
|
||||
# Perform delta if requested
|
||||
if ($self->{bDelta})
|
||||
{
|
||||
# Do checksum delta if --force was not requested and checksums exist
|
||||
my $strChecksum = $oManifest->get($strSection, $strName, MANIFEST_SUBKEY_CHECKSUM, false);
|
||||
|
||||
if (!$self->{bForce} && defined($strChecksum) &&
|
||||
$oFileThread->hash(PATH_DB_ABSOLUTE, $strDestinationFile) eq $strChecksum)
|
||||
{
|
||||
@@ -560,11 +571,11 @@ sub restore_thread
|
||||
PATH_DB_ABSOLUTE, $strDestinationFile,
|
||||
$bSourceCompression, # Source is compressed based on backup settings
|
||||
undef, undef,
|
||||
${$oManifest}{$strSection}{$strName}{modification_time},
|
||||
${$oManifest}{$strSection}{$strName}{permission},
|
||||
$oManifest->get($strSection, $strName, MANIFEST_SUBKEY_MODIFICATION_TIME),
|
||||
$oManifest->get($strSection, $strName, MANIFEST_SUBKEY_MODE),
|
||||
undef,
|
||||
${$oManifest}{$strSection}{$strName}{user},
|
||||
${$oManifest}{$strSection}{$strName}{group});
|
||||
$oManifest->get($strSection, $strName, MANIFEST_SUBKEY_USER),
|
||||
$oManifest->get($strSection, $strName, MANIFEST_SUBKEY_GROUP));
|
||||
}
|
||||
|
||||
# Even number threads move up when they have finished a queue, odd numbered threads move down
|
||||
|
Reference in New Issue
Block a user