From 0e1753613897e12abd9d246176dfc0c83cdcece6 Mon Sep 17 00:00:00 2001 From: Jakub Wartak Date: Fri, 5 Jan 2024 08:33:45 +0100 Subject: [PATCH v3 3/4] Add --copy-file-range to pg_upgrade using pg_copyfile_offload(). Original patch author is Thomas. Co-authored-by: Thomas Munro Discussion: https://www.postgresql.org/message-id/flat/CA%2BhUKGJvLLNQtzb%3DZWcTsYF8kv8cR_%3DH17CX-eL8qNixeC4DAw%40mail.gmail.com#ce606227e39df74c6b2abf80b8eab04a --- src/bin/pg_upgrade/check.c | 409 ++++++++++++++++---------------- src/bin/pg_upgrade/file.c | 37 ++- src/bin/pg_upgrade/option.c | 158 ++++++------ src/bin/pg_upgrade/pg_upgrade.h | 150 ++++++------ 4 files changed, 401 insertions(+), 353 deletions(-) diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c index 87c06628c6..3e6922f3fb 100644 --- a/src/bin/pg_upgrade/check.c +++ b/src/bin/pg_upgrade/check.c @@ -38,7 +38,6 @@ static void check_new_cluster_subscription_configuration(void); static void check_old_cluster_for_valid_slots(bool live_check); static void check_old_cluster_subscription_state(void); - /* * fix_path_separator * For non-Windows, just return the argument. @@ -72,19 +71,16 @@ output_check_banner(bool live_check) { if (user_opts.check && live_check) { - pg_log(PG_REPORT, - "Performing Consistency Checks on Old Live Server\n" + pg_log(PG_REPORT, "Performing Consistency Checks on Old Live Server\n" "------------------------------------------------"); } else { - pg_log(PG_REPORT, - "Performing Consistency Checks\n" + pg_log(PG_REPORT, "Performing Consistency Checks\n" "-----------------------------"); } } - void check_and_dump_old_cluster(bool live_check) { @@ -103,7 +99,6 @@ check_and_dump_old_cluster(bool live_check) get_loadable_libraries(); - /* * Check for various failure cases */ @@ -218,7 +213,6 @@ check_and_dump_old_cluster(bool live_check) stop_postmaster(false); } - void check_new_cluster(void) { @@ -238,6 +232,9 @@ check_new_cluster(void) case TRANSFER_MODE_LINK: check_hard_link(); break; + case TRANSFER_MODE_COPY_FILE_RANGE: + check_copy_file_range(); + break; } check_is_install_user(&new_cluster); @@ -251,7 +248,6 @@ check_new_cluster(void) check_new_cluster_subscription_configuration(); } - void report_clusters_compatible(void) { @@ -265,12 +261,12 @@ report_clusters_compatible(void) exit(0); } - pg_log(PG_REPORT, "\n" + pg_log(PG_REPORT, + "\n" "If pg_upgrade fails after this point, you must re-initdb the\n" "new cluster before continuing."); } - void issue_warnings_and_set_wal_level(void) { @@ -291,7 +287,6 @@ issue_warnings_and_set_wal_level(void) stop_postmaster(false); } - void output_completion_banner(char *deletion_script_file_name) { @@ -308,7 +303,8 @@ output_completion_banner(char *deletion_script_file_name) pg_log(PG_REPORT, "Optimizer statistics are not transferred by pg_upgrade.\n" "Once you start the new server, consider running:\n" - " %s/vacuumdb %s--all --analyze-in-stages", new_cluster.bindir, user_specification.data); + " %s/vacuumdb %s--all --analyze-in-stages", + new_cluster.bindir, user_specification.data); if (deletion_script_file_name) pg_log(PG_REPORT, @@ -316,7 +312,8 @@ output_completion_banner(char *deletion_script_file_name) " %s", deletion_script_file_name); else - pg_log(PG_REPORT, + pg_log( + PG_REPORT, "Could not create a script to delete the old cluster's data files\n" "because user-defined tablespaces or the new cluster's data directory\n" "exist in the old cluster directory. The old cluster's contents must\n" @@ -325,7 +322,6 @@ output_completion_banner(char *deletion_script_file_name) termPQExpBuffer(&user_specification); } - void check_cluster_versions(void) { @@ -341,11 +337,13 @@ check_cluster_versions(void) */ if (GET_MAJOR_VERSION(old_cluster.major_version) < 902) - pg_fatal("This utility can only upgrade from PostgreSQL version %s and later.", + pg_fatal( + "This utility can only upgrade from PostgreSQL version %s and later.", "9.2"); /* Only current PG version is supported as a target */ - if (GET_MAJOR_VERSION(new_cluster.major_version) != GET_MAJOR_VERSION(PG_VERSION_NUM)) + if (GET_MAJOR_VERSION(new_cluster.major_version) != + GET_MAJOR_VERSION(PG_VERSION_NUM)) pg_fatal("This utility can only upgrade to PostgreSQL version %s.", PG_MAJORVERSION); @@ -355,20 +353,22 @@ check_cluster_versions(void) * older versions. */ if (old_cluster.major_version > new_cluster.major_version) - pg_fatal("This utility cannot be used to downgrade to older major PostgreSQL versions."); + pg_fatal("This utility cannot be used to downgrade to older major " + "PostgreSQL versions."); /* Ensure binaries match the designated data directories */ if (GET_MAJOR_VERSION(old_cluster.major_version) != GET_MAJOR_VERSION(old_cluster.bin_version)) - pg_fatal("Old cluster data and binary directories are from different major versions."); + pg_fatal("Old cluster data and binary directories are from different major " + "versions."); if (GET_MAJOR_VERSION(new_cluster.major_version) != GET_MAJOR_VERSION(new_cluster.bin_version)) - pg_fatal("New cluster data and binary directories are from different major versions."); + pg_fatal("New cluster data and binary directories are from different major " + "versions."); check_ok(); } - void check_cluster_compatibility(bool live_check) { @@ -382,7 +382,6 @@ check_cluster_compatibility(bool live_check) "the old and new port numbers must be different."); } - static void check_new_cluster_is_empty(void) { @@ -393,15 +392,14 @@ check_new_cluster_is_empty(void) int relnum; RelInfoArr *rel_arr = &new_cluster.dbarr.dbs[dbnum].rel_arr; - for (relnum = 0; relnum < rel_arr->nrels; - relnum++) + for (relnum = 0; relnum < rel_arr->nrels; relnum++) { /* pg_largeobject and its index should be skipped */ if (strcmp(rel_arr->rels[relnum].nspname, "pg_catalog") != 0) - pg_fatal("New cluster database \"%s\" is not empty: found relation \"%s.%s\"", + pg_fatal("New cluster database \"%s\" is not empty: found relation " + "\"%s.%s\"", new_cluster.dbarr.dbs[dbnum].db_name, - rel_arr->rels[relnum].nspname, - rel_arr->rels[relnum].relname); + rel_arr->rels[relnum].nspname, rel_arr->rels[relnum].relname); } } } @@ -428,8 +426,7 @@ check_for_new_tablespace_dir(void) struct stat statbuf; snprintf(new_tablespace_dir, MAXPGPATH, "%s%s", - os_info.old_tablespaces[tblnum], - new_cluster.tablespace_suffix); + os_info.old_tablespaces[tblnum], new_cluster.tablespace_suffix); if (stat(new_tablespace_dir, &statbuf) == 0 || errno != ENOENT) pg_fatal("new cluster tablespace directory already exists: \"%s\"", @@ -452,8 +449,8 @@ create_script_for_old_cluster_deletion(char **deletion_script_file_name) char old_cluster_pgdata[MAXPGPATH], new_cluster_pgdata[MAXPGPATH]; - *deletion_script_file_name = psprintf("%sdelete_old_cluster.%s", - SCRIPT_PREFIX, SCRIPT_EXT); + *deletion_script_file_name = + psprintf("%sdelete_old_cluster.%s", SCRIPT_PREFIX, SCRIPT_EXT); strlcpy(old_cluster_pgdata, old_cluster.pgdata, MAXPGPATH); canonicalize_path(old_cluster_pgdata); @@ -465,7 +462,9 @@ create_script_for_old_cluster_deletion(char **deletion_script_file_name) if (path_is_prefix_of_path(old_cluster_pgdata, new_cluster_pgdata)) { pg_log(PG_WARNING, - "\nWARNING: new data directory should not be inside the old data directory, i.e. %s", old_cluster_pgdata); + "\nWARNING: new data directory should not be inside the old data " + "directory, i.e. %s", + old_cluster_pgdata); /* Unlink file in case it is left over from a previous run. */ unlink(*deletion_script_file_name); @@ -489,7 +488,9 @@ create_script_for_old_cluster_deletion(char **deletion_script_file_name) { /* reproduce warning from CREATE TABLESPACE that is in the log */ pg_log(PG_WARNING, - "\nWARNING: user-defined tablespace locations should not be inside the data directory, i.e. %s", old_tablespace_dir); + "\nWARNING: user-defined tablespace locations should not be " + "inside the data directory, i.e. %s", + old_tablespace_dir); /* Unlink file in case it is left over from a previous run. */ unlink(*deletion_script_file_name); @@ -502,8 +503,8 @@ create_script_for_old_cluster_deletion(char **deletion_script_file_name) prep_status("Creating script to delete old cluster"); if ((script = fopen_priv(*deletion_script_file_name, "w")) == NULL) - pg_fatal("could not open file \"%s\": %s", - *deletion_script_file_name, strerror(errno)); + pg_fatal("could not open file \"%s\": %s", *deletion_script_file_name, + strerror(errno)); #ifndef WIN32 /* add shebang header */ @@ -560,7 +561,6 @@ create_script_for_old_cluster_deletion(char **deletion_script_file_name) check_ok(); } - /* * check_is_install_user() * @@ -576,8 +576,7 @@ check_is_install_user(ClusterInfo *cluster) prep_status("Checking database user is the install user"); /* Can't use pg_authid because only superusers can view it. */ - res = executeQueryOrDie(conn, - "SELECT rolsuper, oid " + res = executeQueryOrDie(conn, "SELECT rolsuper, oid " "FROM pg_catalog.pg_roles " "WHERE rolname = current_user " "AND rolname !~ '^pg_'"); @@ -589,13 +588,11 @@ check_is_install_user(ClusterInfo *cluster) */ if (PQntuples(res) != 1 || atooid(PQgetvalue(res, 0, 1)) != BOOTSTRAP_SUPERUSERID) - pg_fatal("database user \"%s\" is not the install user", - os_info.user); + pg_fatal("database user \"%s\" is not the install user", os_info.user); PQclear(res); - res = executeQueryOrDie(conn, - "SELECT COUNT(*) " + res = executeQueryOrDie(conn, "SELECT COUNT(*) " "FROM pg_catalog.pg_roles " "WHERE rolname !~ '^pg_'"); @@ -617,7 +614,6 @@ check_is_install_user(ClusterInfo *cluster) check_ok(); } - /* * check_proper_datallowconn * @@ -639,16 +635,15 @@ check_proper_datallowconn(ClusterInfo *cluster) prep_status("Checking database connection settings"); - snprintf(output_path, sizeof(output_path), "%s/%s", - log_opts.basedir, + snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir, "databases_with_datallowconn_false.txt"); conn_template1 = connectToServer(cluster, "template1"); /* get database names */ - dbres = executeQueryOrDie(conn_template1, - "SELECT datname, datallowconn " - "FROM pg_catalog.pg_database"); + dbres = + executeQueryOrDie(conn_template1, "SELECT datname, datallowconn " + "FROM pg_catalog.pg_database"); i_datname = PQfnumber(dbres, "datname"); i_datallowconn = PQfnumber(dbres, "datallowconn"); @@ -675,8 +670,8 @@ check_proper_datallowconn(ClusterInfo *cluster) if (strcmp(datallowconn, "f") == 0) { if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("could not open file \"%s\": %s", - output_path, strerror(errno)); + pg_fatal("could not open file \"%s\": %s", output_path, + strerror(errno)); fprintf(script, "%s\n", datname); } @@ -691,19 +686,20 @@ check_proper_datallowconn(ClusterInfo *cluster) { fclose(script); pg_log(PG_REPORT, "fatal"); - pg_fatal("All non-template0 databases must allow connections, i.e. their\n" + pg_fatal( + "All non-template0 databases must allow connections, i.e. their\n" "pg_database.datallowconn must be true. Your installation contains\n" "non-template0 databases with their pg_database.datallowconn set to\n" "false. Consider allowing connection for all non-template0 databases\n" "or drop the databases which do not allow connections. A list of\n" "databases with the problem is in the file:\n" - " %s", output_path); + " %s", + output_path); } else check_ok(); } - /* * check_for_prepared_transactions() * @@ -718,8 +714,7 @@ check_for_prepared_transactions(ClusterInfo *cluster) prep_status("Checking for prepared transactions"); - res = executeQueryOrDie(conn, - "SELECT * " + res = executeQueryOrDie(conn, "SELECT * " "FROM pg_catalog.pg_prepared_xacts"); if (PQntuples(res) != 0) @@ -737,7 +732,6 @@ check_for_prepared_transactions(ClusterInfo *cluster) check_ok(); } - /* * check_for_isn_and_int8_passing_mismatch() * @@ -762,8 +756,7 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster) return; } - snprintf(output_path, sizeof(output_path), "%s/%s", - log_opts.basedir, + snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir, "contrib_isn_and_int8_pass_by_value.txt"); for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++) @@ -778,8 +771,7 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster) PGconn *conn = connectToServer(cluster, active_db->db_name); /* Find any functions coming from contrib/isn */ - res = executeQueryOrDie(conn, - "SELECT n.nspname, p.proname " + res = executeQueryOrDie(conn, "SELECT n.nspname, p.proname " "FROM pg_catalog.pg_proc p, " " pg_catalog.pg_namespace n " "WHERE p.pronamespace = n.oid AND " @@ -791,15 +783,14 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster) for (rowno = 0; rowno < ntups; rowno++) { if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("could not open file \"%s\": %s", - output_path, strerror(errno)); + pg_fatal("could not open file \"%s\": %s", output_path, + strerror(errno)); if (!db_used) { fprintf(script, "In database: %s\n", active_db->db_name); db_used = true; } - fprintf(script, " %s.%s\n", - PQgetvalue(res, rowno, i_nspname), + fprintf(script, " %s.%s\n", PQgetvalue(res, rowno, i_nspname), PQgetvalue(res, rowno, i_proname)); } @@ -812,13 +803,17 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster) { fclose(script); pg_log(PG_REPORT, "fatal"); - pg_fatal("Your installation contains \"contrib/isn\" functions which rely on the\n" + pg_fatal( + "Your installation contains \"contrib/isn\" functions which rely on " + "the\n" "bigint data type. Your old and new clusters pass bigint values\n" "differently so this cluster cannot currently be upgraded. You can\n" "manually dump databases in the old cluster that use \"contrib/isn\"\n" - "facilities, drop them, perform the upgrade, and then restore them. A\n" + "facilities, drop them, perform the upgrade, and then restore them. " + "A\n" "list of the problem functions is in the file:\n" - " %s", output_path); + " %s", + output_path); } else check_ok(); @@ -836,8 +831,7 @@ check_for_user_defined_postfix_ops(ClusterInfo *cluster) prep_status("Checking for user-defined postfix operators"); - snprintf(output_path, sizeof(output_path), "%s/%s", - log_opts.basedir, + snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir, "postfix_ops.txt"); /* Find any user defined postfix operators */ @@ -861,8 +855,7 @@ check_for_user_defined_postfix_ops(ClusterInfo *cluster) * #define is ever changed, the cutoff we want to use is the value * used by pre-version 14 servers, not that of some future version. */ - res = executeQueryOrDie(conn, - "SELECT o.oid AS oproid, " + res = executeQueryOrDie(conn, "SELECT o.oid AS oproid, " " n.nspname AS oprnsp, " " o.oprname, " " tn.nspname AS typnsp, " @@ -884,20 +877,18 @@ check_for_user_defined_postfix_ops(ClusterInfo *cluster) i_typname = PQfnumber(res, "typname"); for (rowno = 0; rowno < ntups; rowno++) { - if (script == NULL && - (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("could not open file \"%s\": %s", - output_path, strerror(errno)); + if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) + pg_fatal("could not open file \"%s\": %s", output_path, + strerror(errno)); if (!db_used) { fprintf(script, "In database: %s\n", active_db->db_name); db_used = true; } - fprintf(script, " (oid=%s) %s.%s (%s.%s, NONE)\n", - PQgetvalue(res, rowno, i_oproid), - PQgetvalue(res, rowno, i_oprnsp), - PQgetvalue(res, rowno, i_oprname), - PQgetvalue(res, rowno, i_typnsp), + fprintf( + script, " (oid=%s) %s.%s (%s.%s, NONE)\n", + PQgetvalue(res, rowno, i_oproid), PQgetvalue(res, rowno, i_oprnsp), + PQgetvalue(res, rowno, i_oprname), PQgetvalue(res, rowno, i_typnsp), PQgetvalue(res, rowno, i_typname)); } @@ -910,11 +901,14 @@ check_for_user_defined_postfix_ops(ClusterInfo *cluster) { fclose(script); pg_log(PG_REPORT, "fatal"); - pg_fatal("Your installation contains user-defined postfix operators, which are not\n" - "supported anymore. Consider dropping the postfix operators and replacing\n" + pg_fatal("Your installation contains user-defined postfix operators, which " + "are not\n" + "supported anymore. Consider dropping the postfix operators and " + "replacing\n" "them with prefix operators or function calls.\n" "A list of user-defined postfix operators is in the file:\n" - " %s", output_path); + " %s", + output_path); } else check_ok(); @@ -936,8 +930,7 @@ check_for_incompatible_polymorphics(ClusterInfo *cluster) prep_status("Checking for incompatible polymorphic functions"); - snprintf(output_path, sizeof(output_path), "%s/%s", - log_opts.basedir, + snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir, "incompatible_polymorphics.txt"); /* The set of problematic functions varies a bit in different versions */ @@ -975,7 +968,8 @@ check_for_incompatible_polymorphics(ClusterInfo *cluster) * #define is ever changed, the cutoff we want to use is the value * used by pre-version 14 servers, not that of some future version. */ - res = executeQueryOrDie(conn, + res = executeQueryOrDie( + conn, /* Aggregate transition functions */ "SELECT 'aggregate' AS objkind, p.oid::regprocedure::text AS objname " "FROM pg_proc AS p " @@ -1002,9 +996,7 @@ check_for_incompatible_polymorphics(ClusterInfo *cluster) "WHERE op.oid >= 16384 " "AND oprcode = ANY(ARRAY[%s]::regprocedure[]) " "AND oprleft = ANY(ARRAY['anyarray', 'anyelement']::regtype[]);", - old_polymorphics.data, - old_polymorphics.data, - old_polymorphics.data); + old_polymorphics.data, old_polymorphics.data, old_polymorphics.data); ntups = PQntuples(res); @@ -1013,18 +1005,16 @@ check_for_incompatible_polymorphics(ClusterInfo *cluster) for (int rowno = 0; rowno < ntups; rowno++) { - if (script == NULL && - (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("could not open file \"%s\": %s", - output_path, strerror(errno)); + if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) + pg_fatal("could not open file \"%s\": %s", output_path, + strerror(errno)); if (!db_used) { fprintf(script, "In database: %s\n", active_db->db_name); db_used = true; } - fprintf(script, " %s: %s\n", - PQgetvalue(res, rowno, i_objkind), + fprintf(script, " %s: %s\n", PQgetvalue(res, rowno, i_objkind), PQgetvalue(res, rowno, i_objname)); } @@ -1036,13 +1026,18 @@ check_for_incompatible_polymorphics(ClusterInfo *cluster) { fclose(script); pg_log(PG_REPORT, "fatal"); - pg_fatal("Your installation contains user-defined objects that refer to internal\n" - "polymorphic functions with arguments of type \"anyarray\" or \"anyelement\".\n" - "These user-defined objects must be dropped before upgrading and restored\n" - "afterwards, changing them to refer to the new corresponding functions with\n" + pg_fatal("Your installation contains user-defined objects that refer to " + "internal\n" + "polymorphic functions with arguments of type \"anyarray\" or " + "\"anyelement\".\n" + "These user-defined objects must be dropped before upgrading and " + "restored\n" + "afterwards, changing them to refer to the new corresponding " + "functions with\n" "arguments of type \"anycompatiblearray\" and \"anycompatible\".\n" "A list of the problematic objects is in the file:\n" - " %s", output_path); + " %s", + output_path); } else check_ok(); @@ -1062,8 +1057,7 @@ check_for_tables_with_oids(ClusterInfo *cluster) prep_status("Checking for tables WITH OIDS"); - snprintf(output_path, sizeof(output_path), "%s/%s", - log_opts.basedir, + snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir, "tables_with_oids.txt"); /* Find any tables declared WITH OIDS */ @@ -1078,8 +1072,7 @@ check_for_tables_with_oids(ClusterInfo *cluster) DbInfo *active_db = &cluster->dbarr.dbs[dbnum]; PGconn *conn = connectToServer(cluster, active_db->db_name); - res = executeQueryOrDie(conn, - "SELECT n.nspname, c.relname " + res = executeQueryOrDie(conn, "SELECT n.nspname, c.relname " "FROM pg_catalog.pg_class c, " " pg_catalog.pg_namespace n " "WHERE c.relnamespace = n.oid AND " @@ -1092,15 +1085,14 @@ check_for_tables_with_oids(ClusterInfo *cluster) for (rowno = 0; rowno < ntups; rowno++) { if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("could not open file \"%s\": %s", - output_path, strerror(errno)); + pg_fatal("could not open file \"%s\": %s", output_path, + strerror(errno)); if (!db_used) { fprintf(script, "In database: %s\n", active_db->db_name); db_used = true; } - fprintf(script, " %s.%s\n", - PQgetvalue(res, rowno, i_nspname), + fprintf(script, " %s.%s\n", PQgetvalue(res, rowno, i_nspname), PQgetvalue(res, rowno, i_relname)); } @@ -1113,17 +1105,18 @@ check_for_tables_with_oids(ClusterInfo *cluster) { fclose(script); pg_log(PG_REPORT, "fatal"); - pg_fatal("Your installation contains tables declared WITH OIDS, which is not\n" + pg_fatal( + "Your installation contains tables declared WITH OIDS, which is not\n" "supported anymore. Consider removing the oid column using\n" " ALTER TABLE ... SET WITHOUT OIDS;\n" "A list of tables with the problem is in the file:\n" - " %s", output_path); + " %s", + output_path); } else check_ok(); } - /* * check_for_composite_data_type_usage() * Check for system-defined composite types used in user tables. @@ -1143,8 +1136,7 @@ check_for_composite_data_type_usage(ClusterInfo *cluster) prep_status("Checking for system-defined composite types in user tables"); - snprintf(output_path, sizeof(output_path), "%s/%s", - log_opts.basedir, + snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir, "tables_using_composite.txt"); /* @@ -1160,7 +1152,8 @@ check_for_composite_data_type_usage(ClusterInfo *cluster) */ firstUserOid = 16384; - base_query = psprintf("SELECT t.oid FROM pg_catalog.pg_type t " + base_query = psprintf( + "SELECT t.oid FROM pg_catalog.pg_type t " "LEFT JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid " " WHERE typtype = 'c' AND (t.oid < %u OR nspname = 'information_schema')", firstUserOid); @@ -1172,12 +1165,14 @@ check_for_composite_data_type_usage(ClusterInfo *cluster) if (found) { pg_log(PG_REPORT, "fatal"); - pg_fatal("Your installation contains system-defined composite types in user tables.\n" + pg_fatal("Your installation contains system-defined composite types in " + "user tables.\n" "These type OIDs are not stable across PostgreSQL versions,\n" "so this cluster cannot currently be upgraded. You can\n" "drop the problem columns and restart the upgrade.\n" "A list of the problem columns is in the file:\n" - " %s", output_path); + " %s", + output_path); } else check_ok(); @@ -1202,15 +1197,15 @@ check_for_reg_data_type_usage(ClusterInfo *cluster) prep_status("Checking for reg* data types in user tables"); - snprintf(output_path, sizeof(output_path), "%s/%s", - log_opts.basedir, + snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir, "tables_using_reg.txt"); /* * Note: older servers will not have all of these reg* types, so we have * to write the query like this rather than depending on casts to regtype. */ - found = check_for_data_types_usage(cluster, + found = check_for_data_types_usage( + cluster, "SELECT oid FROM pg_catalog.pg_type t " "WHERE t.typnamespace = " " (SELECT oid FROM pg_catalog.pg_namespace " @@ -1233,12 +1228,15 @@ check_for_reg_data_type_usage(ClusterInfo *cluster) if (found) { pg_log(PG_REPORT, "fatal"); - pg_fatal("Your installation contains one of the reg* data types in user tables.\n" + pg_fatal( + "Your installation contains one of the reg* data types in user " + "tables.\n" "These data types reference system OIDs that are not preserved by\n" "pg_upgrade, so this cluster cannot currently be upgraded. You can\n" "drop the problem columns and restart the upgrade.\n" "A list of the problem columns is in the file:\n" - " %s", output_path); + " %s", + output_path); } else check_ok(); @@ -1262,12 +1260,14 @@ check_for_aclitem_data_type_usage(ClusterInfo *cluster) if (check_for_data_type_usage(cluster, "pg_catalog.aclitem", output_path)) { pg_log(PG_REPORT, "fatal"); - pg_fatal("Your installation contains the \"aclitem\" data type in user tables.\n" + pg_fatal( + "Your installation contains the \"aclitem\" data type in user tables.\n" "The internal format of \"aclitem\" changed in PostgreSQL version 16\n" "so this cluster cannot currently be upgraded. You can drop the\n" "problem columns and restart the upgrade. A list of the problem\n" "columns is in the file:\n" - " %s", output_path); + " %s", + output_path); } else check_ok(); @@ -1280,34 +1280,34 @@ check_for_aclitem_data_type_usage(ClusterInfo *cluster) * the exact list. */ static void -check_for_removed_data_type_usage(ClusterInfo *cluster, const char *version, +check_for_removed_data_type_usage(ClusterInfo *cluster, + const char *version, const char *datatype) { char output_path[MAXPGPATH]; char typename[NAMEDATALEN]; - prep_status("Checking for removed \"%s\" data type in user tables", - datatype); + prep_status("Checking for removed \"%s\" data type in user tables", datatype); - snprintf(output_path, sizeof(output_path), "tables_using_%s.txt", - datatype); + snprintf(output_path, sizeof(output_path), "tables_using_%s.txt", datatype); snprintf(typename, sizeof(typename), "pg_catalog.%s", datatype); if (check_for_data_type_usage(cluster, typename, output_path)) { pg_log(PG_REPORT, "fatal"); - pg_fatal("Your installation contains the \"%s\" data type in user tables.\n" + pg_fatal( + "Your installation contains the \"%s\" data type in user tables.\n" "The \"%s\" type has been removed in PostgreSQL version %s,\n" "so this cluster cannot currently be upgraded. You can drop the\n" "problem columns, or change them to another data type, and restart\n" "the upgrade. A list of the problem columns is in the file:\n" - " %s", datatype, datatype, version, output_path); + " %s", + datatype, datatype, version, output_path); } else check_ok(); } - /* * check_for_jsonb_9_4_usage() * @@ -1320,19 +1320,20 @@ check_for_jsonb_9_4_usage(ClusterInfo *cluster) prep_status("Checking for incompatible \"jsonb\" data type"); - snprintf(output_path, sizeof(output_path), "%s/%s", - log_opts.basedir, + snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir, "tables_using_jsonb.txt"); if (check_for_data_type_usage(cluster, "pg_catalog.jsonb", output_path)) { pg_log(PG_REPORT, "fatal"); - pg_fatal("Your installation contains the \"jsonb\" data type in user tables.\n" + pg_fatal( + "Your installation contains the \"jsonb\" data type in user tables.\n" "The internal format of \"jsonb\" changed during 9.4 beta so this\n" "cluster cannot currently be upgraded. You can\n" "drop the problem columns and restart the upgrade.\n" "A list of the problem columns is in the file:\n" - " %s", output_path); + " %s", + output_path); } else check_ok(); @@ -1356,12 +1357,10 @@ check_for_pg_role_prefix(ClusterInfo *cluster) prep_status("Checking for roles starting with \"pg_\""); - snprintf(output_path, sizeof(output_path), "%s/%s", - log_opts.basedir, + snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir, "pg_role_prefix.txt"); - res = executeQueryOrDie(conn, - "SELECT oid AS roloid, rolname " + res = executeQueryOrDie(conn, "SELECT oid AS roloid, rolname " "FROM pg_catalog.pg_roles " "WHERE rolname ~ '^pg_'"); @@ -1371,10 +1370,8 @@ check_for_pg_role_prefix(ClusterInfo *cluster) for (int rowno = 0; rowno < ntups; rowno++) { if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("could not open file \"%s\": %s", - output_path, strerror(errno)); - fprintf(script, "%s (oid=%s)\n", - PQgetvalue(res, rowno, i_rolname), + pg_fatal("could not open file \"%s\": %s", output_path, strerror(errno)); + fprintf(script, "%s (oid=%s)\n", PQgetvalue(res, rowno, i_rolname), PQgetvalue(res, rowno, i_roloid)); } @@ -1390,7 +1387,8 @@ check_for_pg_role_prefix(ClusterInfo *cluster) "\"pg_\" is a reserved prefix for system roles. The cluster\n" "cannot be upgraded until these roles are renamed.\n" "A list of roles starting with \"pg_\" is in the file:\n" - " %s", output_path); + " %s", + output_path); } else check_ok(); @@ -1408,8 +1406,7 @@ check_for_user_defined_encoding_conversions(ClusterInfo *cluster) prep_status("Checking for user-defined encoding conversions"); - snprintf(output_path, sizeof(output_path), "%s/%s", - log_opts.basedir, + snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir, "encoding_conversions.txt"); /* Find any user defined encoding conversions */ @@ -1431,29 +1428,27 @@ check_for_user_defined_encoding_conversions(ClusterInfo *cluster) * #define is ever changed, the cutoff we want to use is the value * used by pre-version 14 servers, not that of some future version. */ - res = executeQueryOrDie(conn, - "SELECT c.oid as conoid, c.conname, n.nspname " - "FROM pg_catalog.pg_conversion c, " - " pg_catalog.pg_namespace n " - "WHERE c.connamespace = n.oid AND " - " c.oid >= 16384"); + res = + executeQueryOrDie(conn, "SELECT c.oid as conoid, c.conname, n.nspname " + "FROM pg_catalog.pg_conversion c, " + " pg_catalog.pg_namespace n " + "WHERE c.connamespace = n.oid AND " + " c.oid >= 16384"); ntups = PQntuples(res); i_conoid = PQfnumber(res, "conoid"); i_conname = PQfnumber(res, "conname"); i_nspname = PQfnumber(res, "nspname"); for (rowno = 0; rowno < ntups; rowno++) { - if (script == NULL && - (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("could not open file \"%s\": %s", - output_path, strerror(errno)); + if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) + pg_fatal("could not open file \"%s\": %s", output_path, + strerror(errno)); if (!db_used) { fprintf(script, "In database: %s\n", active_db->db_name); db_used = true; } - fprintf(script, " (oid=%s) %s.%s\n", - PQgetvalue(res, rowno, i_conoid), + fprintf(script, " (oid=%s) %s.%s\n", PQgetvalue(res, rowno, i_conoid), PQgetvalue(res, rowno, i_nspname), PQgetvalue(res, rowno, i_conname)); } @@ -1467,12 +1462,14 @@ check_for_user_defined_encoding_conversions(ClusterInfo *cluster) { fclose(script); pg_log(PG_REPORT, "fatal"); - pg_fatal("Your installation contains user-defined encoding conversions.\n" + pg_fatal( + "Your installation contains user-defined encoding conversions.\n" "The conversion function parameters changed in PostgreSQL version 14\n" "so this cluster cannot currently be upgraded. You can remove the\n" "encoding conversions in the old cluster and restart the upgrade.\n" "A list of user-defined encoding conversions is in the file:\n" - " %s", output_path); + " %s", + output_path); } else check_ok(); @@ -1524,7 +1521,8 @@ check_new_cluster_logical_replication_slots(void) PQclear(res); - res = executeQueryOrDie(conn, "SELECT setting FROM pg_settings " + res = executeQueryOrDie( + conn, "SELECT setting FROM pg_settings " "WHERE name IN ('wal_level', 'max_replication_slots') " "ORDER BY name DESC;"); @@ -1534,13 +1532,13 @@ check_new_cluster_logical_replication_slots(void) wal_level = PQgetvalue(res, 0, 0); if (strcmp(wal_level, "logical") != 0) - pg_fatal("wal_level must be \"logical\", but is set to \"%s\"", - wal_level); + pg_fatal("wal_level must be \"logical\", but is set to \"%s\"", wal_level); max_replication_slots = atoi(PQgetvalue(res, 1, 0)); if (nslots_on_old > max_replication_slots) - pg_fatal("max_replication_slots (%d) must be greater than or equal to the number of " + pg_fatal("max_replication_slots (%d) must be greater than or equal to the " + "number of " "logical replication slots (%d) on the old cluster", max_replication_slots, nslots_on_old); @@ -1587,7 +1585,8 @@ check_new_cluster_subscription_configuration(void) max_replication_slots = atoi(PQgetvalue(res, 0, 0)); if (nsubs_on_old > max_replication_slots) - pg_fatal("max_replication_slots (%d) must be greater than or equal to the number of " + pg_fatal("max_replication_slots (%d) must be greater than or equal to the " + "number of " "subscriptions (%d) on the old cluster", max_replication_slots, nsubs_on_old); @@ -1611,8 +1610,7 @@ check_old_cluster_for_valid_slots(bool live_check) prep_status("Checking for valid logical replication slots"); - snprintf(output_path, sizeof(output_path), "%s/%s", - log_opts.basedir, + snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir, "invalid_logical_slots.txt"); for (int dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++) @@ -1626,13 +1624,11 @@ check_old_cluster_for_valid_slots(bool live_check) /* Is the slot usable? */ if (slot->invalid) { - if (script == NULL && - (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("could not open file \"%s\": %s", - output_path, strerror(errno)); + if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) + pg_fatal("could not open file \"%s\": %s", output_path, + strerror(errno)); - fprintf(script, "The slot \"%s\" is invalid\n", - slot->slotname); + fprintf(script, "The slot \"%s\" is invalid\n", slot->slotname); continue; } @@ -1646,13 +1642,11 @@ check_old_cluster_for_valid_slots(bool live_check) */ if (!live_check && !slot->caught_up) { - if (script == NULL && - (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("could not open file \"%s\": %s", - output_path, strerror(errno)); + if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) + pg_fatal("could not open file \"%s\": %s", output_path, + strerror(errno)); - fprintf(script, - "The slot \"%s\" has not consumed the WAL yet\n", + fprintf(script, "The slot \"%s\" has not consumed the WAL yet\n", slot->slotname); } } @@ -1663,11 +1657,14 @@ check_old_cluster_for_valid_slots(bool live_check) fclose(script); pg_log(PG_REPORT, "fatal"); - pg_fatal("Your installation contains logical replication slots that can't be upgraded.\n" - "You can remove invalid slots and/or consume the pending WAL for other slots,\n" + pg_fatal("Your installation contains logical replication slots that can't " + "be upgraded.\n" + "You can remove invalid slots and/or consume the pending WAL for " + "other slots,\n" "and then restart the upgrade.\n" "A list of the problematic slots is in the file:\n" - " %s", output_path); + " %s", + output_path); } check_ok(); @@ -1689,8 +1686,7 @@ check_old_cluster_subscription_state(void) prep_status("Checking for subscription state"); - snprintf(output_path, sizeof(output_path), "%s/%s", - log_opts.basedir, + snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir, "subs_invalid.txt"); for (int dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++) { @@ -1705,8 +1701,8 @@ check_old_cluster_subscription_state(void) * Check that all the subscriptions have their respective * replication origin. */ - res = executeQueryOrDie(conn, - "SELECT d.datname, s.subname " + res = executeQueryOrDie( + conn, "SELECT d.datname, s.subname " "FROM pg_catalog.pg_subscription s " "LEFT OUTER JOIN pg_catalog.pg_replication_origin o " " ON o.roname = 'pg_' || s.oid " @@ -1718,11 +1714,12 @@ check_old_cluster_subscription_state(void) for (int i = 0; i < ntup; i++) { if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("could not open file \"%s\": %s", - output_path, strerror(errno)); - fprintf(script, "The replication origin is missing for database:\"%s\" subscription:\"%s\"\n", - PQgetvalue(res, i, 0), - PQgetvalue(res, i, 1)); + pg_fatal("could not open file \"%s\": %s", output_path, + strerror(errno)); + fprintf(script, + "The replication origin is missing for database:\"%s\" " + "subscription:\"%s\"\n", + PQgetvalue(res, i, 0), PQgetvalue(res, i, 1)); } PQclear(res); } @@ -1755,8 +1752,8 @@ check_old_cluster_subscription_state(void) * SUBREL_STATE_UNKNOWN: These states are not stored in the catalog, * so we need not allow these states. */ - res = executeQueryOrDie(conn, - "SELECT r.srsubstate, s.subname, n.nspname, c.relname " + res = executeQueryOrDie( + conn, "SELECT r.srsubstate, s.subname, n.nspname, c.relname " "FROM pg_catalog.pg_subscription_rel r " "LEFT JOIN pg_catalog.pg_subscription s" " ON r.srsubid = s.oid " @@ -1771,15 +1768,14 @@ check_old_cluster_subscription_state(void) for (int i = 0; i < ntup; i++) { if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("could not open file \"%s\": %s", - output_path, strerror(errno)); - - fprintf(script, "The table sync state \"%s\" is not allowed for database:\"%s\" subscription:\"%s\" schema:\"%s\" relation:\"%s\"\n", - PQgetvalue(res, i, 0), - active_db->db_name, - PQgetvalue(res, i, 1), - PQgetvalue(res, i, 2), - PQgetvalue(res, i, 3)); + pg_fatal("could not open file \"%s\": %s", output_path, + strerror(errno)); + + fprintf(script, + "The table sync state \"%s\" is not allowed for database:\"%s\" " + "subscription:\"%s\" schema:\"%s\" relation:\"%s\"\n", + PQgetvalue(res, i, 0), active_db->db_name, PQgetvalue(res, i, 1), + PQgetvalue(res, i, 2), PQgetvalue(res, i, 3)); } PQclear(res); @@ -1790,10 +1786,13 @@ check_old_cluster_subscription_state(void) { fclose(script); pg_log(PG_REPORT, "fatal"); - pg_fatal("Your installation contains subscriptions without origin or having relations not in i (initialize) or r (ready) state.\n" - "You can allow the initial sync to finish for all relations and then restart the upgrade.\n" + pg_fatal("Your installation contains subscriptions without origin or " + "having relations not in i (initialize) or r (ready) state.\n" + "You can allow the initial sync to finish for all relations and " + "then restart the upgrade.\n" "A list of the problematic subscriptions is in the file:\n" - " %s", output_path); + " %s", + output_path); } else check_ok(); diff --git a/src/bin/pg_upgrade/file.c b/src/bin/pg_upgrade/file.c index f91cc548ce..7272c7fdb7 100644 --- a/src/bin/pg_upgrade/file.c +++ b/src/bin/pg_upgrade/file.c @@ -37,6 +37,23 @@ cloneFile(const char *src, const char *dst, const char *schemaName, pg_copyfile_offload(src, dst, action, PG_COPYFILE_IOCTL_FICLONE); } +/* + * copyFileByRange() + * + * Copies a relation file from src to dst. + * schemaName/relName are relation's SQL name (used for error messages only). + */ +void +copyFileByRange(const char *src, const char *dst, const char *schemaName, + const char *relName) +{ + char action[1024]; + + snprintf(action, sizeof(action) - 1, "relation \"%s.%s\"", schemaName, + relName); + pg_copyfile_offload(src, dst, action, PG_COPYFILE_COPY_FILE_RANGE); +} + /* * copyFile() * @@ -264,6 +281,23 @@ check_file_clone(void) PG_COPYFILE_IOCTL_FICLONE); } +void +check_copy_file_range(void) +{ + char existing_file[MAXPGPATH]; + char new_link_file[MAXPGPATH]; + + snprintf(existing_file, sizeof(existing_file), "%s/PG_VERSION", + old_cluster.pgdata); + snprintf(new_link_file, sizeof(new_link_file), + "%s/PG_VERSION.copy_file_range_test", new_cluster.pgdata); + unlink(new_link_file); /* might fail */ + + /* will throw error in case it is not supported */ + pg_copyfile_offload_supported(existing_file, new_link_file, NULL, + PG_COPYFILE_COPY_FILE_RANGE); +} + void check_hard_link(void) { @@ -278,7 +312,8 @@ check_hard_link(void) if (link(existing_file, new_link_file) < 0) pg_fatal( - "could not create hard link between old and new data directories: %s\n" + "could not create hard link between old and new data directories: " + "%s\n" "In link mode the old and new data directories must be on the same " "file system.", strerror(errno)); diff --git a/src/bin/pg_upgrade/option.c b/src/bin/pg_upgrade/option.c index b9d900d0db..9e992c7bbf 100644 --- a/src/bin/pg_upgrade/option.c +++ b/src/bin/pg_upgrade/option.c @@ -20,16 +20,13 @@ #include "utils/pidfile.h" static void usage(void); -static void check_required_directory(char **dirpath, - const char *envVarName, bool useCwd, - const char *cmdLineOption, const char *description, - bool missingOk); +static void check_required_directory(char **dirpath, const char *envVarName, + bool useCwd, const char *cmdLineOption, + const char *description, bool missingOk); #define FIX_DEFAULT_READ_ONLY "-c default_transaction_read_only=false" - UserOpts user_opts; - /* * parseCommandLine() * @@ -59,9 +56,9 @@ parseCommandLine(int argc, char *argv[]) {"clone", no_argument, NULL, 1}, {"copy", no_argument, NULL, 2}, {"sync-method", required_argument, NULL, 3}, + {"copy-file-range", no_argument, NULL, 3}, - {NULL, 0, NULL, 0} - }; + {NULL, 0, NULL, 0}}; int option; /* Command line option */ int optindex = 0; /* used by getopt_long */ int os_user_effective_id; @@ -73,8 +70,10 @@ parseCommandLine(int argc, char *argv[]) os_info.progname = get_progname(argv[0]); /* Process libpq env. variables; load values here for usage() output */ - old_cluster.port = getenv("PGPORTOLD") ? atoi(getenv("PGPORTOLD")) : DEF_PGUPORT; - new_cluster.port = getenv("PGPORTNEW") ? atoi(getenv("PGPORTNEW")) : DEF_PGUPORT; + old_cluster.port = + getenv("PGPORTOLD") ? atoi(getenv("PGPORTOLD")) : DEF_PGUPORT; + new_cluster.port = + getenv("PGPORTNEW") ? atoi(getenv("PGPORTNEW")) : DEF_PGUPORT; os_user_effective_id = get_user_info(&os_info.user); /* we override just the database user name; we got the OS id above */ @@ -197,12 +196,13 @@ parseCommandLine(int argc, char *argv[]) case 1: user_opts.transfer_mode = TRANSFER_MODE_CLONE; break; - case 2: user_opts.transfer_mode = TRANSFER_MODE_COPY; break; - case 3: + user_opts.transfer_mode = TRANSFER_MODE_COPY_FILE_RANGE; + break; + case 4: if (!parse_sync_method(optarg, &unused)) exit(1); user_opts.sync_method = pg_strdup(optarg); @@ -229,8 +229,8 @@ parseCommandLine(int argc, char *argv[]) /* Turn off read-only mode; add prefix to PGOPTIONS? */ if (getenv("PGOPTIONS")) { - char *pgoptions = psprintf("%s %s", FIX_DEFAULT_READ_ONLY, - getenv("PGOPTIONS")); + char *pgoptions = + psprintf("%s %s", FIX_DEFAULT_READ_ONLY, getenv("PGOPTIONS")); setenv("PGOPTIONS", pgoptions, 1); pfree(pgoptions); @@ -239,16 +239,16 @@ parseCommandLine(int argc, char *argv[]) setenv("PGOPTIONS", FIX_DEFAULT_READ_ONLY, 1); /* Get values from env if not already set */ - check_required_directory(&old_cluster.bindir, "PGBINOLD", false, - "-b", _("old cluster binaries reside"), false); - check_required_directory(&new_cluster.bindir, "PGBINNEW", false, - "-B", _("new cluster binaries reside"), true); - check_required_directory(&old_cluster.pgdata, "PGDATAOLD", false, - "-d", _("old cluster data resides"), false); - check_required_directory(&new_cluster.pgdata, "PGDATANEW", false, - "-D", _("new cluster data resides"), false); - check_required_directory(&user_opts.socketdir, "PGSOCKETDIR", true, - "-s", _("sockets will be created"), false); + check_required_directory(&old_cluster.bindir, "PGBINOLD", false, "-b", + _("old cluster binaries reside"), false); + check_required_directory(&new_cluster.bindir, "PGBINNEW", false, "-B", + _("new cluster binaries reside"), true); + check_required_directory(&old_cluster.pgdata, "PGDATAOLD", false, "-d", + _("old cluster data resides"), false); + check_required_directory(&new_cluster.pgdata, "PGDATANEW", false, "-D", + _("new cluster data resides"), false); + check_required_directory(&user_opts.socketdir, "PGSOCKETDIR", true, "-s", + _("sockets will be created"), false); #ifdef WIN32 @@ -268,47 +268,73 @@ parseCommandLine(int argc, char *argv[]) pg_fatal("could not determine current directory"); canonicalize_path(cwd); if (path_is_prefix_of_path(new_cluster_pgdata, cwd)) - pg_fatal("cannot run pg_upgrade from inside the new cluster data directory on Windows"); + pg_fatal("cannot run pg_upgrade from inside the new cluster data " + "directory on Windows"); } #endif } - static void usage(void) { - printf(_("pg_upgrade upgrades a PostgreSQL cluster to a different major version.\n\n")); + printf(_("pg_upgrade upgrades a PostgreSQL cluster to a different major " + "version.\n\n")); printf(_("Usage:\n")); printf(_(" pg_upgrade [OPTION]...\n\n")); printf(_("Options:\n")); - printf(_(" -b, --old-bindir=BINDIR old cluster executable directory\n")); - printf(_(" -B, --new-bindir=BINDIR new cluster executable directory (default\n" + printf( + _(" -b, --old-bindir=BINDIR old cluster executable directory\n")); + printf(_(" -B, --new-bindir=BINDIR new cluster executable directory " + "(default\n" " same directory as pg_upgrade)\n")); - printf(_(" -c, --check check clusters only, don't change any data\n")); + printf(_(" -c, --check check clusters only, don't change " + "any data\n")); printf(_(" -d, --old-datadir=DATADIR old cluster data directory\n")); printf(_(" -D, --new-datadir=DATADIR new cluster data directory\n")); - printf(_(" -j, --jobs=NUM number of simultaneous processes or threads to use\n")); - printf(_(" -k, --link link instead of copying files to new cluster\n")); - printf(_(" -N, --no-sync do not wait for changes to be written safely to disk\n")); - printf(_(" -o, --old-options=OPTIONS old cluster options to pass to the server\n")); - printf(_(" -O, --new-options=OPTIONS new cluster options to pass to the server\n")); - printf(_(" -p, --old-port=PORT old cluster port number (default %d)\n"), old_cluster.port); - printf(_(" -P, --new-port=PORT new cluster port number (default %d)\n"), new_cluster.port); - printf(_(" -r, --retain retain SQL and log files after success\n")); - printf(_(" -s, --socketdir=DIR socket directory to use (default current dir.)\n")); - printf(_(" -U, --username=NAME cluster superuser (default \"%s\")\n"), os_info.user); - printf(_(" -v, --verbose enable verbose internal logging\n")); - printf(_(" -V, --version display version information, then exit\n")); - printf(_(" --clone clone instead of copying files to new cluster\n")); - printf(_(" --copy copy files to new cluster (default)\n")); - printf(_(" --sync-method=METHOD set method for syncing files to disk\n")); + printf(_(" -j, --jobs=NUM number of simultaneous processes " + "or threads to use\n")); + printf(_(" -k, --link link instead of copying files to " + "new cluster\n")); + printf(_(" -N, --no-sync do not wait for changes to be " + "written safely to disk\n")); + printf(_(" -o, --old-options=OPTIONS old cluster options to pass to the " + "server\n")); + printf(_(" -O, --new-options=OPTIONS new cluster options to pass to the " + "server\n")); + printf(_(" -p, --old-port=PORT old cluster port number (default " + "%d)\n"), + old_cluster.port); + printf(_(" -P, --new-port=PORT new cluster port number (default " + "%d)\n"), + new_cluster.port); + printf(_(" -r, --retain retain SQL and log files after " + "success\n")); + printf(_(" -s, --socketdir=DIR socket directory to use (default " + "current dir.)\n")); + printf( + _(" -U, --username=NAME cluster superuser (default \"%s\")\n"), + os_info.user); + printf( + _(" -v, --verbose enable verbose internal logging\n")); + printf(_(" -V, --version display version information, then " + "exit\n")); + printf(_(" --clone clone instead of copying files to " + "new cluster\n")); + printf(_( + " --copy copy files to new cluster (default)\n")); + printf(_(" --copy-file-range copy files to new cluster with " + "copy_file_range()\n")); + + printf(_(" --sync-method=METHOD set method for syncing files to " + "disk\n")); printf(_(" -?, --help show this help, then exit\n")); printf(_("\n" "Before running pg_upgrade you must:\n" " create a new database cluster (using the new version of initdb)\n" " shutdown the postmaster servicing the old cluster\n" " shutdown the postmaster servicing the new cluster\n")); - printf(_("\n" + printf( + _("\n" "When you run pg_upgrade, you must provide the following information:\n" " the data directory for the old cluster (-d DATADIR)\n" " the data directory for the new cluster (-D DATADIR)\n" @@ -316,7 +342,8 @@ usage(void) " the \"bin\" directory for the new version (-B BINDIR)\n")); printf(_("\n" "For example:\n" - " pg_upgrade -d oldCluster/data -D newCluster/data -b oldCluster/bin -B newCluster/bin\n" + " pg_upgrade -d oldCluster/data -D newCluster/data -b " + "oldCluster/bin -B newCluster/bin\n" "or\n")); #ifndef WIN32 printf(_(" $ export PGDATAOLD=oldCluster/data\n" @@ -335,25 +362,25 @@ usage(void) printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL); } - /* * check_required_directory() * * Checks a directory option. - * dirpath - the directory name supplied on the command line, or NULL - * envVarName - the name of an environment variable to get if dirpath is NULL - * useCwd - true if OK to default to CWD + * dirpath - the directory name supplied on the command line, or + *NULL envVarName - the name of an environment variable to get if + *dirpath is NULL useCwd - true if OK to default to CWD * cmdLineOption - the command line option for this directory * description - a description of this directory option - * missingOk - true if OK that both dirpath and envVarName are not existing + * missingOk - true if OK that both dirpath and envVarName are not + *existing * * We use the last two arguments to construct a meaningful error message if the * user hasn't provided the required directory name. */ static void -check_required_directory(char **dirpath, const char *envVarName, bool useCwd, - const char *cmdLineOption, const char *description, - bool missingOk) +check_required_directory(char **dirpath, const char *envVarName, + bool useCwd, const char *cmdLineOption, + const char *description, bool missingOk) { if (*dirpath == NULL || strlen(*dirpath) == 0) { @@ -373,7 +400,8 @@ check_required_directory(char **dirpath, const char *envVarName, bool useCwd, return; else pg_fatal("You must identify the directory where the %s.\n" - "Please use the %s command-line option or the %s environment variable.", + "Please use the %s command-line option or the %s environment " + "variable.", description, cmdLineOption, envVarName); } @@ -440,13 +468,12 @@ adjust_data_dir(ClusterInfo *cluster) if ((output = popen(cmd, "r")) == NULL || fgets(cmd_output, sizeof(cmd_output), output) == NULL) - pg_fatal("could not get data directory using %s: %s", - cmd, strerror(errno)); + pg_fatal("could not get data directory using %s: %s", cmd, strerror(errno)); rc = pclose(output); if (rc != 0) - pg_fatal("could not get data directory using %s: %s", - cmd, wait_result_to_str(rc)); + pg_fatal("could not get data directory using %s: %s", cmd, + wait_result_to_str(rc)); /* strip trailing newline and carriage return */ (void) pg_strip_crlf(cmd_output); @@ -456,7 +483,6 @@ adjust_data_dir(ClusterInfo *cluster) check_ok(); } - /* * get_sock_dir * @@ -483,19 +509,17 @@ get_sock_dir(ClusterInfo *cluster, bool live_check) FILE *fp; int lineno; - snprintf(filename, sizeof(filename), "%s/postmaster.pid", - cluster->pgdata); + snprintf(filename, sizeof(filename), "%s/postmaster.pid", cluster->pgdata); if ((fp = fopen(filename, "r")) == NULL) - pg_fatal("could not open file \"%s\": %s", - filename, strerror(errno)); + pg_fatal("could not open file \"%s\": %s", filename, strerror(errno)); for (lineno = 1; lineno <= Max(LOCK_FILE_LINE_PORT, LOCK_FILE_LINE_SOCKET_DIR); lineno++) { if (fgets(line, sizeof(line), fp) == NULL) - pg_fatal("could not read line %d from file \"%s\": %s", - lineno, filename, strerror(errno)); + pg_fatal("could not read line %d from file \"%s\": %s", lineno, + filename, strerror(errno)); /* potentially overwrite user-supplied value */ if (lineno == LOCK_FILE_LINE_PORT) diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h index d63f13fffc..f993d7255e 100644 --- a/src/bin/pg_upgrade/pg_upgrade.h +++ b/src/bin/pg_upgrade/pg_upgrade.h @@ -5,10 +5,10 @@ * src/bin/pg_upgrade/pg_upgrade.h */ -#include #include #include #include +#include #include "common/relpath.h" #include "libpq-fe.h" @@ -17,18 +17,18 @@ #undef pg_fatal /* Use port in the private/dynamic port number range */ -#define DEF_PGUPORT 50432 +#define DEF_PGUPORT 50432 -#define MAX_STRING 1024 -#define QUERY_ALLOC 8192 +#define MAX_STRING 1024 +#define QUERY_ALLOC 8192 -#define MESSAGE_WIDTH 62 +#define MESSAGE_WIDTH 62 -#define GET_MAJOR_VERSION(v) ((v) / 100) +#define GET_MAJOR_VERSION(v) ((v) / 100) /* contains both global db information and CREATE DATABASE commands */ -#define GLOBALS_DUMP_FILE "pg_upgrade_dump_globals.sql" -#define DB_DUMP_FILE_MASK "pg_upgrade_dump_%u.custom" +#define GLOBALS_DUMP_FILE "pg_upgrade_dump_globals.sql" +#define DB_DUMP_FILE_MASK "pg_upgrade_dump_%u.custom" /* * Base directories that include all the files generated internally, from the @@ -36,14 +36,14 @@ * BASE_OUTPUTDIR/$timestamp/{LOG_OUTPUTDIR,DUMP_OUTPUTDIR} to ensure their * uniqueness in each run. */ -#define BASE_OUTPUTDIR "pg_upgrade_output.d" -#define LOG_OUTPUTDIR "log" -#define DUMP_OUTPUTDIR "dump" +#define BASE_OUTPUTDIR "pg_upgrade_output.d" +#define LOG_OUTPUTDIR "log" +#define DUMP_OUTPUTDIR "dump" -#define DB_DUMP_LOG_FILE_MASK "pg_upgrade_dump_%u.log" -#define SERVER_LOG_FILE "pg_upgrade_server.log" -#define UTILITY_LOG_FILE "pg_upgrade_utility.log" -#define INTERNAL_LOG_FILE "pg_upgrade_internal.log" +#define DB_DUMP_LOG_FILE_MASK "pg_upgrade_dump_%u.log" +#define SERVER_LOG_FILE "pg_upgrade_server.log" +#define UTILITY_LOG_FILE "pg_upgrade_utility.log" +#define INTERNAL_LOG_FILE "pg_upgrade_internal.log" extern char *output_files[]; @@ -64,44 +64,42 @@ extern char *output_files[]; * the error message appropriately. */ #ifndef WIN32 -#define SERVER_START_LOG_FILE SERVER_LOG_FILE -#define SERVER_STOP_LOG_FILE SERVER_LOG_FILE +#define SERVER_START_LOG_FILE SERVER_LOG_FILE +#define SERVER_STOP_LOG_FILE SERVER_LOG_FILE #else -#define SERVER_START_LOG_FILE "pg_upgrade_server_start.log" +#define SERVER_START_LOG_FILE "pg_upgrade_server_start.log" /* * "pg_ctl start" keeps SERVER_START_LOG_FILE and SERVER_LOG_FILE open * while the server is running, so we use UTILITY_LOG_FILE for "pg_ctl * stop". */ -#define SERVER_STOP_LOG_FILE UTILITY_LOG_FILE +#define SERVER_STOP_LOG_FILE UTILITY_LOG_FILE #endif - #ifndef WIN32 -#define pg_mv_file rename -#define PATH_SEPARATOR '/' -#define PATH_QUOTE '\'' -#define RM_CMD "rm -f" -#define RMDIR_CMD "rm -rf" -#define SCRIPT_PREFIX "./" -#define SCRIPT_EXT "sh" -#define ECHO_QUOTE "'" -#define ECHO_BLANK "" +#define pg_mv_file rename +#define PATH_SEPARATOR '/' +#define PATH_QUOTE '\'' +#define RM_CMD "rm -f" +#define RMDIR_CMD "rm -rf" +#define SCRIPT_PREFIX "./" +#define SCRIPT_EXT "sh" +#define ECHO_QUOTE "'" +#define ECHO_BLANK "" #else -#define pg_mv_file pgrename -#define PATH_SEPARATOR '\\' -#define PATH_QUOTE '"' +#define pg_mv_file pgrename +#define PATH_SEPARATOR '\\' +#define PATH_QUOTE '"' /* @ prefix disables command echo in .bat files */ -#define RM_CMD "@DEL /q" -#define RMDIR_CMD "@RMDIR /s/q" -#define SCRIPT_PREFIX "" -#define SCRIPT_EXT "bat" -#define EXE_EXT ".exe" -#define ECHO_QUOTE "" -#define ECHO_BLANK "." +#define RM_CMD "@DEL /q" +#define RMDIR_CMD "@RMDIR /s/q" +#define SCRIPT_PREFIX "" +#define SCRIPT_EXT "bat" +#define EXE_EXT ".exe" +#define ECHO_QUOTE "" +#define ECHO_BLANK "." #endif - /* * The format of visibility map was changed with this 9.6 commit. */ @@ -126,7 +124,6 @@ extern char *output_files[]; */ #define JSONB_FORMAT_CHANGE_CAT_VER 201409291 - /* * Each relation is represented by a relinfo structure. */ @@ -255,6 +252,7 @@ typedef enum TRANSFER_MODE_CLONE, TRANSFER_MODE_COPY, TRANSFER_MODE_LINK, + TRANSFER_MODE_COPY_FILE_RANGE, } transferMode; /* @@ -270,7 +268,6 @@ typedef enum PG_FATAL, } eLogType; - /* * cluster * @@ -295,10 +292,9 @@ typedef struct const char *tablespace_suffix; /* directory specification */ } ClusterInfo; - /* * LogOpts -*/ + */ typedef struct { FILE *internal; /* internal log FILE */ @@ -312,10 +308,9 @@ typedef struct bool isatty; /* is stdout a tty */ } LogOpts; - /* * UserOpts -*/ + */ typedef struct { bool check; /* true -> ask user for permission to make @@ -348,7 +343,6 @@ typedef struct ClusterInfo *running_cluster; } OSInfo; - /* * Global variables */ @@ -358,7 +352,6 @@ extern ClusterInfo old_cluster, new_cluster; extern OSInfo os_info; - /* check.c */ void output_check_banner(bool live_check); @@ -371,44 +364,45 @@ void check_cluster_versions(void); void check_cluster_compatibility(bool live_check); void create_script_for_old_cluster_deletion(char **deletion_script_file_name); - /* controldata.c */ void get_control_data(ClusterInfo *cluster, bool live_check); void check_control_data(ControlData *oldctrl, ControlData *newctrl); void disable_old_cluster(void); - /* dump.c */ void generate_old_dump(void); - /* exec.c */ -#define EXEC_PSQL_ARGS "--echo-queries --set ON_ERROR_STOP=on --no-psqlrc --dbname=template1" +#define EXEC_PSQL_ARGS \ + "--echo-queries --set ON_ERROR_STOP=on --no-psqlrc --dbname=template1" bool exec_prog(const char *log_filename, const char *opt_log_file, - bool report_error, bool exit_on_error, const char *fmt,...) pg_attribute_printf(5, 6); + bool report_error, bool exit_on_error, const char *fmt,...) + pg_attribute_printf(5, 6); void verify_directories(void); bool pid_lock_file_exists(const char *datadir); - /* file.c */ -void cloneFile(const char *src, const char *dst, - const char *schemaName, const char *relName); -void copyFile(const char *src, const char *dst, - const char *schemaName, const char *relName); -void linkFile(const char *src, const char *dst, - const char *schemaName, const char *relName); +void cloneFile(const char *src, const char *dst, const char *schemaName, + const char *relName); +void copyFile(const char *src, const char *dst, const char *schemaName, + const char *relName); +void copyFileByRange(const char *src, const char *dst, const char *schemaName, + const char *relName); +void linkFile(const char *src, const char *dst, const char *schemaName, + const char *relName); void rewriteVisibilityMap(const char *fromfile, const char *tofile, const char *schemaName, const char *relName); void check_file_clone(void); +void check_copy_file_range(void); void check_hard_link(void); /* fopen_priv() is no longer different from fopen() */ -#define fopen_priv(path, mode) fopen(path, mode) +#define fopen_priv(path, mode) fopen(path, mode) /* function.c */ @@ -417,9 +411,8 @@ void check_loadable_libraries(void); /* info.c */ -FileNameMap *gen_db_file_maps(DbInfo *old_db, - DbInfo *new_db, int *nmaps, const char *old_pgdata, - const char *new_pgdata); +FileNameMap *gen_db_file_maps(DbInfo *old_db, DbInfo *new_db, int *nmaps, + const char *old_pgdata, const char *new_pgdata); void get_db_rel_and_slot_infos(ClusterInfo *cluster, bool live_check); int count_old_cluster_logical_slots(void); int count_old_cluster_subscriptions(void); @@ -432,21 +425,21 @@ void get_sock_dir(ClusterInfo *cluster, bool live_check); /* relfilenumber.c */ -void transfer_all_new_tablespaces(DbInfoArr *old_db_arr, - DbInfoArr *new_db_arr, char *old_pgdata, char *new_pgdata); -void transfer_all_new_dbs(DbInfoArr *old_db_arr, - DbInfoArr *new_db_arr, char *old_pgdata, char *new_pgdata, +void transfer_all_new_tablespaces(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr, + char *old_pgdata, char *new_pgdata); +void transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr, + char *old_pgdata, char *new_pgdata, char *old_tablespace); /* tablespace.c */ void init_tablespaces(void); - /* server.c */ PGconn *connectToServer(ClusterInfo *cluster, const char *db_name); -PGresult *executeQueryOrDie(PGconn *conn, const char *fmt,...) pg_attribute_printf(2, 3); +PGresult *executeQueryOrDie(PGconn *conn, const char *fmt,...) + pg_attribute_printf(2, 3); char *cluster_conn_opts(ClusterInfo *cluster); @@ -455,34 +448,31 @@ void stop_postmaster(bool in_atexit); uint32 get_major_server_version(ClusterInfo *cluster); void check_pghost_envvar(void); - /* util.c */ char *quote_identifier(const char *s); int get_user_info(char **user_name_p); void check_ok(void); -void report_status(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3); +void report_status(eLogType type, const char *fmt,...) + pg_attribute_printf(2, 3); void pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3); -void pg_fatal(const char *fmt,...) pg_attribute_printf(1, 2) pg_attribute_noreturn(); +void pg_fatal(const char *fmt,...) pg_attribute_printf(1, 2) + pg_attribute_noreturn(); void end_progress_output(void); void cleanup_output_dirs(void); void prep_status(const char *fmt,...) pg_attribute_printf(1, 2); void prep_status_progress(const char *fmt,...) pg_attribute_printf(1, 2); unsigned int str2uint(const char *str); - /* version.c */ -bool check_for_data_types_usage(ClusterInfo *cluster, - const char *base_query, +bool check_for_data_types_usage(ClusterInfo *cluster, const char *base_query, const char *output_path); -bool check_for_data_type_usage(ClusterInfo *cluster, - const char *type_name, +bool check_for_data_type_usage(ClusterInfo *cluster, const char *type_name, const char *output_path); void old_9_3_check_for_line_data_type_usage(ClusterInfo *cluster); void old_9_6_check_for_unknown_data_type_usage(ClusterInfo *cluster); -void old_9_6_invalidate_hash_indexes(ClusterInfo *cluster, - bool check_mode); +void old_9_6_invalidate_hash_indexes(ClusterInfo *cluster, bool check_mode); void old_11_check_for_sql_identifier_data_type_usage(ClusterInfo *cluster); void report_extension_updates(ClusterInfo *cluster); -- 2.30.2