Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 73da6b8

Browse files
committed
Refactor WaitForLSNReplay() to return the result of waiting
Currently, WaitForLSNReplay() immediately throws an error if waiting for LSN replay is not successful. This commit teaches WaitForLSNReplay() to return the result of waiting, while making pg_wal_replay_wait() responsible for throwing an appropriate error. This is preparation to adding 'no_error' argument to pg_wal_replay_wait() and new function pg_wal_replay_wait_status(), which returns the last wait result status. Additionally, we stop distinguishing situations when we find our instance to be not in a recovery state before entering the waiting loop and inside the waiting loop. Standby promotion may happen at any moment, even between issuing a procedure call statement and pg_wal_replay_wait() doing a first check of recovery status. Thus, there is no pointing distinguishing these situations. Also, since we may exit the waiting loop and see our instance not in recovery without throwing an error, we need to deleteLSNWaiter() in that case. We do this unconditionally for the sake of simplicity, even if standby was already promoted after reaching the target LSN, the startup process surely already deleted us. Reported-by: Michael Paquier Discussion: https://postgr.es/m/ZtUF17gF0pNpwZDI%40paquier.xyz Reviewed-by: Michael Paquier, Pavel Borisov
1 parent 6cfebfe commit 73da6b8

File tree

4 files changed

+54
-24
lines changed

4 files changed

+54
-24
lines changed

src/backend/access/transam/xlogfuncs.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,7 @@ pg_wal_replay_wait(PG_FUNCTION_ARGS)
759759
{
760760
XLogRecPtr target_lsn = PG_GETARG_LSN(0);
761761
int64 timeout = PG_GETARG_INT64(1);
762+
WaitLSNResult result;
762763

763764
if (timeout < 0)
764765
ereport(ERROR,
@@ -799,7 +800,35 @@ pg_wal_replay_wait(PG_FUNCTION_ARGS)
799800
*/
800801
Assert(MyProc->xmin == InvalidTransactionId);
801802

802-
(void) WaitForLSNReplay(target_lsn, timeout);
803+
result = WaitForLSNReplay(target_lsn, timeout);
804+
805+
/*
806+
* Process the result of WaitForLSNReplay(). Throw appropriate error if
807+
* needed.
808+
*/
809+
switch (result)
810+
{
811+
case WAIT_LSN_RESULT_SUCCESS:
812+
/* Nothing to do on success */
813+
break;
814+
815+
case WAIT_LSN_RESULT_TIMEOUT:
816+
ereport(ERROR,
817+
(errcode(ERRCODE_QUERY_CANCELED),
818+
errmsg("timed out while waiting for target LSN %X/%X to be replayed; current replay LSN %X/%X",
819+
LSN_FORMAT_ARGS(target_lsn),
820+
LSN_FORMAT_ARGS(GetXLogReplayRecPtr(NULL)))));
821+
break;
822+
823+
case WAIT_LSN_RESULT_NOT_IN_RECOVERY:
824+
ereport(ERROR,
825+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
826+
errmsg("recovery is not in progress"),
827+
errdetail("Recovery ended before replaying target LSN %X/%X; last replay LSN %X/%X.",
828+
LSN_FORMAT_ARGS(target_lsn),
829+
LSN_FORMAT_ARGS(GetXLogReplayRecPtr(NULL)))));
830+
break;
831+
}
803832

804833
PG_RETURN_VOID();
805834
}

src/backend/access/transam/xlogwait.c

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ WaitLSNCleanup(void)
217217
* Wait using MyLatch till the given LSN is replayed, the postmaster dies or
218218
* timeout happens.
219219
*/
220-
void
220+
WaitLSNResult
221221
WaitForLSNReplay(XLogRecPtr targetLSN, int64 timeout)
222222
{
223223
XLogRecPtr currentLSN;
@@ -240,17 +240,14 @@ WaitForLSNReplay(XLogRecPtr targetLSN, int64 timeout)
240240
* check the last replay LSN before reporting an error.
241241
*/
242242
if (targetLSN <= GetXLogReplayRecPtr(NULL))
243-
return;
244-
ereport(ERROR,
245-
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
246-
errmsg("recovery is not in progress"),
247-
errhint("Waiting for LSN can only be executed during recovery.")));
243+
return WAIT_LSN_RESULT_SUCCESS;
244+
return WAIT_LSN_RESULT_NOT_IN_RECOVERY;
248245
}
249246
else
250247
{
251248
/* If target LSN is already replayed, exit immediately */
252249
if (targetLSN <= GetXLogReplayRecPtr(NULL))
253-
return;
250+
return WAIT_LSN_RESULT_SUCCESS;
254251
}
255252

