Header And Logo

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

relfilenode.c

Go to the documentation of this file.
00001 /*
00002  *  relfilenode.c
00003  *
00004  *  relfilenode functions
00005  *
00006  *  Copyright (c) 2010-2013, PostgreSQL Global Development Group
00007  *  contrib/pg_upgrade/relfilenode.c
00008  */
00009 
00010 #include "postgres_fe.h"
00011 
00012 #include "pg_upgrade.h"
00013 
00014 #include "catalog/pg_class.h"
00015 #include "access/transam.h"
00016 
00017 
00018 static void transfer_single_new_db(pageCnvCtx *pageConverter,
00019                        FileNameMap *maps, int size, char *old_tablespace);
00020 static void transfer_relfile(pageCnvCtx *pageConverter, FileNameMap *map,
00021                              const char *suffix);
00022 
00023 
00024 /*
00025  * transfer_all_new_tablespaces()
00026  *
00027  * Responsible for upgrading all database. invokes routines to generate mappings and then
00028  * physically link the databases.
00029  */
00030 void
00031 transfer_all_new_tablespaces(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
00032                     char *old_pgdata, char *new_pgdata)
00033 {
00034     pg_log(PG_REPORT, "%s user relation files\n",
00035       user_opts.transfer_mode == TRANSFER_MODE_LINK ? "Linking" : "Copying");
00036 
00037     /*
00038      *  Transfering files by tablespace is tricky because a single database
00039      *  can use multiple tablespaces.  For non-parallel mode, we just pass a
00040      *  NULL tablespace path, which matches all tablespaces.  In parallel mode,
00041      *  we pass the default tablespace and all user-created tablespaces
00042      *  and let those operations happen in parallel.
00043      */
00044     if (user_opts.jobs <= 1)
00045         parallel_transfer_all_new_dbs(old_db_arr, new_db_arr, old_pgdata,
00046                                       new_pgdata, NULL);
00047     else
00048     {
00049         int tblnum;
00050 
00051         /* transfer default tablespace */
00052         parallel_transfer_all_new_dbs(old_db_arr, new_db_arr, old_pgdata,
00053                               new_pgdata, old_pgdata);
00054 
00055         for (tblnum = 0; tblnum < os_info.num_old_tablespaces; tblnum++)
00056             parallel_transfer_all_new_dbs(old_db_arr, new_db_arr, old_pgdata,
00057                                   new_pgdata, os_info.old_tablespaces[tblnum]);
00058         /* reap all children */
00059         while (reap_child(true) == true)
00060             ;
00061     }
00062 
00063     end_progress_output();
00064     check_ok();
00065 
00066     return;
00067 }
00068 
00069 
00070 /*
00071  * transfer_all_new_dbs()
00072  *
00073  * Responsible for upgrading all database. invokes routines to generate mappings and then
00074  * physically link the databases.
00075  */
00076 void
00077 transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
00078                     char *old_pgdata, char *new_pgdata, char *old_tablespace)
00079 {
00080     int         old_dbnum,
00081                 new_dbnum;
00082 
00083     /* Scan the old cluster databases and transfer their files */
00084     for (old_dbnum = new_dbnum = 0;
00085          old_dbnum < old_db_arr->ndbs;
00086          old_dbnum++, new_dbnum++)
00087     {
00088         DbInfo     *old_db = &old_db_arr->dbs[old_dbnum],
00089                    *new_db = NULL;
00090         FileNameMap *mappings;
00091         int         n_maps;
00092         pageCnvCtx *pageConverter = NULL;
00093 
00094         /*
00095          * Advance past any databases that exist in the new cluster but not in
00096          * the old, e.g. "postgres".  (The user might have removed the
00097          * 'postgres' database from the old cluster.)
00098          */
00099         for (; new_dbnum < new_db_arr->ndbs; new_dbnum++)
00100         {
00101             new_db = &new_db_arr->dbs[new_dbnum];
00102             if (strcmp(old_db->db_name, new_db->db_name) == 0)
00103                 break;
00104         }
00105 
00106         if (new_dbnum >= new_db_arr->ndbs)
00107             pg_log(PG_FATAL, "old database \"%s\" not found in the new cluster\n",
00108                    old_db->db_name);
00109 
00110         n_maps = 0;
00111         mappings = gen_db_file_maps(old_db, new_db, &n_maps, old_pgdata,
00112                                     new_pgdata);
00113 
00114         if (n_maps)
00115         {
00116             print_maps(mappings, n_maps, new_db->db_name);
00117 
00118 #ifdef PAGE_CONVERSION
00119             pageConverter = setupPageConverter();
00120 #endif
00121             transfer_single_new_db(pageConverter, mappings, n_maps,
00122                                    old_tablespace);
00123 
00124             pg_free(mappings);
00125         }
00126     }
00127 
00128     return;
00129 }
00130 
00131 
00132 /*
00133  * get_pg_database_relfilenode()
00134  *
00135  *  Retrieves the relfilenode for a few system-catalog tables.  We need these
00136  *  relfilenodes later in the upgrade process.
00137  */
00138 void
00139 get_pg_database_relfilenode(ClusterInfo *cluster)
00140 {
00141     PGconn     *conn = connectToServer(cluster, "template1");
00142     PGresult   *res;
00143     int         i_relfile;
00144 
00145     res = executeQueryOrDie(conn,
00146                             "SELECT c.relname, c.relfilenode "
00147                             "FROM   pg_catalog.pg_class c, "
00148                             "       pg_catalog.pg_namespace n "
00149                             "WHERE  c.relnamespace = n.oid AND "
00150                             "       n.nspname = 'pg_catalog' AND "
00151                             "       c.relname = 'pg_database' "
00152                             "ORDER BY c.relname");
00153 
00154     i_relfile = PQfnumber(res, "relfilenode");
00155     cluster->pg_database_oid = atooid(PQgetvalue(res, 0, i_relfile));
00156 
00157     PQclear(res);
00158     PQfinish(conn);
00159 }
00160 
00161 
00162 /*
00163  * transfer_single_new_db()
00164  *
00165  * create links for mappings stored in "maps" array.
00166  */
00167 static void
00168 transfer_single_new_db(pageCnvCtx *pageConverter,
00169                        FileNameMap *maps, int size, char *old_tablespace)
00170 {
00171     int         mapnum;
00172     bool        vm_crashsafe_match = true;
00173     
00174     /*
00175      * Do the old and new cluster disagree on the crash-safetiness of the vm
00176      * files?  If so, do not copy them.
00177      */
00178     if (old_cluster.controldata.cat_ver < VISIBILITY_MAP_CRASHSAFE_CAT_VER &&
00179         new_cluster.controldata.cat_ver >= VISIBILITY_MAP_CRASHSAFE_CAT_VER)
00180         vm_crashsafe_match = false;
00181 
00182     for (mapnum = 0; mapnum < size; mapnum++)
00183     {
00184         if (old_tablespace == NULL ||
00185             strcmp(maps[mapnum].old_tablespace, old_tablespace) == 0)
00186         {
00187             /* transfer primary file */
00188             transfer_relfile(pageConverter, &maps[mapnum], "");
00189     
00190             /* fsm/vm files added in PG 8.4 */
00191             if (GET_MAJOR_VERSION(old_cluster.major_version) >= 804)
00192             {
00193                 /*
00194                  * Copy/link any fsm and vm files, if they exist
00195                  */
00196                 transfer_relfile(pageConverter, &maps[mapnum], "_fsm");
00197                 if (vm_crashsafe_match)
00198                     transfer_relfile(pageConverter, &maps[mapnum], "_vm");
00199             }
00200         }
00201     }
00202 }
00203 
00204 
00205 /*
00206  * transfer_relfile()
00207  *
00208  * Copy or link file from old cluster to new one.
00209  */
00210 static void
00211 transfer_relfile(pageCnvCtx *pageConverter, FileNameMap *map,
00212                  const char *type_suffix)
00213 {
00214     const char *msg;
00215     char        old_file[MAXPGPATH];
00216     char        new_file[MAXPGPATH];
00217     int         fd;
00218     int         segno;
00219     char        extent_suffix[65];
00220     
00221     /*
00222      * Now copy/link any related segments as well. Remember, PG breaks
00223      * large files into 1GB segments, the first segment has no extension,
00224      * subsequent segments are named relfilenode.1, relfilenode.2,
00225      * relfilenode.3.
00226      * copied.
00227      */
00228     for (segno = 0;; segno++)
00229     {
00230         if (segno == 0)
00231             extent_suffix[0] = '\0';
00232         else
00233             snprintf(extent_suffix, sizeof(extent_suffix), ".%d", segno);
00234 
00235         snprintf(old_file, sizeof(old_file), "%s%s/%u/%u%s%s", map->old_tablespace,
00236                  map->old_tablespace_suffix, map->old_db_oid, map->old_relfilenode,
00237                  type_suffix, extent_suffix);
00238         snprintf(new_file, sizeof(new_file), "%s%s/%u/%u%s%s", map->new_tablespace,
00239                  map->new_tablespace_suffix, map->new_db_oid, map->new_relfilenode,
00240                  type_suffix, extent_suffix);
00241     
00242         /* Is it an extent, fsm, or vm file? */
00243         if (type_suffix[0] != '\0' || segno != 0)
00244         {
00245             /* Did file open fail? */
00246             if ((fd = open(old_file, O_RDONLY, 0)) == -1)
00247             {
00248                 /* File does not exist?  That's OK, just return */
00249                 if (errno == ENOENT)
00250                     return;
00251                 else
00252                     pg_log(PG_FATAL, "error while checking for file existance \"%s.%s\" (\"%s\" to \"%s\"): %s\n",
00253                            map->nspname, map->relname, old_file, new_file,
00254                            getErrorText(errno));
00255             }
00256             close(fd);
00257         }
00258 
00259         unlink(new_file);
00260     
00261         /* Copying files might take some time, so give feedback. */
00262         pg_log(PG_STATUS, "%s", old_file);
00263     
00264         if ((user_opts.transfer_mode == TRANSFER_MODE_LINK) && (pageConverter != NULL))
00265             pg_log(PG_FATAL, "This upgrade requires page-by-page conversion, "
00266                    "you must use copy mode instead of link mode.\n");
00267     
00268         if (user_opts.transfer_mode == TRANSFER_MODE_COPY)
00269         {
00270             pg_log(PG_VERBOSE, "copying \"%s\" to \"%s\"\n", old_file, new_file);
00271     
00272             if ((msg = copyAndUpdateFile(pageConverter, old_file, new_file, true)) != NULL)
00273                 pg_log(PG_FATAL, "error while copying relation \"%s.%s\" (\"%s\" to \"%s\"): %s\n",
00274                        map->nspname, map->relname, old_file, new_file, msg);
00275         }
00276         else
00277         {
00278             pg_log(PG_VERBOSE, "linking \"%s\" to \"%s\"\n", old_file, new_file);
00279     
00280             if ((msg = linkAndUpdateFile(pageConverter, old_file, new_file)) != NULL)
00281                 pg_log(PG_FATAL,
00282                        "error while creating link for relation \"%s.%s\" (\"%s\" to \"%s\"): %s\n",
00283                        map->nspname, map->relname, old_file, new_file, msg);
00284         }
00285    }
00286 
00287     return;
00288 }
00289