LCOV - code coverage report
Current view: top level - src/bin/pg_upgrade - relfilenode.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 58 83 69.9 %
Date: 2019-11-13 23:06:49 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-2019, 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             :         case TRANSFER_MODE_CLONE:
      35           0 :             pg_log(PG_REPORT, "Cloning user relation files\n");
      36           0 :             break;
      37             :         case TRANSFER_MODE_COPY:
      38           2 :             pg_log(PG_REPORT, "Copying user relation files\n");
      39           2 :             break;
      40             :         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             : 
      77           2 :     return;
      78             : }
      79             : 
      80             : 
      81             : /*
      82             :  * transfer_all_new_dbs()
      83             :  *
      84             :  * Responsible for upgrading all database. invokes routines to generate mappings and then
      85             :  * physically link the databases.
      86             :  */
      87             : void
      88           2 : transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
      89             :                      char *old_pgdata, char *new_pgdata, char *old_tablespace)
      90             : {
      91             :     int         old_dbnum,
      92             :                 new_dbnum;
      93             : 
      94             :     /* Scan the old cluster databases and transfer their files */
      95          16 :     for (old_dbnum = new_dbnum = 0;
      96          14 :          old_dbnum < old_db_arr->ndbs;
      97          12 :          old_dbnum++, new_dbnum++)
      98             :     {
      99          12 :         DbInfo     *old_db = &old_db_arr->dbs[old_dbnum],
     100          12 :                    *new_db = NULL;
     101             :         FileNameMap *mappings;
     102             :         int         n_maps;
     103             : 
     104             :         /*
     105             :          * Advance past any databases that exist in the new cluster but not in
     106             :          * the old, e.g. "postgres".  (The user might have removed the
     107             :          * 'postgres' database from the old cluster.)
     108             :          */
     109          12 :         for (; new_dbnum < new_db_arr->ndbs; new_dbnum++)
     110             :         {
     111          12 :             new_db = &new_db_arr->dbs[new_dbnum];
     112          12 :             if (strcmp(old_db->db_name, new_db->db_name) == 0)
     113          12 :                 break;
     114             :         }
     115             : 
     116          12 :         if (new_dbnum >= new_db_arr->ndbs)
     117           0 :             pg_fatal("old database \"%s\" not found in the new cluster\n",
     118             :                      old_db->db_name);
     119             : 
     120          12 :         mappings = gen_db_file_maps(old_db, new_db, &n_maps, old_pgdata,
     121             :                                     new_pgdata);
     122          12 :         if (n_maps)
     123             :         {
     124          12 :             print_maps(mappings, n_maps, new_db->db_name);
     125             : 
     126          12 :             transfer_single_new_db(mappings, n_maps, old_tablespace);
     127             :         }
     128             :         /* We allocate something even for n_maps == 0 */
     129          12 :         pg_free(mappings);
     130             :     }
     131             : 
     132           2 :     return;
     133             : }
     134             : 
     135             : /*
     136             :  * transfer_single_new_db()
     137             :  *
     138             :  * create links for mappings stored in "maps" array.
     139             :  */
     140             : static void
     141          12 : transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace)
     142             : {
     143             :     int         mapnum;
     144          12 :     bool        vm_crashsafe_match = true;
     145          12 :     bool        vm_must_add_frozenbit = false;
     146             : 
     147             :     /*
     148             :      * Do the old and new cluster disagree on the crash-safetiness of the vm
     149             :      * files?  If so, do not copy them.
     150             :      */
     151          12 :     if (old_cluster.controldata.cat_ver < VISIBILITY_MAP_CRASHSAFE_CAT_VER &&
     152           0 :         new_cluster.controldata.cat_ver >= VISIBILITY_MAP_CRASHSAFE_CAT_VER)
     153           0 :         vm_crashsafe_match = false;
     154             : 
     155             :     /*
     156             :      * Do we need to rewrite visibilitymap?
     157             :      */
     158          12 :     if (old_cluster.controldata.cat_ver < VISIBILITY_MAP_FROZEN_BIT_CAT_VER &&
     159           0 :         new_cluster.controldata.cat_ver >= VISIBILITY_MAP_FROZEN_BIT_CAT_VER)
     160           0 :         vm_must_add_frozenbit = true;
     161             : 
     162        2180 :     for (mapnum = 0; mapnum < size; mapnum++)
     163             :     {
     164        2168 :         if (old_tablespace == NULL ||
     165           0 :             strcmp(maps[mapnum].old_tablespace, old_tablespace) == 0)
     166             :         {
     167             :             /* transfer primary file */
     168        2168 :             transfer_relfile(&maps[mapnum], "", vm_must_add_frozenbit);
     169             : 
     170             :             /* fsm/vm files added in PG 8.4 */
     171        2168 :             if (GET_MAJOR_VERSION(old_cluster.major_version) >= 804)
     172             :             {
     173             :                 /*
     174             :                  * Copy/link any fsm and vm files, if they exist
     175             :                  */
     176        2168 :                 transfer_relfile(&maps[mapnum], "_fsm", vm_must_add_frozenbit);
     177        2168 :                 if (vm_crashsafe_match)
     178        2168 :                     transfer_relfile(&maps[mapnum], "_vm", vm_must_add_frozenbit);
     179             :             }
     180             :         }
     181             :     }
     182          12 : }
     183             : 
     184             : 
     185             : /*
     186             :  * transfer_relfile()
     187             :  *
     188             :  * Copy or link file from old cluster to new one.  If vm_must_add_frozenbit
     189             :  * is true, visibility map forks are converted and rewritten, even in link
     190             :  * mode.
     191             :  */
     192             : static void
     193        6504 : transfer_relfile(FileNameMap *map, const char *type_suffix, bool vm_must_add_frozenbit)
     194             : {
     195             :     char        old_file[MAXPGPATH];
     196             :     char        new_file[MAXPGPATH];
     197             :     int         segno;
     198             :     char        extent_suffix[65];
     199             :     struct stat statbuf;
     200             : 
     201             :     /*
     202             :      * Now copy/link any related segments as well. Remember, PG breaks large
     203             :      * files into 1GB segments, the first segment has no extension, subsequent
     204             :      * segments are named relfilenode.1, relfilenode.2, relfilenode.3.
     205             :      */
     206        9202 :     for (segno = 0;; segno++)
     207             :     {
     208       11900 :         if (segno == 0)
     209        6504 :             extent_suffix[0] = '\0';
     210             :         else
     211        2698 :             snprintf(extent_suffix, sizeof(extent_suffix), ".%d", segno);
     212             : 
     213        9202 :         snprintf(old_file, sizeof(old_file), "%s%s/%u/%u%s%s",
     214             :                  map->old_tablespace,
     215             :                  map->old_tablespace_suffix,
     216             :                  map->old_db_oid,
     217             :                  map->old_relfilenode,
     218             :                  type_suffix,
     219             :                  extent_suffix);
     220        9202 :         snprintf(new_file, sizeof(new_file), "%s%s/%u/%u%s%s",
     221             :                  map->new_tablespace,
     222             :                  map->new_tablespace_suffix,
     223             :                  map->new_db_oid,
     224             :                  map->new_relfilenode,
     225             :                  type_suffix,
     226             :                  extent_suffix);
     227             : 
     228             :         /* Is it an extent, fsm, or vm file? */
     229        9202 :         if (type_suffix[0] != '\0' || segno != 0)
     230             :         {
     231             :             /* Did file open fail? */
     232        7034 :             if (stat(old_file, &statbuf) != 0)
     233             :             {
     234             :                 /* File does not exist?  That's OK, just return */
     235        6504 :                 if (errno == ENOENT)
     236        6504 :                     return;
     237             :                 else
     238           0 :                     pg_fatal("error while checking for file existence \"%s.%s\" (\"%s\" to \"%s\"): %s\n",
     239             :                              map->nspname, map->relname, old_file, new_file,
     240           0 :                              strerror(errno));
     241             :             }
     242             : 
     243             :             /* If file is empty, just return */
     244         530 :             if (statbuf.st_size == 0)
     245           0 :                 return;
     246             :         }
     247             : 
     248        2698 :         unlink(new_file);
     249             : 
     250             :         /* Copying files might take some time, so give feedback. */
     251        2698 :         pg_log(PG_STATUS, "%s", old_file);
     252             : 
     253        2698 :         if (vm_must_add_frozenbit && strcmp(type_suffix, "_vm") == 0)
     254             :         {
     255             :             /* Need to rewrite visibility map format */
     256           0 :             pg_log(PG_VERBOSE, "rewriting \"%s\" to \"%s\"\n",
     257             :                    old_file, new_file);
     258           0 :             rewriteVisibilityMap(old_file, new_file, map->nspname, map->relname);
     259             :         }
     260             :         else
     261        2698 :             switch (user_opts.transfer_mode)
     262             :             {
     263             :                 case TRANSFER_MODE_CLONE:
     264           0 :                     pg_log(PG_VERBOSE, "cloning \"%s\" to \"%s\"\n",
     265             :                            old_file, new_file);
     266           0 :                     cloneFile(old_file, new_file, map->nspname, map->relname);
     267           0 :                     break;
     268             :                 case TRANSFER_MODE_COPY:
     269        2698 :                     pg_log(PG_VERBOSE, "copying \"%s\" to \"%s\"\n",
     270             :                            old_file, new_file);
     271        2698 :                     copyFile(old_file, new_file, map->nspname, map->relname);
     272        2698 :                     break;
     273             :                 case TRANSFER_MODE_LINK:
     274           0 :                     pg_log(PG_VERBOSE, "linking \"%s\" to \"%s\"\n",
     275             :                            old_file, new_file);
     276           0 :                     linkFile(old_file, new_file, map->nspname, map->relname);
     277             :             }
     278             :     }
     279             : }

Generated by: LCOV version 1.13