1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-14 10:13:05 +02:00
pgbackrest/test/lib/pgBackRestTest/Env/Host/HostDbSyntheticTest.pm
David Steele 7a9b1f6993 Container build improvements:
* More optimized container suite that greatly improves build time.
* Added static Debian packages for Devel::Cover to reduce build time.
* Add deprecated state for containers. Deprecated containers may only be used to build packages.
* Remove Debian 8 from CI because it does not provide additional coverage over Ubuntu 14.04 and Ubuntu 16.04.
2017-06-24 10:59:00 -04:00

730 lines
28 KiB
Perl

####################################################################################################################################
# HostDbTest.pm - Database host
####################################################################################################################################
package pgBackRestTest::Env::Host::HostDbSyntheticTest;
use parent 'pgBackRestTest::Env::Host::HostDbCommonTest';
####################################################################################################################################
# Perl includes
####################################################################################################################################
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use DBI;
use Exporter qw(import);
our @EXPORT = qw();
use Fcntl ':mode';
use File::Basename qw(basename dirname);
use File::stat;
use pgBackRest::Common::Exception;
use pgBackRest::Common::Log;
use pgBackRest::Common::String;
use pgBackRest::Common::Wait;
use pgBackRest::DbVersion;
use pgBackRest::Manifest;
use pgBackRest::Protocol::Storage::Helper;
use pgBackRest::Version;
use pgBackRestTest::Env::Host::HostBackupTest;
use pgBackRestTest::Env::Host::HostBaseTest;
use pgBackRestTest::Env::Host::HostDbCommonTest;
use pgBackRestTest::Common::ContainerTest;
use pgBackRestTest::Common::FileTest;
use pgBackRestTest::Common::RunTest;
####################################################################################################################################
# new
####################################################################################################################################
sub new
{
my $class = shift; # Class name
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$oParam,
) =
logDebugParam
(
__PACKAGE__ . '->new', \@_,
{name => 'oParam', required => false, trace => true},
);
my $self = $class->SUPER::new(
{
strImage => containerRepo() . ':' . testRunGet()->vm() . "-test",
strBackupDestination => $$oParam{strBackupDestination},
oLogTest => $$oParam{oLogTest},
bSynthetic => true,
bStandby => $$oParam{bStandby},
bRepoLocal => $oParam->{bRepoLocal},
});
bless $self, $class;
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'self', value => $self, trace => true}
);
}
####################################################################################################################################
# dbFileCreate
#
# Create a file specifying content, mode, and time.
####################################################################################################################################
sub dbFileCreate
{
my $self = shift;
my $oManifestRef = shift;
my $strTarget = shift;
my $strFile = shift;
my $strContent = shift;
my $lTime = shift;
my $strMode = shift;
# Check that strTarget is a valid
my $strPath = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strTarget}{&MANIFEST_SUBKEY_PATH};
if (!defined($strPath))
{
confess &log(ERROR, "${strTarget} not a valid target: \n" . Dumper(${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}));
}
# Get tablespace path if this is a tablespace
my $strPgPath;
if ($$oManifestRef{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_DB_VERSION} >= PG_VERSION_90 &&
index($strTarget, DB_PATH_PGTBLSPC . '/') == 0)
{
my $iCatalog = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_CATALOG};
$strPgPath = 'PG_' . ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_DB_VERSION} . "_${iCatalog}";
}
# Create actual file location
my $strPathFile = $strPath .
(defined($strPgPath) ? "/${strPgPath}" : '') . "/${strFile}";
if (index($strPathFile, '/') != 0)
{
$strPathFile = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{&MANIFEST_TARGET_PGDATA}{&MANIFEST_SUBKEY_PATH} . '/' .
(defined(dirname($strPathFile)) ? dirname($strPathFile) : '') . "/${strPathFile}";
}
# Create the file
testFileCreate($strPathFile, $strContent, $lTime, $strMode);
# Return path to created file
return $strPathFile;
}
####################################################################################################################################
# dbFileRemove
####################################################################################################################################
sub dbFileRemove
{
my $self = shift;
my $oManifestRef = shift;
my $strTarget = shift;
my $strFile = shift;
my $bIgnoreMissing = shift;
# Get actual path location
my $strDbFile = $self->manifestDbPathGet($oManifestRef, $strTarget, $strFile);
# Remove the file
if (!(defined($bIgnoreMissing) && $bIgnoreMissing && !(-e $strDbFile)))
{
testFileRemove($strDbFile);
}
return $strDbFile;
}
####################################################################################################################################
# dbLinkCreate
#
# Create a file specifying content, mode, and time.
####################################################################################################################################
sub dbLinkCreate
{
my $self = shift;
my $oManifestRef = shift;
my $strTarget = shift;
my $strFile = shift;
my $strDestination = shift;
# Create actual file location
my $strDbFile = $self->manifestDbPathGet($oManifestRef, $strTarget, $strFile);
# Create the file
testLinkCreate($strDbFile, $strDestination);
# Return path to created file
return $strDbFile;
}
####################################################################################################################################
# manifestDbPathGet
#
# Get the db path based on the target and file passed.
####################################################################################################################################
sub manifestDbPathGet
{
my $self = shift;
my $oManifestRef = shift;
my $strTarget = shift;
my $strFile = shift;
# Determine the manifest key
my $strDbPath = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strTarget}{&MANIFEST_SUBKEY_PATH};
# If target is a tablespace and pg version >= 9.0
if (defined(${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strTarget}{&MANIFEST_SUBKEY_TABLESPACE_ID}) &&
$$oManifestRef{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_DB_VERSION} >= PG_VERSION_90)
{
my $iCatalog = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_CATALOG};
$strDbPath .= '/PG_' . ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_DB_VERSION} . "_${iCatalog}";
}
$strDbPath .= defined($strFile) ? "/${strFile}" : '';
return $strDbPath;
}
####################################################################################################################################
# manifestFileCreate
#
# Create a file specifying content, mode, and time and add it to the manifest.
####################################################################################################################################
sub manifestFileCreate
{
my $self = shift;
my $oManifestRef = shift;
my $strTarget = shift;
my $strFile = shift;
my $strContent = shift;
my $strChecksum = shift;
my $lTime = shift;
my $strMode = shift;
my $bMaster = shift;
my $strChecksumPageError = shift;
# Determine the manifest key
my $strManifestKey = $self->manifestKeyGet($oManifestRef, $strTarget, $strFile);
# Create the file
my $strPathFile = $self->dbFileCreate($oManifestRef, $strTarget, $strFile, $strContent, $lTime, $strMode);
# Stat the file
my $oStat = storageTest()->info($strPathFile);
${$oManifestRef}{&MANIFEST_SECTION_TARGET_FILE}{$strManifestKey}{&MANIFEST_SUBKEY_GROUP} = getgrgid($oStat->gid);
${$oManifestRef}{&MANIFEST_SECTION_TARGET_FILE}{$strManifestKey}{&MANIFEST_SUBKEY_USER} = getpwuid($oStat->uid);
${$oManifestRef}{&MANIFEST_SECTION_TARGET_FILE}{$strManifestKey}{&MANIFEST_SUBKEY_MODE} =
sprintf('%04o', S_IMODE($oStat->mode));
${$oManifestRef}{&MANIFEST_SECTION_TARGET_FILE}{$strManifestKey}{&MANIFEST_SUBKEY_TIMESTAMP} = $oStat->mtime;
${$oManifestRef}{&MANIFEST_SECTION_TARGET_FILE}{$strManifestKey}{&MANIFEST_SUBKEY_SIZE} = $oStat->size;
${$oManifestRef}{&MANIFEST_SECTION_TARGET_FILE}{$strManifestKey}{&MANIFEST_SUBKEY_MASTER} =
defined($bMaster) ? ($bMaster ? JSON::PP::true : JSON::PP::false) : JSON::PP::false;
delete(${$oManifestRef}{&MANIFEST_SECTION_TARGET_FILE}{$strManifestKey}{&MANIFEST_SUBKEY_REFERENCE});
my $bChecksumPage = defined($strChecksumPageError) ? false : (isChecksumPage($strManifestKey) ? true : undef);
if (defined($bChecksumPage))
{
$oManifestRef->{&MANIFEST_SECTION_TARGET_FILE}{$strManifestKey}{&MANIFEST_SUBKEY_CHECKSUM_PAGE} =
$bChecksumPage ? JSON::PP::true : JSON::PP::false;
if (!$bChecksumPage && $strChecksumPageError ne '0')
{
my @iyChecksumPageError = eval($strChecksumPageError); ## no critic (BuiltinFunctions::ProhibitStringyEval)
$oManifestRef->{&MANIFEST_SECTION_TARGET_FILE}{$strManifestKey}{&MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR} =
\@iyChecksumPageError;
}
else
{
delete($oManifestRef->{&MANIFEST_SECTION_TARGET_FILE}{$strManifestKey}{&MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR});
}
}
if (defined($strChecksum))
{
${$oManifestRef}{&MANIFEST_SECTION_TARGET_FILE}{$strManifestKey}{checksum} = $strChecksum;
}
}
####################################################################################################################################
# manifestFileRemove
#
# Remove a file from disk and (optionally) the manifest.
####################################################################################################################################
sub manifestFileRemove
{
my $self = shift;
my $oManifestRef = shift;
my $strTarget = shift;
my $strFile = shift;
# Determine the manifest key
my $strManifestKey = $self->manifestKeyGet($oManifestRef, $strTarget, $strFile);
# Remove the file
$self->dbFileRemove($oManifestRef, $strTarget, $strFile, true);
# Remove from manifest
delete(${$oManifestRef}{&MANIFEST_SECTION_TARGET_FILE}{$strManifestKey});
}
####################################################################################################################################
# manifestKeyGet
#
# Get the manifest key based on the target and file/path/link passed.
####################################################################################################################################
sub manifestKeyGet
{
my $self = shift;
my $oManifestRef = shift;
my $strTarget = shift;
my $strFile = shift;
# Determine the manifest key
my $strManifestKey = $strTarget;
# If target is a tablespace and pg version >= 9.0
if (defined(${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strTarget}{&MANIFEST_SUBKEY_TABLESPACE_ID}) &&
$$oManifestRef{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_DB_VERSION} >= PG_VERSION_90)
{
my $iCatalog = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_CATALOG};
$strManifestKey .= '/PG_' . ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_DB_VERSION} . "_${iCatalog}";
}
$strManifestKey .= (defined($strFile) ? "/$strFile" : '');
return $strManifestKey;
}
####################################################################################################################################
# manifestLinkCreate
#
# Create a link and add it to the manifest.
####################################################################################################################################
sub manifestLinkCreate
{
my $self = shift;
my $oManifestRef = shift;
my $strPath = shift;
my $strFile = shift;
my $strDestination = shift;
my $bMaster = shift;
# Determine the manifest key
my $strManifestKey = $self->manifestKeyGet($oManifestRef, $strPath, $strFile);
# Load target
${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strManifestKey}{&MANIFEST_SUBKEY_PATH} = $strDestination;
${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strManifestKey}{&MANIFEST_SUBKEY_TYPE} = MANIFEST_VALUE_LINK;
# Create the link
my $strDbFile = $self->dbLinkCreate($oManifestRef, $strPath, $strFile, $strDestination);
# Stat the link
my $oStat = storageTest()->info($strDbFile);
# Check for errors in stat
if (!defined($oStat))
{
confess 'unable to stat ${strDbFile}';
}
# Load file into manifest
${$oManifestRef}{&MANIFEST_SECTION_TARGET_LINK}{$strManifestKey}{&MANIFEST_SUBKEY_GROUP} = getgrgid($oStat->gid);
${$oManifestRef}{&MANIFEST_SECTION_TARGET_LINK}{$strManifestKey}{&MANIFEST_SUBKEY_USER} = getpwuid($oStat->uid);
${$oManifestRef}{&MANIFEST_SECTION_TARGET_LINK}{$strManifestKey}{&MANIFEST_SUBKEY_DESTINATION} = $strDestination;
# Stat what the link is pointing to
my $strDestinationFile = $strDestination;
if (index($strDestinationFile, '/') != 0)
{
$strDestinationFile = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{&MANIFEST_TARGET_PGDATA}{&MANIFEST_SUBKEY_PATH} . '/' .
(defined(dirname($strPath)) ? dirname($strPath) : '') . "/${strDestination}";
}
$oStat = storageTest()->info($strDestinationFile);
my $strSection = MANIFEST_SECTION_TARGET_PATH;
if (S_ISREG($oStat->mode))
{
$strSection = MANIFEST_SECTION_TARGET_FILE;
${$oManifestRef}{$strSection}{$strManifestKey}{&MANIFEST_SUBKEY_SIZE} = $oStat->size;
${$oManifestRef}{$strSection}{$strManifestKey}{&MANIFEST_SUBKEY_TIMESTAMP} = $oStat->mtime;
(${$oManifestRef}{$strSection}{$strManifestKey}{&MANIFEST_SUBKEY_CHECKSUM}) = storageTest()->hashSize($strDestinationFile);
${$oManifestRef}{$strSection}{$strManifestKey}{&MANIFEST_SUBKEY_MASTER} =
defined($bMaster) ? ($bMaster ? JSON::PP::true : JSON::PP::false) : JSON::PP::false;
${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strManifestKey}{&MANIFEST_SUBKEY_FILE} =
basename(${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strManifestKey}{&MANIFEST_SUBKEY_PATH});
${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strManifestKey}{&MANIFEST_SUBKEY_PATH} =
dirname(${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strManifestKey}{&MANIFEST_SUBKEY_PATH});
}
# Allow a link to a link to be created to test that backrest errors out correctly
elsif (S_ISLNK($oStat->mode))
{
$strSection = MANIFEST_SECTION_TARGET_LINK;
${$oManifestRef}{$strSection}{$strManifestKey}{&MANIFEST_SUBKEY_DESTINATION} = $strDestination;
}
elsif (!S_ISDIR($oStat->mode))
{
confess &log(ASSERT, "unrecognized file type for file $strDestinationFile");
}
${$oManifestRef}{$strSection}{$strManifestKey}{&MANIFEST_SUBKEY_GROUP} = getgrgid($oStat->gid);
${$oManifestRef}{$strSection}{$strManifestKey}{&MANIFEST_SUBKEY_USER} = getpwuid($oStat->uid);
${$oManifestRef}{$strSection}{$strManifestKey}{&MANIFEST_SUBKEY_MODE} = sprintf('%04o', S_IMODE($oStat->mode));
}
####################################################################################################################################
# manifestLinkMap
#
# Remap links to new directories/files
####################################################################################################################################
sub manifestLinkMap
{
my $self = shift;
my $oManifestRef = shift;
my $strTarget = shift;
my $strDestination = shift;
if ($$oManifestRef{&MANIFEST_SECTION_BACKUP_TARGET}{$strTarget}{&MANIFEST_SUBKEY_TYPE} ne MANIFEST_VALUE_LINK)
{
confess "cannot map target ${strTarget} because it is not a link";
}
if (defined($$oManifestRef{&MANIFEST_SECTION_BACKUP_TARGET}{$strTarget}{&MANIFEST_SUBKEY_TABLESPACE_ID}))
{
confess "tablespace ${strTarget} cannot be remapped with this function";
}
if (defined($strDestination))
{
confess "GENERAL LINK REMAP NOT IMPLEMENTED";
}
else
{
delete($$oManifestRef{&MANIFEST_SECTION_BACKUP_TARGET}{$strTarget});
delete($$oManifestRef{&MANIFEST_SECTION_TARGET_LINK}{$strTarget});
}
}
####################################################################################################################################
# manifestLinkRemove
#
# Create a link and add it to the manifest.
####################################################################################################################################
sub manifestLinkRemove
{
my $self = shift;
my $oManifestRef = shift;
my $strPath = shift;
my $strFile = shift;
# Delete the link
my $strDbFile = $self->dbFileRemove($oManifestRef, $strPath, $strFile);
# Determine the manifest key
my $strManifestKey = $self->manifestKeyGet($oManifestRef, $strPath, $strFile);
# Delete from manifest
delete(${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strManifestKey});
delete(${$oManifestRef}{&MANIFEST_SECTION_TARGET_LINK}{$strManifestKey});
delete(${$oManifestRef}{&MANIFEST_SECTION_TARGET_FILE}{$strManifestKey});
delete(${$oManifestRef}{&MANIFEST_SECTION_TARGET_PATH}{$strManifestKey});
}
####################################################################################################################################
# manifestPathCreate
#
# Create a path specifying mode and add it to the manifest.
####################################################################################################################################
sub manifestPathCreate
{
my $self = shift;
my $oManifestRef = shift;
my $strPath = shift;
my $strSubPath = shift;
my $strMode = shift;
# Determine the manifest key
my $strManifestKey = $self->manifestKeyGet($oManifestRef, $strPath, $strSubPath);
# Create the db path
my $strDbPath = $self->dbPathCreate($oManifestRef, $strPath, $strSubPath, defined($strMode) ? $strMode : '0700');
# Stat the file
my $oStat = lstat($strDbPath);
# Check for errors in stat
if (!defined($oStat))
{
confess 'unable to stat ${strSubPath}';
}
# Load file into manifest
my $strSection = MANIFEST_SECTION_TARGET_PATH;
${$oManifestRef}{$strSection}{$strManifestKey}{&MANIFEST_SUBKEY_GROUP} = getgrgid($oStat->gid);
${$oManifestRef}{$strSection}{$strManifestKey}{&MANIFEST_SUBKEY_USER} = getpwuid($oStat->uid);
${$oManifestRef}{$strSection}{$strManifestKey}{&MANIFEST_SUBKEY_MODE} = sprintf('%04o', S_IMODE($oStat->mode));
}
####################################################################################################################################
# manifestReference
#
# Update all files that do not have a reference with the supplied reference.
####################################################################################################################################
sub manifestReference
{
my $self = shift;
my $oManifestRef = shift;
my $strReference = shift;
my $bClear = shift;
# Set prior backup
if (defined($strReference))
{
${$oManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_PRIOR} = $strReference;
}
else
{
delete(${$oManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_PRIOR});
}
# Find all file sections
foreach my $strSectionFile (sort(keys(%$oManifestRef)))
{
# Skip non-file sections
if ($strSectionFile !~ /\:file$/)
{
next;
}
foreach my $strFile (sort(keys(%{${$oManifestRef}{$strSectionFile}})))
{
if (!defined($strReference))
{
delete(${$oManifestRef}{$strSectionFile}{$strFile}{&MANIFEST_SUBKEY_REFERENCE});
}
elsif (defined($bClear) && $bClear)
{
if (defined(${$oManifestRef}{$strSectionFile}{$strFile}{&MANIFEST_SUBKEY_REFERENCE}) &&
${$oManifestRef}{$strSectionFile}{$strFile}{&MANIFEST_SUBKEY_REFERENCE} ne $strReference)
{
delete(${$oManifestRef}{$strSectionFile}{$strFile}{&MANIFEST_SUBKEY_REFERENCE});
}
}
elsif (!defined(${$oManifestRef}{$strSectionFile}{$strFile}{&MANIFEST_SUBKEY_REFERENCE}))
{
${$oManifestRef}{$strSectionFile}{$strFile}{&MANIFEST_SUBKEY_REFERENCE} = $strReference;
}
}
}
}
####################################################################################################################################
# manifestTablespaceCreate
#
# Create a tablespace specifying mode and add it to the manifest.
####################################################################################################################################
sub manifestTablespaceCreate
{
my $self = shift;
my $oManifestRef = shift;
my $iOid = shift;
my $strMode = shift;
# Load linked path into manifest
my $strLinkPath = $self->tablespacePath($iOid);
my $strTarget = MANIFEST_TARGET_PGTBLSPC . "/${iOid}";
my $oStat = storageTest()->info($strLinkPath);
${$oManifestRef}{&MANIFEST_SECTION_TARGET_PATH}{$strTarget}{&MANIFEST_SUBKEY_GROUP} = getgrgid($oStat->gid);
${$oManifestRef}{&MANIFEST_SECTION_TARGET_PATH}{$strTarget}{&MANIFEST_SUBKEY_USER} = getpwuid($oStat->uid);
${$oManifestRef}{&MANIFEST_SECTION_TARGET_PATH}{$strTarget}{&MANIFEST_SUBKEY_MODE} =
sprintf('%04o', S_IMODE($oStat->mode));
# Create the tablespace path if it does not exist
my $strTablespacePath = $strLinkPath;
my $strPathTarget = $strTarget;
if ($$oManifestRef{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_DB_VERSION} >= PG_VERSION_90)
{
my $iCatalog = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_CATALOG};
my $strTablespaceId = 'PG_' . ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_DB_VERSION} . "_${iCatalog}";
$strTablespacePath .= "/${strTablespaceId}";
$strPathTarget .= "/${strTablespaceId}";
}
if (!-e $strTablespacePath)
{
storageTest()->pathCreate($strTablespacePath, {strMode => defined($strMode) ? $strMode : '0700'});
}
# Load tablespace path into manifest
$oStat = storageTest()->info($strTablespacePath);
${$oManifestRef}{&MANIFEST_SECTION_TARGET_PATH}{&MANIFEST_TARGET_PGTBLSPC} =
${$oManifestRef}{&MANIFEST_SECTION_TARGET_PATH}{&MANIFEST_TARGET_PGDATA};
${$oManifestRef}{&MANIFEST_SECTION_TARGET_PATH}{$strPathTarget}{&MANIFEST_SUBKEY_GROUP} = getgrgid($oStat->gid);
${$oManifestRef}{&MANIFEST_SECTION_TARGET_PATH}{$strPathTarget}{&MANIFEST_SUBKEY_USER} = getpwuid($oStat->uid);
${$oManifestRef}{&MANIFEST_SECTION_TARGET_PATH}{$strPathTarget}{&MANIFEST_SUBKEY_MODE} =
sprintf('%04o', S_IMODE($oStat->mode));
# Create the link in DB_PATH_PGTBLSPC
my $strLink = $self->dbBasePath() . '/' . DB_PATH_PGTBLSPC . "/${iOid}";
symlink($strLinkPath, $strLink)
or confess "unable to link ${strLink} to ${strLinkPath}";
# Load link into the manifest
$oStat = storageTest()->info($strLink);
my $strLinkTarget = MANIFEST_TARGET_PGDATA . "/${strTarget}";
${$oManifestRef}{&MANIFEST_SECTION_TARGET_LINK}{$strLinkTarget}{&MANIFEST_SUBKEY_GROUP} = getgrgid($oStat->gid);
${$oManifestRef}{&MANIFEST_SECTION_TARGET_LINK}{$strLinkTarget}{&MANIFEST_SUBKEY_USER} = getpwuid($oStat->uid);
${$oManifestRef}{&MANIFEST_SECTION_TARGET_LINK}{$strLinkTarget}{&MANIFEST_SUBKEY_DESTINATION} = $strLinkPath;
# Load tablespace target into the manifest
${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strTarget}{&MANIFEST_SUBKEY_PATH} = $strLinkPath;
${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strTarget}{&MANIFEST_SUBKEY_TYPE} = MANIFEST_VALUE_LINK;
${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strTarget}{&MANIFEST_SUBKEY_TABLESPACE_ID} = $iOid;
${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strTarget}{&MANIFEST_SUBKEY_TABLESPACE_NAME} = "ts${iOid}";
}
####################################################################################################################################
# manifestTablespaceDrop
#
# Drop a tablespace add remove it from the manifest.
####################################################################################################################################
sub manifestTablespaceDrop
{
my $self = shift;
my $oManifestRef = shift;
my $iOid = shift;
my $iIndex = shift;
# Remove tablespace path/file/link from manifest
my $strTarget = DB_PATH_PGTBLSPC . "/${iOid}";
# Remove manifest path, link, target
delete(${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strTarget});
delete(${$oManifestRef}{&MANIFEST_SECTION_TARGET_LINK}{&MANIFEST_TARGET_PGDATA . "/${strTarget}"});
delete(${$oManifestRef}{&MANIFEST_SECTION_TARGET_PATH}{$strTarget});
# Remove nested manifest files and paths
foreach my $strSection (&MANIFEST_SECTION_TARGET_PATH, &MANIFEST_SECTION_TARGET_FILE)
{
foreach my $strFile (keys(%{${$oManifestRef}{$strSection}}))
{
if (index($strFile, "${strTarget}/") == 0)
{
delete($$oManifestRef{$strSection}{$strFile});
}
}
}
# Drop the link in DB_PATH_PGTBLSPC
testFileRemove($self->dbBasePath($iIndex) . "/${strTarget}");
}
####################################################################################################################################
# dbPathCreate
#
# Create a path specifying mode.
####################################################################################################################################
sub dbPathCreate
{
my $self = shift;
my $oManifestRef = shift;
my $strTarget = shift;
my $strSubPath = shift;
my $strMode = shift;
# Create final file location
my $strFinalPath = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{$strTarget}{&MANIFEST_SUBKEY_PATH};
# Get tablespace path if this is a tablespace
if ($$oManifestRef{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_DB_VERSION} >= PG_VERSION_90 &&
index($strTarget, DB_PATH_PGTBLSPC . '/') == 0)
{
my $iCatalog = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_CATALOG};
$strFinalPath .= '/PG_' . ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_DB_VERSION} . "_${iCatalog}";
}
$strFinalPath .= (defined($strSubPath) ? "/${strSubPath}" : '');
# Create the path
if (!(-e $strFinalPath))
{
storageTest()->pathCreate($strFinalPath, {strMode => $strMode});
}
return $strFinalPath;
}
####################################################################################################################################
# dbPathMode
#
# Change the mode of a path.
####################################################################################################################################
sub dbPathMode
{
my $self = shift;
my $oManifestRef = shift;
my $strTarget = shift;
my $strPath = shift;
my $strMode = shift;
# Get the db path
my $strDbPath = $self->manifestDbPathGet($oManifestRef, $strTarget, $strPath);
testPathMode($strDbPath, $strMode);
return $strDbPath;
}
####################################################################################################################################
# dbPathRemove
#
# Remove a path.
####################################################################################################################################
sub dbPathRemove
{
my $self = shift;
my $oManifestRef = shift;
my $strTarget = shift;
my $strPath = shift;
# Get the db path
my $strDbPath = $self->manifestDbPathGet($oManifestRef, $strTarget, $strPath);
# Create the path
testPathRemove($strDbPath);
return $strDbPath;
}
1;