Skip to content

Commit a4cc7ea

Browse files
committed
Explicitly reset memory context
Attaching memory reset callback to MessageContext is wrong as for background workers that use SPI for query execution such context doesn't exist. There is no other context which lifetime matches our needs, so instead reset our memory context explicitly when we no longer need its data.
1 parent b6ffd37 commit a4cc7ea

1 file changed

Lines changed: 162 additions & 159 deletions

File tree

pg_stat_monitor.c

Lines changed: 162 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -202,18 +202,9 @@ static void pgsm_add_to_list(pgsmEntry *entry, char *query_text, int query_len);
202202
static void pgsm_delete_entry(uint64 queryid);
203203
static pgsmEntry *pgsm_get_entry_for_query(int64 queryid, PlanInfo *plan_info, const char *query_text, int query_len, bool create, CmdType cmd_type);
204204
static int64 get_pgsm_query_id_hash(const char *norm_query, int len);
205-
206-
static void pgsm_cleanup_callback(void *arg);
205+
static void pgsm_cleanup_memory(void);
207206
static void pgsm_store_error(const char *query, ErrorData *edata);
208207

209-
/*---- Local variables ----*/
210-
static MemoryContextCallback mem_cxt_reset_callback =
211-
{
212-
.func = pgsm_cleanup_callback,
213-
.arg = NULL
214-
};
215-
static volatile bool callback_setup = false;
216-
217208
static void pgsm_update_entry(pgsmEntry *entry,
218209
const char *query,
219210
char *comments,
@@ -389,19 +380,6 @@ pgsm_post_parse_analyze_internal(ParseState *pstate, Query *query, JumbleState *
389380
if (!IsSystemInitialized())
390381
return;
391382

392-
if (callback_setup == false)
393-
{
394-
/*
395-
* If MessageContext is valid setup a callback to cleanup our local
396-
* stats list when the MessagContext gets reset
397-
*/
398-
if (MemoryContextIsValid(MessageContext))
399-
{
400-
MemoryContextRegisterResetCallback(MessageContext, &mem_cxt_reset_callback);
401-
callback_setup = true;
402-
}
403-
}
404-
405383
if (!pgsm_enabled(nesting_level))
406384
return;
407385

@@ -757,6 +735,15 @@ pgsm_ExecutorEnd(QueryDesc *queryDesc)
757735
pgsm_delete_entry(queryDesc->plannedstmt->queryId);
758736

759737
num_relations = 0;
738+
739+
#if PG_VERSION_NUM >= 170000
740+
if (nesting_level == 0)
741+
#else
742+
if ((nesting_level + plan_nested_level) == 0)
743+
#endif
744+
{
745+
pgsm_cleanup_memory();
746+
}
760747
}
761748

762749
static bool
@@ -1013,175 +1000,192 @@ pgsm_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
10131000
*
10141001
* Likewise, we don't track execution of DEALLOCATE.
10151002
*/
1016-
if (enabled &&
1017-
!IsA(parsetree, ExecuteStmt) &&
1018-
!IsA(parsetree, PrepareStmt) &&
1019-
!IsA(parsetree, DeallocateStmt))
1003+
PG_TRY();
10201004
{
1021-
pgsmEntry *entry;
1022-
char *query_text;
1023-
int location;
1024-
int query_len;
1025-
instr_time start;
1026-
instr_time duration;
1027-
uint64 rows;
1028-
SysInfo sys_info;
1029-
BufferUsage bufusage;
1030-
BufferUsage bufusage_start = pgBufferUsage;
1031-
WalUsage walusage;
1032-
WalUsage walusage_start = pgWalUsage;
1033-
1034-
if (getrusage(RUSAGE_SELF, &rusage_start) != 0)
1035-
elog(DEBUG1, "[pg_stat_monitor] pgsm_ProcessUtility: Failed to execute getrusage.");
1036-
1037-
INSTR_TIME_SET_CURRENT(start);
1038-
nesting_level++;
1039-
1040-
PG_TRY();
1005+
if (enabled &&
1006+
!IsA(parsetree, ExecuteStmt) &&
1007+
!IsA(parsetree, PrepareStmt) &&
1008+
!IsA(parsetree, DeallocateStmt))
10411009
{
1042-
if (prev_ProcessUtility)
1043-
prev_ProcessUtility(pstmt, queryString,
1044-
readOnlyTree,
1045-
context, params, queryEnv,
1046-
dest,
1047-
qc);
1048-
else
1049-
standard_ProcessUtility(pstmt, queryString,
1010+
pgsmEntry *entry;
1011+
char *query_text;
1012+
int location;
1013+
int query_len;
1014+
instr_time start;
1015+
instr_time duration;
1016+
uint64 rows;
1017+
SysInfo sys_info;
1018+
BufferUsage bufusage;
1019+
BufferUsage bufusage_start = pgBufferUsage;
1020+
WalUsage walusage;
1021+
WalUsage walusage_start = pgWalUsage;
1022+
1023+
if (getrusage(RUSAGE_SELF, &rusage_start) != 0)
1024+
elog(DEBUG1, "[pg_stat_monitor] pgsm_ProcessUtility: Failed to execute getrusage.");
1025+
1026+
INSTR_TIME_SET_CURRENT(start);
1027+
nesting_level++;
1028+
1029+
PG_TRY(1);
1030+
{
1031+
if (prev_ProcessUtility)
1032+
prev_ProcessUtility(pstmt, queryString,
10501033
readOnlyTree,
10511034
context, params, queryEnv,
10521035
dest,
10531036
qc);
1054-
nesting_level--;
1055-
}
1056-
PG_CATCH();
1057-
{
1058-
nesting_level--;
1059-
PG_RE_THROW();
1060-
}
1037+
else
1038+
standard_ProcessUtility(pstmt, queryString,
1039+
readOnlyTree,
1040+
context, params, queryEnv,
1041+
dest,
1042+
qc);
1043+
nesting_level--;
1044+
}
1045+
PG_CATCH(1);
1046+
{
1047+
nesting_level--;
1048+
PG_RE_THROW();
1049+
}
10611050

1062-
sys_info.utime = 0;
1063-
sys_info.stime = 0;
1051+
sys_info.utime = 0;
1052+
sys_info.stime = 0;
10641053

1065-
PG_END_TRY();
1054+
PG_END_TRY(1);
10661055

1067-
if (getrusage(RUSAGE_SELF, &rusage_end) != 0)
1068-
elog(DEBUG1, "[pg_stat_monitor] pgsm_ProcessUtility: Failed to execute getrusage.");
1069-
else
1070-
{
1071-
sys_info.utime = time_diff(rusage_end.ru_utime, rusage_start.ru_utime);
1072-
sys_info.stime = time_diff(rusage_end.ru_stime, rusage_start.ru_stime);
1073-
}
1056+
if (getrusage(RUSAGE_SELF, &rusage_end) != 0)
1057+
elog(DEBUG1, "[pg_stat_monitor] pgsm_ProcessUtility: Failed to execute getrusage.");
1058+
else
1059+
{
1060+
sys_info.utime = time_diff(rusage_end.ru_utime, rusage_start.ru_utime);
1061+
sys_info.stime = time_diff(rusage_end.ru_stime, rusage_start.ru_stime);
1062+
}
10741063

1075-
INSTR_TIME_SET_CURRENT(duration);
1076-
INSTR_TIME_SUBTRACT(duration, start);
1064+
INSTR_TIME_SET_CURRENT(duration);
1065+
INSTR_TIME_SUBTRACT(duration, start);
10771066

1078-
rows = (qc && (qc->commandTag == CMDTAG_COPY ||
1079-
qc->commandTag == CMDTAG_FETCH ||
1080-
qc->commandTag == CMDTAG_SELECT ||
1081-
qc->commandTag == CMDTAG_REFRESH_MATERIALIZED_VIEW))
1082-
? qc->nprocessed
1083-
: 0;
1067+
rows = (qc && (qc->commandTag == CMDTAG_COPY ||
1068+
qc->commandTag == CMDTAG_FETCH ||
1069+
qc->commandTag == CMDTAG_SELECT ||
1070+
qc->commandTag == CMDTAG_REFRESH_MATERIALIZED_VIEW))
1071+
? qc->nprocessed
1072+
: 0;
10841073

1085-
/* calc differences of WAL counters. */
1086-
memset(&walusage, 0, sizeof(WalUsage));
1087-
WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
1074+
/* calc differences of WAL counters. */
1075+
memset(&walusage, 0, sizeof(WalUsage));
1076+
WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
10881077

1089-
/* calc differences of buffer counters. */
1090-
memset(&bufusage, 0, sizeof(BufferUsage));
1091-
BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
1078+
/* calc differences of buffer counters. */
1079+
memset(&bufusage, 0, sizeof(BufferUsage));
1080+
BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
10921081

1093-
/* Create an entry for this query */
1094-
entry = pgsm_create_hash_entry(0, queryId, NULL);
1082+
/* Create an entry for this query */
1083+
entry = pgsm_create_hash_entry(0, queryId, NULL);
10951084

1096-
location = pstmt->stmt_location;
1097-
query_len = pstmt->stmt_len;
1098-
query_text = (char *) CleanQuerytext(queryString, &location, &query_len);
1085+
location = pstmt->stmt_location;
1086+
query_len = pstmt->stmt_len;
1087+
query_text = (char *) CleanQuerytext(queryString, &location, &query_len);
10991088

1100-
entry->pgsm_query_id = get_pgsm_query_id_hash(query_text, query_len);
1101-
entry->counters.info.cmd_type = pstmt->commandType;
1089+
entry->pgsm_query_id = get_pgsm_query_id_hash(query_text, query_len);
1090+
entry->counters.info.cmd_type = pstmt->commandType;
11021091

1103-
pgsm_add_to_list(entry, query_text, query_len);
1092+
pgsm_add_to_list(entry, query_text, query_len);
11041093

1105-
/* Check that we've not exceeded max_stack_depth */
1106-
Assert(list_length(lentries) <= max_stack_depth);
1094+
/* Check that we've not exceeded max_stack_depth */
1095+
Assert(list_length(lentries) <= max_stack_depth);
11071096

1108-
/* The plan details are captured when the query finishes */
1109-
pgsm_update_entry(entry, /* entry */
1110-
(char *) query_text, /* query */
1111-
NULL, /* comments */
1112-
0, /* comments length */
1113-
NULL, /* PlanInfo */
1114-
&sys_info, /* SysInfo */
1115-
NULL, /* ErrorInfo */
1116-
0, /* plan_total_time */
1117-
INSTR_TIME_GET_MILLISEC(duration), /* exec_total_time */
1118-
rows, /* rows */
1119-
&bufusage, /* bufusage */
1120-
&walusage, /* walusage */
1121-
NULL, /* jitusage */
1122-
0, /* parallel_workers_to_launch */
1123-
0, /* parallel_workers_launched */
1124-
false, /* reset */
1125-
PGSM_EXEC); /* kind */
1097+
/* The plan details are captured when the query finishes */
1098+
pgsm_update_entry(entry, /* entry */
1099+
(char *) query_text, /* query */
1100+
NULL, /* comments */
1101+
0, /* comments length */
1102+
NULL, /* PlanInfo */
1103+
&sys_info, /* SysInfo */
1104+
NULL, /* ErrorInfo */
1105+
0, /* plan_total_time */
1106+
INSTR_TIME_GET_MILLISEC(duration), /* exec_total_time */
1107+
rows, /* rows */
1108+
&bufusage, /* bufusage */
1109+
&walusage, /* walusage */
1110+
NULL, /* jitusage */
1111+
0, /* parallel_workers_to_launch */
1112+
0, /* parallel_workers_launched */
1113+
false, /* reset */
1114+
PGSM_EXEC); /* kind */
11261115

1127-
pgsm_store(entry);
1128-
}
1129-
else
1130-
{
1131-
/*
1132-
* Even though we're not tracking execution time for this statement,
1133-
* we must still increment the nesting level, to ensure that functions
1134-
* evaluated within it are not seen as top-level calls. But don't do
1135-
* so for EXECUTE; that way, when control reaches pgss_planner or
1136-
* pgss_ExecutorStart, we will treat the costs as top-level if
1137-
* appropriate. Likewise, don't bump for PREPARE, so that parse
1138-
* analysis will treat the statement as top-level if appropriate.
1139-
*
1140-
* Likewise, we don't track execution of DEALLOCATE.
1141-
*
1142-
* To be absolutely certain we don't mess up the nesting level,
1143-
* evaluate the bump_level condition just once.
1144-
*/
1116+
pgsm_store(entry);
1117+
}
1118+
else
1119+
{
1120+
/*
1121+
* Even though we're not tracking execution time for this
1122+
* statement, we must still increment the nesting level, to ensure
1123+
* that functions evaluated within it are not seen as top-level
1124+
* calls. But don't do so for EXECUTE; that way, when control
1125+
* reaches pgss_planner or pgss_ExecutorStart, we will treat the
1126+
* costs as top-level if appropriate. Likewise, don't bump for
1127+
* PREPARE, so that parse analysis will treat the statement as
1128+
* top-level if appropriate.
1129+
*
1130+
*
1131+
* Likewise, we don't track execution of DEALLOCATE.
1132+
*
1133+
* To be absolutely certain we don't mess up the nesting level,
1134+
* evaluate the bump_level condition just once.
1135+
*/
11451136

11461137
#if PG_VERSION_NUM >= 170000
1147-
bool bump_level =
1148-
!IsA(parsetree, ExecuteStmt) &&
1149-
!IsA(parsetree, PrepareStmt) &&
1150-
!IsA(parsetree, DeallocateStmt);
1138+
bool bump_level =
1139+
!IsA(parsetree, ExecuteStmt) &&
1140+
!IsA(parsetree, PrepareStmt) &&
1141+
!IsA(parsetree, DeallocateStmt);
11511142

1152-
if (bump_level)
1153-
nesting_level++;
1143+
if (bump_level)
1144+
nesting_level++;
11541145

1155-
PG_TRY();
1156-
{
1146+
PG_TRY(2);
1147+
{
11571148
#endif
1158-
if (prev_ProcessUtility)
1159-
prev_ProcessUtility(pstmt, queryString,
1160-
readOnlyTree,
1161-
context, params, queryEnv,
1162-
dest,
1163-
qc);
1164-
else
1165-
standard_ProcessUtility(pstmt, queryString,
1149+
if (prev_ProcessUtility)
1150+
prev_ProcessUtility(pstmt, queryString,
11661151
readOnlyTree,
11671152
context, params, queryEnv,
11681153
dest,
11691154
qc);
1155+
else
1156+
standard_ProcessUtility(pstmt, queryString,
1157+
readOnlyTree,
1158+
context, params, queryEnv,
1159+
dest,
1160+
qc);
11701161

11711162
#if PG_VERSION_NUM >= 170000
1172-
if (bump_level)
1173-
nesting_level--;
1163+
if (bump_level)
1164+
nesting_level--;
1165+
}
1166+
PG_CATCH(2);
1167+
{
1168+
if (bump_level)
1169+
nesting_level--;
1170+
PG_RE_THROW();
1171+
}
1172+
PG_END_TRY(2);
1173+
#endif
11741174
}
1175-
PG_CATCH();
1175+
pgsm_delete_entry(pstmt->queryId);
1176+
}
1177+
PG_FINALLY();
1178+
{
1179+
#if PG_VERSION_NUM >= 170000
1180+
if (nesting_level == 0)
1181+
#else
1182+
if ((nesting_level + plan_nested_level) == 0)
1183+
#endif
11761184
{
1177-
if (bump_level)
1178-
nesting_level--;
1179-
PG_RE_THROW();
1185+
pgsm_cleanup_memory();
11801186
}
1181-
PG_END_TRY();
1182-
#endif
11831187
}
1184-
pgsm_delete_entry(pstmt->queryId);
1188+
PG_END_TRY();
11851189
}
11861190

11871191
/*
@@ -1678,13 +1682,12 @@ pgsm_get_entry_for_query(int64 queryid, PlanInfo *plan_info, const char *query_t
16781682
}
16791683

16801684
static void
1681-
pgsm_cleanup_callback(void *arg)
1685+
pgsm_cleanup_memory()
16821686
{
16831687
/* Reset the memory context holding the list */
16841688
MemoryContextReset(GetPgsmMemoryContext());
16851689

16861690
lentries = NIL;
1687-
callback_setup = false;
16881691
}
16891692

16901693
/*

0 commit comments

Comments
 (0)