Issue - (#34): PostgreSQL Version 13 support added.
parent
5536041539
commit
355436c4dc
|
@ -99,13 +99,13 @@ SELECT query, calls, rows FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
|||
query | calls | rows
|
||||
---------------------------------------------------+-------+------
|
||||
PREPARE pgss_test (int) AS SELECT $1, $2 LIMIT $3 | 1 | 1
|
||||
SELECT $1 | 2 | 2
|
||||
SELECT $1 +| 4 | 4
|
||||
+| |
|
||||
AS "text" | |
|
||||
SELECT $1 + $2 | 2 | 2
|
||||
SELECT $1 + $2 + $3 AS "add" | 3 | 3
|
||||
SELECT $1 AS "float" | 1 | 1
|
||||
SELECT $1 AS "int" | 2 | 2
|
||||
SELECT $1 AS i UNION SELECT $2 ORDER BY i | 1 | 2
|
||||
SELECT $1 || $2 | 1 | 1
|
||||
SELECT pg_stat_monitor_reset() | 1 | 1
|
||||
|
@ -233,8 +233,10 @@ SELECT 1 + 1 AS "two";
|
|||
|
||||
SELECT query, calls, rows FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
||||
query | calls | rows
|
||||
-------+-------+------
|
||||
(0 rows)
|
||||
----------------+-------+------
|
||||
SELECT $1 | 0 | 0
|
||||
SELECT $1 + $2 | 0 | 0
|
||||
(2 rows)
|
||||
|
||||
--
|
||||
-- pg_stat_monitor.track = top
|
||||
|
@ -289,14 +291,16 @@ SELECT PLUS_ONE(10);
|
|||
|
||||
SELECT query, calls, rows FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
||||
query | calls | rows
|
||||
--------------------------------+-------+------
|
||||
-----------------------------------+-------+------
|
||||
SELECT $1 +| 1 | 1
|
||||
+| |
|
||||
AS "text" | |
|
||||
SELECT (i + $2 + $3)::INTEGER | 0 | 0
|
||||
SELECT (i + $2)::INTEGER LIMIT $3 | 0 | 0
|
||||
SELECT PLUS_ONE($1) | 2 | 2
|
||||
SELECT PLUS_TWO($1) | 2 | 2
|
||||
SELECT pg_stat_monitor_reset() | 1 | 1
|
||||
(4 rows)
|
||||
(6 rows)
|
||||
|
||||
--
|
||||
-- pg_stat_monitor.track = all
|
||||
|
@ -393,7 +397,7 @@ SELECT query, calls, rows FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
|||
DROP FUNCTION PLUS_TWO(INTEGER) | 1 | 0
|
||||
DROP TABLE IF EXISTS test | 3 | 0
|
||||
DROP TABLE test | 1 | 0
|
||||
SELECT $1 AS "int" | 1 | 1
|
||||
SELECT $1 | 1 | 1
|
||||
SELECT pg_stat_monitor_reset() | 1 | 1
|
||||
(8 rows)
|
||||
|
||||
|
|
25
guc.c
25
guc.c
|
@ -53,6 +53,7 @@ init_guc(void)
|
|||
.guc_max = 0,
|
||||
.guc_restart = false
|
||||
};
|
||||
|
||||
conf[i++] = (GucVariable) {
|
||||
.guc_name = "pg_stat_monitor.pgsm_normalized_query",
|
||||
.guc_desc = "Selects whether save query in normalized format.",
|
||||
|
@ -112,6 +113,16 @@ init_guc(void)
|
|||
.guc_max = INT_MAX,
|
||||
.guc_restart = true
|
||||
};
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
conf[i++] = (GucVariable) {
|
||||
.guc_name = "pg_stat_monitor.pgsm_track_planning",
|
||||
.guc_desc = "Selects whether planning statistics are tracked.",
|
||||
.guc_default = 1,
|
||||
.guc_min = 0,
|
||||
.guc_max = 0,
|
||||
.guc_restart = false
|
||||
};
|
||||
#endif
|
||||
|
||||
DefineCustomIntVariable("pg_stat_monitor.max",
|
||||
"Sets the maximum number of statements tracked by pg_stat_monitor.",
|
||||
|
@ -173,7 +184,7 @@ init_guc(void)
|
|||
NULL,
|
||||
NULL);
|
||||
|
||||
DefineCustomIntVariable("pg_stat_monitor.PGSM_MAX_buckets ",
|
||||
DefineCustomIntVariable("pg_stat_monitor.pgsm_max_buckets ",
|
||||
"Sets the maximum number of buckets.",
|
||||
NULL,
|
||||
&PGSM_MAX_BUCKETS,
|
||||
|
@ -239,7 +250,7 @@ init_guc(void)
|
|||
NULL,
|
||||
NULL);
|
||||
|
||||
DefineCustomIntVariable("pg_stat_monitor.query_shared_buffer",
|
||||
DefineCustomIntVariable("pg_stat_monitor.pgsm_query_shared_buffer.",
|
||||
"Sets the shared_buffer size",
|
||||
NULL,
|
||||
&PGSM_QUERY_BUF_SIZE,
|
||||
|
@ -251,6 +262,16 @@ init_guc(void)
|
|||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
DefineCustomBoolVariable("pg_stat_monitor.pgsm_track_planning",
|
||||
"Selects whether track planning statistics.",
|
||||
NULL,
|
||||
(bool*)&PGSM_TRACK_PLANNING,
|
||||
true,
|
||||
PGC_SUSET,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,16 @@ CREATE FUNCTION pg_stat_monitor(IN showtext boolean,
|
|||
OUT queryid text,
|
||||
OUT query text,
|
||||
OUT bucket_start_time timestamptz,
|
||||
|
||||
|
||||
OUT plan_calls int8,
|
||||
OUT plan_total_time float8,
|
||||
OUT plan_min_time float8,
|
||||
OUT plan_max_time float8,
|
||||
OUT plan_mean_time float8,
|
||||
OUT plan_stddev_time float8,
|
||||
OUT plan_rows int8,
|
||||
|
||||
OUT calls int8,
|
||||
OUT total_time float8,
|
||||
OUT min_time float8,
|
||||
|
@ -24,6 +34,7 @@ CREATE FUNCTION pg_stat_monitor(IN showtext boolean,
|
|||
OUT mean_time float8,
|
||||
OUT stddev_time float8,
|
||||
OUT rows int8,
|
||||
|
||||
OUT shared_blks_hit int8,
|
||||
OUT shared_blks_read int8,
|
||||
OUT shared_blks_dirtied int8,
|
||||
|
@ -96,12 +107,19 @@ CREATE VIEW pg_stat_monitor AS SELECT
|
|||
dbid,
|
||||
m.queryid,
|
||||
query,
|
||||
plan_calls,
|
||||
round( CAST(plan_total_time as numeric), 2) as plan_total_time,
|
||||
round( CAST(plan_min_time as numeric), 2) as plan_min_timei,
|
||||
round( CAST(plan_max_time as numeric), 2) as plan_max_time,
|
||||
round( CAST(plan_mean_time as numeric), 2) as plan_mean_time,
|
||||
round( CAST(plan_stddev_time as numeric), 2) as plan_stddev_time,
|
||||
plan_rows,
|
||||
calls,
|
||||
total_time,
|
||||
min_time,
|
||||
max_time,
|
||||
mean_time,
|
||||
stddev_time,
|
||||
round( CAST(total_time as numeric), 2)as total_time,
|
||||
round( CAST(min_time as numeric), 2)as min_time,
|
||||
round( CAST(max_time as numeric), 2)as max_time,
|
||||
round( CAST(mean_time as numeric), 2)as mean_time,
|
||||
round( CAST(stddev_time as numeric), 2)as stddev_time,
|
||||
rows,
|
||||
shared_blks_hit,
|
||||
shared_blks_read,
|
||||
|
|
|
@ -25,6 +25,10 @@ void _PG_fini(void);
|
|||
|
||||
/* Current nesting depth of ExecutorRun+ProcessUtility calls */
|
||||
static int nested_level = 0;
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
static int plan_nested_level = 0;
|
||||
static int exec_nested_level = 0;
|
||||
#endif
|
||||
static struct rusage rusage_start;
|
||||
static struct rusage rusage_end;
|
||||
static volatile sig_atomic_t sigterm = false;
|
||||
|
@ -77,10 +81,10 @@ static Datum array_get_datum(int arr[]);
|
|||
static void update_agg_counters(uint64 bucket_id, uint64 queryid, uint64 id, AGG_KEY type);
|
||||
static pgssAggEntry *agg_entry_alloc(pgssAggHashKey *key);
|
||||
void add_object_entry(uint64 queryid, char *objects);
|
||||
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
static PlannedStmt * pgss_planner_hook(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams);
|
||||
#else
|
||||
static void BufferUsageAccumDiff(BufferUsage* bufusage, BufferUsage* pgBufferUsage, BufferUsage* bufusage_start);
|
||||
static PlannedStmt *pgss_planner_hook(Query *parse, int opt, ParamListInfo param);
|
||||
#endif
|
||||
|
||||
|
@ -91,21 +95,34 @@ static void pgss_ExecutorStart(QueryDesc *queryDesc, int eflags);
|
|||
static void pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once);
|
||||
static void pgss_ExecutorFinish(QueryDesc *queryDesc);
|
||||
static void pgss_ExecutorEnd(QueryDesc *queryDesc);
|
||||
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
||||
ProcessUtilityContext context,
|
||||
ParamListInfo params, QueryEnvironment *queryEnv,
|
||||
DestReceiver *dest,
|
||||
QueryCompletion *qc
|
||||
);
|
||||
#else
|
||||
static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
||||
ProcessUtilityContext context, ParamListInfo params,
|
||||
QueryEnvironment *queryEnv,
|
||||
DestReceiver *dest,
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
QueryCompletion *qc);
|
||||
#else
|
||||
char *completionTag);
|
||||
#endif
|
||||
|
||||
static uint64 pgss_hash_string(const char *str, int len);
|
||||
static void pgss_store(const char *query, uint64 queryId,
|
||||
int query_location, int query_len,
|
||||
bool kind,
|
||||
double total_time, uint64 rows,
|
||||
const BufferUsage *bufusage, float utime, float stime,
|
||||
pgssJumbleState *jstate);
|
||||
const BufferUsage *bufusage,
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
const WalUsage *walusage,
|
||||
#endif
|
||||
pgssJumbleState *jstate,
|
||||
float utime, float stime);
|
||||
|
||||
static void pg_stat_monitor_internal(FunctionCallInfo fcinfo,
|
||||
bool showtext);
|
||||
static Size pgss_memsize(void);
|
||||
|
@ -232,10 +249,6 @@ pgss_shmem_startup(void)
|
|||
bool found = false;
|
||||
int32 i;
|
||||
|
||||
elog(WARNING, "pg_stat_monitor: %s()", __FUNCTION__);
|
||||
|
||||
Assert(IsHashInitialize());
|
||||
|
||||
if (prev_shmem_startup_hook)
|
||||
prev_shmem_startup_hook();
|
||||
|
||||
|
@ -290,7 +303,7 @@ pgss_shmem_startup(void)
|
|||
sizeof(pgssAggEntry),
|
||||
PGSM_MAX * 3);
|
||||
|
||||
Assert(!IsHashInitialize());
|
||||
Assert(IsHashInitialize());
|
||||
|
||||
pgssWaitEventEntries = malloc(sizeof (pgssWaitEventEntry) * MAX_BACKEND_PROCESES);
|
||||
for (i = 0; i < MAX_BACKEND_PROCESES; i++)
|
||||
|
@ -372,7 +385,7 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query)
|
|||
Assert(query->queryId == UINT64CONST(0));
|
||||
|
||||
/* Safety check... */
|
||||
if (IsHashInitialize())
|
||||
if (!IsHashInitialize())
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -438,12 +451,16 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query)
|
|||
query->queryId,
|
||||
query->stmt_location,
|
||||
query->stmt_len,
|
||||
PGSS_INVALID,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
&jstate);
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
NULL,
|
||||
#endif
|
||||
&jstate,
|
||||
0.0,
|
||||
0.0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -535,9 +552,9 @@ pgss_ExecutorFinish(QueryDesc *queryDesc)
|
|||
static void
|
||||
pgss_ExecutorEnd(QueryDesc *queryDesc)
|
||||
{
|
||||
uint64 queryId = queryDesc->plannedstmt->queryId;
|
||||
float utime;
|
||||
float stime;
|
||||
uint64 queryId = queryDesc->plannedstmt->queryId;
|
||||
|
||||
if (queryId != UINT64CONST(0) && queryDesc->totaltime && PGSS_ENABLED())
|
||||
{
|
||||
|
@ -549,16 +566,21 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
|
|||
getrusage(RUSAGE_SELF, &rusage_end);
|
||||
utime = TIMEVAL_DIFF(rusage_start.ru_utime, rusage_end.ru_utime);
|
||||
stime = TIMEVAL_DIFF(rusage_start.ru_stime, rusage_end.ru_stime);
|
||||
|
||||
pgss_store(queryDesc->sourceText,
|
||||
queryId,
|
||||
queryDesc->plannedstmt->stmt_location,
|
||||
queryDesc->plannedstmt->stmt_len,
|
||||
PGSS_EXEC,
|
||||
queryDesc->totaltime->total * 1000.0, /* convert to msec */
|
||||
queryDesc->estate->es_processed,
|
||||
&queryDesc->totaltime->bufusage,
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
&queryDesc->totaltime->walusage,
|
||||
#endif
|
||||
NULL,
|
||||
utime,
|
||||
stime,
|
||||
NULL);
|
||||
stime);
|
||||
}
|
||||
|
||||
if (prev_ExecutorEnd)
|
||||
|
@ -571,14 +593,17 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
|
|||
/*
|
||||
* ProcessUtility hook
|
||||
*/
|
||||
static void
|
||||
pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
||||
ProcessUtilityContext context,
|
||||
ParamListInfo params, QueryEnvironment *queryEnv,
|
||||
DestReceiver *dest,
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
QueryCompletion *qc)
|
||||
#else
|
||||
static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
||||
ProcessUtilityContext context, ParamListInfo params,
|
||||
QueryEnvironment *queryEnv,
|
||||
DestReceiver *dest,
|
||||
char *completionTag)
|
||||
#endif
|
||||
{
|
||||
|
@ -598,7 +623,7 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
|||
*
|
||||
* Likewise, we don't track execution of DEALLOCATE.
|
||||
*/
|
||||
if (PGSM_TRACK_UTILITY && PGSS_ENABLED() &&
|
||||
if (PGSM_TRACK_UTILITY &&
|
||||
!IsA(parsetree, ExecuteStmt) &&
|
||||
!IsA(parsetree, PrepareStmt) &&
|
||||
!IsA(parsetree, DeallocateStmt))
|
||||
|
@ -608,42 +633,61 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
|||
uint64 rows;
|
||||
BufferUsage bufusage_start,
|
||||
bufusage;
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
WalUsage walusage_start,
|
||||
walusage;
|
||||
walusage_start = pgWalUsage;
|
||||
exec_nested_level++;
|
||||
#endif
|
||||
|
||||
bufusage_start = pgBufferUsage;
|
||||
INSTR_TIME_SET_CURRENT(start);
|
||||
|
||||
nested_level++;
|
||||
PG_TRY();
|
||||
{
|
||||
if (prev_ProcessUtility)
|
||||
prev_ProcessUtility(pstmt, queryString,
|
||||
context, params, queryEnv,
|
||||
dest
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
dest, qc);
|
||||
,qc
|
||||
#else
|
||||
dest, completionTag);
|
||||
,completionTag
|
||||
#endif
|
||||
);
|
||||
else
|
||||
standard_ProcessUtility(pstmt, queryString,
|
||||
context, params, queryEnv,
|
||||
dest
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
dest, qc);
|
||||
,qc
|
||||
#else
|
||||
dest, completionTag);
|
||||
,completionTag
|
||||
#endif
|
||||
nested_level--;
|
||||
);
|
||||
}
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
PG_FINALLY();
|
||||
{
|
||||
exec_nested_level--;
|
||||
}
|
||||
#else
|
||||
PG_CATCH();
|
||||
{
|
||||
nested_level--;
|
||||
PG_RE_THROW();
|
||||
}
|
||||
PG_END_TRY();
|
||||
|
||||
}
|
||||
#endif
|
||||
PG_END_TRY();
|
||||
INSTR_TIME_SET_CURRENT(duration);
|
||||
INSTR_TIME_SUBTRACT(duration, start);
|
||||
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
rows = (qc && qc->commandTag == CMDTAG_COPY) ? qc->nprocessed : 0;
|
||||
/* calc differences of WAL counters. */
|
||||
memset(&walusage, 0, sizeof(WalUsage));
|
||||
WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
|
||||
#else
|
||||
/* parse command tag to retrieve the number of affected rows. */
|
||||
if (completionTag && strncmp(completionTag, "COPY ", 5) == 0)
|
||||
|
@ -653,64 +697,69 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
|||
#endif
|
||||
|
||||
/* calc differences of buffer counters. */
|
||||
bufusage.shared_blks_hit =
|
||||
pgBufferUsage.shared_blks_hit - bufusage_start.shared_blks_hit;
|
||||
bufusage.shared_blks_read =
|
||||
pgBufferUsage.shared_blks_read - bufusage_start.shared_blks_read;
|
||||
bufusage.shared_blks_dirtied =
|
||||
pgBufferUsage.shared_blks_dirtied - bufusage_start.shared_blks_dirtied;
|
||||
bufusage.shared_blks_written =
|
||||
pgBufferUsage.shared_blks_written - bufusage_start.shared_blks_written;
|
||||
bufusage.local_blks_hit =
|
||||
pgBufferUsage.local_blks_hit - bufusage_start.local_blks_hit;
|
||||
bufusage.local_blks_read =
|
||||
pgBufferUsage.local_blks_read - bufusage_start.local_blks_read;
|
||||
bufusage.local_blks_dirtied =
|
||||
pgBufferUsage.local_blks_dirtied - bufusage_start.local_blks_dirtied;
|
||||
bufusage.local_blks_written =
|
||||
pgBufferUsage.local_blks_written - bufusage_start.local_blks_written;
|
||||
bufusage.temp_blks_read =
|
||||
pgBufferUsage.temp_blks_read - bufusage_start.temp_blks_read;
|
||||
bufusage.temp_blks_written =
|
||||
pgBufferUsage.temp_blks_written - bufusage_start.temp_blks_written;
|
||||
bufusage.blk_read_time = pgBufferUsage.blk_read_time;
|
||||
INSTR_TIME_SUBTRACT(bufusage.blk_read_time, bufusage_start.blk_read_time);
|
||||
bufusage.blk_write_time = pgBufferUsage.blk_write_time;
|
||||
INSTR_TIME_SUBTRACT(bufusage.blk_write_time, bufusage_start.blk_write_time);
|
||||
memset(&bufusage, 0, sizeof(BufferUsage));
|
||||
BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
|
||||
|
||||
pgss_store(queryString,
|
||||
0, /* signal that it's a utility stmt */
|
||||
pstmt->stmt_location,
|
||||
pstmt->stmt_len,
|
||||
PGSS_EXEC,
|
||||
INSTR_TIME_GET_MILLISEC(duration),
|
||||
rows,
|
||||
&bufusage,
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
&walusage,
|
||||
#endif
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
NULL);
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prev_ProcessUtility)
|
||||
prev_ProcessUtility(pstmt, queryString,
|
||||
context, params, queryEnv,
|
||||
dest
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
dest, qc);
|
||||
,qc
|
||||
#else
|
||||
dest, completionTag);
|
||||
,completionTag
|
||||
#endif
|
||||
|
||||
else
|
||||
);
|
||||
standard_ProcessUtility(pstmt, queryString,
|
||||
context, params, queryEnv,
|
||||
dest
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
dest, qc);
|
||||
,qc
|
||||
#else
|
||||
dest, completionTag);
|
||||
,completionTag
|
||||
#endif
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#if PG_VERSION_NUM < 130000
|
||||
static void
|
||||
BufferUsageAccumDiff(BufferUsage* bufusage, BufferUsage* pgBufferUsage, BufferUsage* bufusage_start)
|
||||
{
|
||||
/* calc differences of buffer counters. */
|
||||
bufusage->shared_blks_hit = pgBufferUsage->shared_blks_hit - bufusage_start->shared_blks_hit;
|
||||
bufusage->shared_blks_read = pgBufferUsage->shared_blks_read - bufusage_start->shared_blks_read;
|
||||
bufusage->shared_blks_dirtied = pgBufferUsage->shared_blks_dirtied - bufusage_start->shared_blks_dirtied;
|
||||
bufusage->shared_blks_written = pgBufferUsage->shared_blks_written - bufusage_start->shared_blks_written;
|
||||
bufusage->local_blks_hit = pgBufferUsage->local_blks_hit - bufusage_start->local_blks_hit;
|
||||
bufusage->local_blks_read = pgBufferUsage->local_blks_read - bufusage_start->local_blks_read;
|
||||
bufusage->local_blks_dirtied = pgBufferUsage->local_blks_dirtied - bufusage_start->local_blks_dirtied;
|
||||
bufusage->local_blks_written = pgBufferUsage->local_blks_written - bufusage_start->local_blks_written;
|
||||
bufusage->temp_blks_read = pgBufferUsage->temp_blks_read - bufusage_start->temp_blks_read;
|
||||
bufusage->temp_blks_written = pgBufferUsage->temp_blks_written - bufusage_start->temp_blks_written;
|
||||
bufusage->blk_read_time = pgBufferUsage->blk_read_time;
|
||||
INSTR_TIME_SUBTRACT(bufusage->blk_read_time, bufusage_start->blk_read_time);
|
||||
bufusage->blk_write_time = pgBufferUsage->blk_write_time;
|
||||
INSTR_TIME_SUBTRACT(bufusage->blk_write_time, bufusage_start->blk_write_time);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Given an arbitrarily long query string, produce a hash for the purposes of
|
||||
* identifying the query, without normalizing constants. Used when hashing
|
||||
|
@ -769,12 +818,16 @@ pg_get_client_addr(void)
|
|||
* we have no statistics as yet; we just want to record the normalized
|
||||
* query string. total_time, rows, bufusage are ignored in this case.
|
||||
*/
|
||||
static void
|
||||
pgss_store(const char *query, uint64 queryId,
|
||||
static void pgss_store(const char *query, uint64 queryId,
|
||||
int query_location, int query_len,
|
||||
bool kind,
|
||||
double total_time, uint64 rows,
|
||||
const BufferUsage *bufusage,
|
||||
float utime, float stime, pgssJumbleState *jstate)
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
const WalUsage *walusage,
|
||||
#endif
|
||||
pgssJumbleState *jstate,
|
||||
float utime, float stime)
|
||||
{
|
||||
pgssHashKey key;
|
||||
pgssEntry *entry;
|
||||
|
@ -787,7 +840,7 @@ pgss_store(const char *query, uint64 queryId,
|
|||
Assert(query != NULL);
|
||||
|
||||
/* Safety check... */
|
||||
if (IsHashInitialize() || !pgss_qbuf[pgss->current_wbucket])
|
||||
if (!IsHashInitialize() || !pgss_qbuf[pgss->current_wbucket])
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -917,16 +970,16 @@ pgss_store(const char *query, uint64 queryId,
|
|||
update_agg_counters(entry->key.bucket_id, key.queryid, pg_get_client_addr(), AGG_KEY_HOST);
|
||||
|
||||
/* "Unstick" entry if it was previously sticky */
|
||||
if (e->counters.calls.calls == 0)
|
||||
e->counters.calls.usage = USAGE_INIT;
|
||||
if (e->counters.calls[kind].calls == 0)
|
||||
e->counters.calls[kind].usage = USAGE_INIT;
|
||||
e->counters.calls[kind].calls += 1;
|
||||
e->counters.time[kind].total_time += total_time;
|
||||
|
||||
e->counters.calls.calls += 1;
|
||||
e->counters.time.total_time += total_time;
|
||||
if (e->counters.calls.calls == 1)
|
||||
if (e->counters.calls[kind].calls == 1)
|
||||
{
|
||||
e->counters.time.min_time = total_time;
|
||||
e->counters.time.max_time = total_time;
|
||||
e->counters.time.mean_time = total_time;
|
||||
e->counters.time[kind].min_time = total_time;
|
||||
e->counters.time[kind].max_time = total_time;
|
||||
e->counters.time[kind].mean_time = total_time;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -934,18 +987,18 @@ pgss_store(const char *query, uint64 queryId,
|
|||
* Welford's method for accurately computing variance. See
|
||||
* <http://www.johndcook.com/blog/standard_deviation/>
|
||||
*/
|
||||
double old_mean = e->counters.time.mean_time;
|
||||
double old_mean = e->counters.time[kind].mean_time;
|
||||
|
||||
e->counters.time.mean_time +=
|
||||
(total_time - old_mean) / e->counters.calls.calls;
|
||||
e->counters.time.sum_var_time +=
|
||||
(total_time - old_mean) * (total_time - e->counters.time.mean_time);
|
||||
e->counters.time[kind].mean_time +=
|
||||
(total_time - old_mean) / e->counters.calls[kind].calls;
|
||||
e->counters.time[kind].sum_var_time +=
|
||||
(total_time - old_mean) * (total_time - e->counters.time[kind].mean_time);
|
||||
|
||||
/* calculate min and max time */
|
||||
if (e->counters.time.min_time > total_time)
|
||||
e->counters.time.min_time = total_time;
|
||||
if (e->counters.time.max_time < total_time)
|
||||
e->counters.time.max_time = total_time;
|
||||
if (e->counters.time[kind].min_time > total_time)
|
||||
e->counters.time[kind].min_time = total_time;
|
||||
if (e->counters.time[kind].max_time < total_time)
|
||||
e->counters.time[kind].max_time = total_time;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_RESPONSE_BUCKET - 1; i++)
|
||||
|
@ -959,7 +1012,7 @@ pgss_store(const char *query, uint64 queryId,
|
|||
if (total_time > PGSM_RESPOSE_TIME_LOWER_BOUND + (PGSM_RESPOSE_TIME_STEP * MAX_RESPONSE_BUCKET))
|
||||
pgssBucketEntries[entry->key.bucket_id]->counters.resp_calls[MAX_RESPONSE_BUCKET - 1]++;
|
||||
|
||||
e->counters.calls.rows += rows;
|
||||
e->counters.calls[kind].rows += rows;
|
||||
e->counters.blocks.shared_blks_hit += bufusage->shared_blks_hit;
|
||||
e->counters.blocks.shared_blks_read += bufusage->shared_blks_read;
|
||||
e->counters.blocks.shared_blks_dirtied += bufusage->shared_blks_dirtied;
|
||||
|
@ -972,7 +1025,7 @@ pgss_store(const char *query, uint64 queryId,
|
|||
e->counters.blocks.temp_blks_written += bufusage->temp_blks_written;
|
||||
e->counters.blocks.blk_read_time += INSTR_TIME_GET_MILLISEC(bufusage->blk_read_time);
|
||||
e->counters.blocks.blk_write_time += INSTR_TIME_GET_MILLISEC(bufusage->blk_write_time);
|
||||
e->counters.calls.usage += USAGE_EXEC(total_time);
|
||||
e->counters.calls[kind].usage += USAGE_EXEC(total_time);
|
||||
e->counters.info.host = pg_get_client_addr();
|
||||
e->counters.sysinfo.utime = utime;
|
||||
e->counters.sysinfo.stime = stime;
|
||||
|
@ -1004,7 +1057,7 @@ pg_stat_monitor_reset(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
#define PG_STAT_STATEMENTS_COLS 31 /* maximum of above */
|
||||
#define PG_STAT_STATEMENTS_COLS 38 /* maximum of above */
|
||||
|
||||
Datum
|
||||
pg_stat_wait_events(PG_FUNCTION_ARGS)
|
||||
|
@ -1221,30 +1274,22 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
|
|||
nulls[i++] = true;
|
||||
}
|
||||
|
||||
/* Skip entry if unexecuted (ie, it's a pending "sticky" entry) */
|
||||
if (tmp.calls.calls == 0)
|
||||
continue;
|
||||
|
||||
values[i++] = TimestampGetDatum(pgssBucketEntries[entry->key.bucket_id]->counters.current_time);
|
||||
values[i++] = Int64GetDatumFast(tmp.calls.calls);
|
||||
values[i++] = Float8GetDatumFast(tmp.time.total_time);
|
||||
values[i++] = Float8GetDatumFast(tmp.time.min_time);
|
||||
values[i++] = Float8GetDatumFast(tmp.time.max_time);
|
||||
values[i++] = Float8GetDatumFast(tmp.time.mean_time);
|
||||
|
||||
/*
|
||||
* Note we are calculating the population variance here, not the
|
||||
* sample variance, as we have data for the whole population, so
|
||||
* Bessel's correction is not used, and we don't divide by
|
||||
* tmp.calls - 1.
|
||||
*/
|
||||
if (tmp.calls.calls > 1)
|
||||
stddev = sqrt(tmp.time.sum_var_time / tmp.calls.calls);
|
||||
for (int kind = 0; kind < PGSS_NUMKIND; kind++)
|
||||
{
|
||||
values[i++] = Int64GetDatumFast(tmp.calls[kind].calls);
|
||||
values[i++] = Float8GetDatumFast(tmp.time[kind].total_time);
|
||||
values[i++] = Float8GetDatumFast(tmp.time[kind].min_time);
|
||||
values[i++] = Float8GetDatumFast(tmp.time[kind].max_time);
|
||||
values[i++] = Float8GetDatumFast(tmp.time[kind].mean_time);
|
||||
if (tmp.calls[kind].calls > 1)
|
||||
stddev = sqrt(tmp.time[kind].sum_var_time / tmp.calls[kind].calls);
|
||||
else
|
||||
stddev = 0.0;
|
||||
|
||||
values[i++] = Float8GetDatumFast(stddev);
|
||||
values[i++] = Int64GetDatumFast(tmp.calls.rows);
|
||||
values[i++] = Int64GetDatumFast(tmp.calls[kind].rows);
|
||||
}
|
||||
values[i++] = Int64GetDatumFast(tmp.blocks.shared_blks_hit);
|
||||
values[i++] = Int64GetDatumFast(tmp.blocks.shared_blks_read);
|
||||
values[i++] = Int64GetDatumFast(tmp.blocks.shared_blks_dirtied);
|
||||
|
@ -1332,7 +1377,7 @@ entry_alloc(pgssSharedState *pgss, pgssHashKey *key, Size query_offset, int quer
|
|||
/* reset the statistics */
|
||||
memset(&entry->counters, 0, sizeof(Counters));
|
||||
/* set the appropriate initial usage count */
|
||||
entry->counters.calls.usage = sticky ? pgss->cur_median_usage : USAGE_INIT;
|
||||
entry->counters.calls[0].usage = sticky ? pgss->cur_median_usage : USAGE_INIT;
|
||||
/* re-initialize the mutex each time ... we assume no one using it */
|
||||
SpinLockInit(&entry->mutex);
|
||||
/* ... and don't forget the query text metadata */
|
||||
|
@ -2618,6 +2663,7 @@ static PlannedStmt * pgss_planner_hook(Query *parse, const char *query_string, i
|
|||
static PlannedStmt *pgss_planner_hook(Query *parse, int opt, ParamListInfo param)
|
||||
#endif
|
||||
{
|
||||
PlannedStmt *result;
|
||||
if (MyProc)
|
||||
{
|
||||
int i = MyProc - ProcGlobal->allProcs;
|
||||
|
@ -2625,14 +2671,75 @@ static PlannedStmt *pgss_planner_hook(Query *parse, int opt, ParamListInfo param
|
|||
pgssWaitEventEntries[i]->key.queryid = parse->queryId;
|
||||
}
|
||||
#if PG_VERSION_NUM >= 130000
|
||||
if (PGSM_TRACK_PLANNING && query_string
|
||||
&& parse->queryId != UINT64CONST(0))
|
||||
{
|
||||
instr_time start;
|
||||
instr_time duration;
|
||||
BufferUsage bufusage_start,
|
||||
bufusage;
|
||||
WalUsage walusage_start,
|
||||
walusage;
|
||||
|
||||
/* We need to track buffer usage as the planner can access them. */
|
||||
bufusage_start = pgBufferUsage;
|
||||
|
||||
/*
|
||||
* Similarly the planner could write some WAL records in some cases
|
||||
* (e.g. setting a hint bit with those being WAL-logged)
|
||||
*/
|
||||
walusage_start = pgWalUsage;
|
||||
INSTR_TIME_SET_CURRENT(start);
|
||||
|
||||
plan_nested_level++;
|
||||
PG_TRY();
|
||||
{
|
||||
if (planner_hook_next)
|
||||
return planner_hook_next(parse, query_string, cursorOptions, boundParams);
|
||||
return standard_planner(parse, query_string, cursorOptions, boundParams);
|
||||
result = planner_hook_next(parse, query_string, cursorOptions, boundParams);
|
||||
result = standard_planner(parse, query_string, cursorOptions, boundParams);
|
||||
}
|
||||
PG_FINALLY();
|
||||
{
|
||||
plan_nested_level--;
|
||||
}
|
||||
PG_END_TRY();
|
||||
|
||||
INSTR_TIME_SET_CURRENT(duration);
|
||||
INSTR_TIME_SUBTRACT(duration, start);
|
||||
|
||||
/* calc differences of buffer counters. */
|
||||
memset(&bufusage, 0, sizeof(BufferUsage));
|
||||
BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
|
||||
|
||||
/* calc differences of WAL counters. */
|
||||
memset(&walusage, 0, sizeof(WalUsage));
|
||||
WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
|
||||
pgss_store(query_string,
|
||||
parse->queryId,
|
||||
parse->stmt_location,
|
||||
parse->stmt_len,
|
||||
PGSS_PLAN,
|
||||
INSTR_TIME_GET_MILLISEC(duration),
|
||||
0,
|
||||
&bufusage,
|
||||
&walusage,
|
||||
NULL,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (planner_hook_next)
|
||||
result = planner_hook_next(parse, query_string, cursorOptions, boundParams);
|
||||
result = standard_planner(parse, query_string, cursorOptions, boundParams);
|
||||
}
|
||||
#else
|
||||
if (planner_hook_next)
|
||||
return planner_hook_next(parse, opt, param);
|
||||
return standard_planner(parse, opt, param);
|
||||
result = planner_hook_next(parse, opt, param);
|
||||
result = standard_planner(parse, opt, param);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#include "utils/lsyscache.h"
|
||||
#include "utils/guc.h"
|
||||
|
||||
#define IsHashInitialize() (!pgss || !pgss_hash || !pgss_object_hash || !pgss_agghash || !pgss_buckethash || !pgss_waiteventshash)
|
||||
#define IsHashInitialize() (pgss || pgss_hash || pgss_object_hash || pgss_agghash || pgss_buckethash || pgss_waiteventshash)
|
||||
|
||||
#define MAX_BACKEND_PROCESES (MaxBackends + NUM_AUXILIARY_PROCS + max_prepared_xacts)
|
||||
|
||||
|
@ -73,6 +73,21 @@ typedef struct GucVariables
|
|||
int guc_max;
|
||||
bool guc_restart;
|
||||
} GucVariable;
|
||||
typedef enum pgssStoreKind
|
||||
{
|
||||
PGSS_INVALID = -1,
|
||||
|
||||
/*
|
||||
* PGSS_PLAN and PGSS_EXEC must be respectively 0 and 1 as they're used to
|
||||
* reference the underlying values in the arrays in the Counters struct,
|
||||
* and this order is required in pg_stat_statements_internal().
|
||||
*/
|
||||
PGSS_PLAN = 0,
|
||||
PGSS_EXEC,
|
||||
|
||||
PGSS_NUMKIND /* Must be last value of this enum */
|
||||
} pgssStoreKind;
|
||||
|
||||
|
||||
/*
|
||||
* Type of aggregate keys
|
||||
|
@ -217,9 +232,9 @@ typedef struct SysInfo
|
|||
typedef struct Counters
|
||||
{
|
||||
uint64 bucket_id; /* bucket id */
|
||||
Calls calls;
|
||||
Calls calls[PGSS_NUMKIND];
|
||||
QueryInfo info;
|
||||
CallTime time;
|
||||
CallTime time[PGSS_NUMKIND];
|
||||
Blocks blocks;
|
||||
SysInfo sysinfo;
|
||||
} Counters;
|
||||
|
@ -344,6 +359,7 @@ void init_guc(void);
|
|||
#define PGSM_OBJECT_CACHE conf[8].guc_variable
|
||||
#define PGSM_RESPOSE_TIME_LOWER_BOUND conf[9].guc_variable
|
||||
#define PGSM_RESPOSE_TIME_STEP conf[10].guc_variable
|
||||
#define PGSM_TRACK_PLANNING conf[11].guc_variable
|
||||
|
||||
GucVariable conf[11];
|
||||
GucVariable conf[12];
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue