LCOV - code coverage report
Current view: top level - src/bin/pg_upgrade - relfilenode.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 61 90 67.8 %
Date: 2020-06-01 00:06:26 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  relfilenode.c
       3             :  *
       4             :  *  relfilenode functions
       5             :  *
       6             :  *  Copyright (c) 2010-2020, PostgreSQL Global Development Group
       7             :  *  src/bin/pg_upgrade/relfilenode.c
       8             :  */
       9             : 
      10             : #include "postgres_fe.h"
      11             : 
      12             : #include <sys/stat.h>
      13             : 
      14             : #include "access/transam.h"
      15             : #include "catalog/pg_class_d.h"
      16             : #include "pg_upgrade.h"
      17             : 
      18             : static void transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace);
      19             : static void transfer_relfile(FileNameMap *map, const char *suffix, bool vm_must_add_frozenbit);
      20             : 
      21             : 
      22             : /*
      23             :  * transfer_all_new_tablespaces()
      24             :  *
      25             :  * Responsible for upgrading all database. invokes routines to generate mappings and then
      26             :  * physically link the databases.
      27             :  */
      28             : void
      29           2 : transfer_all_new_tablespaces(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
      30             :                              char *old_pgdata, char *new_pgdata)
      31             : {
      32           2 :     switch (user_opts.transfer_mode)
      33             :     {
      34           0 :         case TRANSFER_MODE_CLONE:
      35           0 :             pg_log(PG_REPORT, "Cloning user relation files\n");
      36           0 :             break;
      37           2 :         case TRANSFER_MODE_COPY:
      38           2 :             pg_log(PG_REPORT, "Copying user relation files\n");
      39           2 :             break;
      40           0 :         case TRANSFER_MODE_LINK:
      41           0 :             pg_log(PG_REPORT, "Linking user relation files\n");
      42           0 :             break;
      43             :     }
      44             : 
      45             :     /*
      46             :      * Transferring files by tablespace is tricky because a single database
      47             :      * can use multiple tablespaces.  For non-parallel mode, we just pass a
      48             :      * NULL tablespace path, which matches all tablespaces.  In parallel mode,
      49             :      * we pass the default tablespace and all user-created tablespaces and let
      50             :      * those operations happen in parallel.
      51             :      */
      52           2 :     if (user_opts.jobs <= 1)
      53           2 :         parallel_transfer_all_new_dbs(old_db_arr, new_db_arr, old_pgdata,
      54             :                                       new_pgdata, NULL);
      55             :     else
      56             :     {
      57             :         int         tblnum;
      58             : 
      59             :         /* transfer default tablespace */
      60           0 :         parallel_transfer_all_new_dbs(old_db_arr, new_db_arr, old_pgdata,
      61             :                                       new_pgdata, old_pgdata);
      62             : 
      63           0 :         for (tblnum = 0; tblnum < os_info.num_old_tablespaces; tblnum++)
      64           0 :             parallel_transfer_all_new_dbs(old_db_arr,
      65             :                                           new_db_arr,
      66             :                                           old_pgdata,
      67             :                                           new_pgdata,
      68           0 :                                           os_info.old_tablespaces[tblnum]);
      69             :         /* reap all children */
      70           0 :         while (reap_child(true) == true)
      71             :             ;
      72             :     }
      73             : 
      74           2 :     end_progress_output();
      75           2 :     check_ok();
      76           2 : }
      77             : 
      78             : 
      79             : /*
      80             :  * transfer_all_new_dbs()
      81             :  *
      82             :  * Responsible for upgrading all database. invokes routines to generate mappings and then
      83             :  * physically link the databases.
      84             :  */
      85             : void
      86           2 : transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
      87             :                      char *old_pgdata, char *new_pgdata, char *old_tablespace)
      88             : {
      89             :     int         old_dbnum,
      90             :                 new_dbnum;
      91             : 
      92             :     /* Scan the old cluster databases and transfer their files */
      93           2 :     for (old_dbnum = new_dbnum = 0;
      94          14 :          old_dbnum < old_db_arr->ndbs;
      95          12 :          old_dbnum++, new_dbnum++)
      96             :     {
      97          12 :         DbInfo     *old_db = &old_db_arr->dbs[old_dbnum],
      98          12 :                    *new_db = NULL;
      99             :         FileNameMap *mappings;
     100             :         int         n_maps;
     101             : 
     102             :         /*
     103             :          * Advance past any databases that exist in the new cluster but not in
     104             :          * the old, e.g. "postgres".  (The user might have removed the
     105             :          * 'postgres' database from the old cluster.)
     106             :          */
     107          12 :         for (; new_dbnum < new_db_arr->ndbs; new_dbnum++)
     108             :         {
     109          12 :             new_db = &new_db_arr->dbs[new_dbnum];
     110          12 :             if (strcmp(old_db->db_name, new_db->db_name) == 0)
     111          12 :                 break;
     112             :         }
     113             : 
     114          12 :         if (new_dbnum >= new_db_arr->ndbs)
     115           0 :             pg_fatal("old database \"%s\" not found in the new cluster\n",
     116             :                      old_db->db_name);
     117             : 
     118          12 :         mappings = gen_db_file_maps(old_db, new_db, &n_maps, old_pgdata,
     119             :                                     new_pgdata);
     120          12 :         if (n_maps)
     121             :         {
     122          12 :             print_maps(mappings, n_maps, new_db->db_name);
     123             : 
     124          12 :             transfer_single_new_db(mappings, n_maps, old_tablespace);
     125             :         }
     126             :         /* We allocate something even for n_maps == 0 */
     127          12 :         pg_free(mappings);
     128             :     }
     129           2 : }
     130             : 
     131             : /*
     132             :  * transfer_single_new_db()
     133             :  *
     134             :  * create links for mappings stored in "maps" array.
     135             :  */
     136             : static void
     137          12 : transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace)
     138             : {
     139             :     int         mapnum;
     140          12 :     bool        vm_crashsafe_match = true;
     141          12 :     bool        vm_must_add_frozenbit = false;
     142             : 
     143             :     /*
     144             :      * Do the old and new cluster disagree on the crash-safetiness of the vm
     145             :      * files?  If so, do not copy them.
     146             :      */
     147          12 :     if (old_cluster.controldata.cat_ver < VISIBILITY_MAP_CRASHSAFE_CAT_VER &&
     148           0 :         new_cluster.controldata.cat_ver >= VISIBILITY_MAP_CRASHSAFE_CAT_VER)
     149           0 :         vm_crashsafe_match = false;
     150             : 
     151             :     /*
     152             :      * Do we need to rewrite visibilitymap?
     153             :      */
     154          12 :     if (old_cluster.controldata.cat_ver < VISIBILITY_MAP_FROZEN_BIT_CAT_VER &&
     155           0 :         new_cluster.controldata.cat_ver >= VISIBILITY_MAP_FROZEN_BIT_CAT_VER)
     156           0 :         vm_must_add_frozenbit = true;
     157             : 
     158        2292 :     for (mapnum = 0; mapnum < size; mapnum++)
     159             :     {
     160        2280 :         if (old_tablespace == NULL ||
     161           0 :             strcmp(maps[mapnum].old_tablespace, old_tablespace) == 0)
     162             :         {
     163             :             /* transfer primary file */
     164        2280 :             transfer_relfile(&maps[mapnum], "", vm_must_add_frozenbit);
     165             : 
     166             :             /* fsm/vm files added in PG 8.4 */
     167        2280 :             if (GET_MAJOR_VERSION(old_cluster.major_version) >= 804)
     168             :             {
     169             :                 /*
     170             :                  * Copy/link any fsm and vm files, if they exist
     171             :                  */
     172        2280 :                 transfer_relfile(&maps[mapnum], "_fsm", vm_must_add_frozenbit);
     173        2280 :                 if (vm_crashsafe_match)
     174        2280 :                     transfer_relfile(&maps[mapnum], "_vm", vm_must_add_frozenbit);
     175             :             }
     176             :         }
     177             :     }
     178          12 : }
     179             : 
     180             : 
     181             : /*
     182             :  * transfer_relfile()
     183             :  *
     184             :  * Copy or link file from old cluster to new one.  If vm_must_add_frozenbit
     185             :  * is true, visibility map forks are converted and rewritten, even in link
     186             :  * mode.
     187             :  */
     188             : static void
     189        6840 : transfer_relfile(FileNameMap *map, const char *type_suffix, bool vm_must_add_frozenbit)
     190             : {
     191             :     char        old_file[MAXPGPATH];
     192             :     char        new_file[MAXPGPATH];
     193             :     int         segno;
     194             :     char        extent_suffix[65];
     195             :     struct stat statbuf;
     196             : 
     197             :     /*
     198             :      * Now copy/link any related segments as well. Remember, PG breaks large
     199             :      * files into 1GB segments, the first segment has no extension, subsequent
     200             :      * segments are named relfilenode.1, relfilenode.2, relfilenode.3.
     201             :      */
     202        6840 :     for (segno = 0;; segno++)
     203             :     {
     204        9668 :         if (segno == 0)
     205        6840 :             extent_suffix[0] = '\0';
     206             :         else
     207        2828 :             snprintf(extent_suffix, sizeof(extent_suffix), ".%d", segno);
     208             : 
     209        9668 :         snprintf(old_file, sizeof(old_file), "%s%s/%u/%u%s%s",
     210             :                  map->old_tablespace,
     211             :                  map->old_tablespace_suffix,
     212             :                  map->old_db_oid,
     213             :                  map->old_relfilenode,
     214             :                  type_suffix,
     215             :                  extent_suffix);
     216        9668 :         snprintf(new_file, sizeof(new_file), "%s%s/%u/%u%s%s",
     217             :                  map->new_tablespace,
     218             :                  map->new_tablespace_suffix,
     219             :                  map->new_db_oid,
     220             :                  map->new_relfilenode,
     221             :                  type_suffix,
     222             :                  extent_suffix);
     223             : 
     224             :         /* Is it an extent, fsm, or vm file? */
     225        9668 :         if (type_suffix[0] != '\0' || segno != 0)
     226             :         {
     227             :             /* Did file open fail? */
     228        7388 :             if (stat(old_file, &statbuf) != 0)
     229             :             {
     230             :                 /* File does not exist?  That's OK, just return */
     231        6840 :                 if (errno == ENOENT)
     232        6840 :                     return;
     233             :                 else
     234           0 :                     pg_fatal("error while checking for file existence \"%s.%s\" (\"%s\" to \"%s\"): %s\n",
     235             :                              map->nspname, map->relname, old_file, new_file,
     236           0 :                              strerror(errno));
     237             :             }
     238             : 
     239             :             /* If file is empty, just return */
     240         548 :             if (statbuf.st_size == 0)
     241           0 :                 return;
     242             :         }
     243             : 
     244        2828 :         unlink(new_file);
     245             : 
     246             :         /* Copying files might take some time, so give feedback. */
     247        2828 :         pg_log(PG_STATUS, "%s", old_file);
     248             : 
     249        2828 :         if (vm_must_add_frozenbit && strcmp(type_suffix, "_vm") == 0)
     250             :         {
     251             :             /* Need to rewrite visibility map format */
     252           0 :             pg_log(PG_VERBOSE, "rewriting \"%s\" to \"%s\"\n",
     253             :                    old_file, new_file);
     254           0 :             rewriteVisibilityMap(old_file, new_file, map->nspname, map->relname);
     255             :         }
     256             :         else
     257        2828 :             switch (user_opts.transfer_mode)
     258             :             {
     259           0 :                 case TRANSFER_MODE_CLONE:
     260           0 :                     pg_log(PG_VERBOSE, "cloning \"%s\" to \"%s\"\n",
     261             :                            old_file, new_file);
     262           0 :                     cloneFile(old_file, new_file, map->nspname, map->relname);
     263           0 :                     break;
     264        2828 :                 case TRANSFER_MODE_COPY:
     265        2828 :                     pg_log(PG_VERBOSE, "copying \"%s\" to \"%s\"\n",
     266             :                            old_file, new_file);
     267        2828 :                     copyFile(old_file, new_file, map->nspname, map->relname);
     268        2828 :                     break;
     269           0 :                 case TRANSFER_MODE_LINK:
     270           0 :                     pg_log(PG_VERBOSE, "linking \"%s\" to \"%s\"\n",
     271             :                            old_file, new_file);
     272           0 :                     linkFile(old_file, new_file, map->nspname, map->relname);
     273             :             }
     274        2828 :     }
     275             : }

Generated by: LCOV version 1.13