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:
parent
d89a67776c
commit
cf1a57518f
@ -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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user