Commit 7fd89f4d authored by Tom Lane's avatar Tom Lane

Fix async.c to not register any SLRU stats counts in the postmaster.

Previously, AsyncShmemInit forcibly initialized the first page of the
async SLRU, to save dealing with that case in asyncQueueAddEntries.
But this is a poor tradeoff, since many installations do not ever use
NOTIFY; for them, expending those cycles in AsyncShmemInit is a
complete waste.  Besides, this only saves a couple of instructions
in asyncQueueAddEntries, which hardly seems likely to be measurable.

The real reason to change this now, though, is that now that we track
SLRU access stats, the existing code is causing the postmaster to
accumulate some access counts, which then get inherited into child
processes by fork(), messing up the statistics.  Delaying the
initialization into the first child that does a NOTIFY fixes that.

Hence, we can revert f3d23d83, which was an incorrect attempt at
fixing that issue.  Also, add an Assert to pgstat.c that should
catch any future errors of the same sort.

Discussion: https://postgr.es/m/8367.1589391884@sss.pgh.pa.us
parent d82a5058
...@@ -200,7 +200,10 @@ typedef struct QueuePosition ...@@ -200,7 +200,10 @@ typedef struct QueuePosition
} while (0) } while (0)
#define QUEUE_POS_EQUAL(x,y) \ #define QUEUE_POS_EQUAL(x,y) \
((x).page == (y).page && (x).offset == (y).offset) ((x).page == (y).page && (x).offset == (y).offset)
#define QUEUE_POS_IS_ZERO(x) \
((x).page == 0 && (x).offset == 0)
/* choose logically smaller QueuePosition */ /* choose logically smaller QueuePosition */
#define QUEUE_POS_MIN(x,y) \ #define QUEUE_POS_MIN(x,y) \
...@@ -515,7 +518,6 @@ void ...@@ -515,7 +518,6 @@ void
AsyncShmemInit(void) AsyncShmemInit(void)
{ {
bool found; bool found;
int slotno;
Size size; Size size;
/* /*
...@@ -562,13 +564,6 @@ AsyncShmemInit(void) ...@@ -562,13 +564,6 @@ AsyncShmemInit(void)
* During start or reboot, clean out the pg_notify directory. * During start or reboot, clean out the pg_notify directory.
*/ */
(void) SlruScanDirectory(AsyncCtl, SlruScanDirCbDeleteAll, NULL); (void) SlruScanDirectory(AsyncCtl, SlruScanDirCbDeleteAll, NULL);
/* Now initialize page zero to empty */
LWLockAcquire(AsyncCtlLock, LW_EXCLUSIVE);
slotno = SimpleLruZeroPage(AsyncCtl, QUEUE_POS_PAGE(QUEUE_HEAD));
/* This write is just to verify that pg_notify/ is writable */
SimpleLruWritePage(AsyncCtl, slotno);
LWLockRelease(AsyncCtlLock);
} }
} }
...@@ -1470,9 +1465,21 @@ asyncQueueAddEntries(ListCell *nextNotify) ...@@ -1470,9 +1465,21 @@ asyncQueueAddEntries(ListCell *nextNotify)
*/ */
queue_head = QUEUE_HEAD; queue_head = QUEUE_HEAD;
/* Fetch the current page */ /*
* If this is the first write since the postmaster started, we need to
* initialize the first page of the async SLRU. Otherwise, the current
* page should be initialized already, so just fetch it.
*
* (We could also take the first path when the SLRU position has just
* wrapped around, but re-zeroing the page is harmless in that case.)
*/
pageno = QUEUE_POS_PAGE(queue_head); pageno = QUEUE_POS_PAGE(queue_head);
slotno = SimpleLruReadPage(AsyncCtl, pageno, true, InvalidTransactionId); if (QUEUE_POS_IS_ZERO(queue_head))
slotno = SimpleLruZeroPage(AsyncCtl, pageno);
else
slotno = SimpleLruReadPage(AsyncCtl, pageno, true,
InvalidTransactionId);
/* Note we mark the page dirty before writing in it */ /* Note we mark the page dirty before writing in it */
AsyncCtl->shared->page_dirty[slotno] = true; AsyncCtl->shared->page_dirty[slotno] = true;
......
...@@ -2906,9 +2906,6 @@ pgstat_initialize(void) ...@@ -2906,9 +2906,6 @@ pgstat_initialize(void)
MyBEEntry = &BackendStatusArray[MaxBackends + MyAuxProcType]; MyBEEntry = &BackendStatusArray[MaxBackends + MyAuxProcType];
} }
/* Initialize SLRU statistics to zero */
memset(&SLRUStats, 0, sizeof(SLRUStats));
/* Set up a process-exit hook to clean up */ /* Set up a process-exit hook to clean up */
on_shmem_exit(pgstat_beshutdown_hook, 0); on_shmem_exit(pgstat_beshutdown_hook, 0);
} }
...@@ -6727,6 +6724,12 @@ pgstat_slru_name(int slru_idx) ...@@ -6727,6 +6724,12 @@ pgstat_slru_name(int slru_idx)
static inline PgStat_MsgSLRU * static inline PgStat_MsgSLRU *
slru_entry(int slru_idx) slru_entry(int slru_idx)
{ {
/*
* The postmaster should never register any SLRU statistics counts; if it
* did, the counts would be duplicated into child processes via fork().
*/
Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
Assert((slru_idx >= 0) && (slru_idx < SLRU_NUM_ELEMENTS)); Assert((slru_idx >= 0) && (slru_idx < SLRU_NUM_ELEMENTS));
return &SLRUStats[slru_idx]; return &SLRUStats[slru_idx];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment