From cc87fe5e053c063c98b95abc3d76c432e848d649 Mon Sep 17 00:00:00 2001 From: Nick Ivanov Date: Fri, 11 Sep 2026 15:18:03 +0100 Subject: [PATCH v1] pg_basebackup to create replication slot early Try to create the replication slot, if requested, before requesting a checkpoint. This addresses the WAL recycle race when multiple basebackups are executed concurrently. Suggested-by: Andrey Borodin Backpatch-through: 15 --- src/bin/pg_basebackup/pg_basebackup.c | 81 +++++++++++++++------------ 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c index c3b87a19e76..35d89695509 100644 --- a/src/bin/pg_basebackup/pg_basebackup.c +++ b/src/bin/pg_basebackup/pg_basebackup.c @@ -613,7 +613,8 @@ LogStreamerMain(logstreamer_param *param) * stream the logfile in parallel with the backups. */ static void -StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier, +StartLogStreamer(PGconn *walconn, char *startpos, uint32 timeline, + char *sysidentifier, pg_compress_algorithm wal_compress_algorithm, int wal_compress_level) { @@ -625,6 +626,7 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier, param->sysidentifier = sysidentifier; param->wal_compress_algorithm = wal_compress_algorithm; param->wal_compress_level = wal_compress_level; + param->bgconn = walconn; /* Convert the starting position */ if (!pg_parse_lsn(startpos, ¶m->startptr)) @@ -639,46 +641,12 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier, pg_fatal("could not create pipe for background process: %m"); #endif - /* Get a second connection */ - param->bgconn = GetConnection(); - if (!param->bgconn) - /* Error message already written in GetConnection() */ - exit(1); - /* In post-10 cluster, pg_xlog has been renamed to pg_wal */ snprintf(param->xlog, sizeof(param->xlog), "%s/%s", basedir, PQserverVersion(conn) < MINIMUM_VERSION_FOR_PG_WAL ? "pg_xlog" : "pg_wal"); - /* Temporary replication slots are only supported in 10 and newer */ - if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_TEMP_SLOTS) - temp_replication_slot = false; - - /* - * Create replication slot if requested - */ - if (temp_replication_slot && !replication_slot) - replication_slot = psprintf("pg_basebackup_%u", - (unsigned int) PQbackendPID(param->bgconn)); - if (temp_replication_slot || create_slot) - { - if (!CreateReplicationSlot(param->bgconn, replication_slot, NULL, - temp_replication_slot, true, true, false, - false, false)) - exit(1); - - if (verbose) - { - if (temp_replication_slot) - pg_log_info("created temporary replication slot \"%s\"", - replication_slot); - else - pg_log_info("created replication slot \"%s\"", - replication_slot); - } - } - if (format == 'p') { /* @@ -1754,6 +1722,7 @@ BaseBackup(char *compression_algorithm, char *compression_detail, int writing_to_stdout; bool use_new_option_syntax = false; PQExpBufferData buf; + PGconn *walconn = NULL; Assert(conn != NULL); initPQExpBuffer(&buf); @@ -1970,6 +1939,46 @@ BaseBackup(char *compression_algorithm, char *compression_detail, compression_detail); } + /* If we were asked to stream WAL, create a separate connection for that */ + if (includewal == STREAM_WAL) + { + walconn = GetConnection(); + if (!walconn) + /* Error message already written in GetConnection() */ + exit(1); + + /* + * If we need to create a slot, do it now, before requesting a checkpoint, + * to ensure the WAL we want is not removed until we actually start + * streaming. + */ + + /* Temporary replication slots are only supported in 10 and newer */ + if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_TEMP_SLOTS) + temp_replication_slot = false; + + if (temp_replication_slot && !replication_slot) + replication_slot = psprintf("pg_basebackup_%u", + (unsigned int) PQbackendPID(walconn)); + if (temp_replication_slot || create_slot) + { + if (!CreateReplicationSlot(walconn, replication_slot, NULL, + temp_replication_slot, true, true, false, + false, false)) + exit(1); + + if (verbose) + { + if (temp_replication_slot) + pg_log_info("created temporary replication slot \"%s\"", + replication_slot); + else + pg_log_info("created replication slot \"%s\"", + replication_slot); + } + } + } + if (verbose) pg_log_info("initiating base backup, waiting for checkpoint to complete"); @@ -2100,7 +2109,7 @@ BaseBackup(char *compression_algorithm, char *compression_detail, wal_compress_level = 0; } - StartLogStreamer(xlogstart, starttli, sysidentifier, + StartLogStreamer(walconn, xlogstart, starttli, sysidentifier, wal_compress_algorithm, wal_compress_level); } -- 2.50.1 (Apple Git-155)