diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c index eddc22fc5ad2..69ad99e3ce47 100644 --- a/src/backend/access/transam/xlogrecovery.c +++ b/src/backend/access/transam/xlogrecovery.c @@ -50,6 +50,7 @@ #include "pgstat.h" #include "postmaster/bgwriter.h" #include "postmaster/startup.h" +#include "postmaster/walsummarizer.h" #include "replication/slot.h" #include "replication/slotsync.h" #include "replication/walreceiver.h" @@ -57,6 +58,7 @@ #include "storage/ipc.h" #include "storage/latch.h" #include "storage/pmsignal.h" +#include "storage/proc.h" #include "storage/procarray.h" #include "storage/spin.h" #include "utils/datetime.h" @@ -3358,6 +3360,24 @@ XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen, } } + /* + * Once replayed, WAL segment files may be re-read in several cases: + * archive_mode is set to always, summarize_wal is enabled or the + * standby acts as a walsender for either logical or physical + * replication. Outside of those conditions, the WAL segment files + * shouldn't be re-read and we can signal the kernel to release any + * cached pages. + */ +#if defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED) + { + int nfree; + + if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS && + !summarize_wal && + (max_wal_senders == 0 || HaveNFreeProcs(max_wal_senders, &nfree, PROC_FREE_WALSENDER))) + (void) posix_fadvise(readFile, 0, 0, POSIX_FADV_DONTNEED); + } +#endif close(readFile); readFile = -1; readSource = XLOG_FROM_ANY; diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 1504fafe6d88..6e4e2eb607ba 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -784,17 +784,36 @@ GetStartupBufferPinWaitBufId(void) * Note: this is designed on the assumption that N will generally be small. */ bool -HaveNFreeProcs(int n, int *nfree) +HaveNFreeProcs(int n, int *nfree, ProcFreeList proc_free_list) { dlist_iter iter; + dlist_head *free_list; Assert(n > 0); Assert(nfree); + switch (proc_free_list) + { + case PROC_FREE_PROCS: + free_list = &ProcGlobal->freeProcs; + break; + case PROC_FREE_AUTOVAC: + free_list = &ProcGlobal->autovacFreeProcs; + break; + case PROC_FREE_BGWORKER: + free_list = &ProcGlobal->bgworkerFreeProcs; + break; + case PROC_FREE_WALSENDER: + free_list = &ProcGlobal->walsenderFreeProcs; + break; + default: + elog(ERROR, "invalid free list: %d", (int) proc_free_list); + } + SpinLockAcquire(ProcStructLock); *nfree = 0; - dlist_foreach(iter, &ProcGlobal->freeProcs) + dlist_foreach(iter, free_list) { (*nfree)++; if (*nfree == n) diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 98f9598cd789..704baf7f09cd 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -931,7 +931,7 @@ InitPostgres(const char *in_dbname, Oid dboid, */ if (AmRegularBackendProcess() && !am_superuser && (SuperuserReservedConnections + ReservedConnections) > 0 && - !HaveNFreeProcs(SuperuserReservedConnections + ReservedConnections, &nfree)) + !HaveNFreeProcs(SuperuserReservedConnections + ReservedConnections, &nfree, PROC_FREE_PROCS)) { if (nfree < SuperuserReservedConnections) ereport(FATAL, diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index c6f5ebceefdd..e6a6ee5a83dc 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -149,6 +149,14 @@ typedef enum PROC_WAIT_STATUS_ERROR, } ProcWaitStatus; +typedef enum +{ + PROC_FREE_PROCS, + PROC_FREE_AUTOVAC, + PROC_FREE_BGWORKER, + PROC_FREE_WALSENDER, +} ProcFreeList; + /* * Each backend has a PGPROC struct in shared memory. There is also a list of * currently-unused PGPROC structs that will be reallocated to new backends. @@ -497,7 +505,7 @@ extern void InitAuxiliaryProcess(void); extern void SetStartupBufferPinWaitBufId(int bufid); extern int GetStartupBufferPinWaitBufId(void); -extern bool HaveNFreeProcs(int n, int *nfree); +extern bool HaveNFreeProcs(int n, int *nfree, ProcFreeList proc_free_list); extern void ProcReleaseLocks(bool isCommit); extern ProcWaitStatus JoinWaitQueue(LOCALLOCK *locallock,