diff --git a/Makefile b/Makefile index c2b66a2..fdbe01e 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ PGFILEDESC = "pg_stat_monitor - execution statistics of SQL statements" LDFLAGS_SL += $(filter -lm, $(LIBS)) REGRESS_OPTS = --temp-config $(top_srcdir)/contrib/pg_stat_monitor/pg_stat_monitor.conf --inputdir=regression -REGRESS = basic version guc user counters relations database top_query application_name cmd_type error rows +REGRESS = basic version guc counters relations database top_query application_name cmd_type error rows # Disabled because these tests require "shared_preload_libraries=pg_stat_statements", # which typical installcheck users do not have (e.g. buildfarm clients). diff --git a/hash_query.c b/hash_query.c index 44a9dbb..a4ab4a5 100644 --- a/hash_query.c +++ b/hash_query.c @@ -21,7 +21,6 @@ static pgssSharedState *pgss; static HTAB *pgss_hash; static HTAB *pgss_query_hash; -static HTAB *pgss_plan_hash; static HTAB* hash_init(const char *hash_name, int key_size, int entry_size, int hash_size); @@ -71,8 +70,7 @@ pgss_startup(void) } pgss_hash = hash_init("pg_stat_monitor: bucket hashtable", sizeof(pgssHashKey), sizeof(pgssEntry), MAX_BUCKET_ENTRIES); - pgss_query_hash = hash_init("pg_stat_monitor: query hashtable", sizeof(pgssQueryHashKey), sizeof(pgssQueryEntry),500000); - pgss_plan_hash = hash_init("pg_stat_monitor: plan hashtable", sizeof(pgssPlanHashKey), sizeof(pgssPlanEntry), MAX_BUCKET_ENTRIES); + pgss_query_hash = hash_init("pg_stat_monitor: query hashtable", sizeof(pgssQueryHashKey), sizeof(pgssQueryEntry),MAX_BUCKET_ENTRIES); LWLockRelease(AddinShmemInitLock); @@ -83,12 +81,6 @@ pgss_startup(void) on_shmem_exit(pgss_shmem_shutdown, (Datum) 0); } -HTAB* -pgsm_get_plan_hash(void) -{ - return pgss_plan_hash; -} - pgssSharedState* pgsm_get_ss(void) { @@ -101,6 +93,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. * @@ -128,33 +126,11 @@ hash_memsize(void) size = MAXALIGN(sizeof(pgssSharedState)); size += MAXALIGN(MAX_QUERY_BUF); size = add_size(size, hash_estimate_size(MAX_BUCKET_ENTRIES, sizeof(pgssEntry))); - size = add_size(size, hash_estimate_size(MAX_BUCKET_ENTRIES, sizeof(pgssPlanEntry))); - size = add_size(size, hash_estimate_size(500000, sizeof(pgssQueryEntry))); + size = add_size(size, hash_estimate_size(MAX_BUCKET_ENTRIES, sizeof(pgssQueryEntry))); return size; } -pgssPlanEntry * -hash_plan_entry_alloc(pgssSharedState *pgss, pgssPlanHashKey *key) -{ - pgssPlanEntry *entry = NULL; - bool found = false; - - if (hash_get_num_entries(pgss_plan_hash) >= MAX_BUCKET_ENTRIES) - return NULL; - - /* Find or create an entry with desired hash code */ - entry = (pgssPlanEntry *) hash_search(pgss_plan_hash, key, HASH_ENTER, &found); - if (!found) - { - memset(&entry->plan_info, 0, sizeof(PlanInfo)); - SpinLockInit(&entry->mutex); - } - if (entry == NULL) - elog(FATAL, "%s", "pg_stat_monitor: out of memory"); - return entry; -} - pgssEntry * hash_entry_alloc(pgssSharedState *pgss, pgssHashKey *key,int encoding) { @@ -163,7 +139,7 @@ hash_entry_alloc(pgssSharedState *pgss, pgssHashKey *key,int encoding) if (hash_get_num_entries(pgss_hash) >= MAX_BUCKET_ENTRIES) { - elog(DEBUG2, "%s", "pg_stat_monitor: out of memory"); + elog(DEBUG1, "%s", "pg_stat_monitor: out of memory"); return NULL; } /* Find or create an entry with desired hash code */ @@ -181,7 +157,7 @@ hash_entry_alloc(pgssSharedState *pgss, pgssHashKey *key,int encoding) entry->encoding = encoding; } if (entry == NULL) - elog(FATAL, "%s", "pg_stat_monitor: out of memory"); + elog(DEBUG1, "%s", "pg_stat_monitor: out of memory"); return entry; } @@ -199,7 +175,7 @@ hash_query_entry_dealloc(int bucket) hash_seq_init(&hash_seq, pgss_query_hash); while ((entry = hash_seq_search(&hash_seq)) != NULL) { - if (entry->key.bucket_id == bucket) + if (entry->key.bucket_id == bucket || bucket < 0) entry = hash_search(pgss_query_hash, &entry->key, HASH_REMOVE, NULL); } } @@ -247,8 +223,8 @@ hash_entry_reset() } /* Caller must accuire lock */ -bool -hash_create_query_entry(uint64 bucket_id, uint64 queryid) +pgssQueryEntry* +hash_create_query_entry(uint64 bucket_id, uint64 queryid, uint64 dbid, uint64 userid, uint64 ip) { pgssQueryHashKey key; pgssQueryEntry *entry; @@ -256,14 +232,17 @@ hash_create_query_entry(uint64 bucket_id, uint64 queryid) key.queryid = queryid; key.bucket_id = bucket_id; + key.dbid = dbid; + key.userid = userid; + key.ip = ip; entry = (pgssQueryEntry *) hash_search(pgss_query_hash, &key, HASH_ENTER, &found); - return (entry != NULL); + return entry; } /* Caller must accuire lock */ -bool -hash_find_query_entry(uint64 bucket_id, uint64 queryid) +pgssQueryEntry* +hash_find_query_entry(uint64 bucket_id, uint64 queryid, uint64 dbid, uint64 userid, uint64 ip) { pgssQueryHashKey key; pgssQueryEntry *entry; @@ -271,10 +250,13 @@ hash_find_query_entry(uint64 bucket_id, uint64 queryid) key.queryid = queryid; key.bucket_id = bucket_id; + key.dbid = dbid; + key.userid = userid; + key.ip = ip; /* Lookup the hash table entry with shared lock. */ entry = (pgssQueryEntry *) hash_search(pgss_query_hash, &key, HASH_FIND, &found); - return ((entry != NULL) && found); + return entry; } bool diff --git a/pg_stat_monitor--1.0.sql b/pg_stat_monitor--1.0.sql index 666639c..bdf3dd8 100644 --- a/pg_stat_monitor--1.0.sql +++ b/pg_stat_monitor--1.0.sql @@ -25,19 +25,20 @@ SELECT string_to_array(get_histogram_timings(), ','); $$ LANGUAGE SQL; CREATE FUNCTION pg_stat_monitor_internal(IN showtext boolean, - OUT bucket int, -- 0 + OUT bucket int8, -- 0 OUT userid oid, OUT dbid oid, OUT client_ip int8, OUT queryid text, -- 4 OUT planid text, - OUT top_queryid text, OUT query text, OUT query_plan text, + OUT state int8, + OUT top_queryid text, OUT application_name text, - OUT relations text, -- 10 + OUT relations text, -- 11 OUT cmd_type int, OUT elevel int, OUT sqlcode TEXT, @@ -57,8 +58,9 @@ CREATE FUNCTION pg_stat_monitor_internal(IN showtext boolean, OUT plan_min_time float8, OUT plan_max_time float8, OUT plan_mean_time float8, + OUT plan_stddev_time float8, - OUT shared_blks_hit int8, -- 28 + OUT shared_blks_hit int8, -- 29 OUT shared_blks_read int8, OUT shared_blks_dirtied int8, OUT shared_blks_written int8, @@ -70,7 +72,7 @@ CREATE FUNCTION pg_stat_monitor_internal(IN showtext boolean, OUT temp_blks_written int8, OUT blk_read_time float8, OUT blk_write_time float8, - OUT resp_calls text, + OUT resp_calls text, -- 41 OUT cpu_user_time float8, OUT cpu_sys_time float8, OUT wal_records int8, @@ -81,6 +83,19 @@ RETURNS SETOF record AS 'MODULE_PATHNAME', 'pg_stat_monitor' LANGUAGE C STRICT VOLATILE PARALLEL SAFE; +CREATE OR REPLACE FUNCTION get_state(state int8) RETURNS TEXT AS +$$ +SELECT + CASE + WHEN state = 0 THEN 'PARSED' + WHEN state = 1 THEN 'PLANNING' + WHEN state = 2 THEN 'EXECUTION FINISHED' + WHEN state = 3 THEN 'ERROR' + WHEN state = 4 THEN 'FINISHED' + END +$$ +LANGUAGE SQL PARALLEL SAFE; + CREATE or REPLACE FUNCTION get_cmd_type (cmd_type INTEGER) RETURNS TEXT AS $$ SELECT @@ -169,7 +184,9 @@ CREATE VIEW pg_stat_monitor AS SELECT round(cpu_sys_time::numeric, 4) as cpu_sys_time, wal_records, wal_fpi, - wal_bytes + wal_bytes, + state, + get_state(state) as state_value FROM pg_stat_monitor_internal(TRUE) p, pg_database d WHERE dbid = oid ORDER BY bucket_start_time; diff --git a/pg_stat_monitor.c b/pg_stat_monitor.c index 8fd5083..815c721 100644 --- a/pg_stat_monitor.c +++ b/pg_stat_monitor.c @@ -1,4 +1,3 @@ - /*------------------------------------------------------------------------- * * pg_stat_monitor.c @@ -22,7 +21,7 @@ PG_MODULE_MAGIC; #define BUILD_VERSION "devel" -#define PG_STAT_STATEMENTS_COLS 49 /* maximum of above */ +#define PG_STAT_STATEMENTS_COLS 51 /* maximum of above */ #define PGSM_TEXT_FILE "/tmp/pg_stat_monitor_query" #define PGUNSIXBIT(val) (((val) & 0x3F) + '0') @@ -52,8 +51,6 @@ do \ void _PG_init(void); void _PG_fini(void); -int64 v = 5631; - /*---- Initicalization Function Declarations ----*/ void _PG_init(void); void _PG_fini(void); @@ -72,10 +69,7 @@ static bool system_init = false; static struct rusage rusage_start; static struct rusage rusage_end; static unsigned char *pgss_qbuf[MAX_BUCKETS]; - static char *pgss_explain(QueryDesc *queryDesc); -static bool pgss_get_plan(uint64 query_hash, PlanInfo *plan_info); -static bool pgss_store_plan(uint64 query_hash, PlanInfo *plan_info); static int get_histogram_bucket(double q_time); static bool IsSystemInitialized(void); @@ -141,7 +135,14 @@ static uint64 pgss_hash_string(const char *str, int len); char *unpack_sql_state(int sql_state); static void pgss_store_error(uint64 queryid, const char * query, ErrorData *edata); -static void pgss_store_query(uint64 queryid, const char * query, CmdType cmd_type, int query_location, int query_len, pgssJumbleState *jstate); +static pgssQueryEntry *pgss_store_query_info(uint64 bucketid, + uint64 queryid, + uint64 dbid, + uint64 userid, + uint64 ip, + const char *query, + uint64 query_len, + pgssStoreKind kind); static void pgss_store_utility(const char *query, double total_time, @@ -173,14 +174,20 @@ static void JumbleExpr(pgssJumbleState *jstate, Node *node); static void RecordConstLocation(pgssJumbleState *jstate, int location); static char *generate_normalized_query(pgssJumbleState *jstate, const char *query, int query_loc, int *query_len_p, int encoding); -static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query, - int query_loc); +static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query, int query_loc); static int comp_location(const void *a, const void *b); static uint64 get_next_wbucket(pgssSharedState *pgss); -static void store_query(int bucket_id, uint64 queryid, const char *query, uint64 query_len); -static uint64 read_query(unsigned char *buf, uint64 queryid, char * query); +static void +pgss_store_query(uint64 queryid, + const char * query, + CmdType cmd_type, + int query_location, + int query_len, + pgssJumbleState *jstate, + pgssStoreKind kind); +static uint64 read_query(unsigned char *buf, uint64 bucketid, uint64 queryid, char * query); int read_query_buffer(int bucket_id, uint64 queryid, char *query_txt); static uint64 get_query_id(pgssJumbleState *jstate, Query *query); @@ -245,9 +252,9 @@ _PG_init(void) ProcessUtility_hook = pgss_ProcessUtility; planner_hook_next = planner_hook; planner_hook = pgss_planner_hook; - emit_log_hook = pgsm_emit_log_hook; + emit_log_hook = pgsm_emit_log_hook; prev_ExecutorCheckPerms_hook = ExecutorCheckPerms_hook; - ExecutorCheckPerms_hook = pgss_ExecutorCheckPerms; + ExecutorCheckPerms_hook = pgss_ExecutorCheckPerms; nested_queryids = (uint64*) malloc(sizeof(uint64) * max_stack_depth); @@ -306,6 +313,7 @@ static void pgss_post_parse_analyze(ParseState *pstate, Query *query) { pgssJumbleState jstate; + pgssStoreKind kind = PGSS_PARSE; if (prev_post_parse_analyze_hook) prev_post_parse_analyze_hook(pstate, query); @@ -344,8 +352,9 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query) pstate->p_sourcetext, /* query */ query->commandType, /* CmdType */ query->stmt_location, /* Query Location */ - query->stmt_len, /* Quer Len */ - &jstate); /* pgssJumbleState */ + query->stmt_len, /* Query Len */ + &jstate, /* pgssJumbleState */ + kind); /*pgssStoreKind */ } /* @@ -355,7 +364,7 @@ static void pgss_ExecutorStart(QueryDesc *queryDesc, int eflags) { if(getrusage(RUSAGE_SELF, &rusage_start) != 0) - elog(WARNING, "pg_stat_monitor: failed to execute getrusage"); + elog(DEBUG1, "pg_stat_monitor: failed to execute getrusage"); if (prev_ExecutorStart) prev_ExecutorStart(queryDesc, eflags); @@ -438,55 +447,6 @@ pgss_ExecutorFinish(QueryDesc *queryDesc) PG_END_TRY(); } - -static bool -pgss_get_plan(uint64 query_hash, PlanInfo *plan_info) -{ - pgssPlanHashKey key; - pgssPlanEntry *entry; - HTAB *pgss_plan_hash = pgsm_get_plan_hash(); - - key.query_hash = query_hash; - entry = (pgssPlanEntry *) hash_search(pgss_plan_hash, &key, HASH_FIND, NULL); - if(entry) - { - memcpy(plan_info, &entry->plan_info, sizeof(PlanInfo)); - return true; - } - return false; -} - -static bool -pgss_store_plan(uint64 query_hash, PlanInfo *plan_info) -{ - pgssPlanHashKey key; - pgssPlanEntry *entry; - HTAB *pgss_plan_hash = pgsm_get_plan_hash(); - pgssSharedState *pgss = pgsm_get_ss(); - bool found = true; - - LWLockAcquire(pgss->lock, LW_SHARED); - - /* Set up key for hashtable search */ - key.query_hash = query_hash; - entry = (pgssPlanEntry *) hash_search(pgss_plan_hash, &key, HASH_FIND, NULL); - if (!entry) - { - entry = hash_plan_entry_alloc(pgss, &key); - if (entry == NULL) - { - LWLockRelease(pgss->lock); - return found; - } - found = false; - } - SpinLockAcquire(&entry->mutex); - memcpy(&entry->plan_info, plan_info, sizeof(PlanInfo)); - SpinLockRelease(&entry->mutex); - LWLockRelease(pgss->lock); - return found; -} - static char * pgss_explain(QueryDesc *queryDesc) { @@ -536,7 +496,7 @@ pgss_ExecutorEnd(QueryDesc *queryDesc) */ InstrEndLoop(queryDesc->totaltime); if(getrusage(RUSAGE_SELF, &rusage_end) != 0) - elog(WARNING, "pg_stat_monitor: failed to execute getrusage"); + elog(DEBUG1, "pg_stat_monitor: failed to execute getrusage"); sys_info.utime = time_diff(rusage_end.ru_utime, rusage_start.ru_utime); sys_info.stime = time_diff(rusage_end.ru_stime, rusage_start.ru_stime); @@ -626,6 +586,7 @@ pgss_planner_hook(Query *parse, const char *query_string, int cursorOptions, Par WalUsage walusage_start; WalUsage walusage; + memset(&plan_info, 0, sizeof(PlanInfo)); /* We need to track buffer usage as the planner can access them. */ bufusage_start = pgBufferUsage; @@ -670,7 +631,7 @@ pgss_planner_hook(Query *parse, const char *query_string, int cursorOptions, Par &bufusage, /* bufusage */ &walusage, /* walusage */ NULL, /* pgssJumbleState */ - PGSS_PLAN); /* pgssStoreKind */ + PGSS_PLAN); /* pgssStoreKind */ } else { @@ -916,7 +877,8 @@ pgss_update_entry(pgssEntry *entry, uint64 rows, BufferUsage *bufusage, WalUsage *walusage, - bool reset) + bool reset, + pgssStoreKind kind) { int index; char application_name[APPLICATIONNAME_LEN]; @@ -925,6 +887,8 @@ pgss_update_entry(pgssEntry *entry, double old_mean; int message_len = error_info ? strlen (error_info->message) : 0; int sqlcode_len = error_info ? strlen (error_info->sqlcode) : 0; + int plan_text_len = plan_info ? strlen (plan_info->plan_text) : 0; + /* volatile block */ { @@ -934,30 +898,58 @@ pgss_update_entry(pgssEntry *entry, if (reset) memset(&entry->counters, 0, sizeof(Counters)); - if (e->counters.calls.calls == 0) - e->counters.calls.usage = USAGE_INIT; - e->counters.calls.calls += 1; - e->counters.time.total_time += total_time; - - if (e->counters.calls.calls == 1) + if (kind == PGSS_PLAN) { - e->counters.time.min_time = total_time; - e->counters.time.max_time = total_time; - e->counters.time.mean_time = total_time; + if (e->counters.plancalls.calls == 0) + e->counters.plancalls.usage = USAGE_INIT; + e->counters.plancalls.calls += 1; + e->counters.plantime.total_time += total_time; + + if (e->counters.plancalls.calls == 1) + { + e->counters.plantime.min_time = total_time; + e->counters.plantime.max_time = total_time; + e->counters.plantime.mean_time = total_time; + } + + /* Increment the counts, except when jstate is not NULL */ + old_mean = e->counters.plantime.mean_time; + e->counters.plantime.mean_time += (total_time - old_mean) / e->counters.plancalls.calls; + e->counters.plantime.sum_var_time +=(total_time - old_mean) * (total_time - e->counters.plantime.mean_time); + + /* calculate min and max time */ + if (e->counters.plantime.min_time > total_time) e->counters.plantime.min_time = total_time; + if (e->counters.plantime.max_time < total_time) e->counters.plantime.max_time = total_time; + } + else + { + e->counters.state = kind; + if (e->counters.calls.calls == 0) + e->counters.calls.usage = USAGE_INIT; + e->counters.calls.calls += 1; + e->counters.time.total_time += total_time; + + if (e->counters.calls.calls == 1) + { + e->counters.time.min_time = total_time; + e->counters.time.max_time = total_time; + e->counters.time.mean_time = total_time; + } + + /* Increment the counts, except when jstate is not NULL */ + old_mean = e->counters.time.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); + + /* 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; + + index = get_histogram_bucket(total_time); + e->counters.resp_calls[index]++; } - /* Increment the counts, except when jstate is not NULL */ - old_mean = e->counters.time.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); - - /* 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; - - index = get_histogram_bucket(total_time); - e->counters.resp_calls[index]++; - + _snprintf(e->counters.planinfo.plan_text, plan_info->plan_text, plan_text_len, PLAN_TEXT_LEN); _snprintf(e->counters.info.application_name, application_name, application_name_len, APPLICATIONNAME_LEN); e->counters.info.num_relations = pgss->num_relations; @@ -1020,7 +1012,7 @@ pgss_get_entry(uint64 bucket_id, uint64 dbid, uint64 queryid, uint64 ip, - bool *found) + uint64 planid) { pgssEntry *entry; pgssHashKey key; @@ -1032,12 +1024,11 @@ pgss_get_entry(uint64 bucket_id, key.dbid = MyDatabaseId; key.queryid = queryid; key.ip = pg_get_client_addr(); + key.planid = planid; entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL); if(!entry) { - if (found) - *found = false; /* OK to create a new hashtable entry */ entry = hash_entry_alloc(pgss, &key, GetDatabaseEncoding()); if (entry == NULL) @@ -1053,7 +1044,8 @@ pgss_store_query(uint64 queryid, CmdType cmd_type, int query_location, int query_len, - pgssJumbleState *jstate) + pgssJumbleState *jstate, + pgssStoreKind kind) { char *norm_query = NULL; @@ -1105,7 +1097,7 @@ pgss_store_query(uint64 queryid, NULL, /* bufusage */ NULL, /* walusage */ jstate, /* pgssJumbleState */ - PGSS_EXEC); /* pgssStoreKind */ + kind); /* pgssStoreKind */ } static void @@ -1117,7 +1109,7 @@ pgss_store_error(uint64 queryid, error_info.elevel = edata->elevel; snprintf(error_info.message, ERROR_MESSAGE_LEN, "%s", edata->message); - snprintf(error_info.sqlcode, ERROR_MESSAGE_LEN, "%s", unpack_sql_state(edata->sqlerrcode)); + snprintf(error_info.sqlcode, SQLCODE_LEN, "%s", unpack_sql_state(edata->sqlerrcode)); pgss_store(queryid, /* query id */ query, /* query text */ @@ -1153,56 +1145,7 @@ pgss_store_utility(const char *query, bufusage, /* bufusage */ walusage, /* walusage */ NULL, /* pgssJumbleState */ - PGSS_EXEC); /* pgssStoreKind */ -} - -static void -update_planinfo(PlanInfo *plan_info, pgssStoreKind kind, double total_time, uint64 userid, uint64 dbid, uint64 queryid, uint64 ip) -{ - char str[64]; - uint64 query_hash; - PlanInfo pi; - - if (plan_info == NULL) - return; - - snprintf(str, 64, "%08lx%08lX%08lX%08lX", userid, dbid, queryid, ip); - query_hash = DatumGetUInt64(hash_any_extended((const unsigned char*)str, strlen(str), 0)); - - if (pgss_get_plan(query_hash, &pi)) - { - if (kind == PGSS_PLAN) - { - double old_mean = 0; - - pi.plans += 1; - pi.time.total_time += total_time; - if (pi.plans == 0) - if (pi.plans == 1) - { - pi.time.min_time = total_time; - pi.time.max_time = total_time; - pi.time.mean_time = total_time; - } - - /* Increment the counts, except when jstate is not NULL */ - old_mean = pi.time.mean_time; - pi.time.mean_time += (total_time - old_mean) / pi.plans; - pi.time.sum_var_time +=(total_time - old_mean) * (total_time - pi.time.mean_time); - - /* calculate min and max time */ - if (pi.time.min_time > total_time) pi.time.min_time = total_time; - if (pi.time.max_time < total_time) pi.time.max_time = total_time; - pgss_store_plan(query_hash, &pi); - } - } - else - { - if (kind == PGSS_EXEC) - { - pgss_store_plan(query_hash, plan_info); - } - } + PGSS_EXEC); /* pgssStoreKind */ } /* @@ -1229,11 +1172,14 @@ pgss_store(uint64 queryid, pgssJumbleState *jstate, pgssStoreKind kind) { - int bucket_id; pgssEntry *entry; pgssSharedState *pgss = pgsm_get_ss(); bool reset = false; - bool found = true; + uint64 bucketid; + uint64 userid = GetUserId(); + uint64 dbid = MyDatabaseId; + uint64 ip = pg_get_client_addr(); + uint64 planid = plan_info ? plan_info->planid: 0; /* Monitoring is disabled */ if (!PGSM_ENABLED) @@ -1245,41 +1191,67 @@ pgss_store(uint64 queryid, if (!IsSystemInitialized() || !pgss_qbuf[pgss->current_wbucket]) return; - bucket_id = get_next_wbucket(pgss); - if (bucket_id != pgss->current_wbucket) + bucketid = get_next_wbucket(pgss); + if (bucketid != pgss->current_wbucket) { reset = true; - pgss->current_wbucket = bucket_id; + pgss->current_wbucket = bucketid; } - update_planinfo(plan_info, kind, total_time, (uint64)GetUserId(), (uint64)MyDatabaseId, queryid, (uint64)pg_get_client_addr()); - LWLockAcquire(pgss->lock, LW_EXCLUSIVE); - entry = pgss_get_entry(bucket_id, GetUserId(), MyDatabaseId, queryid, pg_get_client_addr(), &found); - if (entry == NULL) + + switch (kind) { - LWLockRelease(pgss->lock); - return; + case PGSS_PARSE: + case PGSS_PLAN: + { + pgssQueryEntry *query_entry; + query_entry = pgss_store_query_info(bucketid, queryid, dbid, userid, ip, query, strlen(query), kind); + if (query_entry == NULL) + elog(DEBUG1, "pg_stat_monitor: out of memory"); + break; + } + case PGSS_EXEC: + { + pgssQueryEntry *query_entry; + query_entry = pgss_store_query_info(bucketid, queryid, dbid, userid, ip, query, strlen(query), kind); + if (query_entry == NULL) + { + elog(DEBUG1, "pg_stat_monitor: out of memory"); + break; + } + entry = pgss_get_entry(bucketid, userid, dbid, queryid, ip, planid); + if (entry == NULL) + { + elog(DEBUG1, "pg_stat_monitor: out of memory"); + break; + } + + if (jstate == NULL) + pgss_update_entry(entry, /* entry */ + bucketid, /* bucketid */ + queryid, /* queryid */ + query, /* query */ + plan_info, /* PlanInfo */ + cmd_type, /* CmdType */ + sys_info, /* SysInfo */ + error_info, /* ErrorInfo */ + total_time, /* total_time */ + rows, /* rows */ + bufusage, /* bufusage */ + walusage, /* walusage */ + reset, /* reset */ + kind); /* kind */ + } + break; + case PGSS_FINISHED: + case PGSS_NUMKIND: + case PGSS_INVALID: + break; + + case PGSS_ERROR: + break; } - - /* In case query is not found in the hash, add that into hash. */ - if (!found) - store_query(bucket_id, queryid, query, strlen(query)); - - if (jstate == NULL && kind == PGSS_EXEC) - pgss_update_entry(entry, /* entry */ - bucket_id, /* bucketid */ - queryid, /* queryid */ - query, /* query */ - plan_info, /* PlanInfo */ - cmd_type, /* CmdType */ - sys_info, /* SysInfo */ - error_info, /* ErrorInfo */ - total_time, /* total_time */ - rows, /* rows */ - bufusage, /* bufusage */ - walusage, /* walusage */ - reset); /* reset */ LWLockRelease(pgss->lock); } /* @@ -1296,6 +1268,7 @@ pg_stat_monitor_reset(PG_FUNCTION_ARGS) errmsg("pg_stat_monitor: must be loaded via shared_preload_libraries"))); LWLockAcquire(pgss->lock, LW_EXCLUSIVE); hash_entry_dealloc(-1); + hash_query_entry_dealloc(-1); LWLockRelease(pgss->lock); PG_RETURN_VOID(); } @@ -1307,6 +1280,25 @@ pg_stat_monitor(PG_FUNCTION_ARGS) return (Datum) 0; } +static bool +IsBucketValid(uint64 bucketid) +{ + struct tm tm; + time_t bucket_t,current_t; + double diff_t; + pgssSharedState *pgss = pgsm_get_ss(); + + memset(&tm, 0, sizeof(tm)); + strptime(pgss->bucket_start_time[bucketid], "%Y-%m-%d %H:%M:%S", &tm); + bucket_t = mktime(&tm); + + time(¤t_t); + diff_t = difftime(current_t, bucket_t); + if (diff_t > (PGSM_BUCKET_TIME * PGSM_MAX_BUCKETS)) + return false; + return true; +} + /* Common code for all versions of pg_stat_statements() */ static void pg_stat_monitor_internal(FunctionCallInfo fcinfo, @@ -1317,21 +1309,12 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, Tuplestorestate *tupstore; MemoryContext per_query_ctx; MemoryContext oldcontext; - Oid userid = GetUserId(); - bool is_allowed_role; HASH_SEQ_STATUS hash_seq; pgssEntry *entry; - char *query_txt; - char queryid_txt[64]; - char planid_txt[64]; char parentid_txt[64]; pgssSharedState *pgss = pgsm_get_ss(); HTAB *pgss_hash = pgsm_get_hash(); - - query_txt = (char*) malloc(PGSM_QUERY_MAX_LEN); - - /* Superusers or members of pg_read_all_stats members are allowed */ - is_allowed_role = is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS); + char *query_txt = (char*) malloc(PGSM_QUERY_MAX_LEN); /* Safety check... */ if (!IsSystemInitialized()) @@ -1358,7 +1341,7 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "pg_stat_monitor: return type must be a row type"); - if (tupdesc->natts != 46) + if (tupdesc->natts != 48) elog(ERROR, "pg_stat_monitor: incorrect number of output arguments, required %d", tupdesc->natts); tupstore = tuplestore_begin_heap(true, false, work_mem); @@ -1373,83 +1356,37 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, hash_seq_init(&hash_seq, pgss_hash); while ((entry = hash_seq_search(&hash_seq)) != NULL) { - Datum values[PG_STAT_STATEMENTS_COLS]; - bool nulls[PG_STAT_STATEMENTS_COLS]; - int i = 0; - Counters tmp; - double stddev; - uint64 queryid = entry->key.queryid; - struct tm tm; - time_t bucket_t,current_t; - double diff_t; - char str[64]; - uint64 query_hash; - PlanInfo plan_info; + Datum values[PG_STAT_STATEMENTS_COLS] = {0}; + bool nulls[PG_STAT_STATEMENTS_COLS] = {0}; + int i = 0; + Counters tmp; + double stddev; + char queryid_text[16] = {0}; + char planid_text[16] = {0}; + uint64 queryid = entry->key.queryid; + uint64 bucketid = entry->key.bucket_id; + uint64 dbid = entry->key.dbid; + uint64 userid = entry->key.userid; + uint64 ip = entry->key.ip; + uint64 planid = entry->key.planid; - memset(&plan_info, 0, sizeof(plan_info)); - snprintf(str, 64, "%08lx%08lX%08lX%08lX", (uint64)entry->key.userid, (uint64)entry->key.dbid, queryid, (uint64)entry->key.ip); - query_hash = DatumGetUInt64(hash_any_extended((const unsigned char*)str, strlen(str), 0)); - pgss_get_plan(query_hash, &plan_info); + unsigned char *buf = pgss_qbuf[bucketid]; + char *query_txt = (char*) malloc(PGSM_QUERY_MAX_LEN); + bool is_allowed_role = is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS); - memset(&tm, 0, sizeof(tm)); - strptime(pgss->bucket_start_time[entry->key.bucket_id], "%Y-%m-%d %H:%M:%S", &tm); - bucket_t = mktime(&tm); - - time(¤t_t); - diff_t = difftime(current_t, bucket_t); - if (diff_t > (PGSM_BUCKET_TIME * PGSM_MAX_BUCKETS)) + if (!IsBucketValid(bucketid)) continue; - memset(values, 0, sizeof(values)); - memset(nulls, 0, sizeof(nulls)); + if (!hash_find_query_entry(bucketid, queryid, dbid, userid, ip)) + continue; - if (!hash_find_query_entry(entry->key.bucket_id, queryid)) + if (read_query(buf, bucketid, queryid, query_txt) == 0) { - sprintf(query_txt, "%s", "pg_stat_monitor: queryid not found in hash and in temporay file"); + int len; + len = read_query_buffer(bucketid, queryid, query_txt); + if (len != MAX_QUERY_BUFFER_BUCKET) + sprintf(query_txt, "%s", ""); } - else - { - int len = 0; - unsigned char *buf = pgss_qbuf[entry->key.bucket_id]; - if(read_query(buf, queryid, query_txt) == 0) - { - switch(PGSM_OVERFLOW_TARGET) - { - case OVERFLOW_TARGET_NONE: - sprintf(query_txt, "%s", "query not found in query shared_buffer, no space left"); - break; - case OVERFLOW_TARGET_DISK: - { - len = read_query_buffer(entry->key.bucket_id, queryid, query_txt); - if (len != MAX_QUERY_BUFFER_BUCKET) - sprintf(query_txt, "%s", "query not found either in hash nor in temporay file"); - } - break; - } - } - } - if (query_txt) - sprintf(queryid_txt, "%08lX", queryid); - else - sprintf(queryid_txt, "%08lX", (long unsigned int)0); - - sprintf(planid_txt, "%08lX", plan_info.planid); - - /* bucketid at column number 0 */ - values[i++] = ObjectIdGetDatum(entry->key.bucket_id); - - /* userid at column number 1 */ - values[i++] = ObjectIdGetDatum(entry->key.userid); - - /* dbid at column number 2 */ - values[i++] = ObjectIdGetDatum(entry->key.dbid); - - /* ip address at column number 3 */ - /* Superusers or members of pg_read_all_stats members are allowed */ - if (is_allowed_role || entry->key.userid == userid) - values[i++] = Int64GetDatumFast(entry->key.ip); - else - values[i++] = Int64GetDatumFast(0); /* copy counters to a local variable to keep locking time short */ { @@ -1458,17 +1395,76 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, tmp = e->counters; SpinLockRelease(&e->mutex); } + /* bucketid at column number 0 */ + values[i++] = Int64GetDatumFast(bucketid); - /* queryid at column number 4 */ - values[i++] = CStringGetTextDatum(queryid_txt); + /* userid at column number 1 */ + values[i++] = ObjectIdGetDatum(userid); - /* planid at column number 5 */ - if (plan_info.planid != 0) - values[i++] = CStringGetTextDatum(planid_txt); + /* dbid at column number 2 */ + values[i++] = ObjectIdGetDatum(dbid); + + /* + * ip address at column number 3, + * Superusers or members of pg_read_all_stats members + * are allowed + */ + if (is_allowed_role || userid == GetUserId()) + values[i++] = Int64GetDatumFast(ip); else nulls[i++] = true; - /* parentid at column number 6 */ + /* queryid at column number 4 */ + sprintf(queryid_text, "%08lX", queryid); + values[i++] = CStringGetTextDatum(queryid_text); + + /* planid at column number 5 */ + if (planid) + { + sprintf(planid_text, "%08lX", planid); + values[i++] = CStringGetTextDatum(planid_text); + } + else + { + nulls[i++] = true; + } + if (is_allowed_role || userid == GetUserId()) + { + if (showtext) + { + char *enc; + + /* query at column number 6 */ + enc = pg_any_to_server(query_txt, strlen(query_txt), GetDatabaseEncoding()); + values[i++] = CStringGetTextDatum(enc); + if (enc != query_txt) + pfree(enc); + /* plan at column number 7 */ + if (planid && tmp.planinfo.plan_text) + values[i++] = CStringGetTextDatum(tmp.planinfo.plan_text); + else + nulls[i++] = true; + } + else + { + /* query at column number 6 */ + nulls[i++] = true; + /* plan at column number 7 */ + nulls[i++] = true; + } + } + else + { + /* query text at column number 6 */ + values[i++] = CStringGetTextDatum(""); + values[i++] = CStringGetTextDatum(""); + } + + + /* state at column number 8 */ + values[i++] = Int64GetDatumFast(tmp.state); + + /* parentid at column number 9 */ if (tmp.info.parentid != UINT64CONST(0)) { sprintf(parentid_txt,"%08lX",tmp.info.parentid); @@ -1479,53 +1475,11 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, nulls[i++] = true; } - if (is_allowed_role || entry->key.userid == userid) - { - /* query at column number 7 */ - /* plan at column number 8 */ - if (showtext) - { - if (query_txt) - { - char *enc; - enc = pg_any_to_server(query_txt, strlen(query_txt), entry->encoding); - values[i++] = CStringGetTextDatum(enc); - values[i++] = CStringGetTextDatum(plan_info.plan_text); - if (enc != query_txt) - pfree(enc); - } - else - { - nulls[i++] = true; - nulls[i++] = true; - } - } - else - { - /* Query text not requested */ - nulls[i++] = true; - nulls[i++] = true; - } - } - else - { - /* - * Don't show query text, but hint as to the reason for not doing - * so if it was requested - */ - if (showtext) - values[i++] = CStringGetTextDatum(""); - else - nulls[i++] = true; - /* skip plan_text */ - nulls[i++] = true; - } - /* application_name at column number 9 */ - if (strlen(tmp.info.application_name) == 0) - nulls[i++] = true; - else + if (strlen(tmp.info.application_name) > 0) values[i++] = CStringGetTextDatum(tmp.info.application_name); + else + nulls[i++] = true; /* relations at column number 10 */ if (tmp.info.num_relations > 0) @@ -1608,22 +1562,36 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, /* calls at column number 22 */ values[i++] = Int64GetDatumFast(tmp.calls.rows); - /* plan_calls at column number 23 */ - values[i++] = Int64GetDatumFast(plan_info.plans); + if (tmp.calls.calls == 0) + { + /* Query of pg_stat_monitor itslef started from zero count */ + tmp.calls.calls++; + tmp.resp_calls[0]++; + } - /* plan_total_time at column number 24 */ - values[i++] = Float8GetDatumFast(plan_info.time.total_time); + /* calls at column number 23 */ + values[i++] = Int64GetDatumFast(tmp.plancalls.calls); - /* plan_min_time at column number 25 */ - values[i++] = Float8GetDatumFast(plan_info.time.min_time); + /* total_time at column number 24 */ + values[i++] = Float8GetDatumFast(tmp.plantime.total_time); - /* plan_max_time at column number 26 */ - values[i++] = Float8GetDatumFast(plan_info.time.max_time); + /* min_time at column number 25 */ + values[i++] = Float8GetDatumFast(tmp.plantime.min_time); - /* plan_mean_time at column number 27 */ - values[i++] = Float8GetDatumFast(plan_info.time.mean_time); + /* max_time at column number 26 */ + values[i++] = Float8GetDatumFast(tmp.plantime.max_time); - /* blocks are from column number 28 - 39 */ + /* mean_time at column number 27 */ + values[i++] = Float8GetDatumFast(tmp.plantime.mean_time); + if (tmp.plancalls.calls > 1) + stddev = sqrt(tmp.plantime.sum_var_time / tmp.plancalls.calls); + else + stddev = 0.0; + + /* calls at column number 28 */ + values[i++] = Float8GetDatumFast(stddev); + + /* blocks are from column number 29 - 40 */ values[i++] = Int64GetDatumFast(tmp.blocks.shared_blks_hit); values[i++] = Int64GetDatumFast(tmp.blocks.shared_blks_read); values[i++] = Int64GetDatumFast(tmp.blocks.shared_blks_dirtied); @@ -1637,22 +1605,22 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, values[i++] = Float8GetDatumFast(tmp.blocks.blk_read_time); values[i++] = Float8GetDatumFast(tmp.blocks.blk_write_time); - /* resp_calls at column number 40 */ + /* resp_calls at column number 41 */ values[i++] = IntArrayGetTextDatum(tmp.resp_calls, MAX_RESPONSE_BUCKET); - /* utime at column number 41 */ + /* utime at column number 42 */ values[i++] = Float8GetDatumFast(tmp.sysinfo.utime); - /* stime at column number 42 */ + /* stime at column number 43 */ values[i++] = Float8GetDatumFast(tmp.sysinfo.stime); { char buf[256]; Datum wal_bytes; - /* wal_records at column number 43 */ + /* wal_records at column number 44 */ values[i++] = Int64GetDatumFast(tmp.walusage.wal_records); - /* wal_fpi at column number 44 */ + /* wal_fpi at column number 45 */ values[i++] = Int64GetDatumFast(tmp.walusage.wal_fpi); snprintf(buf, sizeof buf, UINT64_FORMAT, tmp.walusage.wal_bytes); @@ -1662,13 +1630,12 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, CStringGetDatum(buf), ObjectIdGetDatum(0), Int32GetDatum(-1)); - /* wal_bytes at column number 45 */ + /* wal_bytes at column number 46 */ values[i++] = wal_bytes; } tuplestore_putvalues(tupstore, tupdesc, values, nulls); } free(query_txt); - /* clean up and return the tuplestore */ LWLockRelease(pgss->lock); @@ -2651,7 +2618,7 @@ intarray_get_datum(int32 arr[], int len) } static uint64 -read_query(unsigned char *buf, uint64 queryid, char * query) +read_query(unsigned char *buf, uint64 bucketid, uint64 queryid, char * query) { bool found = false; uint64 query_id = 0; @@ -2661,13 +2628,13 @@ read_query(unsigned char *buf, uint64 queryid, char * query) memcpy(&buf_len, buf, sizeof (uint64)); if (buf_len <= 0) - return 0; + goto exit; rlen = sizeof (uint64); /* Move forwad to skip length bytes */ for(;;) { if (rlen >= buf_len) - return 0; + goto exit; memcpy(&query_id, &buf[rlen], sizeof (uint64)); /* query id */ if (query_id == queryid) @@ -2680,7 +2647,7 @@ read_query(unsigned char *buf, uint64 queryid, char * query) memcpy(&query_len, &buf[rlen], sizeof (uint64)); /* query len */ rlen += sizeof (uint64); if (buf_len < rlen + query_len) - return 0; + goto exit; if (found) { @@ -2693,15 +2660,29 @@ read_query(unsigned char *buf, uint64 queryid, char * query) } rlen += query_len; } +exit: + if (PGSM_OVERFLOW_TARGET == OVERFLOW_TARGET_NONE) + { + sprintf(query, "%s", ""); + return -1; + } return 0; } -static void -store_query(int bucket_id, uint64 queryid, const char *query, uint64 query_len) +static pgssQueryEntry* +pgss_store_query_info(uint64 bucketid, + uint64 queryid, + uint64 dbid, + uint64 userid, + uint64 ip, + const char *query, + uint64 query_len, + pgssStoreKind kind) { uint64 buf_len = 0; pgssSharedState *pgss = pgsm_get_ss(); unsigned char *buf = pgss_qbuf[pgss->current_wbucket]; + pgssQueryEntry *entry; if (query_len > PGSM_QUERY_MAX_LEN) query_len = PGSM_QUERY_MAX_LEN; @@ -2709,12 +2690,15 @@ store_query(int bucket_id, uint64 queryid, const char *query, uint64 query_len) /* Already have query in the shared buffer, there * is no need to add that again. */ - if (hash_find_query_entry(bucket_id, queryid)) - return; + entry = hash_find_query_entry(bucketid, queryid, dbid, userid, ip); + if (entry) + return entry; - if (!hash_create_query_entry(bucket_id, queryid)) - return; + entry = hash_create_query_entry(bucketid, queryid, dbid, userid, ip); + if (!entry) + return NULL; + entry->state = kind; memcpy(&buf_len, buf, sizeof (uint64)); if (buf_len == 0) buf_len += sizeof (uint64); @@ -2724,10 +2708,10 @@ store_query(int bucket_id, uint64 queryid, const char *query, uint64 query_len) switch(PGSM_OVERFLOW_TARGET) { case OVERFLOW_TARGET_NONE: - return; + return NULL; case OVERFLOW_TARGET_DISK: { - dump_queries_buffer(bucket_id, buf, MAX_QUERY_BUFFER_BUCKET); + dump_queries_buffer(bucketid, buf, MAX_QUERY_BUFFER_BUCKET); buf_len = sizeof (uint64); } break; @@ -2745,6 +2729,7 @@ store_query(int bucket_id, uint64 queryid, const char *query, uint64 query_len) memcpy(&buf[buf_len], query, query_len); /* query */ buf_len += query_len; memcpy(buf, &buf_len, sizeof (uint64)); + return entry; } static uint64 @@ -2915,7 +2900,7 @@ read_query_buffer(int bucket_id, uint64 queryid, char *query_txt) break; } off += buf_len; - if (read_query(buf, queryid, query_txt)) + if (read_query(buf, bucket_id, queryid, query_txt)) break; } if (fd > 0) diff --git a/pg_stat_monitor.h b/pg_stat_monitor.h index 9f7f12b..1760dae 100644 --- a/pg_stat_monitor.h +++ b/pg_stat_monitor.h @@ -127,8 +127,11 @@ typedef enum pgssStoreKind * 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_PARSE = 0, + PGSS_PLAN, PGSS_EXEC, + PGSS_ERROR, + PGSS_FINISHED, PGSS_NUMKIND /* Must be last value of this enum */ } pgssStoreKind; @@ -160,37 +163,26 @@ typedef struct CallTime typedef struct pgssQueryHashKey { - uint64 queryid; /* query identifier */ uint64 bucket_id; /* bucket number */ + uint64 queryid; /* query identifier */ + uint64 userid; /* user OID */ + uint64 dbid; /* database OID */ + uint64 ip; /* client ip address */ } pgssQueryHashKey; typedef struct pgssQueryEntry { pgssQueryHashKey key; /* hash key of entry - MUST BE FIRST */ uint64 pos; /* bucket number */ + uint64 state; /* query state */ } pgssQueryEntry; typedef struct PlanInfo { uint64 planid; /* plan identifier */ - uint64 plans; /* how many times plan */ - CallTime time; char plan_text[PLAN_TEXT_LEN]; /* plan text */ } PlanInfo; -/* shared nenory storage for the query */ -typedef struct pgssPlanHashKey -{ - uint64 query_hash; /* query reference identifier */ -} pgssPlanHashKey; - -typedef struct pgssPlanEntry -{ - pgssPlanHashKey key; /* hash key of entry - MUST BE FIRST */ - PlanInfo plan_info; /* planning information */ - slock_t mutex; /* protects the counters only */ -} pgssPlanEntry; - typedef struct pgssHashKey { uint64 bucket_id; /* bucket number */ @@ -198,6 +190,7 @@ typedef struct pgssHashKey uint64 userid; /* user OID */ uint64 dbid; /* database OID */ uint64 ip; /* client ip address */ + uint64 planid; /* plan identifier */ } pgssHashKey; typedef struct QueryInfo @@ -263,14 +256,18 @@ typedef struct Counters uint64 bucket_id; /* bucket id */ Calls calls; QueryInfo info; - PlanInfo plan_info; CallTime time; + + Calls plancalls; + CallTime plantime; + PlanInfo planinfo; + Blocks blocks; SysInfo sysinfo; ErrorInfo error; - Wal_Usage walusage; - int plans; + Wal_Usage walusage; int resp_calls[MAX_RESPONSE_BUCKET]; /* execution time's in msec */ + uint64 state; /* query state */ } Counters; /* Some global structure to get the cpu usage, really don't like the idea of global variable */ @@ -362,18 +359,18 @@ void pgss_shmem_shutdown(int code, Datum arg); int pgsm_get_bucket_size(void); pgssSharedState* pgsm_get_ss(void); HTAB *pgsm_get_plan_hash(void); +HTAB *pgsm_get_query_hash(void); HTAB *pgsm_get_hash(void); HTAB *pgsm_get_plan_hash(void); HTAB* pgsm_get_query_hash(void); void hash_entry_reset(void); void hash_query_entry_dealloc(int bucket); void hash_entry_dealloc(int bucket); -pgssPlanEntry *hash_plan_entry_alloc(pgssSharedState *pgss, pgssPlanHashKey *key); pgssEntry* hash_entry_alloc(pgssSharedState *pgss, pgssHashKey *key, int encoding); Size hash_memsize(void); -bool hash_find_query_entry(uint64 bucket_id, uint64 queryid); -bool hash_create_query_entry(uint64 bucket_id, uint64 queryid); +pgssQueryEntry* hash_find_query_entry(uint64 bucket_id, uint64 queryid, uint64 dbid, uint64 userid, uint64 ip); +pgssQueryEntry* hash_create_query_entry(uint64 bucket_id, uint64 queryid, uint64 dbid, uint64 userid, uint64 ip); void pgss_startup(void); void set_qbuf(int i, unsigned char *); diff --git a/regression/expected/application_name.out b/regression/expected/application_name.out index 725af98..46eeec5 100644 --- a/regression/expected/application_name.out +++ b/regression/expected/application_name.out @@ -12,12 +12,11 @@ SELECT 1 AS num; (1 row) SELECT query,application_name FROM pg_stat_monitor ORDER BY query COLLATE "C"; - query | application_name ---------------------------------------------------------------------------------+----------------------------- - SELECT $1 AS num | pg_regress/application_name - SELECT pg_stat_monitor_reset(); | pg_regress/application_name - SELECT query,application_name FROM pg_stat_monitor ORDER BY query COLLATE "C"; | -(3 rows) + query | application_name +---------------------------------+----------------------------- + SELECT $1 AS num | pg_regress/application_name + SELECT pg_stat_monitor_reset(); | pg_regress/application_name +(2 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset diff --git a/regression/expected/basic.out b/regression/expected/basic.out index eb1e8ef..c321b4c 100644 --- a/regression/expected/basic.out +++ b/regression/expected/basic.out @@ -5,12 +5,6 @@ SELECT pg_stat_monitor_reset(); (1 row) -select pg_sleep(.5); - pg_sleep ----------- - -(1 row) - SELECT 1 AS num; num ----- @@ -18,13 +12,11 @@ SELECT 1 AS num; (1 row) SELECT query FROM pg_stat_monitor ORDER BY query COLLATE "C"; - query ---------------------------------------------------------------- + query +--------------------------------- SELECT $1 AS num SELECT pg_stat_monitor_reset(); - SELECT query FROM pg_stat_monitor ORDER BY query COLLATE "C"; - select pg_sleep($1) -(4 rows) +(2 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset diff --git a/regression/expected/cmd_type.out b/regression/expected/cmd_type.out index 49716fe..625eb39 100644 --- a/regression/expected/cmd_type.out +++ b/regression/expected/cmd_type.out @@ -6,6 +6,7 @@ SELECT pg_stat_monitor_reset(); (1 row) CREATE TABLE t1 (a INTEGER); +CREATE TABLE t2 (b INTEGER); INSERT INTO t1 VALUES(1); SELECT a FROM t1; a @@ -15,26 +16,27 @@ SELECT a FROM t1; UPDATE t1 SET a = 2; DELETE FROM t1; -SELECT a FROM t1 FOR UPDATE; - a +SELECT b FROM t2 FOR UPDATE; + b --- (0 rows) TRUNCATE t1; DROP TABLE t1; SELECT query, cmd_type, cmd_type_text FROM pg_stat_monitor ORDER BY query COLLATE "C"; - query | cmd_type | cmd_type_text ------------------------------------------------------------------------------------------+----------+--------------- - CREATE TABLE t1 (a INTEGER); | 0 | - DELETE FROM t1; | 4 | DELETE - DROP TABLE t1; | 0 | - INSERT INTO t1 VALUES($1) | 3 | INSERT - SELECT a FROM t1; | 1 | SELECT - SELECT pg_stat_monitor_reset(); | 1 | SELECT - SELECT query, cmd_type, cmd_type_text FROM pg_stat_monitor ORDER BY query COLLATE "C"; | 0 | - TRUNCATE t1; | 0 | - UPDATE t1 SET a = $1 | 2 | UPDATE -(9 rows) + query | cmd_type | cmd_type_text +---------------------------------+----------+--------------- + CREATE TABLE t1 (a INTEGER); | 0 | + CREATE TABLE t2 (b INTEGER); | 0 | + DELETE FROM t1; | 4 | DELETE + DROP TABLE t1; | 0 | + INSERT INTO t1 VALUES($1) | 3 | INSERT + SELECT a FROM t1; | 1 | SELECT + SELECT b FROM t2 FOR UPDATE; | 1 | SELECT + SELECT pg_stat_monitor_reset(); | 1 | SELECT + TRUNCATE t1; | 0 | + UPDATE t1 SET a = $1 | 2 | UPDATE +(10 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset diff --git a/regression/expected/counters.out b/regression/expected/counters.out index d365ba8..9c11c4f 100644 --- a/regression/expected/counters.out +++ b/regression/expected/counters.out @@ -1,4 +1,10 @@ CREATE EXTENSION pg_stat_monitor; +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + CREATE TABLE t1 (a INTEGER); CREATE TABLE t2 (b INTEGER); CREATE TABLE t3 (c INTEGER); @@ -34,8 +40,7 @@ SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C"; ----------------------------------------------------------------------------------+------- SELECT a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; | 4 SELECT pg_stat_monitor_reset(); | 1 - SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C"; | 1 -(3 rows) +(2 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset @@ -62,12 +67,8 @@ end $$; SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C"; query | calls ---------------------------------------------------------------------------------------------------+------- - SELECT $1 AS num | 1 SELECT a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; | 1000 - SELECT n + $3 | 1 - SELECT n = $3 | 1 SELECT pg_stat_monitor_reset(); | 1 - SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C"; | 1 do $$ +| 1 declare +| n integer:= 1; +| @@ -78,7 +79,7 @@ SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C"; n := n + 1; +| end loop; +| end $$; | -(7 rows) +(3 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset diff --git a/regression/expected/database.out b/regression/expected/database.out index 378cbea..4648e38 100644 --- a/regression/expected/database.out +++ b/regression/expected/database.out @@ -28,13 +28,12 @@ SELECT * FROM t3,t4 WHERE t3.c = t4.d; \c contrib_regression SELECT datname, query FROM pg_stat_monitor ORDER BY query COLLATE "C"; - datname | query ---------------------+------------------------------------------------------------------------ + datname | query +--------------------+---------------------------------------- db1 | SELECT * FROM t1,t2 WHERE t1.a = t2.b; db2 | SELECT * FROM t3,t4 WHERE t3.c = t4.d; - contrib_regression | SELECT datname, query FROM pg_stat_monitor ORDER BY query COLLATE "C"; contrib_regression | SELECT pg_stat_monitor_reset(); -(4 rows) +(3 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset diff --git a/regression/expected/error.out b/regression/expected/error.out index 24228e1..e0ead7b 100644 --- a/regression/expected/error.out +++ b/regression/expected/error.out @@ -21,19 +21,17 @@ RAISE WARNING 'warning message'; END $$; WARNING: warning message SELECT query, elevel,sqlcode, message FROM pg_stat_monitor ORDER BY query COLLATE "C"; - query | elevel | sqlcode | message -----------------------------------------------------------------------------------------+--------+---------+----------------------------------- - ELECET * FROM unknown; | 20 | 42601 | syntax error at or near "ELECET" - SELECT $1/$2 | 0 | | - SELECT * FROM unknown; | 20 | 42P01 | relation "unknown" does not exist - SELECT 1/0; | 20 | 22012 | division by zero - SELECT pg_stat_monitor_reset(); | 0 | | - SELECT query, elevel,sqlcode, message FROM pg_stat_monitor ORDER BY query COLLATE "C"; | 0 | | - do $$ +| 19 | 01000 | warning message - BEGIN +| | | - RAISE WARNING 'warning message'; +| | | - END $$; | | | -(7 rows) + query | elevel | sqlcode | message +----------------------------------+--------+---------+----------------------------------- + ELECET * FROM unknown; | 20 | 42601 | syntax error at or near "ELECET" + SELECT * FROM unknown; | 20 | 42P01 | relation "unknown" does not exist + SELECT 1/0; | 20 | 22012 | division by zero + SELECT pg_stat_monitor_reset(); | 0 | | + do $$ +| 19 | 01000 | warning message + BEGIN +| | | + RAISE WARNING 'warning message';+| | | + END $$; | | | +(5 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset diff --git a/regression/expected/relations.out b/regression/expected/relations.out index ce760d1..1ef8c88 100644 --- a/regression/expected/relations.out +++ b/regression/expected/relations.out @@ -37,15 +37,14 @@ SELECT * FROM foo1, foo2, foo3, foo4; (0 rows) SELECT query, relations from pg_stat_monitor ORDER BY query; - query | relations ---------------------------------------------------------------+--------------------------------------------------- - SELECT * FROM foo1, foo2, foo3, foo4; | {public.foo1,public.foo2,public.foo3,public.foo4} - SELECT * FROM foo1, foo2, foo3; | {public.foo1,public.foo2,public.foo3} - SELECT * FROM foo1, foo2; | {public.foo1,public.foo2} - SELECT * FROM foo1; | {public.foo1} - SELECT pg_stat_monitor_reset(); | - SELECT query, relations from pg_stat_monitor ORDER BY query; | -(6 rows) + query | relations +---------------------------------------+--------------------------------------------------- + SELECT * FROM foo1, foo2, foo3, foo4; | {public.foo1,public.foo2,public.foo3,public.foo4} + SELECT * FROM foo1, foo2, foo3; | {public.foo1,public.foo2,public.foo3} + SELECT * FROM foo1, foo2; | {public.foo1,public.foo2} + SELECT * FROM foo1; | {public.foo1} + SELECT pg_stat_monitor_reset(); | +(5 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset @@ -89,15 +88,14 @@ SELECT * FROM sch1.foo1, sch2.foo2, sch3.foo3, sch4.foo4; (0 rows) SELECT query, relations from pg_stat_monitor ORDER BY query; - query | relations ---------------------------------------------------------------+------------------------------------------- - SELECT * FROM sch1.foo1, sch2.foo2, sch3.foo3, sch4.foo4; | {sch1.foo1,sch2.foo2,sch3.foo3,sch4.foo4} - SELECT * FROM sch1.foo1, sch2.foo2, sch3.foo3; | {sch1.foo1,sch2.foo2,sch3.foo3} - SELECT * FROM sch1.foo1, sch2.foo2; | {sch1.foo1,sch2.foo2} - SELECT * FROM sch1.foo1; | {sch1.foo1} - SELECT pg_stat_monitor_reset(); | - SELECT query, relations from pg_stat_monitor ORDER BY query; | -(6 rows) + query | relations +-----------------------------------------------------------+------------------------------------------- + SELECT * FROM sch1.foo1, sch2.foo2, sch3.foo3, sch4.foo4; | {sch1.foo1,sch2.foo2,sch3.foo3,sch4.foo4} + SELECT * FROM sch1.foo1, sch2.foo2, sch3.foo3; | {sch1.foo1,sch2.foo2,sch3.foo3} + SELECT * FROM sch1.foo1, sch2.foo2; | {sch1.foo1,sch2.foo2} + SELECT * FROM sch1.foo1; | {sch1.foo1} + SELECT pg_stat_monitor_reset(); | +(5 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset @@ -122,13 +120,12 @@ SELECT * FROM sch1.foo1, sch2.foo2, foo1, foo2; (0 rows) SELECT query, relations from pg_stat_monitor ORDER BY query; - query | relations ---------------------------------------------------------------+----------------------------------------------- - SELECT * FROM sch1.foo1, foo1; | {sch1.foo1,public.foo1} - SELECT * FROM sch1.foo1, sch2.foo2, foo1, foo2; | {sch1.foo1,sch2.foo2,public.foo1,public.foo2} - SELECT pg_stat_monitor_reset(); | - SELECT query, relations from pg_stat_monitor ORDER BY query; | -(4 rows) + query | relations +-------------------------------------------------+----------------------------------------------- + SELECT * FROM sch1.foo1, foo1; | {sch1.foo1,public.foo1} + SELECT * FROM sch1.foo1, sch2.foo2, foo1, foo2; | {sch1.foo1,sch2.foo2,public.foo1,public.foo2} + SELECT pg_stat_monitor_reset(); | +(3 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset @@ -168,15 +165,14 @@ SELECT * FROM v1,v2,v3,v4; (0 rows) SELECT query, relations from pg_stat_monitor ORDER BY query; - query | relations ---------------------------------------------------------------+----------------------------------------------------------------------------------------------- - SELECT * FROM v1,v2,v3,v4; | {public.v1*,public.foo1,public.v2*,public.foo2,public.v3*,public.foo3,public.v4*,public.foo4} - SELECT * FROM v1,v2,v3; | {public.v1*,public.foo1,public.v2*,public.foo2,public.v3*,public.foo3} - SELECT * FROM v1,v2; | {public.v1*,public.foo1,public.v2*,public.foo2} - SELECT * FROM v1; | {public.v1*,public.foo1} - SELECT pg_stat_monitor_reset(); | - SELECT query, relations from pg_stat_monitor ORDER BY query; | -(6 rows) + query | relations +---------------------------------+----------------------------------------------------------------------------------------------- + SELECT * FROM v1,v2,v3,v4; | {public.v1*,public.foo1,public.v2*,public.foo2,public.v3*,public.foo3,public.v4*,public.foo4} + SELECT * FROM v1,v2,v3; | {public.v1*,public.foo1,public.v2*,public.foo2,public.v3*,public.foo3} + SELECT * FROM v1,v2; | {public.v1*,public.foo1,public.v2*,public.foo2} + SELECT * FROM v1; | {public.v1*,public.foo1} + SELECT pg_stat_monitor_reset(); | +(5 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset diff --git a/regression/expected/rows.out b/regression/expected/rows.out index ddd1ea5..401acf3 100644 --- a/regression/expected/rows.out +++ b/regression/expected/rows.out @@ -1,6 +1,7 @@ CREATE EXTENSION pg_stat_monitor; CREATE TABLE t1(a int); CREATE TABLE t2(b int); +ERROR: relation "t2" already exists INSERT INTO t1 VALUES(generate_series(1,1000)); INSERT INTO t2 VALUES(generate_series(1,5000)); SELECT pg_stat_monitor_reset(); @@ -8540,15 +8541,14 @@ SELECt * FROM t2 WHERE b % 2 = 0; (2500 rows) SELECT query, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; - query | rows ----------------------------------------------------------------------+------ - SELECT * FROM t1 LIMIT $1 | 10 - SELECT * FROM t1; | 1000 - SELECT * FROM t2; | 5000 - SELECT pg_stat_monitor_reset(); | 1 - SELECT query, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; | 0 - SELECt * FROM t2 WHERE b % $1 = $2 | 2500 -(6 rows) + query | rows +-------------------------------------+------ + SELECT * FROM t1 LIMIT $1 | 10 + SELECT * FROM t1; | 1000 + SELECT b FROM t2 FOR UPDATE; | 5000 + SELECT pg_stat_monitor_reset(); | 1 + SELECt * FROM t2 WHERE b % $1 = $2 | 2500 +(5 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset diff --git a/regression/expected/top_query.out b/regression/expected/top_query.out index 5ef50ab..07e9eee 100644 --- a/regression/expected/top_query.out +++ b/regression/expected/top_query.out @@ -23,25 +23,23 @@ SELECT add2(1,2); (1 row) SELECT query, top_query FROM pg_stat_monitor ORDER BY query COLLATE "C"; - query | top_query ---------------------------------------------------------------------------+-------------------- - CREATE OR REPLACE FUNCTION add(int, int) RETURNS INTEGER AS +| - $$ +| - BEGIN +| - return (select $1 + $2); +| - END; $$ language plpgsql; | - CREATE OR REPLACE function add2(int, int) RETURNS int as +| - $$ +| - BEGIN +| - return add($1,$2); +| - END; +| - $$ language plpgsql; | - SELECT (select $1 + $2) | SELECT add2($1,$2) - SELECT add($1,$2) | - SELECT add2($1,$2) | - SELECT pg_stat_monitor_reset(); | - SELECT query, top_query FROM pg_stat_monitor ORDER BY query COLLATE "C"; | -(7 rows) + query | top_query +-------------------------------------------------------------+-------------------- + CREATE OR REPLACE FUNCTION add(int, int) RETURNS INTEGER AS+| + $$ +| + BEGIN +| + return (select $1 + $2); +| + END; $$ language plpgsql; | + CREATE OR REPLACE function add2(int, int) RETURNS int as +| + $$ +| + BEGIN +| + return add($1,$2); +| + END; +| + $$ language plpgsql; | + SELECT (select $1 + $2) | SELECT add2($1,$2) + SELECT add2($1,$2) | + SELECT pg_stat_monitor_reset(); | +(5 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset diff --git a/regression/expected/user.out b/regression/expected/user.out index 544ad76..dd1a602 100644 --- a/regression/expected/user.out +++ b/regression/expected/user.out @@ -27,18 +27,17 @@ SELECT * FROM t2; SET ROLE su; SELECT userid, query FROM pg_stat_monitor ORDER BY query COLLATE "C"; - userid | query ---------+----------------------------------------------------------------------- + userid | query +--------+--------------------------------- u1 | CREATE TABLE t1 (a int); u2 | CREATE TABLE t2 (a int); u1 | SELECT * FROM t1; u2 | SELECT * FROM t2; su | SELECT pg_stat_monitor_reset(); - su | SELECT userid, query FROM pg_stat_monitor ORDER BY query COLLATE "C"; su | SET ROLE su; u1 | SET ROLE u1; u2 | SET ROLE u2; -(9 rows) +(8 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset diff --git a/regression/sql/basic.sql b/regression/sql/basic.sql index 9dce16f..4cc3bb4 100644 --- a/regression/sql/basic.sql +++ b/regression/sql/basic.sql @@ -1,6 +1,5 @@ CREATE EXTENSION pg_stat_monitor; SELECT pg_stat_monitor_reset(); -select pg_sleep(.5); SELECT 1 AS num; SELECT query FROM pg_stat_monitor ORDER BY query COLLATE "C"; SELECT pg_stat_monitor_reset(); diff --git a/regression/sql/cmd_type.sql b/regression/sql/cmd_type.sql index 68892bb..5f1fa1b 100644 --- a/regression/sql/cmd_type.sql +++ b/regression/sql/cmd_type.sql @@ -2,11 +2,12 @@ CREATE EXTENSION pg_stat_monitor; SELECT pg_stat_monitor_reset(); CREATE TABLE t1 (a INTEGER); +CREATE TABLE t2 (b INTEGER); INSERT INTO t1 VALUES(1); SELECT a FROM t1; UPDATE t1 SET a = 2; DELETE FROM t1; -SELECT a FROM t1 FOR UPDATE; +SELECT b FROM t2 FOR UPDATE; TRUNCATE t1; DROP TABLE t1; SELECT query, cmd_type, cmd_type_text FROM pg_stat_monitor ORDER BY query COLLATE "C"; diff --git a/regression/sql/counters.sql b/regression/sql/counters.sql index f03a3b3..8d5c461 100644 --- a/regression/sql/counters.sql +++ b/regression/sql/counters.sql @@ -1,4 +1,5 @@ CREATE EXTENSION pg_stat_monitor; +SELECT pg_stat_monitor_reset(); CREATE TABLE t1 (a INTEGER); CREATE TABLE t2 (b INTEGER);