Hello, Fetching the timeline from a standby could be useful in various situation. Either for backup tools [1] or failover tools during some kind of election process.
Please, find in attachment a first trivial patch to support pg_walfile_name() and pg_walfile_name_offset() on a standby. Previous restriction on this functions seems related to ThisTimeLineID not being safe on standby. This patch is fetching the timeline from WalRcv->receivedTLI using GetWalRcvWriteRecPtr(). As far as I understand, this is updated each time some data are flushed to the WAL. As the SQL function pg_last_wal_receive_lsn() reads WalRcv->receivedUpto which is flushed in the same time, any tool relying on these functions should be quite fine. It will just have to parse the TL from the walfile name. It doesn't seems perfectly sain though. I suspect a race condition in any SQL statement that would try to get the LSN and the walfile name in the same time if the timeline changes in the meantime. Ideally, a function should be able to return both LSN and TL in the same time, with only one read from WalRcv. I'm not sure if I should change the result from pg_last_wal_receive_lsn() or add a brand new admin function. Any advice? Last, I plan to produce an extension to support this on older release. Is it something that could be integrated in official source tree during a minor release or should I publish it on eg. pgxn? Regards, [1] https://www.postgresql.org/message-id/flat/BF2AD4A8-E7F5-486F-92C8-A6959040DEB6%40yandex-team.ru
>From 9d0fb73d03c6e7e06f2f8be62abab4e54cf01117 Mon Sep 17 00:00:00 2001 From: Jehan-Guillaume de Rorthais <j...@dalibo.com> Date: Tue, 23 Jul 2019 17:28:44 +0200 Subject: [PATCH] Support pg_walfile_name on standby Support executing both SQL functions pg_walfile_name() and pg_walfile_name_offset() on a standby. --- src/backend/access/transam/xlogfuncs.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c index b35043bf71..a8184a20c4 100644 --- a/src/backend/access/transam/xlogfuncs.c +++ b/src/backend/access/transam/xlogfuncs.c @@ -460,13 +460,12 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS) TupleDesc resultTupleDesc; HeapTuple resultHeapTuple; Datum result; + TimeLineID tl; if (RecoveryInProgress()) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("recovery is in progress"), - errhint("%s cannot be executed during recovery.", - "pg_walfile_name_offset()"))); + GetWalRcvWriteRecPtr(NULL, &tl); + else + tl = ThisTimeLineID; /* * Construct a tuple descriptor for the result row. This must match this @@ -484,7 +483,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS) * xlogfilename */ XLByteToPrevSeg(locationpoint, xlogsegno, wal_segment_size); - XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno, wal_segment_size); + XLogFileName(xlogfilename, tl, xlogsegno, wal_segment_size); values[0] = CStringGetTextDatum(xlogfilename); isnull[0] = false; @@ -517,16 +516,15 @@ pg_walfile_name(PG_FUNCTION_ARGS) XLogSegNo xlogsegno; XLogRecPtr locationpoint = PG_GETARG_LSN(0); char xlogfilename[MAXFNAMELEN]; + TimeLineID tl; if (RecoveryInProgress()) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("recovery is in progress"), - errhint("%s cannot be executed during recovery.", - "pg_walfile_name()"))); + GetWalRcvWriteRecPtr(NULL, &tl); + else + tl = ThisTimeLineID; XLByteToPrevSeg(locationpoint, xlogsegno, wal_segment_size); - XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno, wal_segment_size); + XLogFileName(xlogfilename, tl, xlogsegno, wal_segment_size); PG_RETURN_TEXT_P(cstring_to_text(xlogfilename)); } -- 2.20.1