On Thu, Mar 01, 2012 at 09:06:10PM -0500, Bruce Momjian wrote: > OK, combining your and Robert's ideas, how about I have pg_upgrade write > the server log to a file, and the pg_dump output to a file (with its > stderr), and if pg_upgrade fails, I report the failure and mention those > files. If pg_upgrade succeeds, I remove the files? pg_upgrade already > creates temporary files that it removes on completion.
OK, I have completed a rework of pg_upgrade logging. pg_upgrade had 4 logging options, -g, -G, -l, and -v, and still it wasn't possible to get useful logging. :-( What I have done with this patch is to remove -g, -G, and -l, and unconditionally write to 4 log files in the current directory (in addition to the 3 SQL files I already create). If pg_upgrade succeeds, the files are removed, but if it fails (or if the new -r/retain option is used), the files remain. Here is a sample failure when I create a plpgsql function in the old server, but truncate plpgsql.so in the new server: Performing Upgrade ------------------ Analyzing all rows in the new cluster ok Freezing all rows on the new cluster ok Deleting new commit clogs ok Copying old commit clogs to new server ok Setting next transaction ID for new cluster ok Resetting WAL archives ok Setting frozenxid counters in new cluster ok Creating databases in the new cluster ok Adding support functions to new cluster ok Restoring database schema to new cluster Consult the last few lines of "pg_upgrade_restore.log" for the probable cause of the failure. Failure, exiting $ tail pg_upgrade_restore.log COMMENT ON LANGUAGE plpythonu IS 'PL/PythonU untrusted procedural language'; COMMENT SET search_path = public, pg_catalog; SET CREATE FUNCTION x() RETURNS integer LANGUAGE plpgsql AS $$begin select pg_sleep(1); end$$; psql:/usr/local/pgdev/pg_upgrade/pg_upgrade_dump_db.sql:233: ERROR: could not load library "/usr/local/pgsql/lib/plpgsql.so": /usr/local/pgsql/lib/plpgsql.so: file too short That seems quite clear; I enabled --echo-queries in psql so you can see the query that generated the error. These changes should make pg_upgrade errors much easier to diagnose. I hope to apply this for PG 9.2. -- Bruce Momjian <br...@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + It's impossible for everything to be true. +
diff --git a/contrib/pg_upgrade/check.c b/contrib/pg_upgrade/check.c new file mode 100644 index a5f63eb..63f6645 *** a/contrib/pg_upgrade/check.c --- b/contrib/pg_upgrade/check.c *************** issue_warnings(char *sequence_script_fil *** 165,176 **** if (sequence_script_file_name) { prep_status("Adjusting sequences"); ! exec_prog(true, ! SYSTEMQUOTE "\"%s/psql\" --set ON_ERROR_STOP=on " "--no-psqlrc --port %d --username \"%s\" " "-f \"%s\" --dbname template1 >> \"%s\"" SYSTEMQUOTE, new_cluster.bindir, new_cluster.port, os_info.user, ! sequence_script_file_name, log_opts.filename2); unlink(sequence_script_file_name); check_ok(); } --- 165,177 ---- if (sequence_script_file_name) { prep_status("Adjusting sequences"); ! exec_prog(true, UTILITY_LOG_FILE, ! SYSTEMQUOTE "\"%s/psql\" --echo-queries " ! "--set ON_ERROR_STOP=on " "--no-psqlrc --port %d --username \"%s\" " "-f \"%s\" --dbname template1 >> \"%s\"" SYSTEMQUOTE, new_cluster.bindir, new_cluster.port, os_info.user, ! sequence_script_file_name, UTILITY_LOG_FILE); unlink(sequence_script_file_name); check_ok(); } diff --git a/contrib/pg_upgrade/controldata.c b/contrib/pg_upgrade/controldata.c new file mode 100644 index 5239601..debb444 *** a/contrib/pg_upgrade/controldata.c --- b/contrib/pg_upgrade/controldata.c *************** get_control_data(ClusterInfo *cluster, b *** 126,136 **** /* we have the result of cmd in "output". so parse it line by line now */ while (fgets(bufin, sizeof(bufin), output)) { ! if (log_opts.debug) ! fputs(bufin, log_opts.debug_fd); #ifdef WIN32 - /* * Due to an installer bug, LANG=C doesn't work for PG 8.3.3, but does * work 8.2.6 and 8.3.7, so check for non-ASCII output and suggest a --- 126,135 ---- /* we have the result of cmd in "output". so parse it line by line now */ while (fgets(bufin, sizeof(bufin), output)) { ! if (log_opts.verbose) ! pg_log(PG_INFO, "%s", bufin); #ifdef WIN32 /* * Due to an installer bug, LANG=C doesn't work for PG 8.3.3, but does * work 8.2.6 and 8.3.7, so check for non-ASCII output and suggest a diff --git a/contrib/pg_upgrade/dump.c b/contrib/pg_upgrade/dump.c new file mode 100644 index 772ca37..36f9a0f *** a/contrib/pg_upgrade/dump.c --- b/contrib/pg_upgrade/dump.c *************** generate_old_dump(void) *** 22,31 **** * --binary-upgrade records the width of dropped columns in pg_class, and * restores the frozenid's for databases and relations. */ ! exec_prog(true, SYSTEMQUOTE "\"%s/pg_dumpall\" --port %d --username \"%s\" " ! "--schema-only --binary-upgrade > \"%s/" ALL_DUMP_FILE "\"" ! SYSTEMQUOTE, new_cluster.bindir, old_cluster.port, os_info.user, os_info.cwd); check_ok(); } --- 22,32 ---- * --binary-upgrade records the width of dropped columns in pg_class, and * restores the frozenid's for databases and relations. */ ! exec_prog(true, UTILITY_LOG_FILE, SYSTEMQUOTE "\"%s/pg_dumpall\" --port %d --username \"%s\" " ! "--schema-only --binary-upgrade >> \"%s/%s\" 2> \"%s\"" ! SYSTEMQUOTE, new_cluster.bindir, old_cluster.port, os_info.user, ! os_info.cwd, ALL_DUMP_FILE, UTILITY_LOG_FILE); check_ok(); } diff --git a/contrib/pg_upgrade/exec.c b/contrib/pg_upgrade/exec.c new file mode 100644 index b870ded..2aa3cc8 *** a/contrib/pg_upgrade/exec.c --- b/contrib/pg_upgrade/exec.c *************** static int win32_check_directory_write_p *** 34,40 **** * instead of returning should an error occur. */ int ! exec_prog(bool throw_error, const char *fmt,...) { va_list args; int result; --- 34,40 ---- * instead of returning should an error occur. */ int ! exec_prog(bool throw_error, const char *log_file, const char *fmt,...) { va_list args; int result; *************** exec_prog(bool throw_error, const char * *** 50,57 **** if (result != 0) { pg_log(throw_error ? PG_FATAL : PG_INFO, ! "There were problems executing \"%s\"\n", cmd); return 1; } --- 50,60 ---- if (result != 0) { + pg_log(PG_INFO, "There were problems executing \"%s\"\n", cmd); pg_log(throw_error ? PG_FATAL : PG_INFO, ! "Consult the last few lines of \"%s\" for\n" ! "the probable cause of the failure.\n", ! log_file); return 1; } diff --git a/contrib/pg_upgrade/info.c b/contrib/pg_upgrade/info.c new file mode 100644 index 692cdc2..a1f6210 *** a/contrib/pg_upgrade/info.c --- b/contrib/pg_upgrade/info.c *************** create_rel_filename_map(const char *old_ *** 132,150 **** void print_maps(FileNameMap *maps, int n_maps, const char *db_name) { ! if (log_opts.debug) { int mapnum; ! pg_log(PG_DEBUG, "mappings for database \"%s\":\n", db_name); for (mapnum = 0; mapnum < n_maps; mapnum++) ! pg_log(PG_DEBUG, "%s.%s: %u to %u\n", maps[mapnum].nspname, maps[mapnum].relname, maps[mapnum].old_relfilenode, maps[mapnum].new_relfilenode); ! pg_log(PG_DEBUG, "\n\n"); } } --- 132,150 ---- void print_maps(FileNameMap *maps, int n_maps, const char *db_name) { ! if (log_opts.verbose) { int mapnum; ! pg_log(PG_INFO, "mappings for database \"%s\":\n", db_name); for (mapnum = 0; mapnum < n_maps; mapnum++) ! pg_log(PG_INFO, "%s.%s: %u to %u\n", maps[mapnum].nspname, maps[mapnum].relname, maps[mapnum].old_relfilenode, maps[mapnum].new_relfilenode); ! pg_log(PG_INFO, "\n\n"); } } *************** get_db_and_rel_infos(ClusterInfo *cluste *** 168,176 **** for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++) get_rel_infos(cluster, &cluster->dbarr.dbs[dbnum]); ! if (log_opts.debug) { ! pg_log(PG_DEBUG, "\n%s databases:\n", CLUSTER_NAME(cluster)); print_db_infos(&cluster->dbarr); } } --- 168,176 ---- for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++) get_rel_infos(cluster, &cluster->dbarr.dbs[dbnum]); ! if (log_opts.verbose) { ! pg_log(PG_INFO, "\n%s databases:\n", CLUSTER_NAME(cluster)); print_db_infos(&cluster->dbarr); } } *************** print_db_infos(DbInfoArr *db_arr) *** 368,376 **** for (dbnum = 0; dbnum < db_arr->ndbs; dbnum++) { ! pg_log(PG_DEBUG, "Database: %s\n", db_arr->dbs[dbnum].db_name); print_rel_infos(&db_arr->dbs[dbnum].rel_arr); ! pg_log(PG_DEBUG, "\n\n"); } } --- 368,378 ---- for (dbnum = 0; dbnum < db_arr->ndbs; dbnum++) { ! if (log_opts.verbose) ! pg_log(PG_INFO, "Database: %s\n", db_arr->dbs[dbnum].db_name); print_rel_infos(&db_arr->dbs[dbnum].rel_arr); ! if (log_opts.verbose) ! pg_log(PG_INFO, "\n\n"); } } *************** print_rel_infos(RelInfoArr *arr) *** 380,387 **** { int relnum; ! for (relnum = 0; relnum < arr->nrels; relnum++) ! pg_log(PG_DEBUG, "relname: %s.%s: reloid: %u reltblspace: %s\n", ! arr->rels[relnum].nspname, arr->rels[relnum].relname, ! arr->rels[relnum].reloid, arr->rels[relnum].tablespace); } --- 382,390 ---- { int relnum; ! if (log_opts.verbose) ! for (relnum = 0; relnum < arr->nrels; relnum++) ! pg_log(PG_INFO, "relname: %s.%s: reloid: %u reltblspace: %s\n", ! arr->rels[relnum].nspname, arr->rels[relnum].relname, ! arr->rels[relnum].reloid, arr->rels[relnum].tablespace); } diff --git a/contrib/pg_upgrade/option.c b/contrib/pg_upgrade/option.c new file mode 100644 index 0a105ef..2f30625 *** a/contrib/pg_upgrade/option.c --- b/contrib/pg_upgrade/option.c *************** parseCommandLine(int argc, char *argv[]) *** 46,63 **** {"user", required_argument, NULL, 'u'}, {"check", no_argument, NULL, 'c'}, - {"debug", no_argument, NULL, 'g'}, - {"debugfile", required_argument, NULL, 'G'}, {"link", no_argument, NULL, 'k'}, ! {"logfile", required_argument, NULL, 'l'}, {"verbose", no_argument, NULL, 'v'}, {NULL, 0, NULL, 0} }; int option; /* Command line option */ int optindex = 0; /* used by getopt_long */ int os_user_effective_id; char *return_buf; ! user_opts.transfer_mode = TRANSFER_MODE_COPY; os_info.progname = get_progname(argv[0]); --- 46,63 ---- {"user", required_argument, NULL, 'u'}, {"check", no_argument, NULL, 'c'}, {"link", no_argument, NULL, 'k'}, ! {"retain", no_argument, NULL, 'r'}, {"verbose", no_argument, NULL, 'v'}, {NULL, 0, NULL, 0} }; int option; /* Command line option */ int optindex = 0; /* used by getopt_long */ int os_user_effective_id; + FILE *fp; char *return_buf; ! int i; ! user_opts.transfer_mode = TRANSFER_MODE_COPY; os_info.progname = get_progname(argv[0]); *************** parseCommandLine(int argc, char *argv[]) *** 98,104 **** if (return_buf == NULL) pg_log(PG_FATAL, "Could not access current working directory: %s\n", getErrorText(errno)); ! while ((option = getopt_long(argc, argv, "d:D:b:B:cgG:kl:o:O:p:P:u:v", long_options, &optindex)) != -1) { switch (option) --- 98,104 ---- if (return_buf == NULL) pg_log(PG_FATAL, "Could not access current working directory: %s\n", getErrorText(errno)); ! while ((option = getopt_long(argc, argv, "d:D:b:B:cko:O:p:P:ru:v", long_options, &optindex)) != -1) { switch (option) *************** parseCommandLine(int argc, char *argv[]) *** 125,151 **** new_cluster.pgconfig = pg_strdup(optarg); break; - case 'g': - pg_log(PG_REPORT, "Running in debug mode\n"); - log_opts.debug = true; - break; - - case 'G': - if ((log_opts.debug_fd = fopen(optarg, "w")) == NULL) - { - pg_log(PG_FATAL, "cannot open debug file\n"); - exit(1); - } - break; - case 'k': user_opts.transfer_mode = TRANSFER_MODE_LINK; break; - case 'l': - log_opts.filename = pg_strdup(optarg); - break; - case 'o': old_cluster.pgopts = pg_strdup(optarg); break; --- 125,134 ---- *************** parseCommandLine(int argc, char *argv[]) *** 175,180 **** --- 158,167 ---- } break; + case 'r': + log_opts.retain = true; + break; + case 'u': pg_free(os_info.user); os_info.user = pg_strdup(optarg); *************** parseCommandLine(int argc, char *argv[]) *** 189,194 **** --- 176,183 ---- case 'v': pg_log(PG_REPORT, "Running in verbose mode\n"); log_opts.verbose = true; + /* renable retain too */ + log_opts.retain = true; break; default: *************** parseCommandLine(int argc, char *argv[]) *** 199,235 **** } } ! if (log_opts.filename != NULL) { ! /* ! * We must use append mode so output generated by child processes via ! * ">>" will not be overwritten, and we want the file truncated on ! * start. ! */ ! /* truncate */ ! if ((log_opts.fd = fopen(log_opts.filename, "w")) == NULL) ! pg_log(PG_FATAL, "cannot write to log file %s\n", log_opts.filename); ! fclose(log_opts.fd); ! if ((log_opts.fd = fopen(log_opts.filename, "a")) == NULL) ! pg_log(PG_FATAL, "cannot write to log file %s\n", log_opts.filename); } - else - log_opts.filename = pg_strdup(DEVNULL); ! /* WIN32 files do not accept writes from multiple processes */ ! #ifndef WIN32 ! log_opts.filename2 = pg_strdup(log_opts.filename); ! #else ! log_opts.filename2 = pg_strdup(DEVNULL); ! #endif ! ! /* if no debug file name, output to the terminal */ ! if (log_opts.debug && !log_opts.debug_fd) ! { ! log_opts.debug_fd = fopen(DEVTTY, "w"); ! if (!log_opts.debug_fd) ! pg_log(PG_FATAL, "cannot write to terminal\n"); ! } /* Get values from env if not already set */ check_required_directory(&old_cluster.bindir, "PGBINOLD", "-b", --- 188,204 ---- } } ! /* truncate log files because we append to them */ ! for (i = 0; i < NUM_OUTPUT_FILES; i++) { ! if ((fp = fopen(output_files[i], "w")) == NULL) ! pg_log(PG_FATAL, "cannot write to log file %s\n", ! output_files[i]); ! fclose(fp); } ! if ((log_opts.fp = fopen(INTERNAL_LOG_FILE, "w")) == NULL) ! pg_log(PG_FATAL, "cannot write to log file %s\n", INTERNAL_LOG_FILE); /* Get values from env if not already set */ check_required_directory(&old_cluster.bindir, "PGBINOLD", "-b", *************** Options:\n\ *** 256,271 **** -c, --check check clusters only, don't change any data\n\ -d, --old-datadir=OLDDATADIR old cluster data directory\n\ -D, --new-datadir=NEWDATADIR new cluster data directory\n\ - -g, --debug enable debugging\n\ - -G, --debugfile=FILENAME output debugging activity to file\n\ -k, --link link instead of copying files to new cluster\n\ - -l, --logfile=FILENAME log internal activity to file\n\ -o, --old-options=OPTIONS old cluster options to pass to the server\n\ -O, --new-options=OPTIONS new cluster options to pass to the server\n\ -p, --old-port=OLDPORT old cluster port number (default %d)\n\ -P, --new-port=NEWPORT new cluster port number (default %d)\n\ -u, --user=NAME cluster superuser (default \"%s\")\n\ ! -v, --verbose enable verbose output\n\ -V, --version display version information, then exit\n\ -h, --help show this help, then exit\n\ \n\ --- 225,238 ---- -c, --check check clusters only, don't change any data\n\ -d, --old-datadir=OLDDATADIR old cluster data directory\n\ -D, --new-datadir=NEWDATADIR new cluster data directory\n\ -k, --link link instead of copying files to new cluster\n\ -o, --old-options=OPTIONS old cluster options to pass to the server\n\ -O, --new-options=OPTIONS new cluster options to pass to the server\n\ -p, --old-port=OLDPORT old cluster port number (default %d)\n\ -P, --new-port=NEWPORT new cluster port number (default %d)\n\ + -r, --retain retain SQL and log files after success\n\ -u, --user=NAME cluster superuser (default \"%s\")\n\ ! -v, --verbose enable verbose logging, enables -r/--retain\n\ -V, --version display version information, then exit\n\ -h, --help show this help, then exit\n\ \n\ *************** adjust_data_dir(ClusterInfo *cluster) *** 354,372 **** { char filename[MAXPGPATH]; char cmd[MAXPGPATH], cmd_output[MAX_STRING]; ! FILE *fd, *output; /* If there is no postgresql.conf, it can't be a config-only dir */ snprintf(filename, sizeof(filename), "%s/postgresql.conf", cluster->pgconfig); ! if ((fd = fopen(filename, "r")) == NULL) return; ! fclose(fd); /* If PG_VERSION exists, it can't be a config-only dir */ snprintf(filename, sizeof(filename), "%s/PG_VERSION", cluster->pgconfig); ! if ((fd = fopen(filename, "r")) != NULL) { ! fclose(fd); return; } --- 321,339 ---- { char filename[MAXPGPATH]; char cmd[MAXPGPATH], cmd_output[MAX_STRING]; ! FILE *fp, *output; /* If there is no postgresql.conf, it can't be a config-only dir */ snprintf(filename, sizeof(filename), "%s/postgresql.conf", cluster->pgconfig); ! if ((fp = fopen(filename, "r")) == NULL) return; ! fclose(fp); /* If PG_VERSION exists, it can't be a config-only dir */ snprintf(filename, sizeof(filename), "%s/PG_VERSION", cluster->pgconfig); ! if ((fp = fopen(filename, "r")) != NULL) { ! fclose(fp); return; } diff --git a/contrib/pg_upgrade/pg_upgrade.c b/contrib/pg_upgrade/pg_upgrade.c new file mode 100644 index 3078bcd..3579c9d *** a/contrib/pg_upgrade/pg_upgrade.c --- b/contrib/pg_upgrade/pg_upgrade.c *************** ClusterInfo old_cluster, *** 55,60 **** --- 55,71 ---- new_cluster; OSInfo os_info; + char *output_files[NUM_OUTPUT_FILES] = { + ALL_DUMP_FILE, + GLOBALS_DUMP_FILE, + DB_DUMP_FILE, + SERVER_LOG_FILE, + RESTORE_LOG_FILE, + UTILITY_LOG_FILE, + INTERNAL_LOG_FILE + }; + + int main(int argc, char **argv) { *************** main(int argc, char **argv) *** 127,135 **** * because there is no need to have the schema load use new oids. */ prep_status("Setting next OID for new cluster"); ! exec_prog(true, SYSTEMQUOTE "\"%s/pg_resetxlog\" -o %u \"%s\" > " ! DEVNULL SYSTEMQUOTE, ! new_cluster.bindir, old_cluster.controldata.chkpnt_nxtoid, new_cluster.pgdata); check_ok(); create_script_for_old_cluster_deletion(&deletion_script_file_name); --- 138,148 ---- * because there is no need to have the schema load use new oids. */ prep_status("Setting next OID for new cluster"); ! exec_prog(true, UTILITY_LOG_FILE, ! SYSTEMQUOTE "\"%s/pg_resetxlog\" -o %u \"%s\" >> \"%s\" 2>&1" ! SYSTEMQUOTE, ! new_cluster.bindir, old_cluster.controldata.chkpnt_nxtoid, ! new_cluster.pgdata, UTILITY_LOG_FILE); check_ok(); create_script_for_old_cluster_deletion(&deletion_script_file_name); *************** prepare_new_cluster(void) *** 193,202 **** * --analyze so autovacuum doesn't update statistics later */ prep_status("Analyzing all rows in the new cluster"); ! exec_prog(true, SYSTEMQUOTE "\"%s/vacuumdb\" --port %d --username \"%s\" " "--all --analyze >> \"%s\" 2>&1" SYSTEMQUOTE, ! new_cluster.bindir, new_cluster.port, os_info.user, log_opts.filename2); check_ok(); /* --- 206,215 ---- * --analyze so autovacuum doesn't update statistics later */ prep_status("Analyzing all rows in the new cluster"); ! exec_prog(true, UTILITY_LOG_FILE, SYSTEMQUOTE "\"%s/vacuumdb\" --port %d --username \"%s\" " "--all --analyze >> \"%s\" 2>&1" SYSTEMQUOTE, ! new_cluster.bindir, new_cluster.port, os_info.user, UTILITY_LOG_FILE); check_ok(); /* *************** prepare_new_cluster(void) *** 206,215 **** * later. */ prep_status("Freezing all rows on the new cluster"); ! exec_prog(true, SYSTEMQUOTE "\"%s/vacuumdb\" --port %d --username \"%s\" " "--all --freeze >> \"%s\" 2>&1" SYSTEMQUOTE, ! new_cluster.bindir, new_cluster.port, os_info.user, log_opts.filename2); check_ok(); get_pg_database_relfilenode(&new_cluster); --- 219,228 ---- * later. */ prep_status("Freezing all rows on the new cluster"); ! exec_prog(true, UTILITY_LOG_FILE, SYSTEMQUOTE "\"%s/vacuumdb\" --port %d --username \"%s\" " "--all --freeze >> \"%s\" 2>&1" SYSTEMQUOTE, ! new_cluster.bindir, new_cluster.port, os_info.user, UTILITY_LOG_FILE); check_ok(); get_pg_database_relfilenode(&new_cluster); *************** prepare_new_databases(void) *** 243,255 **** * support functions in template1 but pg_dumpall creates database using * the template0 template. */ ! exec_prog(true, ! SYSTEMQUOTE "\"%s/psql\" --set ON_ERROR_STOP=on " ! /* --no-psqlrc prevents AUTOCOMMIT=off */ "--no-psqlrc --port %d --username \"%s\" " ! "-f \"%s/%s\" --dbname template1 >> \"%s\"" SYSTEMQUOTE, new_cluster.bindir, new_cluster.port, os_info.user, os_info.cwd, ! GLOBALS_DUMP_FILE, log_opts.filename2); check_ok(); /* we load this to get a current list of databases */ --- 256,269 ---- * support functions in template1 but pg_dumpall creates database using * the template0 template. */ ! exec_prog(true, RESTORE_LOG_FILE, ! SYSTEMQUOTE "\"%s/psql\" --echo-queries " ! "--set ON_ERROR_STOP=on " ! /* --no-psqlrc prevents AUTOCOMMIT=off */ "--no-psqlrc --port %d --username \"%s\" " ! "-f \"%s/%s\" --dbname template1 >> \"%s\" 2>&1" SYSTEMQUOTE, new_cluster.bindir, new_cluster.port, os_info.user, os_info.cwd, ! GLOBALS_DUMP_FILE, RESTORE_LOG_FILE); check_ok(); /* we load this to get a current list of databases */ *************** create_new_objects(void) *** 275,286 **** check_ok(); prep_status("Restoring database schema to new cluster"); ! exec_prog(true, ! SYSTEMQUOTE "\"%s/psql\" --set ON_ERROR_STOP=on " "--no-psqlrc --port %d --username \"%s\" " ! "-f \"%s/%s\" --dbname template1 >> \"%s\"" SYSTEMQUOTE, new_cluster.bindir, new_cluster.port, os_info.user, os_info.cwd, ! DB_DUMP_FILE, log_opts.filename2); check_ok(); /* regenerate now that we have objects in the databases */ --- 289,301 ---- check_ok(); prep_status("Restoring database schema to new cluster"); ! exec_prog(true, RESTORE_LOG_FILE, ! SYSTEMQUOTE "\"%s/psql\" --echo-queries " ! "--set ON_ERROR_STOP=on " "--no-psqlrc --port %d --username \"%s\" " ! "-f \"%s/%s\" --dbname template1 >> \"%s\" 2>&1" SYSTEMQUOTE, new_cluster.bindir, new_cluster.port, os_info.user, os_info.cwd, ! DB_DUMP_FILE, RESTORE_LOG_FILE); check_ok(); /* regenerate now that we have objects in the databases */ *************** copy_clog_xlog_xid(void) *** 306,334 **** check_ok(); prep_status("Copying old commit clogs to new server"); #ifndef WIN32 ! exec_prog(true, SYSTEMQUOTE "%s \"%s\" \"%s\"" SYSTEMQUOTE, "cp -Rf", #else /* flags: everything, no confirm, quiet, overwrite read-only */ ! exec_prog(true, SYSTEMQUOTE "%s \"%s\" \"%s\\\"" SYSTEMQUOTE, "xcopy /e /y /q /r", #endif ! old_clog_path, new_clog_path); check_ok(); /* set the next transaction id of the new cluster */ prep_status("Setting next transaction ID for new cluster"); ! exec_prog(true, SYSTEMQUOTE "\"%s/pg_resetxlog\" -f -x %u \"%s\" > " DEVNULL SYSTEMQUOTE, ! new_cluster.bindir, old_cluster.controldata.chkpnt_nxtxid, new_cluster.pgdata); check_ok(); /* now reset the wal archives in the new cluster */ prep_status("Resetting WAL archives"); ! exec_prog(true, SYSTEMQUOTE "\"%s/pg_resetxlog\" -l %u,%u,%u \"%s\" >> \"%s\" 2>&1" SYSTEMQUOTE, ! new_cluster.bindir, old_cluster.controldata.chkpnt_tli, ! old_cluster.controldata.logid, old_cluster.controldata.nxtlogseg, ! new_cluster.pgdata, log_opts.filename2); check_ok(); } --- 321,358 ---- check_ok(); prep_status("Copying old commit clogs to new server"); + exec_prog(true, UTILITY_LOG_FILE, #ifndef WIN32 ! SYSTEMQUOTE "%s \"%s\" \"%s\" >> \"%s\" 2>&1" SYSTEMQUOTE, "cp -Rf", #else /* flags: everything, no confirm, quiet, overwrite read-only */ ! SYSTEMQUOTE "%s \"%s\" \"%s\\\" >> \"%s\" 2>&1" SYSTEMQUOTE, "xcopy /e /y /q /r", #endif ! old_clog_path, new_clog_path, UTILITY_LOG_FILE); check_ok(); /* set the next transaction id of the new cluster */ prep_status("Setting next transaction ID for new cluster"); ! exec_prog(true, UTILITY_LOG_FILE, ! SYSTEMQUOTE ! "\"%s/pg_resetxlog\" -f -x %u \"%s\" >> \"%s\" 2>&1" ! SYSTEMQUOTE, new_cluster.bindir, ! old_cluster.controldata.chkpnt_nxtxid, ! new_cluster.pgdata, UTILITY_LOG_FILE); check_ok(); /* now reset the wal archives in the new cluster */ prep_status("Resetting WAL archives"); ! exec_prog(true, UTILITY_LOG_FILE, ! SYSTEMQUOTE ! "\"%s/pg_resetxlog\" -l %u,%u,%u \"%s\" >> \"%s\" 2>&1" ! SYSTEMQUOTE, new_cluster.bindir, ! old_cluster.controldata.chkpnt_tli, ! old_cluster.controldata.logid, ! old_cluster.controldata.nxtlogseg, ! new_cluster.pgdata, UTILITY_LOG_FILE); check_ok(); } *************** set_frozenxids(void) *** 421,438 **** static void cleanup(void) { ! char filename[MAXPGPATH]; ! ! if (log_opts.fd) ! fclose(log_opts.fd); ! if (log_opts.debug_fd) ! fclose(log_opts.debug_fd); ! snprintf(filename, sizeof(filename), "%s/%s", os_info.cwd, ALL_DUMP_FILE); ! unlink(filename); ! snprintf(filename, sizeof(filename), "%s/%s", os_info.cwd, GLOBALS_DUMP_FILE); ! unlink(filename); ! snprintf(filename, sizeof(filename), "%s/%s", os_info.cwd, DB_DUMP_FILE); ! unlink(filename); } --- 445,463 ---- static void cleanup(void) { ! fclose(log_opts.fp); ! /* Remove dump and log files? */ ! if (!log_opts.retain) ! { ! int i; ! char filename[MAXPGPATH]; ! for (i = 0; i < NUM_OUTPUT_FILES; i++) ! { ! snprintf(filename, sizeof(filename), "%s/%s", os_info.cwd, ! output_files[i]); ! unlink(filename); ! } ! } } diff --git a/contrib/pg_upgrade/pg_upgrade.h b/contrib/pg_upgrade/pg_upgrade.h new file mode 100644 index a954815..2a7f7e1 *** a/contrib/pg_upgrade/pg_upgrade.h --- b/contrib/pg_upgrade/pg_upgrade.h *************** *** 35,40 **** --- 35,68 ---- #define GLOBALS_DUMP_FILE "pg_upgrade_dump_globals.sql" #define DB_DUMP_FILE "pg_upgrade_dump_db.sql" + #define SERVER_LOG_FILE "pg_upgrade_server.log" + #define RESTORE_LOG_FILE "pg_upgrade_restore.log" + #define UTILITY_LOG_FILE "pg_upgrade_utility.log" + #define INTERNAL_LOG_FILE "pg_upgrade_internal.log" + + #define NUM_OUTPUT_FILES 7 + extern char *output_files[]; + + /* + * WIN32 files do not accept writes from multiple processes + * + * On Win32, we can't send both pg_upgrade output and command output to the + * same file because we get the error: "The process cannot access the file + * because it is being used by another process." so send the pg_ctl + * command-line output to the utility log file on Windows, rather than + * into the server log file. + * + * We could use the Windows pgwin32_open() flags to allow shared file + * writes but is unclear how all other tools would use those flags, so + * we just avoid it and log a little differently on Windows; we adjust + * the error message appropriately. + */ + #ifndef WIN32 + #define SERVER_LOG_FILE2 SERVER_LOG_FILE + #else + #define SERVER_LOG_FILE2 UTILITY_LOG_FILE + #endif + #ifndef WIN32 #define pg_copy_file copy_file #define pg_mv_file rename *************** typedef enum *** 169,176 **** PG_INFO, PG_REPORT, PG_WARNING, ! PG_FATAL, ! PG_DEBUG } eLogType; --- 197,203 ---- PG_INFO, PG_REPORT, PG_WARNING, ! PG_FATAL } eLogType; *************** typedef struct *** 204,227 **** */ typedef struct { ! char *filename; /* name of log file (may be /dev/null) */ ! /* ! * WIN32 files do not accept writes from multiple processes ! * ! * On Win32, we can't send both pg_upgrade output and command output to the ! * same file because we get the error: "The process cannot access the file ! * because it is being used by another process." so we have to send all ! * other output to 'nul'. Therefore, we set this to DEVNULL on Win32, and ! * it equals 'filename' on all other platforms. ! * ! * We could use the Windows pgwin32_open() flags to allow shared file ! * writes but is unclear how all other tools would use those flags, so ! * we just avoid it and log a little less on Windows. ! */ ! char *filename2; ! FILE *fd; /* log FILE */ ! bool debug; /* TRUE -> log more information */ ! FILE *debug_fd; /* debug-level log FILE */ bool verbose; /* TRUE -> be verbose in messages */ } LogOpts; --- 231,238 ---- */ typedef struct { ! bool retain; /* retain log files on success */ ! FILE *fp; /* log FILE */ bool verbose; /* TRUE -> be verbose in messages */ } LogOpts; *************** void split_old_dump(void); *** 294,301 **** /* exec.c */ ! int exec_prog(bool throw_error, const char *cmd, ...) ! __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3))); void verify_directories(void); bool is_server_running(const char *datadir); --- 305,312 ---- /* exec.c */ ! int exec_prog(bool throw_error, const char *log_file, const char *cmd, ...) ! __attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4))); void verify_directories(void); bool is_server_running(const char *datadir); diff --git a/contrib/pg_upgrade/server.c b/contrib/pg_upgrade/server.c new file mode 100644 index 989af63..22c4f65 *** a/contrib/pg_upgrade/server.c --- b/contrib/pg_upgrade/server.c *************** executeQueryOrDie(PGconn *conn, const ch *** 80,86 **** vsnprintf(command, sizeof(command), fmt, args); va_end(args); ! pg_log(PG_DEBUG, "executing: %s\n", command); result = PQexec(conn, command); status = PQresultStatus(result); --- 80,87 ---- vsnprintf(command, sizeof(command), fmt, args); va_end(args); ! if (log_opts.verbose) ! pg_log(PG_INFO, "executing: %s\n", command); result = PQexec(conn, command); status = PQresultStatus(result); *************** start_postmaster(ClusterInfo *cluster) *** 161,177 **** snprintf(cmd, sizeof(cmd), SYSTEMQUOTE "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" " "-o \"-p %d %s %s\" start >> \"%s\" 2>&1" SYSTEMQUOTE, ! cluster->bindir, log_opts.filename2, cluster->pgconfig, cluster->port, (cluster->controldata.cat_ver >= BINARY_UPGRADE_SERVER_FLAG_CAT_VER) ? "-b" : "-c autovacuum=off -c autovacuum_freeze_max_age=2000000000", ! cluster->pgopts ? cluster->pgopts : "", log_opts.filename2); /* * Don't throw an error right away, let connecting throw the error because * it might supply a reason for the failure. */ ! pg_ctl_return = exec_prog(false, "%s", cmd); /* Check to see if we can connect to the server; if not, report it. */ if ((conn = get_db_conn(cluster, "template1")) == NULL || --- 162,183 ---- snprintf(cmd, sizeof(cmd), SYSTEMQUOTE "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" " "-o \"-p %d %s %s\" start >> \"%s\" 2>&1" SYSTEMQUOTE, ! cluster->bindir, SERVER_LOG_FILE, cluster->pgconfig, cluster->port, (cluster->controldata.cat_ver >= BINARY_UPGRADE_SERVER_FLAG_CAT_VER) ? "-b" : "-c autovacuum=off -c autovacuum_freeze_max_age=2000000000", ! cluster->pgopts ? cluster->pgopts : "", SERVER_LOG_FILE2); /* * Don't throw an error right away, let connecting throw the error because * it might supply a reason for the failure. */ ! pg_ctl_return = exec_prog(false, ! /* pass both file names if the differ */ ! (strcmp(SERVER_LOG_FILE, SERVER_LOG_FILE2) == 0) ? ! SERVER_LOG_FILE : ! SERVER_LOG_FILE " or " SERVER_LOG_FILE2, ! "%s", cmd); /* Check to see if we can connect to the server; if not, report it. */ if ((conn = get_db_conn(cluster, "template1")) == NULL || *************** stop_postmaster(bool fast) *** 211,221 **** snprintf(cmd, sizeof(cmd), SYSTEMQUOTE "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" -o \"%s\" " "%s stop >> \"%s\" 2>&1" SYSTEMQUOTE, ! cluster->bindir, log_opts.filename2, cluster->pgconfig, cluster->pgopts ? cluster->pgopts : "", ! fast ? "-m fast" : "", log_opts.filename2); ! exec_prog(fast ? false : true, "%s", cmd); os_info.running_cluster = NULL; } --- 217,227 ---- snprintf(cmd, sizeof(cmd), SYSTEMQUOTE "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" -o \"%s\" " "%s stop >> \"%s\" 2>&1" SYSTEMQUOTE, ! cluster->bindir, SERVER_LOG_FILE2, cluster->pgconfig, cluster->pgopts ? cluster->pgopts : "", ! fast ? "-m fast" : "", SERVER_LOG_FILE2); ! exec_prog(fast ? false : true, SERVER_LOG_FILE2, "%s", cmd); os_info.running_cluster = NULL; } diff --git a/contrib/pg_upgrade/util.c b/contrib/pg_upgrade/util.c new file mode 100644 index 94eaa18..ab78e3e *** a/contrib/pg_upgrade/util.c --- b/contrib/pg_upgrade/util.c *************** pg_log(eLogType type, char *fmt,...) *** 77,89 **** vsnprintf(message, sizeof(message), fmt, args); va_end(args); ! if (log_opts.fd != NULL) { ! fwrite(message, strlen(message), 1, log_opts.fd); /* if we are using OVERWRITE_MESSAGE, add newline */ if (strchr(message, '\r') != NULL) ! fwrite("\n", 1, 1, log_opts.fd); ! fflush(log_opts.fd); } switch (type) --- 77,89 ---- vsnprintf(message, sizeof(message), fmt, args); va_end(args); ! if (type != PG_INFO || log_opts.verbose) { ! fwrite(message, strlen(message), 1, log_opts.fp); /* if we are using OVERWRITE_MESSAGE, add newline */ if (strchr(message, '\r') != NULL) ! fwrite("\n", 1, 1, log_opts.fp); ! fflush(log_opts.fp); } switch (type) *************** pg_log(eLogType type, char *fmt,...) *** 104,114 **** exit(1); break; - case PG_DEBUG: - if (log_opts.debug) - fprintf(log_opts.debug_fd, "%s\n", _(message)); - break; - default: break; } --- 104,109 ---- diff --git a/doc/src/sgml/pgupgrade.sgml b/doc/src/sgml/pgupgrade.sgml new file mode 100644 index 4f263fe..84b01a8 *** a/doc/src/sgml/pgupgrade.sgml --- b/doc/src/sgml/pgupgrade.sgml *************** *** 91,120 **** </varlistentry> <varlistentry> - <term><option>-g</option></term> - <term><option>--debug</option></term> - <listitem><para>enable debugging</para></listitem> - </varlistentry> - - <varlistentry> - <term><option>-G</option> <replaceable>debug_filename</></term> - <term><option>--debugfile=</option><replaceable>debug_filename</></term> - <listitem><para>output debugging activity to file</para></listitem> - </varlistentry> - - <varlistentry> <term><option>-k</option></term> <term><option>--link</option></term> <listitem><para>use hard links instead of copying files to the new cluster</para></listitem> </varlistentry> <varlistentry> - <term><option>-l</option> <replaceable>log_filename</></term> - <term><option>--logfile=</option><replaceable>log_filename</></term> - <listitem><para>log internal activity to file</para></listitem> - </varlistentry> - - <varlistentry> <term><option>-o</option> <replaceable class="parameter">options</replaceable></term> <term><option>--old-options</option> <replaceable class="parameter">options</replaceable></term> <listitem><para>options to be passed directly to the --- 91,102 ---- *************** *** 143,148 **** --- 125,137 ---- </varlistentry> <varlistentry> + <term><option>-r</option></term> + <term><option>--retain</option></term> + <listitem><para>retain SQL and log files even after successful completion + </para></listitem> + </varlistentry> + + <varlistentry> <term><option>-u</option> <replaceable>user_name</></term> <term><option>--user=</option><replaceable>user_name</></term> <listitem><para>cluster's super user name; environment *************** *** 152,158 **** <varlistentry> <term><option>-v</option></term> <term><option>--verbose</option></term> ! <listitem><para>enable verbose output</para></listitem> </varlistentry> <varlistentry> --- 141,148 ---- <varlistentry> <term><option>-v</option></term> <term><option>--verbose</option></term> ! <listitem><para>enable verbose internal logging, also enables ! <option>-r</option>/<option>--retain</option></para></listitem> </varlistentry> <varlistentry>
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers