diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2024-04-01 16:46:24 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2024-04-01 16:46:24 -0400 |
commit | 959b38d770ba1f8f35edab27ef3ccf8b1d99f5dd (patch) | |
tree | e1396f20b9672178d2ff3d452851078bc7b12202 /src/bin/pg_upgrade/pg_upgrade.c | |
parent | a45c78e3284b269085e9a0cbd0ea3b236b7180fa (diff) | |
download | postgresql-959b38d770ba1f8f35edab27ef3ccf8b1d99f5dd.tar.gz postgresql-959b38d770ba1f8f35edab27ef3ccf8b1d99f5dd.zip |
Invent --transaction-size option for pg_restore.
This patch allows pg_restore to wrap its commands into transaction
blocks, somewhat like --single-transaction, except that we commit
and start a new block after every N objects. Using this mode
with a size limit of 1000 or so objects greatly reduces the number
of transactions consumed by the restore, while preventing any
one transaction from taking enough locks to overrun the receiving
server's shared lock table.
(A value of 1000 works well with the default lock table size of
around 6400 locks. Higher --transaction-size values can be used
if one has increased the receiving server's lock table size.)
Excessive consumption of XIDs has been reported as a problem for
pg_upgrade in particular, but it could be bad for any restore; and the
change also reduces the number of fsyncs and amount of WAL generated,
so it should provide speed benefits too.
This patch does not try to make parallel workers batch the SQL
commands they issue. The trouble with doing that is that other
workers may need to see the objects a worker creates right away.
Possibly this can be improved later.
In this patch I have hard-wired pg_upgrade to use a transaction size
of 1000 divided by the number of parallel restore jobs allowed
(without that, we'd still be at risk of overrunning the shared lock
table). Perhaps there would be value in adding another pg_upgrade
option to allow user control of that, but I'm unsure that it's worth
the trouble; I think few users would use it, and any who did would see
not that much benefit compared to the default.
Patch by me, but the original idea to batch SQL commands during
restore is due to Robins Tharakan.
Discussion: https://postgr.es/m/a9f9376f1c3343a6bb319dce294e20ac@EX13D05UWC001.ant.amazon.com
Diffstat (limited to 'src/bin/pg_upgrade/pg_upgrade.c')
-rw-r--r-- | src/bin/pg_upgrade/pg_upgrade.c | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c index f6143b6bc47..af370768b60 100644 --- a/src/bin/pg_upgrade/pg_upgrade.c +++ b/src/bin/pg_upgrade/pg_upgrade.c @@ -51,6 +51,13 @@ #include "fe_utils/string_utils.h" #include "pg_upgrade.h" +/* + * Maximum number of pg_restore actions (TOC entries) to process within one + * transaction. At some point we might want to make this user-controllable, + * but for now a hard-wired setting will suffice. + */ +#define RESTORE_TRANSACTION_SIZE 1000 + static void set_locale_and_encoding(void); static void prepare_new_cluster(void); static void prepare_new_globals(void); @@ -562,10 +569,12 @@ create_new_objects(void) true, true, "\"%s/pg_restore\" %s %s --exit-on-error --verbose " + "--transaction-size=%d " "--dbname postgres \"%s/%s\"", new_cluster.bindir, cluster_conn_opts(&new_cluster), create_opts, + RESTORE_TRANSACTION_SIZE, log_opts.dumpdir, sql_file_name); @@ -578,6 +587,7 @@ create_new_objects(void) log_file_name[MAXPGPATH]; DbInfo *old_db = &old_cluster.dbarr.dbs[dbnum]; const char *create_opts; + int txn_size; /* Skip template1 in this pass */ if (strcmp(old_db->db_name, "template1") == 0) @@ -597,13 +607,28 @@ create_new_objects(void) else create_opts = "--create"; + /* + * In parallel mode, reduce the --transaction-size of each restore job + * so that the total number of locks that could be held across all the + * jobs stays in bounds. + */ + txn_size = RESTORE_TRANSACTION_SIZE; + if (user_opts.jobs > 1) + { + txn_size /= user_opts.jobs; + /* Keep some sanity if -j is huge */ + txn_size = Max(txn_size, 10); + } + parallel_exec_prog(log_file_name, NULL, "\"%s/pg_restore\" %s %s --exit-on-error --verbose " + "--transaction-size=%d " "--dbname template1 \"%s/%s\"", new_cluster.bindir, cluster_conn_opts(&new_cluster), create_opts, + txn_size, log_opts.dumpdir, sql_file_name); } |