On Wed, 23 Jul 2025 at 09:24, Fujii Masao <masao.fu...@gmail.com> wrote:
> On Mon, Jul 21, 2025 at 2:38 PM Japin Li <japi...@hotmail.com> wrote:
>>
>>
>> Hi, hackers,
>>
>> I was recently reviewing the KeepFileRestoredFromArchive() function and came
>> across a section that raised a question for me:
>>
>>     /*
>>      * Create .done file forcibly to prevent the restored segment from being
>>      * archived again later.
>>      */
>>     if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
>>         XLogArchiveForceDone(xlogfname);
>>     else
>>         XLogArchiveNotify(xlogfname);
>>
>> My understanding is that the WAL segment in this context has just been
>> restored from the archive.
>>
>> However, for archive_mode=always, the code calls 
>> XLogArchiveNotify(xlogfname),
>> which, if I understand correctly, signals the archiver to re-archive this
>> already-archived WAL segment.
>>
>> Is there a specific scenario or benefit I'm overlooking?
>
> One possible scenario is when the archive directory used by restore_command
> is different from the one used by archive_command. For example, the primary
> and standby servers might each have their own separate archive directories,
> with archive_command configured to archive WAL files to their
> respective directories.
> Meanwhile, the standby’s restore_command might be set up to fetch WAL files
> from the primary’s archive directory. This kind of setup can be used
> when there’s
> no shared archive directory between the primary and standby. In such cases,
> even WAL files restored on the standby might need to be archived again.
>

Thanks for your explanation.

Yes, I've encountered this exact scenario: when promoting a standby and then
re-joining the old primary, they maintain separate WAL archive directories.
I've attached a script to reproduce this.

I've observed that WalReceiverMain() archives WALs upon receipt, and
StartupXLOG() subsequently restores them from the archive directory, and then
re-archives them via KeepFileRestoredFromArchive().

-- 
Regards,
Japin Li

#!/bin/bash

# Cleanup the data.
rm -rf /tmp/{pgdata,arch,log}{1,2}

# Create the archive directories.
mkdir -p /tmp/arch{1,2}

# Initialize the primary node.
initdb -k -D /tmp/pgdata1 -U jerry
cat <<EOF >>/tmp/pgdata1/postgresql.auto.conf
port = '9967'
archive_mode = 'always'
archive_command = 'test ! -f /tmp/arch1/%f && cp %p /tmp/arch1/%f'
restore_command = 'cp /tmp/arch1/%f %p'

logging_collector = 'on'
log_destination = 'csvlog'
log_filename = 'postgresql-%d.log'
log_directory = '/tmp/log1'
EOF

# Startup the primary node.
pg_ctl -l 1.log -D /tmp/pgdata1 start

# Create the standby node.
pg_basebackup -U jerry -h localhost -p 9967 -R -Fp -Xs -P -D /tmp/pgdata2
cat <<EOF >>/tmp/pgdata2/postgresql.auto.conf
port = '9968'
archive_mode = 'always'
archive_command = 'test ! -f /tmp/arch2/%f && cp %p /tmp/arch2/%f'
restore_command = 'cp /tmp/arch2/%f %p'

logging_collector = 'on'
log_destination = 'csvlog'
log_filename = 'postgresql-%d.log'
log_directory = '/tmp/log2'
EOF

# Startup the standby node.
pg_ctl -l 2.log -D /tmp/pgdata2 start

# Check the replication.
psql -U jerry -p 9967 postgres -xc 'select * from pg_stat_replication'

# Stop the primary and then promote the standby to new primary.
pg_ctl -l 1.log -D /tmp/pgdata1 stop
pg_ctl -l 2.log -D /tmp/pgdata2 promote

# Re-join the old primary as new standby.
cat <<EOF >>/tmp/pgdata1/postgresql.auto.conf
primary_conninfo = 'user=jerry host=localhost port=9968'
EOF
touch /tmp/pgdata1/standby.signal
pg_ctl -l 1.log -D /tmp/pgdata1 start

# Check the replication
psql -U jerry -p 9968 postgres -xc 'select * from pg_stat_replication'

# Check the archiver process status.
ps -ef | grep archiver

pg_ctl -l 2.log -D /tmp/pgdata2 stop
pg_ctl -l 1.log -D /tmp/pgdata1 stop

Reply via email to