4 * per-page conversion operations
6 * Copyright (c) 2010, PostgreSQL Global Development Group
7 * contrib/pg_upgrade/page.c
10 #include "pg_upgrade.h"
12 #include "storage/bufpage.h"
15 #ifdef PAGE_CONVERSION
18 static const char *getPageVersion(
19 uint16 *version, const char *pathName);
20 static pageCnvCtx *loadConverterPlugin(
21 uint16 newPageVersion, uint16 oldPageVersion);
25 * setupPageConverter()
27 * This function determines the PageLayoutVersion of the old cluster and
28 * the PageLayoutVersion of the new cluster. If the versions differ, this
29 * function loads a converter plugin and returns a pointer to a pageCnvCtx
30 * object (in *result) that knows how to convert pages from the old format
31 * to the new format. If the versions are identical, this function just
32 * returns a NULL pageCnvCtx pointer to indicate that page-by-page conversion
35 * If successful this function sets *result and returns NULL. If an error
36 * occurs, this function returns an error message in the form of an null-terminated
40 setupPageConverter(pageCnvCtx **result)
42 uint16 oldPageVersion;
43 uint16 newPageVersion;
44 pageCnvCtx *converter;
46 char dstName[MAXPGPATH];
47 char srcName[MAXPGPATH];
49 snprintf(dstName, sizeof(dstName), "%s/global/%u", new_cluster.pgdata,
50 new_cluster.pg_database_oid);
51 snprintf(srcName, sizeof(srcName), "%s/global/%u", old_cluster.pgdata,
52 old_cluster.pg_database_oid);
54 if ((msg = getPageVersion(&oldPageVersion, srcName)) != NULL)
57 if ((msg = getPageVersion(&newPageVersion, dstName)) != NULL)
61 * If the old cluster and new cluster use the same page layouts, then we
62 * don't need a page converter.
64 if (newPageVersion == oldPageVersion)
71 * The clusters use differing page layouts, see if we can find a plugin
72 * that knows how to convert from the old page layout to the new page
76 if ((converter = loadConverterPlugin(newPageVersion, oldPageVersion)) == NULL)
77 return "can't find plugin to convert from old page layout to new page layout";
89 * Retrieves the PageLayoutVersion for the given relation.
91 * Returns NULL on success (and stores the PageLayoutVersion at *version),
92 * if an error occurs, this function returns an error message (in the form
93 * of a null-terminated string).
96 getPageVersion(uint16 *version, const char *pathName)
102 if ((relfd = open(pathName, O_RDONLY, 0)) < 0)
103 return "can't open relation";
105 if ((bytesRead = read(relfd, &page, sizeof(page))) != sizeof(page))
108 return "can't read page header";
111 *version = PageGetPageLayoutVersion(&page);
120 * loadConverterPlugin()
122 * This function loads a page-converter plugin library and grabs a
123 * pointer to each of the (interesting) functions provided by that
124 * plugin. The name of the plugin library is derived from the given
125 * newPageVersion and oldPageVersion. If a plugin is found, this
126 * function returns a pointer to a pageCnvCtx object (which will contain
127 * a collection of plugin function pointers). If the required plugin
128 * is not found, this function returns NULL.
131 loadConverterPlugin(uint16 newPageVersion, uint16 oldPageVersion)
133 char pluginName[MAXPGPATH];
137 * Try to find a plugin that can convert pages of oldPageVersion into
138 * pages of newPageVersion. For example, if we oldPageVersion = 3 and
139 * newPageVersion is 4, we search for a plugin named:
140 * plugins/convertLayout_3_to_4.dll
144 * FIXME: we are searching for plugins relative to the current directory,
145 * we should really search relative to our own executable instead.
147 snprintf(pluginName, sizeof(pluginName), "./plugins/convertLayout_%d_to_%d%s",
148 oldPageVersion, newPageVersion, DLSUFFIX);
150 if ((plugin = pg_dlopen(pluginName)) == NULL)
154 pageCnvCtx *result = (pageCnvCtx *) pg_malloc(sizeof(*result));
156 result->old.PageVersion = oldPageVersion;
157 result->new.PageVersion = newPageVersion;
159 result->startup = (pluginStartup) pg_dlsym(plugin, "init");
160 result->convertFile = (pluginConvertFile) pg_dlsym(plugin, "convertFile");
161 result->convertPage = (pluginConvertPage) pg_dlsym(plugin, "convertPage");
162 result->shutdown = (pluginShutdown) pg_dlsym(plugin, "fini");
163 result->pluginData = NULL;
166 * If the plugin has exported an initializer, go ahead and invoke it.
169 result->startup(MIGRATOR_API_VERSION, &result->pluginVersion,
170 newPageVersion, oldPageVersion, &result->pluginData);