Skip to content

Commit 38bfae3

Browse files
committed
pg_upgrade: Move all the files generated internally to a subdirectory
Historically, the location of any files generated by pg_upgrade, as of the per-database logs and internal dumps, has been the current working directory, leaving all those files behind when using --retain or on a failure. Putting all those contents in a targeted subdirectory makes the whole easier to debug, and simplifies the code in charge of cleaning up the logs. Note that another reason is that this facilitates the move of pg_upgrade to TAP with a fixed location for all the logs to grab if the test fails repeatedly. Initially, we thought about being able to specify the output directory with a new option, but we have settled on using a subdirectory located at the root of the new cluster's data folder, "pg_upgrade_output.d", instead, as at the end the new data directory is the location of all the data generated by pg_upgrade. There is a take with group permissions here though: if the new data folder has been initialized with this option, we need to create all the files and paths with the correct permissions or a base backup taken after a pg_upgrade --retain would fail, meaning that GetDataDirectoryCreatePerm() has to be called before creating the log paths, before a couple of sanity checks on the clusters and before getting the socket directory for the cluster's host settings. The idea of the new location is based on a suggestion from Peter Eisentraut. Also thanks to Andrew Dunstan, Peter Eisentraut, Daniel Gustafsson, Tom Lane and Bruce Momjian for the discussion (in alphabetical order). Author: Justin Pryzby Discussion: https://postgr.es/m/20211212025017.GN17618@telsasoft.com
1 parent cbadfc1 commit 38bfae3

File tree

11 files changed

+113
-73
lines changed

11 files changed

+113
-73
lines changed

doc/src/sgml/ref/pgupgrade.sgml

+2-2
Original file line numberDiff line numberDiff line change
@@ -768,8 +768,8 @@ psql --username=postgres --file=script.sql postgres
768768

769769
<para>
770770
<application>pg_upgrade</application> creates various working files, such
771-
as schema dumps, in the current working directory. For security, be sure
772-
that that directory is not readable or writable by any other users.
771+
as schema dumps, stored within <literal>pg_upgrade_output.d</literal> in
772+
the directory of the new cluster.
773773
</para>
774774

775775
<para>

src/bin/pg_upgrade/.gitignore

-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
/pg_upgrade
22
# Generated by test suite
3-
/pg_upgrade_internal.log
43
/delete_old_cluster.sh
54
/delete_old_cluster.bat
65
/reindex_hash.sql
7-
/loadable_libraries.txt
86
/log/
97
/tmp_check/

src/bin/pg_upgrade/Makefile

+1-3
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,7 @@ uninstall:
4545
clean distclean maintainer-clean:
4646
rm -f pg_upgrade$(X) $(OBJS)
4747
rm -rf delete_old_cluster.sh log/ tmp_check/ \
48-
loadable_libraries.txt reindex_hash.sql \
49-
pg_upgrade_dump_globals.sql \
50-
pg_upgrade_dump_*.custom pg_upgrade_*.log
48+
reindex_hash.sql
5149

5250
# When $(MAKE) is present, make automatically infers that this is a
5351
# recursive make. which is not actually what we want here, as that

src/bin/pg_upgrade/check.c

+8-4
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,8 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
783783
return;
784784
}
785785

