Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

-2
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

+51-2
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

+14-9
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)