Header And Logo

PostgreSQL
| The world's most advanced open source database.

page.c

Go to the documentation of this file.
00001 /*
00002  *  page.c
00003  *
00004  *  per-page conversion operations
00005  *
00006  *  Copyright (c) 2010-2013, PostgreSQL Global Development Group
00007  *  contrib/pg_upgrade/page.c
00008  */
00009 
00010 #include "postgres_fe.h"
00011 
00012 #include "pg_upgrade.h"
00013 
00014 #include "storage/bufpage.h"
00015 
00016 
00017 #ifdef PAGE_CONVERSION
00018 
00019 
00020 static void getPageVersion(
00021                uint16 *version, const char *pathName);
00022 static pageCnvCtx *loadConverterPlugin(
00023                     uint16 newPageVersion, uint16 oldPageVersion);
00024 
00025 
00026 /*
00027  * setupPageConverter()
00028  *
00029  *  This function determines the PageLayoutVersion of the old cluster and
00030  *  the PageLayoutVersion of the new cluster.  If the versions differ, this
00031  *  function loads a converter plugin and returns a pointer to a pageCnvCtx
00032  *  object (in *result) that knows how to convert pages from the old format
00033  *  to the new format.  If the versions are identical, this function just
00034  *  returns a NULL pageCnvCtx pointer to indicate that page-by-page conversion
00035  *  is not required.
00036  */
00037 pageCnvCtx *
00038 setupPageConverter(void)
00039 {
00040     uint16      oldPageVersion;
00041     uint16      newPageVersion;
00042     pageCnvCtx *converter;
00043     const char *msg;
00044     char        dstName[MAXPGPATH];
00045     char        srcName[MAXPGPATH];
00046 
00047     snprintf(dstName, sizeof(dstName), "%s/global/%u", new_cluster.pgdata,
00048              new_cluster.pg_database_oid);
00049     snprintf(srcName, sizeof(srcName), "%s/global/%u", old_cluster.pgdata,
00050              old_cluster.pg_database_oid);
00051 
00052     getPageVersion(&oldPageVersion, srcName);
00053     getPageVersion(&newPageVersion, dstName);
00054 
00055     /*
00056      * If the old cluster and new cluster use the same page layouts, then we
00057      * don't need a page converter.
00058      */
00059     if (newPageVersion != oldPageVersion)
00060     {
00061         /*
00062          * The clusters use differing page layouts, see if we can find a plugin
00063          * that knows how to convert from the old page layout to the new page
00064          * layout.
00065          */
00066     
00067         if ((converter = loadConverterPlugin(newPageVersion, oldPageVersion)) == NULL)
00068             pg_log(PG_FATAL, "could not find plugin to convert from old page layout to new page layout\n");
00069 
00070         return converter;
00071     }
00072     else
00073         return NULL;
00074 }
00075 
00076 
00077 /*
00078  * getPageVersion()
00079  *
00080  *  Retrieves the PageLayoutVersion for the given relation.
00081  *
00082  *  Returns NULL on success (and stores the PageLayoutVersion at *version),
00083  *  if an error occurs, this function returns an error message (in the form
00084  *  of a null-terminated string).
00085  */
00086 static void
00087 getPageVersion(uint16 *version, const char *pathName)
00088 {
00089     int         relfd;
00090     PageHeaderData page;
00091     ssize_t     bytesRead;
00092 
00093     if ((relfd = open(pathName, O_RDONLY, 0)) < 0)
00094         pg_log(PG_FATAL, "could not open relation %s\n", pathName);
00095 
00096     if ((bytesRead = read(relfd, &page, sizeof(page))) != sizeof(page))
00097         pg_log(PG_FATAL, "could not read page header of %s\n", pathName);
00098 
00099     *version = PageGetPageLayoutVersion(&page);
00100 
00101     close(relfd);
00102 
00103     return;
00104 }
00105 
00106 
00107 /*
00108  * loadConverterPlugin()
00109  *
00110  *  This function loads a page-converter plugin library and grabs a
00111  *  pointer to each of the (interesting) functions provided by that
00112  *  plugin.  The name of the plugin library is derived from the given
00113  *  newPageVersion and oldPageVersion.  If a plugin is found, this
00114  *  function returns a pointer to a pageCnvCtx object (which will contain
00115  *  a collection of plugin function pointers). If the required plugin
00116  *  is not found, this function returns NULL.
00117  */
00118 static pageCnvCtx *
00119 loadConverterPlugin(uint16 newPageVersion, uint16 oldPageVersion)
00120 {
00121     char        pluginName[MAXPGPATH];
00122     void       *plugin;
00123 
00124     /*
00125      * Try to find a plugin that can convert pages of oldPageVersion into
00126      * pages of newPageVersion.  For example, if we oldPageVersion = 3 and
00127      * newPageVersion is 4, we search for a plugin named:
00128      * plugins/convertLayout_3_to_4.dll
00129      */
00130 
00131     /*
00132      * FIXME: we are searching for plugins relative to the current directory,
00133      * we should really search relative to our own executable instead.
00134      */
00135     snprintf(pluginName, sizeof(pluginName), "./plugins/convertLayout_%d_to_%d%s",
00136              oldPageVersion, newPageVersion, DLSUFFIX);
00137 
00138     if ((plugin = pg_dlopen(pluginName)) == NULL)
00139         return NULL;
00140     else
00141     {
00142         pageCnvCtx *result = (pageCnvCtx *) pg_malloc(sizeof(*result));
00143 
00144         result->old.PageVersion = oldPageVersion;
00145         result->new.PageVersion = newPageVersion;
00146 
00147         result->startup = (pluginStartup) pg_dlsym(plugin, "init");
00148         result->convertFile = (pluginConvertFile) pg_dlsym(plugin, "convertFile");
00149         result->convertPage = (pluginConvertPage) pg_dlsym(plugin, "convertPage");
00150         result->shutdown = (pluginShutdown) pg_dlsym(plugin, "fini");
00151         result->pluginData = NULL;
00152 
00153         /*
00154          * If the plugin has exported an initializer, go ahead and invoke it.
00155          */
00156         if (result->startup)
00157             result->startup(MIGRATOR_API_VERSION, &result->pluginVersion,
00158                         newPageVersion, oldPageVersion, &result->pluginData);
00159 
00160         return result;
00161     }
00162 }
00163 
00164 
00165 
00166 #endif