786-
snprintf(output_path, sizeof(output_path),
786+
snprintf(output_path, sizeof(output_path), "%s/%s",
787+
log_opts.basedir,
787788
"contrib_isn_and_int8_pass_by_value.txt");
788789

789790
for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
@@ -860,7 +861,8 @@ check_for_user_defined_postfix_ops(ClusterInfo *cluster)
860861

861862
prep_status("Checking for user-defined postfix operators");
862863

863-
snprintf(output_path, sizeof(output_path),
864+
snprintf(output_path, sizeof(output_path), "%s/%s",
865+
log_opts.basedir,
864866
"postfix_ops.txt");
865867

866868
/* Find any user defined postfix operators */
@@ -959,7 +961,8 @@ check_for_tables_with_oids(ClusterInfo *cluster)
959961

960962
prep_status("Checking for tables WITH OIDS");
961963

962-
snprintf(output_path, sizeof(output_path),
964+
snprintf(output_path, sizeof(output_path), "%s/%s",
965+
log_opts.basedir,
963966
"tables_with_oids.txt");
964967

965968
/* Find any tables declared WITH OIDS */
@@ -1214,7 +1217,8 @@ check_for_user_defined_encoding_conversions(ClusterInfo *cluster)
12141217

12151218
prep_status("Checking for user-defined encoding conversions");
12161219

1217-
snprintf(output_path, sizeof(output_path),
1220+
snprintf(output_path, sizeof(output_path), "%s/%s",
1221+
log_opts.basedir,
12181222
"encoding_conversions.txt");
12191223

12201224
/* Find any user defined encoding conversions */

src/bin/pg_upgrade/dump.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ generate_old_dump(void)
2222
/* run new pg_dumpall binary for globals */
2323
exec_prog(UTILITY_LOG_FILE, NULL, true, true,
2424
"\"%s/pg_dumpall\" %s --globals-only --quote-all-identifiers "
25-
"--binary-upgrade %s -f %s",
25+
"--binary-upgrade %s -f \"%s/%s\"",
2626
new_cluster.bindir, cluster_conn_opts(&old_cluster),
2727
log_opts.verbose ? "--verbose" : "",
28+
log_opts.dumpdir,
2829
GLOBALS_DUMP_FILE);
2930
check_ok();
3031

@@ -52,9 +53,10 @@ generate_old_dump(void)
5253

5354
parallel_exec_prog(log_file_name, NULL,
5455
"\"%s/pg_dump\" %s --schema-only --quote-all-identifiers "
55-
"--binary-upgrade --format=custom %s --file=\"%s\" %s",
56+
"--binary-upgrade --format=custom %s --file=\"%s/%s\" %s",
5657
new_cluster.bindir, cluster_conn_opts(&old_cluster),
5758
log_opts.verbose ? "--verbose" : "",
59+
log_opts.dumpdir,
5860
sql_file_name, escaped_connstr.data);
5961

6062
termPQExpBuffer(&escaped_connstr);

src/bin/pg_upgrade/exec.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,12 @@ get_bin_version(ClusterInfo *cluster)
7878
* The code requires it be called first from the primary thread on Windows.
7979
*/
8080
bool
81-
exec_prog(const char *log_file, const char *opt_log_file,
81+
exec_prog(const char *log_filename, const char *opt_log_file,
8282
bool report_error, bool exit_on_error, const char *fmt,...)
8383
{
8484
int result = 0;
8585
int written;
86+
char log_file[MAXPGPATH];
8687

8788
#define MAXCMDLEN (2 * MAXPGPATH)
8889
char cmd[MAXCMDLEN];
@@ -97,6 +98,8 @@ exec_prog(const char *log_file, const char *opt_log_file,
9798
mainThreadId = GetCurrentThreadId();
9899
#endif
99100

101+
snprintf(log_file, MAXPGPATH, "%s/%s", log_opts.logdir, log_filename);
102+
100103
written = 0;
101104
va_start(ap, fmt);
102105
written += vsnprintf(cmd + written, MAXCMDLEN - written, fmt, ap);

src/bin/pg_upgrade/function.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ check_loadable_libraries(void)
128128

129129
prep_status("Checking for presence of required libraries");
130130

131-
snprintf(output_path, sizeof(output_path), "loadable_libraries.txt");
131+
snprintf(output_path, sizeof(output_path), "%s/%s",
132+
log_opts.basedir, "loadable_libraries.txt");
132133

133134
/*
134135
* Now we want to sort the library names into order. This avoids multiple

src/bin/pg_upgrade/option.c

-22
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
#include "postgres_fe.h"
1111

12-
#include <time.h>
1312
#ifdef WIN32
1413
#include <io.h>
1514
#endif
@@ -63,9 +62,6 @@ parseCommandLine(int argc, char *argv[])
6362
int option; /* Command line option */
6463
int optindex = 0; /* used by getopt_long */
6564
int os_user_effective_id;
66-
FILE *fp;
67-
char **filename;
68-
time_t run_time = time(NULL);
6965

7066
user_opts.do_sync = true;
7167
user_opts.transfer_mode = TRANSFER_MODE_COPY;
@@ -208,27 +204,9 @@ parseCommandLine(int argc, char *argv[])
208204
if (optind < argc)
209205
pg_fatal("too many command-line arguments (first is \"%s\")\n", argv[optind]);
210206

211-
if ((log_opts.internal = fopen_priv(INTERNAL_LOG_FILE, "a")) == NULL)
212-
pg_fatal("could not open log file \"%s\": %m\n", INTERNAL_LOG_FILE);
213-
214207
if (log_opts.verbose)
215208
pg_log(PG_REPORT, "Running in verbose mode\n");
216209

217-
/* label start of upgrade in logfiles */
218-
for (filename = output_files; *filename != NULL; filename++)
219-
{
220-
if ((fp = fopen_priv(*filename, "a")) == NULL)
221-
pg_fatal("could not write to log file \"%s\": %m\n", *filename);
222-
223-
/* Start with newline because we might be appending to a file. */
224-
fprintf(fp, "\n"
225-
"-----------------------------------------------------------------\n"
226-
" pg_upgrade run on %s"
227-
"-----------------------------------------------------------------\n\n",
228-
ctime(&run_time));
229-
fclose(fp);
230-
}
231-
232210
/* Turn off read-only mode; add prefix to PGOPTIONS? */
233211
if (getenv("PGOPTIONS"))
234212
{

src/bin/pg_upgrade/pg_upgrade.c

+76-34
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838

3939
#include "postgres_fe.h"
4040

41+
#include <time.h>
42+
4143
#ifdef HAVE_LANGINFO_H
4244
#include <langinfo.h>
4345
#endif
@@ -54,6 +56,7 @@ static void prepare_new_globals(void);
5456
static void create_new_objects(void);
5557
static void copy_xact_xlog_xid(void);
5658
static void set_frozenxids(bool minmxid_only);
59+
static void make_outputdirs(char *pgdata);
5760
static void setup(char *argv0, bool *live_check);
5861
static void cleanup(void);
5962

@@ -92,6 +95,22 @@ main(int argc, char **argv)
9295
adjust_data_dir(&old_cluster);
9396
adjust_data_dir(&new_cluster);
9497

98+
/*
99+
* Set mask based on PGDATA permissions, needed for the creation of the
100+
* output directories with correct permissions.
101+
*/
102+
if (!GetDataDirectoryCreatePerm(new_cluster.pgdata))
103+
pg_fatal("could not read permissions of directory \"%s\": %s\n",
104+
new_cluster.pgdata, strerror(errno));
105+
106+
umask(pg_mode_mask);
107+
108+
/*
109+
* This needs to happen after adjusting the data directory of the new
110+
* cluster in adjust_data_dir().
111+
*/
112+
make_outputdirs(new_cluster.pgdata);
113+
95114
setup(argv[0], &live_check);
96115

97116
output_check_banner(live_check);
@@ -103,13 +122,6 @@ main(int argc, char **argv)
103122

104123
check_cluster_compatibility(live_check);
105124

106-
/* Set mask based on PGDATA permissions */
107-
if (!GetDataDirectoryCreatePerm(new_cluster.pgdata))
108-
pg_fatal("could not read permissions of directory \"%s\": %s\n",
109-
new_cluster.pgdata, strerror(errno));
110-
111-
umask(pg_mode_mask);
112-
113125
check_and_dump_old_cluster(live_check);
114126

115127

@@ -197,6 +209,56 @@ main(int argc, char **argv)
197209
return 0;
198210
}
199211

212+
/*
213+
* Create and assign proper permissions to the set of output directories
214+
* used to store any data generated internally, filling in log_opts in
215+
* the process.
216+
*/
217+
static void
218+
make_outputdirs(char *pgdata)
219+
{
220+
FILE *fp;
221+
char **filename;
222+
time_t run_time = time(NULL);
223+
char filename_path[MAXPGPATH];
224+
225+
log_opts.basedir = (char *) pg_malloc(MAXPGPATH);
226+
snprintf(log_opts.basedir, MAXPGPATH, "%s/%s", pgdata, BASE_OUTPUTDIR);
227+
log_opts.dumpdir = (char *) pg_malloc(MAXPGPATH);
228+
snprintf(log_opts.dumpdir, MAXPGPATH, "%s/%s", pgdata, LOG_OUTPUTDIR);
229+
log_opts.logdir = (char *) pg_malloc(MAXPGPATH);
230+
snprintf(log_opts.logdir, MAXPGPATH, "%s/%s", pgdata, DUMP_OUTPUTDIR);
231+
232+
if (mkdir(log_opts.basedir, pg_dir_create_mode))
233+
pg_fatal("could not create directory \"%s\": %m\n", log_opts.basedir);
234+
if (mkdir(log_opts.dumpdir, pg_dir_create_mode))
235+
pg_fatal("could not create directory \"%s\": %m\n", log_opts.dumpdir);
236+
if (mkdir(log_opts.logdir, pg_dir_create_mode))
237+
pg_fatal("could not create directory \"%s\": %m\n", log_opts.logdir);
238+
239+
snprintf(filename_path, sizeof(filename_path), "%s/%s", log_opts.logdir,
240+
INTERNAL_LOG_FILE);
241+
if ((log_opts.internal = fopen_priv(filename_path, "a")) == NULL)
242+
pg_fatal("could not open log file \"%s\": %m\n", filename_path);
243+
244+
/* label start of upgrade in logfiles */
245+
for (filename = output_files; *filename != NULL; filename++)
246+
{
247+
snprintf(filename_path, sizeof(filename_path), "%s/%s",
248+
log_opts.logdir, *filename);
249+
if ((fp = fopen_priv(filename_path, "a")) == NULL)
250+
pg_fatal("could not write to log file \"%s\": %m\n", filename_path);
251+
252+
/* Start with newline because we might be appending to a file. */
253+
fprintf(fp, "\n"
254+
"-----------------------------------------------------------------\n"
255+
" pg_upgrade run on %s"
256+
"-----------------------------------------------------------------\n\n",
257+
ctime(&run_time));
258+
fclose(fp);
259+
}
260+
}
261+
200262

201263
static void
202264
setup(char *argv0, bool *live_check)
@@ -306,8 +368,9 @@ prepare_new_globals(void)
306368
prep_status("Restoring global objects in the new cluster");
307369

308370
exec_prog(UTILITY_LOG_FILE, NULL, true, true,
309-
"\"%s/psql\" " EXEC_PSQL_ARGS " %s -f \"%s\"",
371+
"\"%s/psql\" " EXEC_PSQL_ARGS " %s -f \"%s/%s\"",
310372
new_cluster.bindir, cluster_conn_opts(&new_cluster),
373+
log_opts.dumpdir,
311374
GLOBALS_DUMP_FILE);
312375
check_ok();
313376
}
@@ -352,10 +415,11 @@ create_new_objects(void)
352415
true,
353416
true,
354417
"\"%s/pg_restore\" %s %s --exit-on-error --verbose "
355-
"--dbname postgres \"%s\"",
418+
"--dbname postgres \"%s/%s\"",
356419
new_cluster.bindir,
357420
cluster_conn_opts(&new_cluster),
358421
create_opts,
422+
log_opts.dumpdir,
359423
sql_file_name);
360424

361425
break; /* done once we've processed template1 */
@@ -389,10 +453,11 @@ create_new_objects(void)
389453
parallel_exec_prog(log_file_name,
390454
NULL,
391455
"\"%s/pg_restore\" %s %s --exit-on-error --verbose "
392-
"--dbname template1 \"%s\"",
456+
"--dbname template1 \"%s/%s\"",
393457
new_cluster.bindir,
394458
cluster_conn_opts(&new_cluster),
395459
create_opts,
460+
log_opts.dumpdir,
396461
sql_file_name);
397462
}
398463

@@ -689,28 +754,5 @@ cleanup(void)
689754

690755
/* Remove dump and log files? */
691756
if (!log_opts.retain)
692-
{
693-
int dbnum;
694-
char **filename;
695-
696-
for (filename = output_files; *filename != NULL; filename++)
697-
unlink(*filename);
698-
699-
/* remove dump files */
700-
unlink(GLOBALS_DUMP_FILE);
701-
702-
if (old_cluster.dbarr.dbs)
703-
for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
704-
{
705-
char sql_file_name[MAXPGPATH],
706-
log_file_name[MAXPGPATH];
707-
DbInfo *old_db = &old_cluster.dbarr.dbs[dbnum];
708-
709-
snprintf(sql_file_name, sizeof(sql_file_name), DB_DUMP_FILE_MASK, old_db->db_oid);
710-
unlink(sql_file_name);
711-
712-
snprintf(log_file_name, sizeof(log_file_name), DB_DUMP_LOG_FILE_MASK, old_db->db_oid);
713-
unlink(log_file_name);
714-
}
715-
}
757+
rmtree(log_opts.basedir, true);
716758
}

src/bin/pg_upgrade/pg_upgrade.h

+12
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@
2626
#define GLOBALS_DUMP_FILE "pg_upgrade_dump_globals.sql"
2727
#define DB_DUMP_FILE_MASK "pg_upgrade_dump_%u.custom"
2828

29+
/*
30+
* Base directories that include all the files generated internally,
31+
* from the root path of the new cluster.
32+
*/
33+
#define BASE_OUTPUTDIR "pg_upgrade_output.d"
34+
#define LOG_OUTPUTDIR BASE_OUTPUTDIR "/log"
35+
#define DUMP_OUTPUTDIR BASE_OUTPUTDIR "/dump"
36+
2937
#define DB_DUMP_LOG_FILE_MASK "pg_upgrade_dump_%u.log"
3038
#define SERVER_LOG_FILE "pg_upgrade_server.log"
3139
#define UTILITY_LOG_FILE "pg_upgrade_utility.log"
@@ -262,6 +270,10 @@ typedef struct
262270
FILE *internal; /* internal log FILE */
263271
bool verbose; /* true -> be verbose in messages */
264272
bool retain; /* retain log files on success */
273+
/* Set of internal directories for output files */
274+
char *basedir; /* Base output directory */
275+
char *dumpdir; /* Dumps */
276+
char *logdir; /* Log files */
265277
} LogOpts;
266278

267279

src/bin/pg_upgrade/server.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,10 @@ start_postmaster(ClusterInfo *cluster, bool report_and_exit_on_error)
238238
* vacuumdb --freeze actually freezes the tuples.
239239
*/
240240
snprintf(cmd, sizeof(cmd),
241-
"\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" -o \"-p %d -b%s %s%s\" start",
242-
cluster->bindir, SERVER_LOG_FILE, cluster->pgconfig, cluster->port,
241+
"\"%s/pg_ctl\" -w -l \"%s/%s\" -D \"%s\" -o \"-p %d -b%s %s%s\" start",
242+
cluster->bindir,
243+
log_opts.logdir,
244+
SERVER_LOG_FILE, cluster->pgconfig, cluster->port,
243245
(cluster == &new_cluster) ?
244246
" -c synchronous_commit=off -c fsync=off -c full_page_writes=off -c vacuum_defer_cleanup_age=0" : "",
245247
cluster->pgopts ? cluster->pgopts : "", socket_string);

0 commit comments

Comments
 (0)