Files
openGauss-server/contrib/pg_upgrade/page.cpp
2020-06-30 17:38:27 +08:00

176 lines
5.4 KiB
C++

/*
* page.c
*
* per-page conversion operations
*
* Copyright (c) 2010-2012, PostgreSQL Global Development Group
* contrib/pg_upgrade/page.c
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "pg_upgrade.h"
#include "storage/bufpage.h"
#ifdef PAGE_CONVERSION
static const char* getPageVersion(uint16* version, const char* pathName);
static pageCnvCtx* loadConverterPlugin(uint16 newPageVersion, uint16 oldPageVersion);
/*
* setupPageConverter()
*
* This function determines the PageLayoutVersion of the old cluster and
* the PageLayoutVersion of the new cluster. If the versions differ, this
* function loads a converter plugin and returns a pointer to a pageCnvCtx
* object (in *result) that knows how to convert pages from the old format
* to the new format. If the versions are identical, this function just
* returns a NULL pageCnvCtx pointer to indicate that page-by-page conversion
* is not required.
*
* If successful this function sets *result and returns NULL. If an error
* occurs, this function returns an error message in the form of an null-terminated
* string.
*/
const char* setupPageConverter(pageCnvCtx** result)
{
uint16 oldPageVersion;
uint16 newPageVersion;
pageCnvCtx* converter = NULL;
const char* msg = NULL;
char dstName[MAXPGPATH];
char srcName[MAXPGPATH];
int nRet = 0;
nRet = snprintf_s(
dstName, sizeof(dstName), sizeof(dstName) - 1, "%s/global/%u", new_cluster.pgdata, new_cluster.pg_database_oid);
securec_check_ss_c(nRet, "\0", "\0");
nRet = snprintf_s(
srcName, sizeof(srcName), sizeof(srcName) - 1, "%s/global/%u", old_cluster.pgdata, old_cluster.pg_database_oid);
securec_check_ss_c(nRet, "\0", "\0");
if ((msg = getPageVersion(&oldPageVersion, srcName)) != NULL)
return msg;
if ((msg = getPageVersion(&newPageVersion, dstName)) != NULL)
return msg;
/*
* If the old cluster and new cluster use the same page layouts, then we
* don't need a page converter.
*/
if (newPageVersion == oldPageVersion) {
*result = NULL;
return NULL;
}
/*
* The clusters use differing page layouts, see if we can find a plugin
* that knows how to convert from the old page layout to the new page
* layout.
*/
if ((converter = loadConverterPlugin(newPageVersion, oldPageVersion)) == NULL)
return "could not find plugin to convert from old page layout to new page layout";
else {
*result = converter;
return NULL;
}
}
/*
* getPageVersion()
*
* Retrieves the PageLayoutVersion for the given relation.
*
* Returns NULL on success (and stores the PageLayoutVersion at *version),
* if an error occurs, this function returns an error message (in the form
* of a null-terminated string).
*/
static const char* getPageVersion(uint16* version, const char* pathName)
{
int relfd;
PageHeaderData page;
ssize_t bytesRead;
if ((relfd = open(pathName, O_RDONLY, 0)) < 0)
return "could not open relation";
if ((bytesRead = read(relfd, &page, sizeof(page))) != sizeof(page)) {
close(relfd);
return "could not read page header";
}
*version = PageGetPageLayoutVersion(&page);
close(relfd);
return NULL;
}
/*
* loadConverterPlugin()
*
* This function loads a page-converter plugin library and grabs a
* pointer to each of the (interesting) functions provided by that
* plugin. The name of the plugin library is derived from the given
* newPageVersion and oldPageVersion. If a plugin is found, this
* function returns a pointer to a pageCnvCtx object (which will contain
* a collection of plugin function pointers). If the required plugin
* is not found, this function returns NULL.
*/
static pageCnvCtx* loadConverterPlugin(uint16 newPageVersion, uint16 oldPageVersion)
{
char pluginName[MAXPGPATH];
void* plugin = NULL;
int nRet = 0;
/*
* Try to find a plugin that can convert pages of oldPageVersion into
* pages of newPageVersion. For example, if we oldPageVersion = 3 and
* newPageVersion is 4, we search for a plugin named:
* plugins/convertLayout_3_to_4.dll
*/
/*
* FIXME: we are searching for plugins relative to the current directory,
* we should really search relative to our own executable instead.
*/
nRet = snprintf_s(pluginName,
sizeof(pluginName),
sizeof(pluginName) - 1,
"./plugins/convertLayout_%d_to_%d%s",
oldPageVersion,
newPageVersion,
DLSUFFIX);
securec_check_ss_c(nRet, "\0", "\0");
if ((plugin = pg_dlopen(pluginName)) == NULL)
return NULL;
else {
pageCnvCtx* result = (pageCnvCtx*)pg_malloc(sizeof(*result));
result->old.PageVersion = oldPageVersion;
result->newm.PageVersion = newPageVersion;
result->startup = (pluginStartup)pg_dlsym(plugin, "init");
result->convertFile = (pluginConvertFile)pg_dlsym(plugin, "convertFile");
result->convertPage = (pluginConvertPage)pg_dlsym(plugin, "convertPage");
result->shutdown = (pluginShutdown)pg_dlsym(plugin, "fini");
result->pluginData = NULL;
/*
* If the plugin has exported an initializer, go ahead and invoke it.
*/
if (result->startup)
result->startup(
MIGRATOR_API_VERSION, &result->pluginVersion, newPageVersion, oldPageVersion, &result->pluginData);
return result;
}
}
#endif