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