256253
if (timeout > 0)
@@ -276,17 +273,13 @@ WaitForLSNReplay(XLogRecPtr targetLSN, int64 timeout)
276273
{
277274
/*
278275
* Recovery was ended, but recheck if target LSN was already
279-
* replayed.
276+
* replayed. See the comment regarding deleteLSNWaiter() below.
280277
*/
278+
deleteLSNWaiter();
281279
currentLSN = GetXLogReplayRecPtr(NULL);
282280
if (targetLSN <= currentLSN)
283-
return;
284-
ereport(ERROR,
285-
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
286-
errmsg("recovery is not in progress"),
287-
errdetail("Recovery ended before replaying target LSN %X/%X; last replay LSN %X/%X.",
288-
LSN_FORMAT_ARGS(targetLSN),
289-
LSN_FORMAT_ARGS(currentLSN))));
281+
return WAIT_LSN_RESULT_SUCCESS;
282+
return WAIT_LSN_RESULT_NOT_IN_RECOVERY;
290283
}
291284
else
292285
{
@@ -338,11 +331,7 @@ WaitForLSNReplay(XLogRecPtr targetLSN, int64 timeout)
338331
* If we didn't reach the target LSN, we must be exited by timeout.
339332
*/
340333
if (targetLSN > currentLSN)
341-
{
342-
ereport(ERROR,
343-
(errcode(ERRCODE_QUERY_CANCELED),
344-
errmsg("timed out while waiting for target LSN %X/%X to be replayed; current replay LSN %X/%X",
345-
LSN_FORMAT_ARGS(targetLSN),
346-
LSN_FORMAT_ARGS(currentLSN))));
347-
}
334+
return WAIT_LSN_RESULT_TIMEOUT;
335+
336+
return WAIT_LSN_RESULT_SUCCESS;
348337
}

src/include/access/xlogwait.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,23 @@ typedef struct WaitLSNState
7070
WaitLSNProcInfo procInfos[FLEXIBLE_ARRAY_MEMBER];
7171
} WaitLSNState;
7272

73+
/*
74+
* Result statuses for WaitForLSNReplay().
75+
*/
76+
typedef enum
77+
{
78+
WAIT_LSN_RESULT_SUCCESS, /* Target LSN is reached */
79+
WAIT_LSN_RESULT_TIMEOUT, /* Timeout occurred */
80+
WAIT_LSN_RESULT_NOT_IN_RECOVERY, /* Recovery ended before or during our
81+
* wait */
82+
} WaitLSNResult;
83+
7384
extern PGDLLIMPORT WaitLSNState *waitLSNState;
7485

7586
extern Size WaitLSNShmemSize(void);
7687
extern void WaitLSNShmemInit(void);
7788
extern void WaitLSNSetLatches(XLogRecPtr currentLSN);
7889
extern void WaitLSNCleanup(void);
79-
extern void WaitForLSNReplay(XLogRecPtr targetLSN, int64 timeout);
90+
extern WaitLSNResult WaitForLSNReplay(XLogRecPtr targetLSN, int64 timeout);
8091

8192
#endif /* XLOG_WAIT_H */

src/tools/pgindent/typedefs.list

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3126,6 +3126,7 @@ WaitEventIPC
31263126
WaitEventSet
31273127
WaitEventTimeout
31283128
WaitLSNProcInfo
3129+
WaitLSNResult
31293130
WaitLSNState
31303131
WaitPMResult
31313132
WalCloseMethod

0 commit comments

Comments
 (0)