Skip to content

Commit

Permalink
PG-592: Treat queries with different parent queries as separate entri…
Browse files Browse the repository at this point in the history
…es (#403)

* PG-592: Treat queries with different parent queries as separate entries

1. Previously pg_stat_monitor had a `topquery` and `topqueryid` field, but it was only a sample:
it showed one of the top queries executing the specific query.

With this change, the same entry executed by two different functions will result in two entries in the statistics table.

2. This also fixes a bug where the content of these field disappeared for every second query executed:
previously the update function changed topqueryid to `0` if it was non zero, and changed it to the proper id when it was 0.
This resulted in an alternating behavior, where for every second executed query the top query disappeared.

After these changes, the top query is always shown.

3. The previous implementation also leaked dsa memory used to store the parent queries. This is now also fixed.

* PG-502: Fixing review comments

* dsa_free changed to assert as it can never happen
* restructured the ifs to be cleaner
  Note: kept the two-level ifs, as that makes more sense with the assert
  Note: didn't convert nested_level checks to macro, as it is used differently at different parts of the code

* PG-502: Fixing review comments

* PG-592 Add regression test

* Make test compatible with PG12

* Remove redundant line

---------

Co-authored-by: Artem Gavrilov <[email protected]>
  • Loading branch information
dutow and artemgavrilov authored Aug 6, 2024
1 parent 1aa3081 commit 130d6b5
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 13 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
*.mod*
*.cmd
.tmp_versions/
.deps/
modules.order
Module.symvers
Mkfile.old
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ LDFLAGS_SL += $(filter -lm, $(LIBS))

TAP_TESTS = 1
REGRESS_OPTS = --temp-config $(top_srcdir)/contrib/pg_stat_monitor/pg_stat_monitor.conf --inputdir=regression
REGRESS = basic version guc pgsm_query_id functions counters relations database error_insert application_name application_name_unique top_query cmd_type error rows tags user level_tracking
REGRESS = basic version guc pgsm_query_id functions counters relations database error_insert application_name application_name_unique top_query different_parent_queries cmd_type error rows tags user level_tracking

# Disabled because these tests require "shared_preload_libraries=pg_stat_statements",
# which typical installcheck users do not have (e.g. buildfarm clients).
Expand Down
34 changes: 23 additions & 11 deletions pg_stat_monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -1542,15 +1542,13 @@ pgsm_update_entry(pgsmEntry * entry,
e->counters.info.num_relations = num_relations;
_snprintf2(e->counters.info.relations, relations, num_relations, REL_LEN);

if (nesting_level > 0 && e->counters.info.parentid == 0 && pgsm_track == PGSM_TRACK_ALL)
if (nesting_level > 0 && nesting_level < max_stack_depth && e->key.parentid != 0 && pgsm_track == PGSM_TRACK_ALL)
{
if (nesting_level >= 0 && nesting_level < max_stack_depth)
if (!DsaPointerIsValid(e->counters.info.parent_query))
{
int parent_query_len = nested_query_txts[nesting_level - 1] ?
strlen(nested_query_txts[nesting_level - 1]) : 0;

e->counters.info.parentid = nested_queryids[nesting_level - 1];
e->counters.info.parent_query = InvalidDsaPointer;
/* If we have a parent query, store it in the raw dsa area */
if (parent_query_len > 0)
{
Expand All @@ -1577,8 +1575,7 @@ pgsm_update_entry(pgsmEntry * entry,
}
else
{
e->counters.info.parentid = UINT64CONST(0);
e->counters.info.parent_query = InvalidDsaPointer;
Assert(!DsaPointerIsValid(e->counters.info.parent_query));
}
}

Expand Down Expand Up @@ -1826,6 +1823,7 @@ pgsm_create_hash_entry(uint64 bucket_id, uint64 queryid, PlanInfo * plan_info)
entry->key.dbid = MyDatabaseId;
entry->key.queryid = queryid;
entry->key.bucket_id = bucket_id;
entry->key.parentid = 0;

#if PG_VERSION_NUM < 140000
entry->key.toplevel = 1;
Expand Down Expand Up @@ -1947,13 +1945,24 @@ pgsm_store(pgsmEntry * entry)
memcpy(&jitusage.optimization_counter, &entry->counters.jitinfo.instr_optimization_counter, sizeof(instr_time));
memcpy(&jitusage.emission_counter, &entry->counters.jitinfo.instr_emission_counter, sizeof(instr_time));


// Update parent id if needed
if(pgsm_track == PGSM_TRACK_ALL && nesting_level > 0 && nesting_level < max_stack_depth)
{
entry->key.parentid = nested_queryids[nesting_level - 1];
}
else
{
entry->key.parentid = UINT64CONST(0);
}

#if PG_VERSION_NUM >= 170000
memcpy(&jitusage.deform_counter, &entry->counters.jitinfo.instr_deform_counter, sizeof(instr_time));
#endif

/*
* Acquire a share lock to start with. We'd have to acquire exclusive if
* we need ot create the entry.
* we need to create the entry.
*/
LWLockAcquire(pgsm->lock, LW_SHARED);
shared_hash_entry = (pgsmEntry *) pgsm_hash_find(get_pgsmHash(), &entry->key, &found);
Expand Down Expand Up @@ -2047,6 +2056,7 @@ pgsm_store(pgsmEntry * entry)
shared_hash_entry->pgsm_query_id = entry->pgsm_query_id;
shared_hash_entry->encoding = entry->encoding;
shared_hash_entry->counters.info.cmd_type = entry->counters.info.cmd_type;
shared_hash_entry->counters.info.parent_query = InvalidDsaPointer;

snprintf(shared_hash_entry->datname, sizeof(shared_hash_entry->datname), "%s", entry->datname);
snprintf(shared_hash_entry->username, sizeof(shared_hash_entry->username), "%s", entry->username);
Expand Down Expand Up @@ -2233,6 +2243,7 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
bool nulls[PG_STAT_MONITOR_COLS] = {0};
int i = 0;
Counters tmp;
pgsmHashKey tmpkey;
double stddev;
uint64 queryid = entry->key.queryid;
int64 bucketid = entry->key.bucket_id;
Expand Down Expand Up @@ -2269,6 +2280,7 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,

SpinLockAcquire(&e->mutex);
tmp = e->counters;
tmpkey = e->key;
SpinLockRelease(&e->mutex);
}

Expand All @@ -2285,7 +2297,7 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
}

/* read the parent query text if any */
if (tmp.info.parentid != UINT64CONST(0))
if (tmpkey.parentid != UINT64CONST(0))
{
if (DsaPointerIsValid(tmp.info.parent_query))
{
Expand Down Expand Up @@ -2370,10 +2382,10 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
else
nulls[i++] = true;

/* parentid at column number 11 */
if (tmp.info.parentid != UINT64CONST(0))
/* parentid at column number 9 */
if (tmpkey.parentid != UINT64CONST(0))
{
values[i++] = UInt64GetDatum(tmp.info.parentid);
values[i++] = UInt64GetDatum(tmpkey.parentid);
values[i++] = CStringGetTextDatum(parent_query_txt);
}
else
Expand Down
2 changes: 1 addition & 1 deletion pg_stat_monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,11 @@ typedef struct pgsmHashKey
Oid dbid; /* database OID */
uint32 ip; /* client ip address */
bool toplevel; /* query executed at top level */
uint64 parentid; /* parent queryid of current query */
} pgsmHashKey;

typedef struct QueryInfo
{
uint64 parentid; /* parent queryid of current query */
dsa_pointer parent_query;
int64 type; /* type of query, options are query, info,
* warning, error, fatal */
Expand Down
54 changes: 54 additions & 0 deletions regression/expected/different_parent_queries.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
CREATE EXTENSION pg_stat_monitor;
SET pg_stat_monitor.pgsm_track='all';
SELECT pg_stat_monitor_reset();
pg_stat_monitor_reset
-----------------------

(1 row)

CREATE OR REPLACE FUNCTION test() RETURNS VOID AS
$$
BEGIN
PERFORM 1 + 2;
END; $$ language plpgsql;
CREATE OR REPLACE FUNCTION test2() RETURNS VOID AS
$$
BEGIN
PERFORM 1 + 2;
END; $$ language plpgsql;
SELECT pg_stat_monitor_reset();
pg_stat_monitor_reset
-----------------------

(1 row)

SELECT test();
test
------

(1 row)

SELECT test2();
test2
-------

(1 row)

SELECT 1 + 2;
?column?
----------
3
(1 row)

SELECT left(query, 15) as query, calls, top_query, pgsm_query_id FROM pg_stat_monitor ORDER BY query, top_query COLLATE "C";
query | calls | top_query | pgsm_query_id
-----------------+-------+-----------------+----------------------
SELECT 1 + 2 | 1 | SELECT test(); | 5193804135051352284
SELECT 1 + 2 | 1 | SELECT test2(); | 5193804135051352284
SELECT 1 + 2 | 1 | | 5193804135051352284
SELECT pg_stat_ | 1 | | 689150021118383254
SELECT test() | 1 | | -6801876889834540522
SELECT test2() | 1 | | 369102705908374543
(6 rows)

DROP EXTENSION pg_stat_monitor;
24 changes: 24 additions & 0 deletions regression/sql/different_parent_queries.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
CREATE EXTENSION pg_stat_monitor;
SET pg_stat_monitor.pgsm_track='all';
SELECT pg_stat_monitor_reset();

CREATE OR REPLACE FUNCTION test() RETURNS VOID AS
$$
BEGIN
PERFORM 1 + 2;
END; $$ language plpgsql;

CREATE OR REPLACE FUNCTION test2() RETURNS VOID AS
$$
BEGIN
PERFORM 1 + 2;
END; $$ language plpgsql;

SELECT pg_stat_monitor_reset();
SELECT test();
SELECT test2();

SELECT 1 + 2;
SELECT left(query, 15) as query, calls, top_query, pgsm_query_id FROM pg_stat_monitor ORDER BY query, top_query COLLATE "C";

DROP EXTENSION pg_stat_monitor;

0 comments on commit 130d6b5

Please sign in to comment.