PostgreSQL Source Code git master
relfilenumber.c
Go to the documentation of this file.
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
20static void transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace, char *new_tablespace);
21static 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
46static int sync_queue_len;
47
48static inline void
50{
52 return;
53
54 sync_queue_inited = true;
55 for (int i = 0; i < SYNC_QUEUE_MAX_LEN; i++)
57}
58
59static inline void
61{
63 return;
64
65 for (int i = 0; i < sync_queue_len; i++)
66 {
67 if (fsync_fname(sync_queue[i], false) != 0)
68 pg_fatal("could not synchronize file \"%s\": %m", sync_queue[i]);
69 }
70
72}
73
74static inline void
75sync_queue_push(const char *fname)
76{
78
79 pre_sync_fname(fname, false);
80
81 strncpy(sync_queue[sync_queue_len++], fname, MAXPGPATH);
84}
85
86static inline void
88{
90 return;
91
92 sync_queue_inited = false;
94 for (int i = 0; i < SYNC_QUEUE_MAX_LEN; i++)
95 {
97 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 */
107void
109 char *old_pgdata, char *new_pgdata)
110{
111 switch (user_opts.transfer_mode)
112 {
114 prep_status_progress("Cloning user relation files");
115 break;
117 prep_status_progress("Copying user relation files");
118 break;
120 prep_status_progress("Copying user relation files with copy_file_range");
121 break;
123 prep_status_progress("Linking user relation files");
124 break;
126 prep_status_progress("Swapping data directories");
127 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 if (user_opts.jobs <= 1)
138 parallel_transfer_all_new_dbs(old_db_arr, new_db_arr, old_pgdata,
139 new_pgdata, NULL, NULL);
140 else
141 {
142 int tblnum;
143
144 /* transfer default tablespace */
145 parallel_transfer_all_new_dbs(old_db_arr, new_db_arr, old_pgdata,
146 new_pgdata, old_pgdata, new_pgdata);
147
148 for (tblnum = 0; tblnum < old_cluster.num_tablespaces; tblnum++)
150 new_db_arr,
151 old_pgdata,
152 new_pgdata,
153 old_cluster.tablespaces[tblnum],
154 new_cluster.tablespaces[tblnum]);
155 /* reap all children */
156 while (reap_child(true) == true)
157 ;
158 }
159
161 check_ok();
162}
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 */
171void
172transfer_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 int old_dbnum,
177 new_dbnum;
178
179 /* Scan the old cluster databases and transfer their files */
180 for (old_dbnum = new_dbnum = 0;
181 old_dbnum < old_db_arr->ndbs;
182 old_dbnum++, new_dbnum++)
183 {
184 DbInfo *old_db = &old_db_arr->dbs[old_dbnum],
185 *new_db = NULL;
186 FileNameMap *mappings;
187 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 for (; new_dbnum < new_db_arr->ndbs; new_dbnum++)
195 {
196 new_db = &new_db_arr->dbs[new_dbnum];
197 if (strcmp(old_db->db_name, new_db->db_name) == 0)
198 break;
199 }
200
201 if (new_dbnum >= new_db_arr->ndbs)
202 pg_fatal("old database \"%s\" not found in the new cluster",
203 old_db->db_name);
204
205 mappings = gen_db_file_maps(old_db, new_db, &n_maps, old_pgdata,
206 new_pgdata);
207 if (n_maps)
208 {
209 transfer_single_new_db(mappings, n_maps, old_tablespace, new_tablespace);
210 }
211 /* We allocate something even for n_maps == 0 */
212 pg_free(mappings);
213 }
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 */
221}
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 */
238static bool
239prepare_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 const char *old_tblspc_suffix;
244 const char *new_tblspc_suffix;
245 char old_tblspc[MAXPGPATH];
246 char new_tblspc[MAXPGPATH];
247 char moved_tblspc[MAXPGPATH];
248 char old_db_dir[MAXPGPATH];
249 struct stat st;
250
251 if (strcmp(old_tablespace, old_cluster.pgdata) == 0)
252 old_tblspc_suffix = "/base";
253 else
254 old_tblspc_suffix = old_cluster.tablespace_suffix;
255
256 if (strcmp(new_tablespace, new_cluster.pgdata) == 0)
257 new_tblspc_suffix = "/base";
258 else
259 new_tblspc_suffix = new_cluster.tablespace_suffix;
260
261 /* Old and new cluster paths. */
262 snprintf(old_tblspc, sizeof(old_tblspc), "%s%s", old_tablespace, old_tblspc_suffix);
263 snprintf(new_tblspc, sizeof(new_tblspc), "%s%s", new_tablespace, new_tblspc_suffix);
264 snprintf(old_db_dir, sizeof(old_db_dir), "%s/%u", old_tblspc, db_oid);
265 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 snprintf(moved_tblspc, sizeof(moved_tblspc), "%s/moved_for_upgrade", old_tblspc);
272 snprintf(old_catalog_dir, MAXPGPATH, "%s/%u_old_catalogs", moved_tblspc, db_oid);
273 snprintf(moved_db_dir, MAXPGPATH, "%s/%u", moved_tblspc, db_oid);
274
275 /* Check that the database directory exists in the given tablespace. */
276 if (stat(old_db_dir, &st) != 0)
277 {
278 if (errno != ENOENT)
279 pg_fatal("could not stat file \"%s\": %m", old_db_dir);
280 return false;
281 }
282
283 /* Create directory for stuff that is moved aside. */
284 if (pg_mkdir_p(moved_tblspc, pg_dir_create_mode) != 0 && errno != EEXIST)
285 pg_fatal("could not create directory \"%s\": %m", moved_tblspc);
286
287 /* Create directory for old catalog files. */
288 if (pg_mkdir_p(old_catalog_dir, pg_dir_create_mode) != 0)
289 pg_fatal("could not create directory \"%s\": %m", old_catalog_dir);
290
291 /* Move the new cluster's database directory aside. */
292 if (rename(new_db_dir, moved_db_dir) != 0)
293 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 if (rename(old_db_dir, new_db_dir) != 0)
297 pg_fatal("could not rename directory \"%s\" to \"%s\": %m", old_db_dir, new_db_dir);
298
299 return true;
300}
301
302/*
303 * FileNameMapCmp()
304 *
305 * qsort() comparator for FileNameMap that sorts by RelFileNumber.
306 */
307static int
308FileNameMapCmp(const void *a, const void *b)
309{
310 const FileNameMap *map1 = (const FileNameMap *) a;
311 const FileNameMap *map2 = (const FileNameMap *) b;
312
313 return pg_cmp_u32(map1->relfilenumber, map2->relfilenumber);
314}
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 */
323static RelFileNumber
325{
326 char *endp;
327 unsigned long n;
328
329 if (filename[0] < '1' || filename[0] > '9')
331
332 errno = 0;
333 n = strtoul(filename, &endp, 10);
334 if (errno || filename == endp || n <= 0 || n > PG_UINT32_MAX)
336
337 return (RelFileNumber) n;
338}
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 */
354static void
355swap_catalog_files(FileNameMap *maps, int size, const char *old_catalog_dir,
356 const char *new_db_dir, const char *moved_db_dir)
357{
358 DIR *dir;
359 struct dirent *de;
360 char path[MAXPGPATH];
361 char dest[MAXPGPATH];
362 RelFileNumber rfn;
363
364 /* Move the old catalog files aside. */
365 dir = opendir(new_db_dir);
366 if (dir == NULL)
367 pg_fatal("could not open directory \"%s\": %m", new_db_dir);
368 while (errno = 0, (de = readdir(dir)) != NULL)
369 {
370 snprintf(path, sizeof(path), "%s/%s", new_db_dir, de->d_name);
371 if (get_dirent_type(path, de, false, PG_LOG_ERROR) != PGFILETYPE_REG)
372 continue;
373
374 rfn = parse_relfilenumber(de->d_name);
375 if (RelFileNumberIsValid(rfn))
376 {
377 FileNameMap key = {.relfilenumber = rfn};
378
379 if (bsearch(&key, maps, size, sizeof(FileNameMap), FileNameMapCmp))
380 continue;
381 }
382
383 snprintf(dest, sizeof(dest), "%s/%s", old_catalog_dir, de->d_name);
384 if (rename(path, dest) != 0)
385 pg_fatal("could not rename file \"%s\" to \"%s\": %m", path, dest);
386 }
387 if (errno)
388 pg_fatal("could not read directory \"%s\": %m", new_db_dir);
389 (void) closedir(dir);
390
391 /* Move the new catalog files into place. */
392 dir = opendir(moved_db_dir);
393 if (dir == NULL)
394 pg_fatal("could not open directory \"%s\": %m", moved_db_dir);
395 while (errno = 0, (de = readdir(dir)) != NULL)
396 {
397 snprintf(path, sizeof(path), "%s/%s", moved_db_dir, de->d_name);
398 if (get_dirent_type(path, de, false, PG_LOG_ERROR) != PGFILETYPE_REG)
399 continue;
400
401 rfn = parse_relfilenumber(de->d_name);
402 if (RelFileNumberIsValid(rfn))
403 {
404 FileNameMap key = {.relfilenumber = rfn};
405
406 if (bsearch(&key, maps, size, sizeof(FileNameMap), FileNameMapCmp))
407 continue;
408 }
409
410 snprintf(dest, sizeof(dest), "%s/%s", new_db_dir, de->d_name);
411 if (rename(path, dest) != 0)
412 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 if (user_opts.do_sync)
424 }
425 if (errno)
426 pg_fatal("could not read directory \"%s\": %m", moved_db_dir);
427 (void) closedir(dir);
428
429 /* Ensure the directory entries are persisted to disk. */
430 if (fsync_fname(new_db_dir, true) != 0)
431 pg_fatal("could not synchronize directory \"%s\": %m", new_db_dir);
432 if (fsync_parent_path(new_db_dir) != 0)
433 pg_fatal("could not synchronize parent directory of \"%s\": %m", new_db_dir);
434}
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 */
444static void
445do_swap(FileNameMap *maps, int size, char *old_tablespace, char *new_tablespace)
446{
447 char old_catalog_dir[MAXPGPATH];
448 char new_db_dir[MAXPGPATH];
449 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 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 if (old_tablespace)
464 {
465 if (prepare_for_swap(old_tablespace, new_tablespace, maps[0].db_oid,
466 old_catalog_dir, new_db_dir, moved_db_dir))
468 old_catalog_dir, new_db_dir, moved_db_dir);
469 }
470 else
471 {
473 old_catalog_dir, new_db_dir, moved_db_dir))
475 old_catalog_dir, new_db_dir, moved_db_dir);
476
477 for (int tblnum = 0; tblnum < old_cluster.num_tablespaces; tblnum++)
478 {
480 new_cluster.tablespaces[tblnum],
481 maps[0].db_oid,
482 old_catalog_dir, new_db_dir, moved_db_dir))
484 old_catalog_dir, new_db_dir, moved_db_dir);
485 }
486 }
487}
488
489/*
490 * transfer_single_new_db()
491 *
492 * create links for mappings stored in "maps" array.
493 */
494static void
496 char *old_tablespace, char *new_tablespace)
497{
498 int mapnum;
499 bool vm_must_add_frozenbit = false;
500
501 /*
502 * Do we need to rewrite visibilitymap?
503 */
506 vm_must_add_frozenbit = true;
507
508 /* --swap has its own subroutine */
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 Assert(!vm_must_add_frozenbit);
517
518 do_swap(maps, size, old_tablespace, new_tablespace);
519 return;
520 }
521
522 for (mapnum = 0; mapnum < size; mapnum++)
523 {
524 if (old_tablespace == NULL ||
525 strcmp(maps[mapnum].old_tablespace, old_tablespace) == 0)
526 {
527 /* transfer primary file */
528 transfer_relfile(&maps[mapnum], "", vm_must_add_frozenbit);
529
530 /*
531 * Copy/link any fsm and vm files, if they exist
532 */
533 transfer_relfile(&maps[mapnum], "_fsm", vm_must_add_frozenbit);
534 transfer_relfile(&maps[mapnum], "_vm", vm_must_add_frozenbit);
535 }
536 }
537}
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 */
547static void
548transfer_relfile(FileNameMap *map, const char *type_suffix, bool vm_must_add_frozenbit)
549{
550 char old_file[MAXPGPATH];
551 char new_file[MAXPGPATH];
552 int segno;
553 char extent_suffix[65];
554 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 for (segno = 0;; segno++)
562 {
563 if (segno == 0)
564 extent_suffix[0] = '\0';
565 else
566 snprintf(extent_suffix, sizeof(extent_suffix), ".%d", segno);
567
568 snprintf(old_file, sizeof(old_file), "%s%s/%u/%u%s%s",
569 map->old_tablespace,
571 map->db_oid,
572 map->relfilenumber,
573 type_suffix,
574 extent_suffix);
575 snprintf(new_file, sizeof(new_file), "%s%s/%u/%u%s%s",
576 map->new_tablespace,
578 map->db_oid,
579 map->relfilenumber,
580 type_suffix,
581 extent_suffix);
582
583 /* Is it an extent, fsm, or vm file? */
584 if (type_suffix[0] != '\0' || segno != 0)
585 {
586 /* Did file open fail? */
587 if (stat(old_file, &statbuf) != 0)
588 {
589 /* File does not exist? That's OK, just return */
590 if (errno == ENOENT)
591 return;
592 else
593 pg_fatal("error while checking for file existence \"%s.%s\" (\"%s\" to \"%s\"): %m",
594 map->nspname, map->relname, old_file, new_file);
595 }
596
597 /* If file is empty, just return */
598 if (statbuf.st_size == 0)
599 return;
600 }
601
602 unlink(new_file);
603
604 /* Copying files might take some time, so give feedback. */
605 pg_log(PG_STATUS, "%s", old_file);
606
607 if (vm_must_add_frozenbit && strcmp(type_suffix, "_vm") == 0)
608 {
609 /* Need to rewrite visibility map format */
610 pg_log(PG_VERBOSE, "rewriting \"%s\" to \"%s\"",
611 old_file, new_file);
612 rewriteVisibilityMap(old_file, new_file, map->nspname, map->relname);
613 }
614 else
615 switch (user_opts.transfer_mode)
616 {
618 pg_log(PG_VERBOSE, "cloning \"%s\" to \"%s\"",
619 old_file, new_file);
620 cloneFile(old_file, new_file, map->nspname, map->relname);
621 break;
623 pg_log(PG_VERBOSE, "copying \"%s\" to \"%s\"",
624 old_file, new_file);
625 copyFile(old_file, new_file, map->nspname, map->relname);
626 break;
628 pg_log(PG_VERBOSE, "copying \"%s\" to \"%s\" with copy_file_range",
629 old_file, new_file);
630 copyFileByRange(old_file, new_file, map->nspname, map->relname);
631 break;
633 pg_log(PG_VERBOSE, "linking \"%s\" to \"%s\"",
634 old_file, new_file);
635 linkFile(old_file, new_file, map->nspname, map->relname);
636 break;
638 /* swap mode is handled in its own code path */
639 pg_fatal("should never happen");
640 break;
641 }
642 }
643}
void parallel_transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr, char *old_pgdata, char *new_pgdata, char *old_tablespace, char *new_tablespace)
Definition: parallel.c:173
bool reap_child(bool wait_for_child)
Definition: parallel.c:281
#define PG_UINT32_MAX
Definition: c.h:600
int closedir(DIR *)
Definition: dirent.c:127
struct dirent * readdir(DIR *)
Definition: dirent.c:78
DIR * opendir(const char *)
Definition: dirent.c:33
void fsync_fname(const char *fname, bool isdir)
Definition: fd.c:753
static int fsync_parent_path(const char *fname, int elevel)
Definition: fd.c:3935
void pg_free(void *ptr)
Definition: fe_memutils.c:105
void linkFile(const char *src, const char *dst, const char *schemaName, const char *relName)
Definition: file.c:190
void rewriteVisibilityMap(const char *fromfile, const char *tofile, const char *schemaName, const char *relName)
Definition: file.c:216
void cloneFile(const char *src, const char *dst, const char *schemaName, const char *relName)
Definition: file.c:39
void copyFileByRange(const char *src, const char *dst, const char *schemaName, const char *relName)
Definition: file.c:151
void copyFile(const char *src, const char *dst, const char *schemaName, const char *relName)
Definition: file.c:82
int pg_dir_create_mode
Definition: file_perm.c:18
PGFileType get_dirent_type(const char *path, const struct dirent *de, bool look_through_symlinks, int elevel)
Definition: file_utils.c:547
@ PGFILETYPE_REG
Definition: file_utils.h:22
Assert(PointerIsAligned(start, uint64))
FileNameMap * gen_db_file_maps(DbInfo *old_db, DbInfo *new_db, int *nmaps, const char *old_pgdata, const char *new_pgdata)
Definition: info.c:45
static void check_ok(void)
Definition: initdb.c:2106
static int pg_cmp_u32(uint32 a, uint32 b)
Definition: int.h:652
int b
Definition: isn.c:74
int a
Definition: isn.c:73
int i
Definition: isn.c:77
@ PG_LOG_ERROR
Definition: logging.h:43
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc(Size size)
Definition: mcxt.c:1365
#define pg_fatal(...)
#define MAXPGPATH
static char * filename
Definition: pg_dumpall.c:120
ClusterInfo new_cluster
Definition: pg_upgrade.c:73
ClusterInfo old_cluster
Definition: pg_upgrade.c:72
#define VISIBILITY_MAP_FROZEN_BIT_CAT_VER
Definition: pg_upgrade.h:107
void void pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2
@ TRANSFER_MODE_COPY
Definition: pg_upgrade.h:262
@ TRANSFER_MODE_LINK
Definition: pg_upgrade.h:264
@ TRANSFER_MODE_SWAP
Definition: pg_upgrade.h:265
@ TRANSFER_MODE_CLONE
Definition: pg_upgrade.h:261
@ TRANSFER_MODE_COPY_FILE_RANGE
Definition: pg_upgrade.h:263
void void prep_status_progress(const char *fmt,...) pg_attribute_printf(1
void void pg_noreturn void void end_progress_output(void)
Definition: util.c:43
@ PG_STATUS
Definition: pg_upgrade.h:274
@ PG_VERBOSE
Definition: pg_upgrade.h:273
int pg_mkdir_p(char *path, int omode)
Definition: pgmkdirp.c:57
#define snprintf
Definition: port.h:239
#define qsort(a, b, c, d)
Definition: port.h:479
unsigned int Oid
Definition: postgres_ext.h:32
void transfer_all_new_tablespaces(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr, char *old_pgdata, char *new_pgdata)
static bool prepare_for_swap(const char *old_tablespace, const char *new_tablespace, Oid db_oid, char *old_catalog_dir, char *new_db_dir, char *moved_db_dir)
static void do_swap(FileNameMap *maps, int size, char *old_tablespace, char *new_tablespace)
static char * sync_queue[SYNC_QUEUE_MAX_LEN]
Definition: relfilenumber.c:44
static RelFileNumber parse_relfilenumber(const char *filename)
static void sync_queue_init(void)
Definition: relfilenumber.c:49
static void sync_queue_destroy(void)
Definition: relfilenumber.c:87
static void transfer_relfile(FileNameMap *map, const char *type_suffix, bool vm_must_add_frozenbit)
static int sync_queue_len
Definition: relfilenumber.c:46
static bool sync_queue_inited
Definition: relfilenumber.c:45
void transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr, char *old_pgdata, char *new_pgdata, char *old_tablespace, char *new_tablespace)
static void sync_queue_push(const char *fname)
Definition: relfilenumber.c:75
static void swap_catalog_files(FileNameMap *maps, int size, const char *old_catalog_dir, const char *new_db_dir, const char *moved_db_dir)
#define SYNC_QUEUE_MAX_LEN
Definition: relfilenumber.c:42
static int FileNameMapCmp(const void *a, const void *b)
static void transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace, char *new_tablespace)
static void sync_queue_sync_all(void)
Definition: relfilenumber.c:60
Oid RelFileNumber
Definition: relpath.h:25
#define InvalidRelFileNumber
Definition: relpath.h:26
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
UserOpts user_opts
Definition: option.c:30
char * pgdata
Definition: pg_upgrade.h:292
int num_tablespaces
Definition: pg_upgrade.h:304
ControlData controldata
Definition: pg_upgrade.h:289
char ** tablespaces
Definition: pg_upgrade.h:303
const char * tablespace_suffix
Definition: pg_upgrade.h:305
uint32 cat_ver
Definition: pg_upgrade.h:232
Definition: dirent.c:26
DbInfo * dbs
Definition: pg_upgrade.h:220
char * db_name
Definition: pg_upgrade.h:199
const char * new_tablespace
Definition: pg_upgrade.h:183
const char * old_tablespace_suffix
Definition: pg_upgrade.h:184
const char * old_tablespace
Definition: pg_upgrade.h:182
RelFileNumber relfilenumber
Definition: pg_upgrade.h:187
char * relname
Definition: pg_upgrade.h:190
char * nspname
Definition: pg_upgrade.h:189
const char * new_tablespace_suffix
Definition: pg_upgrade.h:185
bool do_sync
Definition: pg_upgrade.h:336
transferMode transfer_mode
Definition: pg_upgrade.h:337
int jobs
Definition: pg_upgrade.h:338
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15
__int64 st_size
Definition: win32_port.h:263
static const pg_conv_map maps[]
#define stat
Definition: win32_port.h:274