Commit Graph

213 Commits (7bddd5a0332c1eb360d3318c3f87807e2bea1c0d)

Author SHA1 Message Date
Ibrar Ahmed 7c5ad48276
Merge pull request #334 from EngineeredVirus/main
PG-354: pg_stat_monitor: Remove pg_stat_monitor_settings view
2022-12-21 20:34:00 +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
Hamid Akhtar 2917ae6805 PG-354: pg_stat_monitor: Remove pg_stat_monitor_settings view
Removing the view for 2.0. Updating the required SQL files to manage
the upgrade. Downgrade from 2.x to 1.x is not supported.

Also part of this fix is the SQL regression. This does not update the
tap test cases.
2022-12-13 17:05:46 +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
Muhammad Usama 2f2c40ed22
PG-555 :Infrastructure to allow multiple SQL APIs (#320)
Creating the infrastructure that'll allow using newer versions
of the loadable module with old SQL declarations.
Also updating the build version to 2.0.0-dev
2022-11-21 18:27:21 +05:00
Ibrar Ahmed 710103cd0d PG-320: Removing the query state code from the view. 2022-11-16 19:37:15 +00:00
Ibrar Ahmed bc19c99c0b PG-306: The bucket start time should be timestamp instead of TEXT. 2022-11-15 18:11:10 +00:00
Ibrar Ahmed 40afdce2eb PG-552: Remove unnecessary columns from PostgreSQL 11 and 12 views.
There was a typo while checking the PostgreSQL version in the SQL file. This commit
will fix the typo, and only the necessary columns will be visible in the view.
2022-11-15 17:10:42 +00:00
Ibrar Ahmed db5a6aa30e PG-320: Removing the query state code from the view.
The query status monitoring code was used to track the current query state, for example,     
parsing, executing and finishing. After careful review, we have figured out that  
it does not make sense while a lot of time same query is running. Therefore it  
is also consuming resources. This commit will remove that feature. The upgrade
SQL from 1.0 - 2.0 is also updated.
2022-11-15 16:31:37 +00:00
Kai Wagner 2cef796e92 PG-526: bump version to 1.1.1 and adding release notes
Signed-off-by: Kai Wagner <kai.wagner@percona.com>
2022-11-08 23:31:01 +05:00
Muhammad Usama 0fe9908d5f PG-520 pg_stat_monitor does not work with PG15
PG 15 requires additional shared memory and LWLocks requests to be made from the
newly introduced shmem_request_hook and disallows the requests initiated
from outside the hook.
The commit makes moves the additional shared memory and LWLocks requests
from _PG_init to shmem_request_hook for PG15
2022-11-08 23:30:29 +05:00
Ibrar Ahmed 634f0ce580
PG-174: Code cleanup. (#310)
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 - Fixing compilation issue, cause by previous commit, where we removed
the benchmarking code. It was causing problem for PostgreSQL-12.
2022-10-25 01:04:23 +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
Hamid Akhtar b920224e0f
Merging the 1.1.0 branch back to main branch (#303)
* PG-475: Inconsistent behaviour of PGSM

Reverting the bucket locking mechanism to previous behavior. This has
a lot of room for improvement that needs to be part of a major refactoring
in the 2.x release.

* PG-481 Release notes 1.1.0 (#294)

modified:   RELEASE_NOTES.md

* PG-500: Bump the version of pg_stat_monitor to 1.1.0 (#297)

* PG-501: Missing Buckets and incorrect calls count. (#298)

prev_bucket_sec holds the actual time at which the previous bucket was created
and it is used to compute if the previous bucket time has elapsed and when is
the time to create a new one. But since the bucket start time is rounded down
to logical time window start, that makes the prev_bucket_sec and bucket start
time out of sync with each other, and depending on the query arrival time there
is a high probability that a bucket gets missed especially when the last bucket
was created around the end of the bucket time window.

Solution is to keep the prev_bucket_sec and bucket start time in-sync.

Moreover, we are using the unint64 for storing the prev_bucket_sec which is kind
of an overkill and a simple uint should be good enough for the purpose. But that
change can be taken up as part of the create-bucket function refactoring task.

* PG-501: Missing Buckets and incorrect calls count.

Ensuring the outer bound for the bucket is an exclusive boundary and it
as it belongs to the next bucket. To explain the point further, a set of
five second bucket would be:
    Bucket 1: 00:00:00.00 -> 00:00:04.99...
    Bucket 2: 00:00:00.05 -> 00:00:09.99...
    Bucket 3: 00:00:00.10 -> 00:00:14.99...
    ...

Co-authored-by: Ibrar Ahmed <ibrar.ahmed@percona.com>
Co-authored-by: Anastasia Alexandrova <anastasia.alexandrova@percona.com>
Co-authored-by: Muhammad Usama <m.usama@gmail.com>
2022-09-13 15:59:39 +05:00
Hamid Akhtar a3ad4033e0 PG-476: pg_stat_monitor causing errors : could not read file /tmp/pg_stat_monitor_query: No such file or directory
This only fixes the basic the path issue. It moves the query overflow file
from /tmp to PGSTAT folder data directory.
2022-08-04 13:47:36 +05: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
Ibrar Ahmed 926eade1eb
PG-449: Despite pgsm_extract_comments='no', comments are still visible. (#271)
Check for GUC (pgsm_extract_comments) was missing.
2022-06-29 00:38:37 +05:00
Ibrar Ahmed 14c390d201
Merge pull request #275 from EngineeredVirus/main
[PG-455] PGSM doesn't gather data for some pgsm_bucket_time settings
2022-06-29 00:30:25 +05:00
Hamid Akhtar ebfade5e92 [PG-455] PGSM doesn't gather data for some pgsm_bucket_time settings
Fixing the issue introduced by 7efc3fa.
2022-06-29 00:22:40 +05:00
Ibrar Ahmed 15c73407c3
PG-453: Normalize query does not work with INSERT statements.        … (#268)
PG-453: Normalize query does not work with INSERT statements.                  

The commit fixes the issue similar to pg_stat_statements. Jumble query skips in    
case of INSERT statements to avoid the duplicate queryid, but in another      
commit we already solved that problem with another way.
2022-06-22 11:53:42 +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
Hamid Akhtar 053f1d6e56 [PG-436] Completing the merge process by resolving feedback received during
the review process. Updating version to 1.1.0-dev.
2022-06-20 15:53:20 +05:00
Ibrar Ahmed 1f9b1feff6
PG-300: Fix potential duplicate queryid issue. (#262)
There is some potential problem where there is a chance
that we got a duplicate queryid. This patch will eliminate
that problem.
2022-06-17 16:32:55 +05:00
Ibrar Ahmed 1ff4891191
PG-439: Remove warning of comparison of unsigned enum expression. (#257) 2022-06-14 18:04:43 +05:00
Ibrar Ahmed 1b89fa1814
PG-289: Remove ‘for’ loop initial declarations. (#256) 2022-06-09 16:13:43 +05:00
Kai Wagner 8586816194
PG-424: bump version to 1.0.1 (#235)
Signed-off-by: Kai Wagner <kai.wagner@percona.com>
2022-05-25 11:43:11 -04:00
Kai Wagner c6f3e76310
Merge pull request #236 from ibrarahmad/REL1_0_STABLE
PG-382: Adjust the maximum value for histogram buckets.
2022-05-25 17:05:15 +02:00
Ibrar Ahmed f60d3422df 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 for PostgreSQL-12.

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

Fix the TAP test cases.
2022-05-24 17:15:03 +00:00
Kai Wagner 5abd8bb3a7 DISTPG-427: replaced return with goto exit to not break other extensions
Signed-off-by: Kai Wagner <kai.wagner@percona.com>
2022-05-16 15:00:01 +02:00
Ibrar Ahmed b99e1018af PG-380: Bump version to 1.0.0. 2022-04-20 07:44:11 +00:00
Diego Fronza 409f384ce8 PG-369: Fix wal_bytes values on PG <= 12.
Similar to pg_stat_statements, pg_stat_monitor tracks wal data metrics
since PostgreSQL 13, the problem was that for PostgreSQL versions 11 and
12 we left the WalUsage variable declared in the stack unitialized,
thus leading to garbage values.

Fixed the problem by ignoring the WalUsage variable value for PG <= 12.
2022-04-11 14:20:43 -03:00
Ibrar Ahmed 34e14104d7
PG-338: Calls count is not correct in PG-13.; PG-331: Default values for better presentation in PMM (#191)
* PG-338: Calls count is not correct in PG-13.
* PG-331: Defaults values for better presentation in PMM.
* Update pg_stat_monitor.c

Co-authored-by: Lenz Grimmer <lenz.grimmer@percona.com>
Co-authored-by: Hamid Akhtar <hamid.akhtar@gmail.com>
Co-authored-by: Ibrar Ahmad <ibrar.ahmad@gmail.com>
2022-03-21 17:53:59 +05:00
Hamid Akhtar 9abef85ede
Merge pull request #190 from ibrarahmad/REL1_0_STABLE
PG-338: Calls count is not correct in PG-13.
2022-03-15 18:20:17 +05: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
Hamid Akhtar 961ddd9e11 PG-356: Bump version to 1.0.0-rc.2. 2022-03-09 19:30:09 +05:00
Ibrar Ahmed 7debd7a962 PG-355: Collect accumulative value of sys_time and user_time.
Collect accumulative value of sys_time and user_time, because
separate value for each same query will override the previous value.
2022-03-03 17:25:07 +00:00
Diego Fronza 5db7056840 Resolving compilation failures after cherry-picking of require commits
from the main branch.
2022-03-01 19:25:29 +05:00
Diego Fronza d839cc4255 PG-350: Fix bucket time overflow.
To check if a bucket has expired, a comparison of the time elapsed
since last bucket change was being done in get_next_wbucket() function
using the following line:

while ((current_usec - current_bucket_usec) > (PGSM_BUCKET_TIME
* 1000 * 1000))

The problem is that the expression compares a uint64 (current_usec)
with a int32 (PGSM_BUCKET_TIME), if a given user configures a value for
pgsm_bucket_time GUC (let's call it T) that could overflow int32 range
in the expression T*1000*1000 > 2**31-1, then the result would be a
negative integer cast to (uint64), resulting in a large uint64 value that
would evaluate the expression as false, thus never updating bucket
number.

When querying pg_stat_monitor view, for every entry it's verified if
the entry has not yet expired by calling IsBucketValid(bucket_number).
Using the entry's bucket number the function calculates if the time
since the bucket started, using shared global variable
pgss->bucket_start_time[bucket_id], is still valid.

Since pgss->bucket_start_time is not properly initialized in
get_next_wbucket(), the function IsBucketValid() will always
return false, thus not listing any entries in the view.
2022-03-01 19:23:25 +05:00
Diego Fronza 79e0a86e4b PG-338: Fix query call count (utilities).
There was a missing increment/decrement to exec_nested_level in
pgss_ProcessUtility hook, due to this, some utility statements could
end up being processed more than once, as PostgreSQL may recurse into
this hook for sub-statements or when processing a query string
containing multiple semicolon-separated statements.
2022-03-01 13:13:28 +05:00
Diego Fronza 9f8f94ed9c PG-325: Fix deadlock.
If a query exceeds pg_stat_monitor.pgsm_query_max_len, then it's
truncated before we save it into the query buffer (SaveQueryText).

When reading the query back, on pg_stat_monitor_internal, we allocate a
buffer for the query with length = pg_stat_monitor.pgsm_query_max_len,
the problem is that the read_query function adds a '\0' to the end of
the buffer when reading a query, thus if a query has been truncated, for
example, to 1024, when reading it back read_query will store the '\0' at
the position 1025, an out of array bounds position.

Then, when we call pfree to release the buffer, PostgreSQL notices the
buffer overrun and triggers an error assertion, the assertion calls our
error hook which attempts to acquire the shared pgss->lock before
pg_stat_monitor_internal has released it, leading to a deadlock.

To avoid the problem we add 1 more byte to the extra '\0' during palloc
call for query_text and parent_query_text.

Also, we release the lock before calling pfree, just in case PostgreSQL
finds a problem in pfree we won't deadlock again and get the error
reported correctly.
2022-02-17 19:49:51 +05:00
Diego Fronza 24ae3fa66f PG-296: Fix application name.
If a backend would change the application name during execution,
pg_stat_monitor would then fail to read the updated value, as it caches
the result in order to avoid calling the expensive functions
pgstat_fetch_stat_numbackends() and pgstat_fetch_stat_local_beentry().

A workaround was found, we can just read an exported GUC from
PostgreSQL backend itself, namely application_name, from utils/guc.h,
thus saving us from having to call those expensive functions.
2022-02-17 19:49:45 +05:00
Diego Fronza e079e65da0 PG-299: Fix conflicts between devel and master.
Updated sql files (pg_stat_monitor_settings view).

Using right variable name and level checking on pgss_store:
key.toplevel = ((exec_nested_level + plan_nested_level) == 0);
2022-02-17 19:49:17 +05:00
Diego Fronza 4ed0b7cf3e PG-286: Several improvements.
This commit introduces serveral improvements:

1. Removal of pgss_store_query and pgss_store_utility functions: To
   store a query, we just use pgss_store(), this makes the code more
   uniform.

2. Always pass the query length to the pgss_store function using parse
   state from PostgreSQL to avoid calculating query length again.

3. Always clean the query (extra spaces, update query location) in
   pgss_store.

4. Normalize queries right before adding them to the query buffer, but
   only if user asked for query normalization.

5. Correctly handle utility queries among different PostgreSQL versions:
   - A word about how utility functions are handled on PG 13 and later
     versions:
      - On PostgreSQL <= 13, we have to compute a query ID, on later
        versions we can call EnableQueryId() to inform Postmaster we
	want to enable query ID computation.

      - On PostgreSQL <= 13, post_parse hook is called after process
        utility hook, on PostgreSQL >= 14, post_parse hook is called
        before process utility functions.

   - Based on that information, on PostgreSQL <= 13 / process utility,
     we pass 0 as queryid to the pgss_store function, then we calculate a
     queryid after cleaning the query (CleanQueryText) using
     pgss_hash_string.

   - On PostgreSQL 14 onward, post_parse() is called before
     pgss_ProcessUtility, we Clear queryId for prepared statements
     related utility, on process utility hook, we save the query ID for
     passing it to the pgss_store function, but mark the query ID with
     zero to avoid instrumenting it again on executor hooks.
2022-02-17 19:48:28 +05:00
Diego Fronza b798ffd461 PG-286: Reduce calls to pgstat_fetch_stat_numbackends().
After couple CPU profiling sessions with perf, it was detected that the
function pgstat_fetch_stat_numbackends() is very expensive, reading the
implementation on PostgreSQL's backend_status.c just confirmed that.

We use that function on pg_stat_monitor to retrieve the application name
and IP address of the client, we now cache the results in order to avoid
calling it for every query being processed.
2022-02-17 19:47:12 +05: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
Diego Fronza 7d92b3ac59 PG-290: Fix crash when enabling debugging log level on PostgreSQL.
There were couple issues to handle, the main one was that our log hook
(pgsm_emit_log_hook) was being called after the shared memory hook
completed (pgss_shmem_startup) but before PostgreSQL boostraping code
finished, thus triggering the following assertion during a call to
LWLockAcquire():
Assert(!(proc == NULL && IsUnderPostmaster));

proc is a pointer to MyProc, a PostgreSQL's shared global variable that
was not yet initalized by PostgreSQL.

We must also check for a NULL pointer return in pg_get_backend_status()
the pgstat_fetch_stat_local_beentry() function may return a NULL pointer
during initialization, in which case we use "127.0.0.1" for the client
address, and "postmaster" for application name.
2022-02-17 19:45:55 +05:00
Ibrar Ahmed 8fe7676923 PG-284: Bump version to 1.0.0-rc.1. 2021-11-24 18:55:13 +00:00
Diego Fronza 47e84f96c3 PG-234: Fix loading both pg_stat_monitor and pg_stat_statements.
If both modules are loaded then pg_stat_monitor detects that and avoid
calling standard_ProcessUtility() in ProcessUtility_hook hook, as
calling it twice is an error and triggers an assertion on PostgreSQL.

On PostgreSQL 13, pg_stat_monitor must be loaded after
pg_stat_statements, as pg_stat_statements doesn't do such verifications,
it end calling standard_ProcessUtility() and other functions even if
another module is registered, that is an error.

They fixed this problem with pg_stat_statements in PostgreSQL 14 and onward.
2021-11-22 15:13:30 -03: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
Ibrar Ahmed 192ec4e470
Merge pull request #133 from percona/devel
Devel
2021-11-13 00:37:52 +05:00
Ibrar Ahmed f1166c306a
Merge pull request #130 from darkfronza/PG-272_fix_server_crash
PG-272: Fix server crash when calling pg_stat_monitor_reset().
2021-11-12 20:42:29 +05:00
Ibrar Ahmed 0148409b33
Merge pull request #131 from percona/devel
Devel
2021-11-12 20:41:37 +05:00
Diego Fronza 997639c067 PG-272: Fix server crash when calling pg_stat_monitor_reset().
The loop that resets the query buffers was incorrecly using MAX_BUCKETS
to indicate the number of buckets to clear, which defaults to 10. If a
user lowers this value the loop would access a pointer beyond the number
of query buffers allocated.

Fix the problem by using the correct PGSM_MAX_BUCKETS GUC as the limit
to the loop.
2021-11-12 10:58:56 -03:00
Ibrar Ahmed 06b5e4c5fe PG-210: Columns names should match upstream pg_stat_statements column names. 2021-11-10 19:30:32 +00:00
Evgeniy Patlan ac7aa57995 PG-264 fix version 2021-11-01 14:49:35 +02: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 c3d167e452 PG-220: Check possible query buffer overflow.
In SaveQueryText() we check for a possible overflow in the query buffer,
but if overflow would happen and pgsm_overflow_target value is 1 (the
default), then we dump the query buffer to a temporary file and reset
the buffer (start saving queries from the start of the buffer). The
problem is that after resetting the buffer we don't check if the current
query length would exceed the buffer size of MAX_QUERY_BUFFER_BUCKET, if
that is the case the buffer would overflow and probably crash the
process or in the worst case become an attack vector for exploitation.

This commit fix the problem by adding an additional check for overflow
after resetting the query buffer.
2021-10-22 15:40:27 -03:00
Ibrar Ahmed 693838c979 PG-263: Bump version to 1.0.0 - Beta2. 2021-10-22 16:27:36 +00:00
Diego Fronza a9a36905f2 PG-262: Fix comment extraction on queries.
The regular expression was updated to properly capture comments in SQL
in the form /* */.

The previous regex was capturing everything from /* until the last */
because regex are greedy, this was presenting problems if a input query
has something like:
SELECT /* comment 1 */ field /* comment 2 */ from FOO;

As such, the previous regex would capture anytying between /* comment 1
and comment 2 */, the result would be:
/* comment 1 field comment 2*/.

Multiline comments are also captured.

Multiple comments in one query are now stored in the pg_stat_monitor
comments field in the form: /* Comment 1 */, ... , /* Comment N */.
2021-10-18 11:41:37 -03:00
Diego Fronza bf8c93b185 PG-261: Fix regression tests on distribution packages.
The code added in pgss_store() to handle an assertion failure when
GetUserId() was being called introduced a problem with regression tests
in some builds, specifically our PG11 and PG12 distributions for Ubuntu.

The problem was detected when calling some json functions that would
trigger parallel workers, to solve the problem now we check if our hooks
are being called by parallel workers, in this case we can avoid doing
work, it also fixes the issue mentioned above as we won't call
GetUserId() anymore in an invalid context.
2021-10-15 11:56:28 -03:00
Diego Fronza 0e06a4c701 PG-260: Fix display of queries in pg_stat_monitor view.
Don't display queries in PARSE or PLAN state, to keep it consistent
with previous behavior, this avoids showing intermediate scripts like
part of a procedure, such as:
$1
$1 := $3
2021-10-14 10:24:41 -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 fc9e630497 PG-254: Postpone variable initialization.
There were many variables being initialized in pgss_store() before
checking if the module was actually active, this would waste cpu
processor if the module is disabled.

To fix that, declare variables and initialize them only after check
that pg_stat_monitor is active.
2021-10-06 14:44:57 -03:00
Ibrar Ahmed a93ba37ac3 PG-246, PG-211, PG-147: Fix performance issue while querying the pg_stat_monitor.
This performance fix resolves two more issues (PG-211, PG-147).
2021-10-05 20:33:34 +00: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 b4d4dae29f PG-232: revome unsed declrations 2021-09-22 17:10:52 +03:00
Hamid Akhtar d633126a2d Bumping version for upcoming 0.9.2-beta1 release 2021-09-06 15:21:55 +05:00
Diego Fronza eafb2e89a8 PG-225: Fix deadlock in pgss_store.
The deadlock scenario is describe below:
1. pgss_store is called, it acquires the lock pgss->lock.
2. An error ocurr, mostly out of memory when accessing internal hash
   tables used to store internal data, on functions
   pgss_store_query_info and pgss_get_entry.
3. Call elog() to report out of memory error.
4. Our pgsm_emit_log_hook is called, it calls pgss_store_error, which in
   turn calls pgss_store.
5. Try to acquire already acquired lock pgss->lock, deadlock happens.

To fix the problem, there are two modifications worth mentioning done by
this commit:
1. We are now passing HASH_ENTER_NULL flag to hash_search, instead of
   HASH_ENTER, as read in postgresql sources, this prevents this
   function from reporting error when out of memory, but instead it will
   only return NULL if we pass HASH_ENTER_NULL, so we can handle the
   error ourselves.
2. In pgss_store, if an error happens after the pgss->lock is acquired,
   we only set a flag, then, after releasing the lock, we check if the
   flag is set and report the error accordingly.
2021-09-03 14:43:32 -04:00
Diego Fronza b8198278cd PG-204: Fix save previous emit_log_hook.
pg_stat_monitor was not saving the pointer to the previous hook for
emit_log_hook, this commit fix the issue.
2021-09-01 11:19:48 -04:00
Diego Fronza b5aa300e82 pg-224: Fix memory leak on extract_query_comments.
There were two objects leaking memory in this function, the comments
variable of type char * allocated using palloc0, and the regular
expression object preg.

If the regcomp function failed, the function was returning without
releasing the comments variable allocated previously.

If the regexec function failed, the function was returning without
releasing the preg object and the comments variable.

This commit does two changes, first it turns the comments in
extract_query_comments an argument to the function, in pgss_store we
declare the comments variable in the stack, so it will clean up after
itself.

The second change was to move the regular expression object to global
scope, this way we compile the object only once, during module
initialization.

With these two changes we fix the memory leak and avoid
allocating/releasing memory for every call to this function.
2021-08-31 18:29:22 -04:00
Ibrar Ahmed 3d3ece2f99 PG-221: Use alternate of GetUserID function in error hook. 2021-08-31 14:55:53 +00:00
Ibrar Ahmed aee45ebe52 PG-221: Use alternat of GetUserID function in error hook. 2021-08-31 12:10:11 +00:00
Diego Fronza 549347025d PG-223: Use memcpy and strlcpy to copy relations to counters.
We redefine macro _snprintf to use memcpy, which performs better, we
also update call sites using this macro to add the null terminator
'\0' to the source string length, this way memcpy also correctly
copies the null terminator to the destination string.

We update _snprintf2 macro to use strlcpy, the reason we don't use
memcpy here is because in the place where this macro is called,
pgss_update_entry, only the maximum string length of REL_LEN=1000 is
specified as an upper bound to copy the relations string vector to the
destination counters, but since this data is string, we don't need to
copy 1k bytes for every entry, by using strlcpy the copy ends as soon as
the null terminator '\0' is found in the source string.
2021-08-27 17:07:34 -04: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
Ibrar Ahmed f3962509fb
Merge pull request #94 from darkfronza/PG-203_possible_memory_leak
PG-203: Fix memory leak.
2021-08-23 21:30:54 +05: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 33b22e4ef2 PG-203: Fix memory leak.
The query_txt variable is allocated at the beginning of the
pg_stat_monitor_internal() function and released at the end, but an
extra malloc call to allocate it was added within an internal loop in
the funcion, thus allocating memory for every loop iteration, without
releasing the memory in the loop.

The query_txt variable can be reused inside the loop body, so this
commit removes the redundant declaration of query_txt from inside the
loop, which also fixes the leak.
2021-08-06 15:52:29 -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 6c2e052396 PG-194: PostgreSQL 13.3 and 14 support. 2021-07-27 13:37:13 +00:00
Ibrar Ahmed 1dcf596194 Merge branch 'master' of https://github.com/percona/pg_stat_monitor 2021-07-27 12:58:22 +00:00
Ibrar Ahmed 815e543bfe PG-194: PostgreSQL 13.3 and 14 support. 2021-07-27 12:57:29 +00:00
Diego Fronza a3a4c99011 PG-197: Fix conflict with pg_stat_statements.
If pg_stat_monitor is loaded after pg_stat_statement, then it will end
up calling standard_planner function twice in the pgss_planner_hook()
function, this will trigger an assertion failure from PostgreSQL as this
function expects an untouched Query* object, and the first call to
standard_planner() done by pg_stat_statements modifies the object.

To address the problem, we avoid calling standard_planner function twice
in pg_stat_monitor, if a previous handler is installed for the hook
planner_hook, then we assume that this previous hook has already called
standard_planner function and don't do it again.
2021-07-26 10:16:29 -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 f42893472a PG-189: Regression crash in case of PostgreSQL 11.
The size of string required to contain the queryid is smaller which
produce the crash.
2021-03-21 00:39:29 +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 0c9c25fbd9 PG-181: Segmentation fault in case of track_utility is ON. 2021-02-16 16:46:32 +00:00
Ibrar Ahmed b115d748a8 PG-179. Skip lines for checking, and badge to README.
Patch By:  Mikhail Samoylov
2021-02-16 12:46:53 +00:00