Skip to content

Commit ee3f8d3

Browse files
committed
pgstat: Bring up pgstat in BaseInit() to fix uninitialized use of pgstat by AV.
Previously pgstat_initialize() was called in InitPostgres() and AuxiliaryProcessMain(). As it turns out there was at least one case where we reported stats before pgstat_initialize() was called, see AutoVacWorkerMain()'s intentionally early call to pgstat_report_autovac(). This turns out to not be a problem with the current pgstat implementation as pgstat_initialize() only registers a shutdown callback. But in the shared memory based stats implementation we are working towards pgstat_initialize() has to do more work. After b406478 BaseInit() is a central place where initialization shared by normal backends and auxiliary backends can be put. Obviously BaseInit() is called before InitPostgres() registers ShutdownPostgres. Previously ShutdownPostgres was the first before_shmem_exit callback, now that's commonly pgstats. That should be fine. Previously pgstat_initialize() was not called in bootstrap mode, but there does not appear to be a need for that. It's now done unconditionally. To detect future issues like this, assertions are added to a few places verifying that the pgstat subsystem is initialized and not yet shut down. Author: Andres Freund <andres@anarazel.de> Discussion: https://postgr.es/m/20210405092914.mmxqe7j56lsjfsej@alap3.anarazel.de Discussion: https://postgr.es/m/20210802164124.ufo5buo4apl6yuvs@alap3.anarazel.de
1 parent 5c056b0 commit ee3f8d3

File tree

3 files changed

+65
-13
lines changed

3 files changed

+65
-13
lines changed

src/backend/postmaster/auxprocess.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,6 @@ AuxiliaryProcessMain(AuxProcType auxtype)
125125
*/
126126
CreateAuxProcessResourceOwner();
127127

128-
/* Initialize statistics reporting */
129-
pgstat_initialize();
130128

131129
/* Initialize backend status information */
132130
pgstat_beinit();

src/backend/postmaster/pgstat.c

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,15 @@ static List *pending_write_requests = NIL;
295295
*/
296296
static instr_time total_func_time;
297297

298+
/*
299+
* For assertions that check pgstat is not used before initialization / after
300+
* shutdown.
301+
*/
302+
#ifdef USE_ASSERT_CHECKING
303+
static bool pgstat_is_initialized = false;
304+
static bool pgstat_is_shutdown = false;
305+
#endif
306+
298307

299308
/* ----------
300309
* Local function forward declarations
@@ -330,6 +339,7 @@ static void pgstat_send_connstats(bool disconnect, TimestampTz last_report);
330339
static PgStat_TableStatus *get_tabstat_entry(Oid rel_id, bool isshared);
331340

332341
static void pgstat_setup_memcxt(void);
342+
static void pgstat_assert_is_up(void);
333343

334344
static void pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype);
335345
static void pgstat_send(void *msg, int len);
@@ -854,6 +864,8 @@ pgstat_report_stat(bool disconnect)
854864
TabStatusArray *tsa;
855865
int i;
856866

867+
pgstat_assert_is_up();
868+
857869
/*
858870
* Don't expend a clock check if nothing to do.
859871
*
@@ -1960,6 +1972,8 @@ pgstat_init_function_usage(FunctionCallInfo fcinfo,
19601972
PgStat_BackendFunctionEntry *
19611973
find_funcstat_entry(Oid func_id)
19621974
{
1975+
pgstat_assert_is_up();
1976+
19631977
if (pgStatFunctions == NULL)
19641978
return NULL;
19651979

@@ -2078,6 +2092,8 @@ get_tabstat_entry(Oid rel_id, bool isshared)
20782092
TabStatusArray *tsa;
20792093
bool found;
20802094

2095+
pgstat_assert_is_up();
2096+
20812097
/*
20822098
* Create hash table if we don't have it already.
20832099
*/
@@ -2938,6 +2954,8 @@ pgstat_fetch_replslot(NameData slotname)
29382954
static void
29392955
pgstat_shutdown_hook(int code, Datum arg)
29402956
{
2957+
Assert(!pgstat_is_shutdown);
2958+
29412959
/*
29422960
* If we got as far as discovering our own database ID, we can report what
29432961
* we did to the collector. Otherwise, we'd be sending an invalid
@@ -2946,20 +2964,26 @@ pgstat_shutdown_hook(int code, Datum arg)
29462964
*/
29472965
if (OidIsValid(MyDatabaseId))
29482966
pgstat_report_stat(true);
2967+
2968+
#ifdef USE_ASSERT_CHECKING
2969+
pgstat_is_shutdown = true;
2970+
#endif
29492971
}
29502972

