mirror of
https://github.com/percona/pg_stat_monitor.git
synced 2026-02-04 05:56:21 +00:00
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.
This commit is contained in:
committed by
Hamid Akhtar
parent
b3c7ba8c60
commit
c21a3de00d
87
hash_query.c
87
hash_query.c
@@ -22,19 +22,8 @@
|
||||
|
||||
static pgssSharedState *pgss;
|
||||
static HTAB *pgss_hash;
|
||||
static HTAB *pgss_query_hash;
|
||||
|
||||
static HTAB* hash_init(const char *hash_name, int key_size, int entry_size, int hash_size);
|
||||
/*
|
||||
* Copy query from src_buffer to dst_buff.
|
||||
* Use query_id and query_pos to fast locate query in source buffer.
|
||||
* Store updated query position in the destination buffer into param query_pos.
|
||||
*/
|
||||
static bool copy_query(uint64 bucket_id,
|
||||
uint64 query_id,
|
||||
uint64 query_pos,
|
||||
unsigned char *dst_buf,
|
||||
unsigned char *src_buf,
|
||||
size_t *new_query_pos);
|
||||
|
||||
static HTAB*
|
||||
hash_init(const char *hash_name, int key_size, int entry_size, int hash_size)
|
||||
@@ -50,7 +39,6 @@ void
|
||||
pgss_startup(void)
|
||||
{
|
||||
bool found = false;
|
||||
int32 i;
|
||||
|
||||
/* reset in case this is a restart within the postmaster */
|
||||
|
||||
@@ -75,16 +63,10 @@ pgss_startup(void)
|
||||
init_hook_stats();
|
||||
#endif
|
||||
|
||||
pgss->query_buf_size_bucket = MAX_QUERY_BUF / PGSM_MAX_BUCKETS;
|
||||
|
||||
for (i = 0; i < PGSM_MAX_BUCKETS; i++)
|
||||
{
|
||||
unsigned char *buf = (unsigned char *)ShmemAlloc(pgss->query_buf_size_bucket);
|
||||
set_qbuf(i, buf);
|
||||
memset(buf, 0, sizeof (uint64));
|
||||
}
|
||||
set_qbuf((unsigned char *)ShmemAlloc(MAX_QUERY_BUF));
|
||||
|
||||
pgss_hash = hash_init("pg_stat_monitor: bucket hashtable", sizeof(pgssHashKey), sizeof(pgssEntry), MAX_BUCKET_ENTRIES);
|
||||
pgss_query_hash = hash_init("pg_stat_monitor: queryID hashtable", sizeof(uint64), sizeof(pgssQueryEntry), MAX_BUCKET_ENTRIES);
|
||||
|
||||
LWLockRelease(AddinShmemInitLock);
|
||||
|
||||
@@ -107,6 +89,12 @@ pgsm_get_hash(void)
|
||||
return pgss_hash;
|
||||
}
|
||||
|
||||
HTAB*
|
||||
pgsm_get_query_hash(void)
|
||||
{
|
||||
return pgss_query_hash;
|
||||
}
|
||||
|
||||
/*
|
||||
* shmem_shutdown hook: Dump statistics into file.
|
||||
*
|
||||
@@ -182,22 +170,15 @@ hash_entry_alloc(pgssSharedState *pgss, pgssHashKey *key, int encoding)
|
||||
* Caller must hold an exclusive lock on pgss->lock.
|
||||
*/
|
||||
void
|
||||
hash_entry_dealloc(int new_bucket_id, int old_bucket_id, unsigned char *query_buffer[])
|
||||
hash_entry_dealloc(int new_bucket_id, int old_bucket_id, unsigned char *query_buffer)
|
||||
{
|
||||
HASH_SEQ_STATUS hash_seq;
|
||||
pgssEntry *entry = NULL;
|
||||
pgssSharedState *pgss = pgsm_get_ss();
|
||||
|
||||
/* Store pending query ids from the previous bucket. */
|
||||
List *pending_entries = NIL;
|
||||
ListCell *pending_entry;
|
||||
|
||||
if (new_bucket_id != -1)
|
||||
{
|
||||
/* Clear all queries in the query buffer for the new bucket. */
|
||||
memset(query_buffer[new_bucket_id], 0, pgss->query_buf_size_bucket);
|
||||
}
|
||||
|
||||
/* Iterate over the hash table. */
|
||||
hash_seq_init(&hash_seq, pgss_hash);
|
||||
while ((entry = hash_seq_search(&hash_seq)) != NULL)
|
||||
@@ -210,6 +191,11 @@ hash_entry_dealloc(int new_bucket_id, int old_bucket_id, unsigned char *query_bu
|
||||
(entry->key.bucket_id == new_bucket_id &&
|
||||
(entry->counters.state == PGSS_FINISHED || entry->counters.state == PGSS_ERROR)))
|
||||
{
|
||||
if (new_bucket_id == -1) {
|
||||
/* pg_stat_monitor_reset(), remove entry from query hash table too. */
|
||||
hash_search(pgss_query_hash, &(entry->key.queryid), HASH_REMOVE, NULL);
|
||||
}
|
||||
|
||||
entry = hash_search(pgss_hash, &entry->key, HASH_REMOVE, NULL);
|
||||
}
|
||||
|
||||
@@ -268,13 +254,6 @@ hash_entry_dealloc(int new_bucket_id, int old_bucket_id, unsigned char *query_bu
|
||||
new_entry->counters = old_entry->counters;
|
||||
SpinLockInit(&new_entry->mutex);
|
||||
new_entry->encoding = old_entry->encoding;
|
||||
/* copy query's text from previous bucket to the new one. */
|
||||
copy_query(new_bucket_id,
|
||||
new_entry->key.queryid, /* query id */
|
||||
old_entry->query_pos, /* query position in buffer */
|
||||
query_buffer[new_bucket_id], /* destination query buffer */
|
||||
query_buffer[old_bucket_id], /* source query buffer */
|
||||
&new_entry->query_pos); /* position in which query was inserted into destination buffer */
|
||||
}
|
||||
|
||||
free(old_entry);
|
||||
@@ -310,39 +289,3 @@ IsHashInitialize(void)
|
||||
return (pgss != NULL &&
|
||||
pgss_hash != NULL);
|
||||
}
|
||||
|
||||
static bool copy_query(uint64 bucket_id,
|
||||
uint64 query_id,
|
||||
uint64 query_pos,
|
||||
unsigned char *dst_buf,
|
||||
unsigned char *src_buf,
|
||||
size_t *new_query_pos)
|
||||
{
|
||||
uint64 query_len = 0;
|
||||
uint64 buf_len = 0;
|
||||
|
||||
memcpy(&buf_len, src_buf, sizeof (uint64));
|
||||
if (buf_len <= 0)
|
||||
return false;
|
||||
|
||||
/* Try to locate the query directly. */
|
||||
if (query_pos != 0 && (query_pos + sizeof(uint64) + sizeof(uint64)) < buf_len)
|
||||
{
|
||||
if (*(uint64 *)&src_buf[query_pos] != query_id)
|
||||
return false;
|
||||
|
||||
query_pos += sizeof(uint64);
|
||||
|
||||
memcpy(&query_len, &src_buf[query_pos], sizeof(uint64)); /* query len */
|
||||
query_pos += sizeof(uint64);
|
||||
|
||||
if (query_pos + query_len > buf_len) /* avoid reading past buffer's length. */
|
||||
return false;
|
||||
|
||||
return SaveQueryText(bucket_id, query_id, dst_buf,
|
||||
(const char *)&src_buf[query_pos],
|
||||
query_len, new_query_pos);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user