1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-03-03 14:52:21 +02:00

Refactor restoreManifestMap() to be driven by link-map.

This will allow new links to be added in a future commit. The current implementation is driven by the links that already exist in the manifest, which would make the new use case more complex to implement.

Also, add a more helpful error when a tablespace link is specified.
This commit is contained in:
David Steele 2021-09-30 14:29:49 -04:00
parent d89a67776c
commit cf1a57518f
2 changed files with 77 additions and 56 deletions

View File

@ -527,80 +527,98 @@ restoreManifestMap(Manifest *manifest)
// Remap links
// -------------------------------------------------------------------------------------------------------------------------
KeyValue *linkMap = varKv(cfgOption(cfgOptLinkMap));
bool linkAll = cfgOptionBool(cfgOptLinkAll);
const KeyValue *const linkMap = varKv(cfgOption(cfgOptLinkMap));
StringList *linkRemapped = strLstNew();
for (unsigned int targetIdx = 0; targetIdx < manifestTargetTotal(manifest); targetIdx++)
if (linkMap != NULL)
{
const ManifestTarget *target = manifestTarget(manifest, targetIdx);
const StringList *const linkMapList = strLstSort(strLstNewVarLst(kvKeyList(linkMap)), sortOrderAsc);
// Is this a link?
if (target->type == manifestTargetTypeLink && target->tablespaceId == 0)
for (unsigned int linkMapIdx = 0; linkMapIdx < strLstSize(linkMapList); linkMapIdx++)
{
const String *link = strSub(target->name, strSize(MANIFEST_TARGET_PGDATA_STR) + 1);
const String *linkPath = linkMap == NULL ? NULL : varStr(kvGet(linkMap, VARSTR(link)));
const String *const link = strLstGet(linkMapList, linkMapIdx);
const String *const linkPath = varStr(kvGet(linkMap, VARSTR(link)));
const String *const manifestName = strNewFmt(MANIFEST_TARGET_PGDATA "/%s", strZ(link));
// Remap link if a mapping was found
if (linkPath != NULL)
// Attempt to find the link target
ManifestTarget target = {0};
if (manifestTargetFindDefault(manifest, manifestName, NULL) != NULL)
target = *manifestTargetFind(manifest, manifestName);
// Error if the target was not found
if (target.name == NULL)
THROW_FMT(LinkMapError, "unable to remap invalid link '%s'", strZ(link));
// Update target to new path
target.path = linkPath;
// The target must be a link since pg_data/ was prepended and pgdata is the only allowed path
CHECK(target.type == manifestTargetTypeLink);
// Error if the target is a tablespace
if (target.tablespaceId != 0)
{
LOG_INFO_FMT("map link '%s' to '%s'", strZ(link), strZ(linkPath));
manifestLinkUpdate(manifest, target->name, linkPath);
THROW_FMT(
LinkMapError,
"unable to remap tablespace '%s'\n"
"HINT: use '" CFGOPT_TABLESPACE_MAP "' option to remap tablespaces.",
strZ(link));
}
// If the link is a file separate the file name from the path to update the target
const String *linkFile = NULL;
LOG_INFO_FMT("map link '%s' to '%s'", strZ(link), strZ(target.path));
if (target->file != NULL)
// Update link with new destination
manifestLinkUpdate(manifest, target.name, target.path);
// If the link is a file separate the file name from the path
if (target.file != NULL)
{
// The link destination must have at least one path component in addition to the file part. So '..' would
// not be a valid destination but '../file' or '/file' is.
if (strSize(strPath(target.path)) == 0)
{
// The link destination must have at least one path component in addition to the file part. So '..' would
// not be a valid destination but '../file' or '/file' is.
if (strSize(strPath(linkPath)) == 0)
{
THROW_FMT(
LinkMapError, "'%s' is not long enough to be the destination for file link '%s'", strZ(linkPath),
strZ(link));
}
linkFile = strBase(linkPath);
linkPath = strPath(linkPath);
THROW_FMT(
LinkMapError, "'%s' is not long enough to be the destination for file link '%s'", strZ(target.path),
strZ(link));
}
manifestTargetUpdate(manifest, target->name, linkPath, linkFile);
// Add to remapped list for later validation that all links were valid
strLstAdd(linkRemapped, link);
target.file = strBase(target.path);
target.path = strPath(target.path);
}
// If all links are not being restored then remove the target and link
else if (!linkAll)
{
if (target->file != NULL)
LOG_WARN_FMT("file link '%s' will be restored as a file at the same location", strZ(link));
else
{
LOG_WARN_FMT(
"contents of directory link '%s' will be restored in a directory at the same location", strZ(link));
}
manifestLinkRemove(manifest, target->name);
manifestTargetRemove(manifest, target->name);
targetIdx--;
}
// Update target with new path/file
manifestTargetUpdate(manifest, target.name, target.path, target.file);
}
}
// Error on invalid links
if (linkMap != NULL)
// If all links are not being restored then check for links that were not remapped and remove them
if (!cfgOptionBool(cfgOptLinkAll))
{
const VariantList *linkMapList = kvKeyList(linkMap);
strLstSort(linkRemapped, sortOrderAsc);
for (unsigned int linkMapIdx = 0; linkMapIdx < varLstSize(linkMapList); linkMapIdx++)
for (unsigned int targetIdx = 0; targetIdx < manifestTargetTotal(manifest); targetIdx++)
{
const String *link = varStr(varLstGet(linkMapList, linkMapIdx));
const ManifestTarget *const target = manifestTarget(manifest, targetIdx);
if (!strLstExists(linkRemapped, link))
THROW_FMT(LinkMapError, "unable to remap invalid link '%s'", strZ(link));
// Is this a non-tablespace link?
if (target->type == manifestTargetTypeLink && target->tablespaceId == 0)
{
const String *const link = strSub(target->name, strSize(MANIFEST_TARGET_PGDATA_STR) + 1);
// If the link was not remapped then remove it
if (linkMap == NULL || kvGet(linkMap, VARSTR(link)) == NULL)
{
if (target->file != NULL)
LOG_WARN_FMT("file link '%s' will be restored as a file at the same location", strZ(link));
else
{
LOG_WARN_FMT(
"contents of directory link '%s' will be restored in a directory at the same location", strZ(link));
}
manifestLinkRemove(manifest, target->name);
manifestTargetRemove(manifest, target->name);
targetIdx--;
}
}
}
}
}

View File

@ -806,7 +806,10 @@ testRun(void)
hrnCfgArgRawZ(argList, cfgOptLinkMap, "pg_tblspc/1=/ignored");
HRN_CFG_LOAD(cfgCmdRestore, argList);
TEST_ERROR(restoreManifestMap(manifest), LinkMapError, "unable to remap invalid link 'pg_tblspc/1'");
TEST_ERROR(
restoreManifestMap(manifest), LinkMapError,
"unable to remap tablespace 'pg_tblspc/1'\n"
"HINT: use 'tablespace-map' option to remap tablespaces.");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("error on invalid file link path");