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