Hello all, Following the threads here <https://www.postgresql.org/message-id/flat/CAFWczPvi_5FWH%2BJTqkWbi%2Bw83hy%3DMYg%3D2hKK0%3DJZBe9%3DhTpE4w%40mail.gmail.com> and there <https://commitfest.postgresql.org/13/958/>, I decided to submit this patch.
Following is the description which is also written in the commit message: MAX_SEND_SIZE parameter was used in WALSender to limit maximum size of a WAL data packet sent to a WALReceiver during replication. Although its default value (128kB) was a reasonable value, it was written in 2010. Since the hardwares have changed a lot since then, a PostgreSQL user might need to customize this value. For example, if a database's disk has a high bandwidth and a high latency at the same time, it makes more sense to read bigger chunks of data from disk in each iteration. One example of such disks is a remote disk. (e.g. an RBD volume) However, this value does not need to be larger than wal_segment_size, thus its checker function returns false if a larger value is set for this. This is my first patch. So, I hope I haven't done something wrong. :'D Best regards Majid
From 218a925d1161878c888bef8adb3f246ec2b44d12 Mon Sep 17 00:00:00 2001 From: Majid Garoosi <amoomaji...@gmail.com> Date: Fri, 19 Jan 2024 22:48:23 +0330 Subject: [PATCH v1] GUC-ify MAX_SEND_SIZE constant in WALSender MAX_SEND_SIZE parameter was used in WALSender to limit maximum size of a WAL data packet sent to a WALReceiver during replication. Although its default value (128kB) was a reasonable value, it was written in 2010. Since the hardwares have changed a lot since then, a PostgreSQL user might need to customize this value. For example, if a database's disk has a high bandwidth and a high latency at the same time, it makes more sense to read bigger chunks of data from disk in each iteration. One example of such disks is a remote disk. (e.g. an RBD volume) However, this value does not need to be larger than wal_segment_size, thus its checker function returns false if a larger value is set for this. --- src/backend/replication/walsender.c | 18 +++++------------- src/backend/utils/init/postinit.c | 11 +++++++++++ src/backend/utils/misc/guc_tables.c | 13 +++++++++++++ src/include/replication/walsender.h | 1 + src/include/utils/guc_hooks.h | 1 + 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index 087031e9dc..0299859d97 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -96,17 +96,6 @@ #include "utils/timeout.h" #include "utils/timestamp.h" -/* - * Maximum data payload in a WAL data message. Must be >= XLOG_BLCKSZ. - * - * We don't have a good idea of what a good value would be; there's some - * overhead per message in both walsender and walreceiver, but on the other - * hand sending large batches makes walsender less responsive to signals - * because signals are checked only between messages. 128kB (with - * default 8k blocks) seems like a reasonable guess for now. - */ -#define MAX_SEND_SIZE (XLOG_BLCKSZ * 16) - /* Array of WalSnds in shared memory */ WalSndCtlData *WalSndCtl = NULL; @@ -124,6 +113,9 @@ int max_wal_senders = 10; /* the maximum number of concurrent * walsenders */ int wal_sender_timeout = 60 * 1000; /* maximum time to send one WAL * data message */ +int wal_sender_max_send_size = XLOG_BLCKSZ * 16; /* Maximum data + * payload in a WAL + * data message */ bool log_replication_commands = false; /* @@ -3087,7 +3079,7 @@ XLogSendPhysical(void) */ startptr = sentPtr; endptr = startptr; - endptr += MAX_SEND_SIZE; + endptr += wal_sender_max_send_size; /* if we went beyond SendRqstPtr, back off */ if (SendRqstPtr <= endptr) @@ -3106,7 +3098,7 @@ XLogSendPhysical(void) } nbytes = endptr - startptr; - Assert(nbytes <= MAX_SEND_SIZE); + Assert(nbytes <= wal_sender_max_send_size); /* * OK to read and send the slice. diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 1ad3367159..8d61b006c4 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -617,6 +617,17 @@ check_max_wal_senders(int *newval, void **extra, GucSource source) return true; } +/* + * GUC check_hook for wal_sender_max_send_size + */ +bool +check_wal_sender_max_send_size(int *newval, void **extra, GucSource source) +{ + if (*newval > wal_segment_size) + return false; + return true; +} + /* * Early initialization of a backend (either standalone or under postmaster). * This happens even before InitPostgres. diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index e53ebc6dc2..76f755cbd3 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -2892,6 +2892,19 @@ struct config_int ConfigureNamesInt[] = NULL, NULL, NULL }, + { + {"wal_sender_max_send_size", PGC_SIGHUP, REPLICATION_SENDING, + gettext_noop("Sets size of the maximum data payload in a WAL data message."), + gettext_noop("Walsender procedure consists of a loop, reading wal_sender_max_send_size " + "bytes of WALs from disk and sending them to the receiver. Sending large " + "batches makes walsender less responsive to signals."), + GUC_UNIT_BYTE, + }, + &wal_sender_max_send_size, + 16 * XLOG_BLCKSZ, XLOG_BLCKSZ, INT_MAX, + check_wal_sender_max_send_size, NULL, NULL + }, + { {"commit_delay", PGC_SUSET, WAL_SETTINGS, gettext_noop("Sets the delay in microseconds between transaction commit and " diff --git a/src/include/replication/walsender.h b/src/include/replication/walsender.h index 1b58d50b3b..f4d3c73f4d 100644 --- a/src/include/replication/walsender.h +++ b/src/include/replication/walsender.h @@ -31,6 +31,7 @@ extern PGDLLIMPORT bool wake_wal_senders; /* user-settable parameters */ extern PGDLLIMPORT int max_wal_senders; extern PGDLLIMPORT int wal_sender_timeout; +extern PGDLLIMPORT int wal_sender_max_send_size; extern PGDLLIMPORT bool log_replication_commands; extern void InitWalSender(void); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 5300c44f3b..b0ac07171c 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -84,6 +84,7 @@ extern bool check_maintenance_io_concurrency(int *newval, void **extra, extern void assign_maintenance_io_concurrency(int newval, void *extra); extern bool check_max_connections(int *newval, void **extra, GucSource source); extern bool check_max_wal_senders(int *newval, void **extra, GucSource source); +extern bool check_wal_sender_max_send_size(int *newval, void **extra, GucSource source); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); extern void assign_max_wal_size(int newval, void *extra); -- 2.34.1