29512973
/* ----------
29522974
* pgstat_initialize() -
29532975
*
2954-
* Initialize pgstats state, and set up our on-proc-exit hook.
2955-
* Called from InitPostgres and AuxiliaryProcessMain.
2976+
* Initialize pgstats state, and set up our on-proc-exit hook. Called from
2977+
* BaseInit().
29562978
*
29572979
* NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful.
29582980
* ----------
29592981
*/
29602982
void
29612983
pgstat_initialize(void)
29622984
{
2985+
Assert(!pgstat_is_initialized);
2986+
29632987
/*
29642988
* Initialize prevWalUsage with pgWalUsage so that pgstat_send_wal() can
29652989
* calculate how much pgWalUsage counters are increased by subtracting
@@ -2969,6 +2993,10 @@ pgstat_initialize(void)
29692993

29702994
/* Set up a process-exit hook to clean up */
29712995
on_shmem_exit(pgstat_shutdown_hook, 0);
2996+
2997+
#ifdef USE_ASSERT_CHECKING
2998+
pgstat_is_initialized = true;
2999+
#endif
29723000
}
29733001

29743002
/* ------------------------------------------------------------
@@ -3001,6 +3029,8 @@ pgstat_send(void *msg, int len)
30013029
{
30023030
int rc;
30033031

3032+
pgstat_assert_is_up();
3033+
30043034
if (pgStatSock == PGINVALID_SOCKET)
30053035
return;
30063036

@@ -3053,6 +3083,8 @@ pgstat_send_bgwriter(void)
30533083
/* We assume this initializes to zeroes */
30543084
static const PgStat_MsgBgWriter all_zeroes;
30553085

3086+
pgstat_assert_is_up();
3087+
30563088
/*
30573089
* This function can be called even if nothing at all has happened. In
30583090
* this case, avoid sending a completely empty message to the stats
@@ -4629,6 +4661,8 @@ backend_read_statsfile(void)
46294661
Oid inquiry_db;
46304662
int count;
46314663

4664+
pgstat_assert_is_up();
4665+
46324666
/* already read it? */
46334667
if (pgStatDBHash)
46344668
return;
@@ -4765,6 +4799,17 @@ pgstat_setup_memcxt(void)
47654799
ALLOCSET_SMALL_SIZES);
47664800
}
47674801

4802+
/*
4803+
* Stats should only be reported after pgstat_initialize() and before
4804+
* pgstat_shutdown(). This check is put in a few central places to catch
4805+
* violations of this rule more easily.
4806+
*/
4807+
static void
4808+
pgstat_assert_is_up(void)
4809+
{
4810+
Assert(pgstat_is_initialized && !pgstat_is_shutdown);
4811+
}
4812+
47684813

47694814
/* ----------
47704815
* pgstat_clear_snapshot() -
@@ -4779,6 +4824,8 @@ pgstat_setup_memcxt(void)
47794824
void
47804825
pgstat_clear_snapshot(void)
47814826
{
4827+
pgstat_assert_is_up();
4828+
47824829
/* Release memory, if any was allocated */
47834830
if (pgStatLocalContext)
47844831
MemoryContextDelete(pgStatLocalContext);
@@ -5897,6 +5944,8 @@ pgstat_slru_name(int slru_idx)
58975944
static inline PgStat_MsgSLRU *
58985945
slru_entry(int slru_idx)
58995946
{
5947+
pgstat_assert_is_up();
5948+
59005949
/*
59015950
* The postmaster should never register any SLRU statistics counts; if it
59025951
* did, the counts would be duplicated into child processes via fork().

src/backend/utils/init/postinit.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,14 @@ BaseInit(void)
517517
*/
518518
DebugFileOpen();
519519

520+
/*
521+
* Initialize statistics reporting. This needs to happen early to ensure
522+
* that pgstat's shutdown callback runs after the shutdown callbacks of
523+
* all subsystems that can produce stats (like e.g. transaction commits
524+
* can).
525+
*/
526+
pgstat_initialize();
527+
520528
/* Do local initialization of file, storage and buffer managers */
521529
InitFileAccess();
522530
InitSync();
@@ -646,10 +654,6 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
646654
/* Initialize portal manager */
647655
EnablePortalManager();
648656

649-
/* Initialize stats collection --- must happen before first xact */
650-
if (!bootstrap)
651-
pgstat_initialize();
652-
653657
/* Initialize status reporting */
654658
if (!bootstrap)
655659
pgstat_beinit();
@@ -662,11 +666,12 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
662666

663667
/*
664668
* Set up process-exit callback to do pre-shutdown cleanup. This is the
665-
* first before_shmem_exit callback we register; thus, this will be the
666-
* last thing we do before low-level modules like the buffer manager begin
667-
* to close down. We need to have this in place before we begin our first
668-
* transaction --- if we fail during the initialization transaction, as is
669-
* entirely possible, we need the AbortTransaction call to clean up.
669+
* one of the first before_shmem_exit callbacks we register; thus, this
670+
* will be one the last things we do before low-level modules like the
671+
* buffer manager begin to close down. We need to have this in place
672+
* before we begin our first transaction --- if we fail during the
673+
* initialization transaction, as is entirely possible, we need the
674+
* AbortTransaction call to clean up.
670675
*/
671676
before_shmem_exit(ShutdownPostgres, 0);
672677

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy