Commit Graph

80 Commits (fe558bdcaeca7b06b5de65b2f585123bb41e6c8c)

Author SHA1 Message Date
Muhammad Usama fe558bdcae Use separate memory context to store intermediate stats 2023-02-22 15:50:16 +05:00
Hamid Akhtar 1d4b0036e7 Fixing issue with server crash because of get_database_name without a transaction. Also, added out of memory warning to log as well as pg_stat_monitor_internal view 2023-02-19 05:09:33 +05:00
Hamid Akhtar 446b88dbc7 Fixing issue with data not showing when database or the user is no longer valid 2023-02-18 20:48:45 +05:00
Hamid Akhtar 549451fe51 Updated variable and functions by replacing pgss with pgsm. Also updated messages to make the format consistent 2023-02-17 01:23:24 +05:00
Hamid Akhtar 031547cf6d Fixing data types and cleaning up some code 2023-02-17 01:09:45 +05:00
Hamid Akhtar 8d4e99a7af Reducing memory footprint of the PGSM entry by reducing relation size to match typlen of name type. Also, updated some gucs for better MAX and default values. 2023-02-16 14:51:28 +05:00
Hamid Akhtar b7d90d8b32 Updating counters etc. 2023-02-14 17:36:22 +05:00
Hamid Akhtar e3fc69049c Changes from Usama and Hamid; error storing needs update. 2023-02-14 02:11:23 +05:00
Hamid Akhtar 2c9013917a
Setting up framework for locally tracking the queries without using shared hash table (#375)
This is the initial framework for locally maintaining hash entries so that we can insert the data in one go in the hash table being maintained in the shared memory.

Pending issues:

This causes the regression to fail (and crash) from the counters test case
The top query test case is failing,
pgsm_store function is not saving all the data at the moment, especially the buffers, JIT and WAL information.
The total time needs to be stored separately for planning and execution.
2023-02-13 13:14:52 +05:00
Muhammad Usama 5648b99eee
PG-585: pg_stat_monitor: Add code comments to the DSA related funcs.. (#360)
Adding code comments for the DSA related functionality.
2023-01-23 14:36:23 +05:00
Hamid Akhtar 1662e9efa1 PG-562: Histogram Ranges/Buckets are not correct.
Replaced the error on server start with a warning. The functionality
now handles "pgsm_histogram_buckets" as the maximum number of histogram
buckets to be created. On init, pg_stat_monitor calculates the max
number of buckets that can be created within the given min/max time
range. If the number is below the user configuration, it emits a
warning in the log file stating the number of max buckets set.
2023-01-23 12:37:51 +05:00
Hamid Akhtar 209f370cef PG-562: Histogram Ranges/Buckets are not correct.
Added buckets for queries that take less than minimum histogram time
and one for the ones taking more than the max value specified.

Also, in case the buckets end up overlapping, on server start, an
error will be thrown informing the user of this issue and requesting
a rectification.

Refactored the code to consolidate the calculations in a single
function.
2023-01-23 12:37:51 +05:00
Muhammad Usama a75e47add9 PG-400: pg_stat_monitor: Timezone in msgtime column...
The bucket start time reported by pg_stat_monitor does not match the PG time and
timezone. The fix is to use TimestampTz for recording the bucket start time.
2023-01-18 16:38:23 +05:00
Muhammad Usama 2c5e12af0a
PG-488: pg_stat_monitor: Overflow management. (#342)
* PG-488: pg_stat_monitor: Overflow management.

Reimplement the storage mechanism of buckets (for PG-15 onward) and query texts
using Dynamic shared memory. Since the dynamic shared memory can grow into a
swap area, so we get the overflow out of the box.

As PostgreSQL versions prior to V15 does not support sequence scan on dynamic
shared memory hashes, so older versions has to live with the classic shared
memory hash for storing the buckets.

Another noteworthy change with the new design is: it saves the query pointer
inside the bucket, and eventually, the query text gets evicted with the bucket
recycle.

Finally, the dynamic shared memory hash has a built-in locking mechanism, so we
can revisit the whole locking in pg_stat_monitor has the potential for lots of
performance improvements.

* Fixing tap test reported issues and also disabling dynamic hash for all versions

* Updating the expected out file for top_query test case

Co-authored-by: Hamid Akhtar <hamid.akhtar@percona.com>
2023-01-10 17:54:17 +05:00
Hamid Akhtar b20eda7066 PG-545: pg_stat_monitor: Same query text should generate same queryid
Regardless of the database or the user, the same query will yield the
same query ID. As part of this, a new column, 'pgsm_query_id', is added.

* pgsm_query_id:
pgsm_query_id has the same data type of int8 as the queryid column. If
the incoming SQL command includes any constants, it internally normalizes
the query to remove those constant values with placeholders. Otherwise,
it uses the query directly to generate the query hash.

Since we no longer depend on the server's parse tree mechanism, we can
generate the same hash for the same query text for all server versions.

Also, it is important to note that the hash being calculated is a database,
schema and user independent. So same query text in different databases
will generate the same hash.

This column is not part of the key; rather, for observability purposes only.

* Regression
SQL test case pgsm_query_id.sql is added to the SQL regression.
2022-12-28 14:24:19 +05:00
Ibrar Ahmed 802774a2a7
PG-488: Revert pg_stat_monitor: Overflow management. (#338)
PG-488: Revert pg_stat_monitor: Overflow management.

This patch does not work for  < PostgreSQL - 15. More work required.
2022-12-22 19:15:14 +05:00
Muhammad Usama df0580b741 PG-488: pg_stat_monitor: Overflow management.
Reimplement the storage mechanism of buckets and query texts
using Dynamic shared memory. Since the dynamic shared memory
can grow into a swap area, so we get the overflow out of the box.

oreover the new design saves the query pointer inside the bucket
and eventually, the query text gets evicted with the bucket recycle.

Finally, the dynamic shared memory hash has a built-in locking
mechanism so we can revisit the whole locking in pg_stat_monitor
has potential for lots of performance improvements
2022-12-20 17:29:15 +05:00
Muhammad Usama 913064b68d
PG-435: Adding new counters that are available in PG15 (#329)
In line with pg_stat_statments for PG15, This commit adds eight new cumulative
counters for jit operations, making it easier to diagnose how JIT is used in an
installation. And two new columns, temp_blk_read_time, and temp_blk_write_time,
respectively, show the time spent reading and writing temporary file blocks
on disk.
Moreover, The commit also contains a few indentations and API adjustments.
2022-12-07 15:40:13 +05:00
Ibrar Ahmed f7860b472f
PG-310: Bucket is “Done” vs still being current/last. (#321)
A new column is added to mention that bucket is active or done. there is    
some timing based adjustment was required with that too.   

Co-authored-by: Hamid Akhtar <hamid.akhtar@percona.com>
2022-11-23 02:23:28 +05:00
Ibrar Ahmed 0af6295513 PG-174: Code cleanup.
pg_stat_monitor is a bit longer; therefore, it requires some code cleanup.
Therefore I decided to turn these tasks into multiple commits and PR to avoid
various changes in one PR. This will ease the review and Q/A process.
In this commit, I have done these tasks.

1 - Remove all benchmarking and debugging code.
2022-10-24 17:42:38 +00:00
Ibrar Ahmed a9187117f9
PG-456: Running pgindent to make source PostgreSQL compatible. (#269)
PG-456: Running pgindent to make source indentation/spacing PostgreSQLCompatible.

PostgreSQL uses pgindent from time to time to make source code PostgreSQL
style guide compatible, it is a very long time since we have not done that.
Commit fixes a lot of indentation and spacing issues.

Co-authored-by: Hamid Akhtar <hamid.akhtar@gmail.com>
2022-06-29 00:42:40 +05:00
Hamid Akhtar 7efc3fa50e [PG-159] pg_stat_monitor: Bucket start time should be aligned with fix number of seconds
The buckets are now created with the start time a modulus of the bucket time size.
So if we have a 10 second bucket, the start times would reflect that:
- Bucket1: 00:00:00
- Bucket2: 00:00:10
- Bucket3: 00:00:20
...

Previously, the start time of the bucket was aligned with the first query that
arrives in that bucket. However, now the behaviour is changed. So, even if the
first query for bucket 2 arrives at 00:00:13, the start time would still be set
to 00:00:10.

This change now makes the bucketing separated out by fixed time windows so that
external applications can easily consume that data and chart it.

Also, as part of this change, locking of pgss is updated now and extended
to last the bucket related changes.
2022-06-20 17:53:43 +05:00
Ibrar Ahmed 13eedd579e PG-382: Adjust the maximum value for histogram buckets.
There was no maximum limit set for the number of maximum histograms
bucket, which can lead to a crash in case of higher value.

PG-382: Adjust the maximum value for histogram buckets.

Fix the regression issue related to GUC and set the maximum
buckets value correctly.

PG-382: Adjust the maximum value for histogram buckets.

Fix the TAP test cases.
2022-05-24 17:50:07 +00:00
Ibrar Ahmed 153f8d2e87 PG-338: Calls count is not correct in PG-13.
cherry-pick patch (b6838049b6) by Diego
and I did some refatoring.
2022-03-14 18:14:11 +00:00
Diego Fronza 8c61e24f95 PG-286: Fix query buffer overflow management.
If pgsm_overflow_target is ON (default, 1) and the query buffer
overflows, we now dump the buffer and keep track of how many times
pg_stat_monitor changed bucket since that.

If an overflow happen again before pg_stat_monitor cycle through
pgsm_max_buckets buckets (default 10), then we don't dump the buffer
again, but instead report an error, this ensures that only one dump file
of size pgsm_query_shared_buffer will be in disk at any time, avoiding
slowing down queries to the pg_stat_monitor view.

As soon as pg_stat_monitor cycles through all buckets, we remove the
dump file and reset the counter (pgss->n_bucket_cycles).
2022-02-17 19:47:07 +05:00
Diego Fronza df89c3f4a3 PG-286: Small performance improvements.
pgss_ExecutorEnd: Avoid unnecessary memset(plan_info, 0, ...).
We only use this object if the condition below is true, in which case we
already initialize all the fields in the object, also we now store the
plan string length (plan_info.plan_len) to avoid calling strlen on it
again later:
if (queryDesc->operation == CMD_SELECT && PGSM_QUERY_PLAN) {
... here we initialize plan_info

If the condition is false, then we pass a NULL PlanInfo* to the
pgss_store to avoid more unnecessary processing.

pgss_planner_hook: Similar, avoid memset(plan_info, 0, ...) this object
is not used here, so we pass NULL to pgss_store.

pg_get_application_name: Remove call to strlen, snprintf already give us
the calculated string length, so we just return it.

pg_get_client_addr: Cache localhost, avoid calling
ntohl(inet_addr("127.0.0.1")) all the time.

pgss_update_entry: Make use of PlanInfo->plan_len, avoiding a call to
strlen again.

intarray_get_datum: Init the string by setting the first byte to '\0'.
2022-02-17 19:46:39 +05:00
Diego Fronza c21a3de00d PG-286: Avoid duplicate queries in text buffer.
The memory area reserved for query text (pgsm_query_shared_buffer) was
divided evenly for each bucket, this allowed to have the same query,
e.g. "SELECT 1", duplicated in different buckets, thus wasting space.

This commit fix the query text duplication by adding a new hash table
whose only purpose is to verify if a given query is already added to the
buffer (by using the queryID).

This allows different buckets that share the same query to point to a
unique entry in the query buffer (pgss_qbuf).

When pg_stat_monitor moves to a new bucket id, by avoiding adding a
query that already exists in the buffer it can also save some CPU time.
2022-02-17 19:46:35 +05:00
Ibrar Ahmed 680c7fda42 PG-210: Add new column toplevel. 2021-11-16 11:23:59 +00:00
Ibrar Ahmed 5f6177daa3 PG-210: Add new column toplevel. 2021-11-16 10:48:11 +00:00
Diego Fronza f66b45afd6 PG-220: Fix read/write of dumped query buffer to files.
This commit fix some issues when the query buffer overflows and
pg_stat_monitor attempts to dump its contents to a file.

The dump process is now as follows:

1. The dump will always be a full dump of the current query buffer,
   meaning pg_stat_monitor will dump MAX_QUERY_BUFFER_BUCKET bytes to
   the dump file.
2. When scanning the dump file, read chunks of size
   MAX_QUERY_BUFFER_BUCKET, then look for the query ID using that chunk
   and the query position metadata, this allows pg_stat_monitor to avoid
   scanning the whole chunk when looking for a query ID.

The code in charge to read from/write to the dump file now takes into
account that read() and write() may return less bytes than what it was
asked for, the code now ensures that we actually read or write the
amount of bytes required (MAX_QUERY_BUFFER_BUCKET), also it handles
rare but posssible interrupts when doing those operations.
2021-10-25 16:55:30 -03:00
Diego Fronza fa55eb333d PG-220: Fix pgsm_overflow_target defaults.
The GUC variable pgsm_overflow_target was pointing to the wrong index
(12, pgsm_track_planning) in the "GucVariable conf[MAX_SETTINGS]" array.

Adjusted it to the right index, 11.
2021-10-22 15:40:27 -03:00
Diego Fronza 8fdf0946fe PG-254: Add query location to hash table entries.
Whenever a new query is added to a query buffer, record the position
in which the query was inserted, we can then use this information to
locate the query in a faster way later on when required.

This allowed to simplify the logic in hash_entry_dealloc(), after
creating the list of pending queries, as the list is scanned we can copy
the query from the previous query buffer to the new one by using the
query position (query_pos), this avoids scanning the whole query buffer
when looking up for the queryid.

Also, when moving a query to a new buffer (copy_query), we update
the query_pos for the hash table entry, so it points to the right place
in the new query buffer.

read_query() function was updated to allow query position to be passed
as argument, if pos != 0 use it to locate the query directly, otherwise
fallback to the previous mode of scanning the whole buffer.

SaveQueryText() was updated to pass a reference to the query position as
argument, this value is updated after the function finishes with the
position that the query was stored into the buffer.
2021-10-07 10:06:20 -03:00
Diego Fronza fcb70ffed1 PG-254: Removal of pgss_query_hash hash table.
There was no necessity for using a separate hash table to keep track
of queries as all the necessary information is already available in
the pgss_hash table.

The code that moves pending queries' text in hash_query_entry_dealloc
was merged into hash_entry_dealloc.

Couple functions were not necessary anymore, thus were removed:
- hash_create_query_entry
- pgss_store_query_info
- pgss_get_entry (this logic was added directly into pgss_store).

We simplified the logic in pgss_store, it basically works as follows:
1. Create a key (bucketid, queryid, etc...) for the query event.
2. Lookup the key in pgss_hash, if no entry exists for the key, create a
   new one, save the query text into the current query buffer.
3. If jstate == NULL, then update stats counters for the entry.
2021-10-06 14:57:15 -03:00
Diego Fronza a959acb3d5 PG-244: Move pending queries' text to new bucket after bucket expiration.
Added code to move all pending queries text from an expired bucket's query
buffer to the next, active query buffer.

The previous implementation was not very efficient, it worked like this,
as soon as a query is processed and a bucket expires:

1. Allocate memory to save the contents of the next query buffer.
2. Clear the next query buffer.
3. Iterate over pgss_query_hash, then, for each entry:
   - If the entry's bucket id is equal to the next bucket then:
     -- If the query for this entry has finished or ended in error, then
        remove it from the hash table.
     -- Else, if the query is not yet finished, copy the query from the
        backup query buffer to the new query buffer.
	Now, this copy was really expensive, because it was implemented
	using read_query() / SaveQueryText(), and read_query() scans the
	whole query buffer looking for some query ID, since we do this
	extra lookup loop for each pending query we end up with a O(n^2)
	algorithm.
4. Release the backup query buffer.

Since now we always move pending queries from an expired bucket to the
next one, there is no need to scan the next query buffer for pending
queries (the pending queries are always in the current bucket, and when
it expires we move them to the next one).

Taking that into consideration, the new implementation works as follows,
whenever a bucket expires:

1. Clear the next query buffer (all entries).
2. Define an array to store pending query ids from the expired bucket,
   we use this array later on in the algorithm.
3. Iterate over pgss_query_hash, then, for each entry:
   - If the entry's bucket id is equal to the next bucket then:
     -- If the query for this entry has finished or ended in error, then
        remove it from the hash table. This is equal to the previous
	implementation.
   - Else, if the entry's bucket id is equal to the just expired bucket
     id (old bucket id) and the query state is pending (not yet finished),
     then add this query ID to the array of pending query IDs.

     Note: We define the array to hold up to 128 pending entries, if there
     are more entries than this we try to allocate memory in the heap to
     store them, then, if the allocation fails we manually copy every
     pending query past the 128th to the next query buffer, using the
     previous algorithm (read_query() / SaveQueryText), this should be a
     very rare situation.
4. Finally, if there are pending queries, copy them from the previous
   query buffer to the next one using copy_queries.

Now, copy_queries() is better than looping through each query entry and
calling read_query() / SaveQueryText() to copy each of them to the new
buffer, as explained, read_query() scans the whole query buffer for
every call.

copy_queries(), instead, scans the query buffer only once, and for every
element it checks if the current query id is in the list of queries to
be copied, this is an array of uint64 that is small enough to fit in L1
cache.

Another important fix in this commit is the addition of the line 1548 in
pg_stat_monitor.c / pgss_store():
query_entry->state = kind;

Before the addition of this line, all entries in the pgss_query_hash
hash table were not having their status updated when the query entered
execution / finished or ended in error, effectively leaving all entries
as pending, thus whenever a bucket expired all entries were being copied
from the expired bucket to the next one.
2021-10-01 15:27:45 -03:00
Diego Fronza 89743e9243 PG-244: Fix race condition in get_next_wbucket().
The if condition bellow in geta_next_wbucket() was subject to a race
condition:
if ((current_usec - pgss->prev_bucket_usec) > (PGSM_BUCKET_TIME * 1000 *
1000))

Two or more threads/processes could easily evaluate this condition to
true, thus executing more than once the block that would calculate a
new bucket id, clear/move old entries in the pgss_query_hash and
pgss_hash hash tables.

To avoid this problem, we define prev_bucket_usec and current_wbucket
variables as atomic and execute a loop to check if another thread has
updated prev_bucket_usec before the current one.
2021-09-30 17:13:27 -03:00
Diego Fronza 273f23b161 PG-230: Fix duplicated query entries.
A problem during bucket management was allowing some queries to be
duplicated, old entries would sit around without having their statistics
updated.

The problem would arise during the following chain of events:
1. A query goes through pgss_post_parse_analyze, in this stage (PGSS_PARSE)
   we only save the query into the query buffer and create an entry in the
   query hash table.
2. The query then goes through pgss_ExecutorStart (PGSS_EXEC), in this stage
   we create an entry for query statistic counters with default values,
   all time stats equal zero, etc.
3. The query then goes through pgss_ExecutorEnd (PGSS_FINISH), in this stage
   we update the query statistis, no. calls, total time taken, min_time, etc.

The problem is that between steps 2 and 3, the current bucket ID timer may
have been expired.

For example, during steps 1 and 2 the query may have been stored in
bucket ID 1, but when the query is finished (pgss_ExecutorEnd) the
current bucket ID may have been updated to 2.

This is leaving an entry for the query in bucket ID 1 with state ACTIVE,
with time statistics not updated yet.

This is also creating an entry for the query in the bucket ID 2, with all
statistics (time and others) being updated for this entry.

To solve this problem, during transition to a new bucket id, we scan all
pending queries in the previous bucket id and move them to the new
bucket id.

This way finished queries will always be associated with the bucket id
that was active at the time they've finished.
2021-09-28 16:12:34 -03:00
Andrew Pogrebnoy aecfb7a5cd PG-232: remove unused function
and fix a couple of typos
2021-09-21 10:37:10 +03:00
Diego Fronza a847ed95de PG-223: Remove relations and num_relations from pgssSharedState.
These variables can't be in shared state, as the following problem was
taking place:
1. Process1 call pgss_ExecutorCheckPerms(), acquire lock, update
   relations and num_relations, release lock.
2. Process 2 call pgss_ExecutorCheckPerms(), acquire lock, update
   num_relations = 0;
3. Process 1 read num_relations = 0 in pgss_update_entry, this value is
   wrong as it was updated by Process 2.

Even if we acquire the lock in pgss_update_entry to read num_relations
and relations variable, Process 1 may end up acquiring the lock after
Process 2 has ovewritten the variable values, leading to Process 1
reading of wrong data.

By defining relations and num_relations to be static and global in
pg_stat_monitor.c we take advantage that each individual PostgreSQL
backend will have its own copy of this data, which allows us to remove
the locking in pgss_ExecutorCheckPerms to update these variables,
improving pg_stat_monitor overall performance.
2021-08-27 15:53:11 -04:00
Diego Fronza 775c087fb2 PG-222: Add benchmark support for measuring hook execution time.
Added a new view 'pg_stat_monitor_hook_stats' that provide execution
time statistics for all hooks installed by the module, following is a
description of the fields:
  -       hook: The hook function name.
  -   min_time: The fastest execution time recorded for the given hook.
  -   max_time: The slowest execution time recorded for the given hook.
  - total_time: Total execution time taken by all calls to the hook.
  -   avg_time: Average execution time of a call to the hook.
  -     ncalls: Total number of calls to the hook.
  - load_comparison: A percentual of time taken by an individual hook
                     compared to every other hook.

To enable benchmark, code must be compiled with -DBENCHMARK flag, this
will make the hook functions to be replaced by a function with the same
name plus a '_benchmark' suffix, e.g. hook_function_benchmark.

The hook_function_benchmark will call the original function and
calculate the amount of time it took to execute, than it will update
statistics for that hook.
2021-08-23 11:50:56 -04:00
Diego Fronza 99f01d37e3 PG-200: Add application name to the bucket ID.
Add application name to the key used to identify queries in the hash
table, this allows different applications to have separate entries in
pg_stat_monitor view if they issued the same query.
2021-07-29 15:05:08 -04:00
Ibrar Ahmed f470ba591a PG-194: PostgreSQL-14 support added. 2021-05-21 21:29:58 +05:00
Ibrar Ahmed 67b3d961ca PG-193: Comment based tags to identify different parameters. 2021-05-19 22:15:37 +05:00
Ibrar Ahmed 89614e442b PG-190: Does not show query, if query elapsed time is greater than bucket time. 2021-04-08 15:29:42 +05:00
Ibrar Ahmed f8ed33a92a PG-188: Added a new column to monitor the query state. 2021-03-21 00:04:39 +05:00
Ibrar Ahmed 96a7603aae PG-187: Compilation Error for PostgreSQL 11 and PostgreSQL 12. 2021-03-17 20:42:58 +05:00
Ibrar Ahmed e0fc683810 PG-186: Add support to monitor query execution plan. 2021-03-17 18:56:39 +05:00
Ibrar Ahmed 066162c3f6 PG-186: Add support to monitor query execution plan.
This requires refactoring of code to add this functionality. Along with
that this patch contains regression test cases.
2021-03-12 18:55:12 +00:00
Ibrar Ahmed 6aa1b2e7b6 PG-182: Added a new option for the query buffer overflow. 2021-02-17 13:08:39 +00:00
Ibrar Ahmed ed6fe2d8dc PG-147 Stored Procedure Support add parentid to track caller.
Patch By: Martin Sun
Reviewed By: Hamid Akhtar
2021-02-12 11:42:36 +00:00
Ibrar Ahmed cba6bbfbd4 PG-177: Error in Histogram ranges. 2021-02-11 19:07:39 +00:00