Line data Source code
1 : /*
2 : * relfilenumber.c
3 : *
4 : * relfilenumber functions
5 : *
6 : * Copyright (c) 2010-2025, PostgreSQL Global Development Group
7 : * src/bin/pg_upgrade/relfilenumber.c
8 : */
9 :
10 : #include "postgres_fe.h"
11 :
12 : #include <sys/stat.h>
13 :
14 : #include "common/file_perm.h"
15 : #include "common/file_utils.h"
16 : #include "common/int.h"
17 : #include "common/logging.h"
18 : #include "pg_upgrade.h"
19 :
20 : static void transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace);
21 : static void transfer_relfile(FileNameMap *map, const char *type_suffix, bool vm_must_add_frozenbit);
22 :
23 : /*
24 : * The following set of sync_queue_* functions are used for --swap to reduce
25 : * the amount of time spent synchronizing the swapped catalog files. When a
26 : * file is added to the queue, we also alert the file system that we'd like it
27 : * to be persisted to disk in the near future (if that operation is supported
28 : * by the current platform). Once the queue is full, all of the files are
29 : * synchronized to disk. This strategy should generally be much faster than
30 : * simply calling fsync() on the files right away.
31 : *
32 : * The general usage pattern should be something like:
33 : *
34 : * for (int i = 0; i < num_files; i++)
35 : * sync_queue_push(files[i]);
36 : *
37 : * // be sure to sync any remaining files in the queue
38 : * sync_queue_sync_all();
39 : * synq_queue_destroy();
40 : */
41 :
42 : #define SYNC_QUEUE_MAX_LEN (1024)
43 :
44 : static char *sync_queue[SYNC_QUEUE_MAX_LEN];
45 : static bool sync_queue_inited;
46 : static int sync_queue_len;
47 :
48 : static inline void
49 0 : sync_queue_init(void)
50 : {
51 0 : if (sync_queue_inited)
52 0 : return;
53 :
54 0 : sync_queue_inited = true;
55 0 : for (int i = 0; i < SYNC_QUEUE_MAX_LEN; i++)
56 0 : sync_queue[i] = palloc(MAXPGPATH);
57 : }
58 :
59 : static inline void
60 16 : sync_queue_sync_all(void)
61 : {
62 16 : if (!sync_queue_inited)
63 16 : return;
64 :
65 0 : for (int i = 0; i < sync_queue_len; i++)
66 : {
67 0 : if (fsync_fname(sync_queue[i], false) != 0)
68 0 : pg_fatal("could not synchronize file \"%s\": %m", sync_queue[i]);
69 : }
70 :
71 0 : sync_queue_len = 0;
72 : }
73 :
74 : static inline void
75 0 : sync_queue_push(const char *fname)
76 : {
77 0 : sync_queue_init();
78 :
79 0 : pre_sync_fname(fname, false);
80 :
81 0 : strncpy(sync_queue[sync_queue_len++], fname, MAXPGPATH);
82 0 : if (sync_queue_len >= SYNC_QUEUE_MAX_LEN)
83 0 : sync_queue_sync_all();
84 0 : }
85 :
86 : static inline void
87 16 : sync_queue_destroy(void)
88 : {
89 16 : if (!sync_queue_inited)
90 16 : return;
91 :
92 0 : sync_queue_inited = false;
93 0 : sync_queue_len = 0;
94 0 : for (int i = 0; i < SYNC_QUEUE_MAX_LEN; i++)
95 : {
96 0 : pfree(sync_queue[i]);
97 0 : sync_queue[i] = NULL;
98 : }
99 : }
100 :
101 : /*
102 : * transfer_all_new_tablespaces()
103 : *
104 : * Responsible for upgrading all database. invokes routines to generate mappings and then
105 : * physically link the databases.
106 : */
107 : void
108 16 : transfer_all_new_tablespaces(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
109 : char *old_pgdata, char *new_pgdata)
110 : {
111 16 : switch (user_opts.transfer_mode)
112 : {
113 0 : case TRANSFER_MODE_CLONE:
114 0 : prep_status_progress("Cloning user relation files");
115 0 : break;
116 10 : case TRANSFER_MODE_COPY:
117 10 : prep_status_progress("Copying user relation files");
118 10 : break;
119 2 : case TRANSFER_MODE_COPY_FILE_RANGE:
120 2 : prep_status_progress("Copying user relation files with copy_file_range");
121 2 : break;
122 2 : case TRANSFER_MODE_LINK:
123 2 : prep_status_progress("Linking user relation files");
124 2 : break;
125 2 : case TRANSFER_MODE_SWAP:
126 2 : prep_status_progress("Swapping data directories");
127 2 : break;
128 : }
129 :
130 : /*
131 : * Transferring files by tablespace is tricky because a single database
132 : * can use multiple tablespaces. For non-parallel mode, we just pass a
133 : * NULL tablespace path, which matches all tablespaces. In parallel mode,
134 : * we pass the default tablespace and all user-created tablespaces and let
135 : * those operations happen in parallel.
136 : */
137 16 : if (user_opts.jobs <= 1)
138 16 : parallel_transfer_all_new_dbs(old_db_arr, new_db_arr, old_pgdata,
139 : new_pgdata, NULL);
140 : else
141 : {
142 : int tblnum;
143 :
144 : /* transfer default tablespace */
145 0 : parallel_transfer_all_new_dbs(old_db_arr, new_db_arr, old_pgdata,
146 : new_pgdata, old_pgdata);
147 :
148 0 : for (tblnum = 0; tblnum < os_info.num_old_tablespaces; tblnum++)
149 0 : parallel_transfer_all_new_dbs(old_db_arr,
150 : new_db_arr,
151 : old_pgdata,
152 : new_pgdata,
153 0 : os_info.old_tablespaces[tblnum]);
154 : /* reap all children */
155 0 : while (reap_child(true) == true)
156 : ;
157 : }
158 :
159 16 : end_progress_output();
160 16 : check_ok();
161 16 : }
162 :
163 :
164 : /*
165 : * transfer_all_new_dbs()
166 : *
167 : * Responsible for upgrading all database. invokes routines to generate mappings and then
168 : * physically link the databases.
169 : */
170 : void
171 16 : transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
172 : char *old_pgdata, char *new_pgdata, char *old_tablespace)
173 : {
174 : int old_dbnum,
175 : new_dbnum;
176 :
177 : /* Scan the old cluster databases and transfer their files */
178 16 : for (old_dbnum = new_dbnum = 0;
179 64 : old_dbnum < old_db_arr->ndbs;
180 48 : old_dbnum++, new_dbnum++)
181 : {
182 48 : DbInfo *old_db = &old_db_arr->dbs[old_dbnum],
183 48 : *new_db = NULL;
184 : FileNameMap *mappings;
185 : int n_maps;
186 :
187 : /*
188 : * Advance past any databases that exist in the new cluster but not in
189 : * the old, e.g. "postgres". (The user might have removed the
190 : * 'postgres' database from the old cluster.)
191 : */
192 48 : for (; new_dbnum < new_db_arr->ndbs; new_dbnum++)
193 : {
194 48 : new_db = &new_db_arr->dbs[new_dbnum];
195 48 : if (strcmp(old_db->db_name, new_db->db_name) == 0)
196 48 : break;
197 : }
198 :
199 48 : if (new_dbnum >= new_db_arr->ndbs)
200 0 : pg_fatal("old database \"%s\" not found in the new cluster",
201 : old_db->db_name);
202 :
203 48 : mappings = gen_db_file_maps(old_db, new_db, &n_maps, old_pgdata,
204 : new_pgdata);
205 48 : if (n_maps)
206 : {
207 48 : transfer_single_new_db(mappings, n_maps, old_tablespace);
208 : }
209 : /* We allocate something even for n_maps == 0 */
210 48 : pg_free(mappings);
211 : }
212 :
213 : /*
214 : * Make sure anything pending synchronization in swap mode is fully
215 : * persisted to disk. This is a no-op for other transfer modes.
216 : */
217 16 : sync_queue_sync_all();
218 16 : sync_queue_destroy();
219 16 : }
220 :
221 : /*
222 : * prepare_for_swap()
223 : *
224 : * This function moves the database directory from the old cluster to the new
225 : * cluster in preparation for moving the pg_restore-generated catalog files
226 : * into place. Returns false if the database with the given OID does not have
227 : * a directory in the given tablespace, otherwise returns true.
228 : *
229 : * This function will return paths in the following variables, which the caller
230 : * must ensure are sized to MAXPGPATH bytes:
231 : *
232 : * old_catalog_dir: The directory for the old cluster's catalog files.
233 : * new_db_dir: The new cluster's database directory for db_oid.
234 : * moved_db_dir: Destination for the pg_restore-generated database directory.
235 : */
236 : static bool
237 6 : prepare_for_swap(const char *old_tablespace, Oid db_oid,
238 : char *old_catalog_dir, char *new_db_dir, char *moved_db_dir)
239 : {
240 : const char *new_tablespace;
241 : const char *old_tblspc_suffix;
242 : const char *new_tblspc_suffix;
243 : char old_tblspc[MAXPGPATH];
244 : char new_tblspc[MAXPGPATH];
245 : char moved_tblspc[MAXPGPATH];
246 : char old_db_dir[MAXPGPATH];
247 : struct stat st;
248 :
249 6 : if (strcmp(old_tablespace, old_cluster.pgdata) == 0)
250 : {
251 6 : new_tablespace = new_cluster.pgdata;
252 6 : new_tblspc_suffix = "/base";
253 6 : old_tblspc_suffix = "/base";
254 : }
255 : else
256 : {
257 : /*
258 : * XXX: The below line is a hack to deal with the fact that we
259 : * presently don't have an easy way to find the corresponding new
260 : * tablespace's path. This will need to be fixed if/when we add
261 : * pg_upgrade support for in-place tablespaces.
262 : */
263 0 : new_tablespace = old_tablespace;
264 :
265 0 : new_tblspc_suffix = new_cluster.tablespace_suffix;
266 0 : old_tblspc_suffix = old_cluster.tablespace_suffix;
267 : }
268 :
269 : /* Old and new cluster paths. */
270 6 : snprintf(old_tblspc, sizeof(old_tblspc), "%s%s", old_tablespace, old_tblspc_suffix);
271 6 : snprintf(new_tblspc, sizeof(new_tblspc), "%s%s", new_tablespace, new_tblspc_suffix);
272 6 : snprintf(old_db_dir, sizeof(old_db_dir), "%s/%u", old_tblspc, db_oid);
273 6 : snprintf(new_db_dir, MAXPGPATH, "%s/%u", new_tblspc, db_oid);
274 :
275 : /*
276 : * Paths for "moved aside" stuff. We intentionally put these in the old
277 : * cluster so that the delete_old_cluster.{sh,bat} script handles them.
278 : */
279 6 : snprintf(moved_tblspc, sizeof(moved_tblspc), "%s/moved_for_upgrade", old_tblspc);
280 6 : snprintf(old_catalog_dir, MAXPGPATH, "%s/%u_old_catalogs", moved_tblspc, db_oid);
281 6 : snprintf(moved_db_dir, MAXPGPATH, "%s/%u", moved_tblspc, db_oid);
282 :
283 : /* Check that the database directory exists in the given tablespace. */
284 6 : if (stat(old_db_dir, &st) != 0)
285 : {
286 0 : if (errno != ENOENT)
287 0 : pg_fatal("could not stat file \"%s\": %m", old_db_dir);
288 0 : return false;
289 : }
290 :
291 : /* Create directory for stuff that is moved aside. */
292 6 : if (pg_mkdir_p(moved_tblspc, pg_dir_create_mode) != 0 && errno != EEXIST)
293 0 : pg_fatal("could not create directory \"%s\"", moved_tblspc);
294 :
295 : /* Create directory for old catalog files. */
296 6 : if (pg_mkdir_p(old_catalog_dir, pg_dir_create_mode) != 0)
297 0 : pg_fatal("could not create directory \"%s\"", old_catalog_dir);
298 :
299 : /* Move the new cluster's database directory aside. */
300 6 : if (rename(new_db_dir, moved_db_dir) != 0)
301 0 : pg_fatal("could not rename \"%s\" to \"%s\"", new_db_dir, moved_db_dir);
302 :
303 : /* Move the old cluster's database directory into place. */
304 6 : if (rename(old_db_dir, new_db_dir) != 0)
305 0 : pg_fatal("could not rename \"%s\" to \"%s\"", old_db_dir, new_db_dir);
306 :
307 6 : return true;
308 : }
309 :
310 : /*
311 : * FileNameMapCmp()
312 : *
313 : * qsort() comparator for FileNameMap that sorts by RelFileNumber.
314 : */
315 : static int
316 6876 : FileNameMapCmp(const void *a, const void *b)
317 : {
318 6876 : const FileNameMap *map1 = (const FileNameMap *) a;
319 6876 : const FileNameMap *map2 = (const FileNameMap *) b;
320 :
321 6876 : return pg_cmp_u32(map1->relfilenumber, map2->relfilenumber);
322 : }
323 :
324 : /*
325 : * parse_relfilenumber()
326 : *
327 : * Attempt to parse the RelFileNumber of the given file name. If we can't,
328 : * return InvalidRelFileNumber. Note that this code snippet is lifted from
329 : * parse_filename_for_nontemp_relation().
330 : */
331 : static RelFileNumber
332 3624 : parse_relfilenumber(const char *filename)
333 : {
334 : char *endp;
335 : unsigned long n;
336 :
337 3624 : if (filename[0] < '1' || filename[0] > '9')
338 36 : return InvalidRelFileNumber;
339 :
340 3588 : errno = 0;
341 3588 : n = strtoul(filename, &endp, 10);
342 3588 : if (errno || filename == endp || n <= 0 || n > PG_UINT32_MAX)
343 0 : return InvalidRelFileNumber;
344 :
345 3588 : return (RelFileNumber) n;
346 : }
347 :
348 : /*
349 : * swap_catalog_files()
350 : *
351 : * Moves the old catalog files aside, and moves the new catalog files into
352 : * place. prepare_for_swap() should have already been called (and returned
353 : * true) for the tablespace/database being transferred.
354 : *
355 : * The arguments for the following parameters should be the corresponding
356 : * variables returned by prepare_for_swap():
357 : *
358 : * old_catalog_dir: The directory for the old cluster's catalog files.
359 : * new_db_dir: New cluster's database directory (for DB being transferred).
360 : * moved_db_dir: Moved-aside pg_restore-generated database directory.
361 : */
362 : static void
363 6 : swap_catalog_files(FileNameMap *maps, int size, const char *old_catalog_dir,
364 : const char *new_db_dir, const char *moved_db_dir)
365 : {
366 : DIR *dir;
367 : struct dirent *de;
368 : char path[MAXPGPATH];
369 : char dest[MAXPGPATH];
370 : RelFileNumber rfn;
371 :
372 : /* Move the old catalog files aside. */
373 6 : dir = opendir(new_db_dir);
374 6 : if (dir == NULL)
375 0 : pg_fatal("could not open directory \"%s\": %m", new_db_dir);
376 1830 : while (errno = 0, (de = readdir(dir)) != NULL)
377 : {
378 1824 : snprintf(path, sizeof(path), "%s/%s", new_db_dir, de->d_name);
379 1824 : if (get_dirent_type(path, de, false, PG_LOG_ERROR) != PGFILETYPE_REG)
380 12 : continue;
381 :
382 1812 : rfn = parse_relfilenumber(de->d_name);
383 1812 : if (RelFileNumberIsValid(rfn))
384 : {
385 1794 : FileNameMap key = {.relfilenumber = rfn};
386 :
387 1794 : if (bsearch(&key, maps, size, sizeof(FileNameMap), FileNameMapCmp))
388 18 : continue;
389 : }
390 :
391 1794 : snprintf(dest, sizeof(dest), "%s/%s", old_catalog_dir, de->d_name);
392 1794 : if (rename(path, dest) != 0)
393 0 : pg_fatal("could not rename \"%s\" to \"%s\": %m", path, dest);
394 : }
395 6 : if (errno)
396 0 : pg_fatal("could not read directory \"%s\": %m", new_db_dir);
397 6 : (void) closedir(dir);
398 :
399 : /* Move the new catalog files into place. */
400 6 : dir = opendir(moved_db_dir);
401 6 : if (dir == NULL)
402 0 : pg_fatal("could not open directory \"%s\": %m", moved_db_dir);
403 1830 : while (errno = 0, (de = readdir(dir)) != NULL)
404 : {
405 1824 : snprintf(path, sizeof(path), "%s/%s", moved_db_dir, de->d_name);
406 1824 : if (get_dirent_type(path, de, false, PG_LOG_ERROR) != PGFILETYPE_REG)
407 12 : continue;
408 :
409 1812 : rfn = parse_relfilenumber(de->d_name);
410 1812 : if (RelFileNumberIsValid(rfn))
411 : {
412 1794 : FileNameMap key = {.relfilenumber = rfn};
413 :
414 1794 : if (bsearch(&key, maps, size, sizeof(FileNameMap), FileNameMapCmp))
415 18 : continue;
416 : }
417 :
418 1794 : snprintf(dest, sizeof(dest), "%s/%s", new_db_dir, de->d_name);
419 1794 : if (rename(path, dest) != 0)
420 0 : pg_fatal("could not rename \"%s\" to \"%s\": %m", path, dest);
421 :
422 : /*
423 : * We don't fsync() the database files in the file synchronization
424 : * stage of pg_upgrade in swap mode, so we need to synchronize them
425 : * ourselves. We only do this for the catalog files because they were
426 : * created during pg_restore with fsync=off. We assume that the user
427 : * data files files were properly persisted to disk when the user last
428 : * shut it down.
429 : */
430 1794 : if (user_opts.do_sync)
431 0 : sync_queue_push(dest);
432 : }
433 6 : if (errno)
434 0 : pg_fatal("could not read directory \"%s\": %m", moved_db_dir);
435 6 : (void) closedir(dir);
436 :
437 : /* Ensure the directory entries are persisted to disk. */
438 6 : if (fsync_fname(new_db_dir, true) != 0)
439 0 : pg_fatal("could not synchronize directory \"%s\": %m", new_db_dir);
440 6 : if (fsync_parent_path(new_db_dir) != 0)
441 0 : pg_fatal("could not synchronize parent directory of \"%s\": %m", new_db_dir);
442 6 : }
443 :
444 : /*
445 : * do_swap()
446 : *
447 : * Perform the required steps for --swap for a single database. In short this
448 : * moves the old cluster's database directory into the new cluster and then
449 : * replaces any files for system catalogs with the ones that were generated
450 : * during pg_restore.
451 : */
452 : static void
453 6 : do_swap(FileNameMap *maps, int size, char *old_tablespace)
454 : {
455 : char old_catalog_dir[MAXPGPATH];
456 : char new_db_dir[MAXPGPATH];
457 : char moved_db_dir[MAXPGPATH];
458 :
459 : /*
460 : * We perform many lookups on maps by relfilenumber in swap mode, so make
461 : * sure it's sorted by relfilenumber. maps should already be sorted by
462 : * OID, so in general this shouldn't have much work to do.
463 : */
464 6 : qsort(maps, size, sizeof(FileNameMap), FileNameMapCmp);
465 :
466 : /*
467 : * If an old tablespace is given, we only need to process that one. If no
468 : * old tablespace is specified, we need to process all the tablespaces on
469 : * the system.
470 : */
471 6 : if (old_tablespace)
472 : {
473 0 : if (prepare_for_swap(old_tablespace, maps[0].db_oid,
474 : old_catalog_dir, new_db_dir, moved_db_dir))
475 0 : swap_catalog_files(maps, size,
476 : old_catalog_dir, new_db_dir, moved_db_dir);
477 : }
478 : else
479 : {
480 6 : if (prepare_for_swap(old_cluster.pgdata, maps[0].db_oid,
481 : old_catalog_dir, new_db_dir, moved_db_dir))
482 6 : swap_catalog_files(maps, size,
483 : old_catalog_dir, new_db_dir, moved_db_dir);
484 :
485 6 : for (int tblnum = 0; tblnum < os_info.num_old_tablespaces; tblnum++)
486 : {
487 0 : if (prepare_for_swap(os_info.old_tablespaces[tblnum], maps[0].db_oid,
488 : old_catalog_dir, new_db_dir, moved_db_dir))
489 0 : swap_catalog_files(maps, size,
490 : old_catalog_dir, new_db_dir, moved_db_dir);
491 : }
492 : }
493 6 : }
494 :
495 : /*
496 : * transfer_single_new_db()
497 : *
498 : * create links for mappings stored in "maps" array.
499 : */
500 : static void
501 48 : transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace)
502 : {
503 : int mapnum;
504 48 : bool vm_must_add_frozenbit = false;
505 :
506 : /*
507 : * Do we need to rewrite visibilitymap?
508 : */
509 48 : if (old_cluster.controldata.cat_ver < VISIBILITY_MAP_FROZEN_BIT_CAT_VER &&
510 0 : new_cluster.controldata.cat_ver >= VISIBILITY_MAP_FROZEN_BIT_CAT_VER)
511 0 : vm_must_add_frozenbit = true;
512 :
513 : /* --swap has its own subroutine */
514 48 : if (user_opts.transfer_mode == TRANSFER_MODE_SWAP)
515 : {
516 : /*
517 : * We don't support --swap to upgrade from versions that require
518 : * rewriting the visibility map. We should've failed already if
519 : * someone tries to do that.
520 : */
521 : Assert(!vm_must_add_frozenbit);
522 :
523 6 : do_swap(maps, size, old_tablespace);
524 6 : return;
525 : }
526 :
527 2962 : for (mapnum = 0; mapnum < size; mapnum++)
528 : {
529 2920 : if (old_tablespace == NULL ||
530 0 : strcmp(maps[mapnum].old_tablespace, old_tablespace) == 0)
531 : {
532 : /* transfer primary file */
533 2920 : transfer_relfile(&maps[mapnum], "", vm_must_add_frozenbit);
534 :
535 : /*
536 : * Copy/link any fsm and vm files, if they exist
537 : */
538 2920 : transfer_relfile(&maps[mapnum], "_fsm", vm_must_add_frozenbit);
539 2920 : transfer_relfile(&maps[mapnum], "_vm", vm_must_add_frozenbit);
540 : }
541 : }
542 : }
543 :
544 :
545 : /*
546 : * transfer_relfile()
547 : *
548 : * Copy or link file from old cluster to new one. If vm_must_add_frozenbit
549 : * is true, visibility map forks are converted and rewritten, even in link
550 : * mode.
551 : */
552 : static void
553 8760 : transfer_relfile(FileNameMap *map, const char *type_suffix, bool vm_must_add_frozenbit)
554 : {
555 : char old_file[MAXPGPATH];
556 : char new_file[MAXPGPATH];
557 : int segno;
558 : char extent_suffix[65];
559 : struct stat statbuf;
560 :
561 : /*
562 : * Now copy/link any related segments as well. Remember, PG breaks large
563 : * files into 1GB segments, the first segment has no extension, subsequent
564 : * segments are named relfilenumber.1, relfilenumber.2, relfilenumber.3.
565 : */
566 8760 : for (segno = 0;; segno++)
567 : {
568 12266 : if (segno == 0)
569 8760 : extent_suffix[0] = '\0';
570 : else
571 3506 : snprintf(extent_suffix, sizeof(extent_suffix), ".%d", segno);
572 :
573 12266 : snprintf(old_file, sizeof(old_file), "%s%s/%u/%u%s%s",
574 : map->old_tablespace,
575 : map->old_tablespace_suffix,
576 : map->db_oid,
577 : map->relfilenumber,
578 : type_suffix,
579 : extent_suffix);
580 12266 : snprintf(new_file, sizeof(new_file), "%s%s/%u/%u%s%s",
581 : map->new_tablespace,
582 : map->new_tablespace_suffix,
583 : map->db_oid,
584 : map->relfilenumber,
585 : type_suffix,
586 : extent_suffix);
587 :
588 : /* Is it an extent, fsm, or vm file? */
589 12266 : if (type_suffix[0] != '\0' || segno != 0)
590 : {
591 : /* Did file open fail? */
592 9346 : if (stat(old_file, &statbuf) != 0)
593 : {
594 : /* File does not exist? That's OK, just return */
595 8758 : if (errno == ENOENT)
596 8758 : return;
597 : else
598 0 : pg_fatal("error while checking for file existence \"%s.%s\" (\"%s\" to \"%s\"): %m",
599 : map->nspname, map->relname, old_file, new_file);
600 : }
601 :
602 : /* If file is empty, just return */
603 588 : if (statbuf.st_size == 0)
604 2 : return;
605 : }
606 :
607 3506 : unlink(new_file);
608 :
609 : /* Copying files might take some time, so give feedback. */
610 3506 : pg_log(PG_STATUS, "%s", old_file);
611 :
612 3506 : if (vm_must_add_frozenbit && strcmp(type_suffix, "_vm") == 0)
613 : {
614 : /* Need to rewrite visibility map format */
615 0 : pg_log(PG_VERBOSE, "rewriting \"%s\" to \"%s\"",
616 : old_file, new_file);
617 0 : rewriteVisibilityMap(old_file, new_file, map->nspname, map->relname);
618 : }
619 : else
620 3506 : switch (user_opts.transfer_mode)
621 : {
622 0 : case TRANSFER_MODE_CLONE:
623 0 : pg_log(PG_VERBOSE, "cloning \"%s\" to \"%s\"",
624 : old_file, new_file);
625 0 : cloneFile(old_file, new_file, map->nspname, map->relname);
626 0 : break;
627 3474 : case TRANSFER_MODE_COPY:
628 3474 : pg_log(PG_VERBOSE, "copying \"%s\" to \"%s\"",
629 : old_file, new_file);
630 3474 : copyFile(old_file, new_file, map->nspname, map->relname);
631 3474 : break;
632 16 : case TRANSFER_MODE_COPY_FILE_RANGE:
633 16 : pg_log(PG_VERBOSE, "copying \"%s\" to \"%s\" with copy_file_range",
634 : old_file, new_file);
635 16 : copyFileByRange(old_file, new_file, map->nspname, map->relname);
636 16 : break;
637 16 : case TRANSFER_MODE_LINK:
638 16 : pg_log(PG_VERBOSE, "linking \"%s\" to \"%s\"",
639 : old_file, new_file);
640 16 : linkFile(old_file, new_file, map->nspname, map->relname);
641 16 : break;
642 0 : case TRANSFER_MODE_SWAP:
643 : /* swap mode is handled in its own code path */
644 0 : pg_fatal("should never happen");
645 : break;
646 : }
647 3506 : }
648 : }
|