From 41035d97254e06582903aff2d569cca5f0c52263 Mon Sep 17 00:00:00 2001 From: ChangAo Chen Date: Fri, 28 Aug 2026 17:01:23 +0800 Subject: [PATCH v4] Fix WAIT FOR LSN timeout handling. Limit WAIT FOR LSN timeouts to the int range and update the WaitForLSN() interface and its callers accordingly. This prevents large timeout values from overflowing while calculating the deadline. Check for negative values before rounding, so negative sub-millisecond timeouts cannot be rounded to zero and interpreted as an indefinite wait. Likewise, round positive values smaller than one millisecond up to one millisecond, since zero means waiting indefinitely. --- src/backend/access/transam/xlogwait.c | 2 +- src/backend/commands/repack_worker.c | 4 ++-- src/backend/commands/wait.c | 24 ++++++++++++++---------- src/include/access/xlogwait.h | 2 +- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/backend/access/transam/xlogwait.c b/src/backend/access/transam/xlogwait.c index eee90e7f626..2ea8c24a74f 100644 --- a/src/backend/access/transam/xlogwait.c +++ b/src/backend/access/transam/xlogwait.c @@ -437,7 +437,7 @@ WaitLSNTypeRequiresRecovery(WaitLSNType t) * or replica got promoted before the target LSN reached. */ WaitLSNResult -WaitForLSN(WaitLSNType lsnType, XLogRecPtr targetLSN, int64 timeout) +WaitForLSN(WaitLSNType lsnType, XLogRecPtr targetLSN, int timeout) { XLogRecPtr currentLSN; WaitLSNProcInfo *procInfo; diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c index af7e2a94764..a9870d9c8f2 100644 --- a/src/backend/commands/repack_worker.c +++ b/src/backend/commands/repack_worker.c @@ -447,7 +447,7 @@ decode_concurrent_changes(LogicalDecodingContext *ctx, if (record == NULL) { - int64 timeout = 0; + int timeout = 0; WaitLSNResult res; /* @@ -466,7 +466,7 @@ decode_concurrent_changes(LogicalDecodingContext *ctx, * should already have been flushed to disk. */ if (!XLogRecPtrIsValid(lsn_upto)) - timeout = 100L; + timeout = 100; res = WaitForLSN(WAIT_LSN_TYPE_PRIMARY_FLUSH, ctx->reader->EndRecPtr + 1, timeout); diff --git a/src/backend/commands/wait.c b/src/backend/commands/wait.c index 9ba4c75021e..2f4b91a7c48 100644 --- a/src/backend/commands/wait.c +++ b/src/backend/commands/wait.c @@ -35,7 +35,7 @@ ExecWaitStmt(ParseState *pstate, WaitStmt *stmt, bool isTopLevel, DestReceiver *dest) { XLogRecPtr lsn; - int64 timeout = 0; + int timeout = 0; WaitLSNResult waitLSNResult; WaitLSNType lsnType = WAIT_LSN_TYPE_STANDBY_REPLAY; /* default */ bool throw = true; @@ -108,25 +108,29 @@ ExecWaitStmt(ParseState *pstate, WaitStmt *stmt, bool isTopLevel, hintmsg ? errhint("%s", _(hintmsg)) : 0); } + if (dval < 0.0) + ereport(ERROR, + errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("timeout cannot be negative")); + /* * Get rid of any fractional part in the input. This is so we * don't fail on just-out-of-range values that would round into - * range. + * range. Round values in (0, 1) up to 1 to avoid treating them as + * zero, which means waiting indefinitely. */ - dval = rint(dval); + if (dval > 0.0 && dval < 1.0) + dval = 1.0; + else + dval = rint(dval); /* Range check */ - if (unlikely(isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))) + if (unlikely(isnan(dval) || !FLOAT8_FITS_IN_INT32(dval))) ereport(ERROR, errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("timeout value is out of range")); - if (dval < 0) - ereport(ERROR, - errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("timeout cannot be negative")); - - timeout = (int64) dval; + timeout = (int) dval; } else if (strcmp(defel->defname, "no_throw") == 0) { diff --git a/src/include/access/xlogwait.h b/src/include/access/xlogwait.h index 07157f220ea..2bf0263e9e2 100644 --- a/src/include/access/xlogwait.h +++ b/src/include/access/xlogwait.h @@ -104,6 +104,6 @@ extern XLogRecPtr GetCurrentLSNForWaitType(WaitLSNType lsnType); extern void WaitLSNWakeup(WaitLSNType lsnType, XLogRecPtr currentLSN); extern void WaitLSNCleanup(void); extern WaitLSNResult WaitForLSN(WaitLSNType lsnType, XLogRecPtr targetLSN, - int64 timeout); + int timeout); #endif /* XLOG_WAIT_H */ -- 2.53.0