diff --git a/guc.c b/guc.c index 405490a..7d76701 100644 --- a/guc.c +++ b/guc.c @@ -22,7 +22,7 @@ void init_guc(void) { int i = 0; - conf[i++] = (GucVariable) { + conf[i++] = (GucVariable) { .guc_name = "pg_stat_monitor.pgsm_max", .guc_desc = "Sets the maximum number of statements tracked by pg_stat_monitor.", .guc_default = 5000, @@ -31,15 +31,15 @@ init_guc(void) .guc_restart = true }; - conf[i++] = (GucVariable) { + conf[i++] = (GucVariable) { .guc_name = "pg_stat_monitor.pgsm_query_max_len", .guc_desc = "Sets the maximum length of query.", - .guc_default = 1024, + .guc_default = 1024, .guc_min = 1024, .guc_max = INT_MAX, .guc_restart = true }; - conf[i++] = (GucVariable) { + conf[i++] = (GucVariable) { .guc_name = "pg_stat_monitor.pgsm_enable", .guc_desc = "Enable/Disable statistics collector.", .guc_default = 1, @@ -47,7 +47,7 @@ init_guc(void) .guc_max = 0, .guc_restart = true }; - conf[i++] = (GucVariable) { + conf[i++] = (GucVariable) { .guc_name = "pg_stat_monitor.pgsm_track_utility", .guc_desc = "Selects whether utility commands are tracked.", .guc_default = 0, @@ -56,7 +56,7 @@ init_guc(void) .guc_restart = false }; - conf[i++] = (GucVariable) { + conf[i++] = (GucVariable) { .guc_name = "pg_stat_monitor.pgsm_normalized_query", .guc_desc = "Selects whether save query in normalized format.", .guc_default = 1, @@ -64,7 +64,7 @@ init_guc(void) .guc_max = 0, .guc_restart = false }; - conf[i++] = (GucVariable) { + conf[i++] = (GucVariable) { .guc_name = "pg_stat_monitor.pgsm_max_buckets", .guc_desc = "Sets the maximum number of buckets.", .guc_default = 10, @@ -72,7 +72,7 @@ init_guc(void) .guc_max = 10, .guc_restart = true }; - conf[i++] = (GucVariable) { + conf[i++] = (GucVariable) { .guc_name = "pg_stat_monitor.pgsm_bucket_time", .guc_desc = "Sets the time in seconds per bucket.", .guc_default = 60, @@ -80,16 +80,8 @@ init_guc(void) .guc_max = INT_MAX, .guc_restart = true }; - conf[i++] = (GucVariable) { - .guc_name = "pg_stat_monitor.pgsm_object_cache", - .guc_desc = "Sets the maximum number of object cache", - .guc_default = 50, - .guc_min = 50, - .guc_max = INT_MAX, - .guc_restart = true - }; - - conf[i++] = (GucVariable) { + + conf[i++] = (GucVariable) { .guc_name = "pg_stat_monitor.pgsm_respose_time_lower_bound", .guc_desc = "Sets the time in millisecond.", .guc_default = 1, @@ -97,8 +89,8 @@ init_guc(void) .guc_max = INT_MAX, .guc_restart = true }; - - conf[i++] = (GucVariable) { + + conf[i++] = (GucVariable) { .guc_name = "pg_stat_monitor.pgsm_respose_time_step", .guc_desc = "Sets the response time steps in millisecond.", .guc_default = 1, @@ -107,7 +99,7 @@ init_guc(void) .guc_restart = true }; - conf[i++] = (GucVariable) { + conf[i++] = (GucVariable) { .guc_name = "pg_stat_monitor.pgsm_query_shared_buffer", .guc_desc = "Sets the query shared_buffer size.", .guc_default = 500000, @@ -116,7 +108,7 @@ init_guc(void) .guc_restart = true }; #if PG_VERSION_NUM >= 130000 - conf[i++] = (GucVariable) { + conf[i++] = (GucVariable) { .guc_name = "pg_stat_monitor.pgsm_track_planning", .guc_desc = "Selects whether planning statistics are tracked.", .guc_default = 1, @@ -124,8 +116,8 @@ init_guc(void) .guc_max = 0, .guc_restart = false }; -#endif - +#endif + DefineCustomIntVariable("pg_stat_monitor.pgsm_max", "Sets the maximum number of statements tracked by pg_stat_monitor.", NULL, @@ -212,19 +204,6 @@ init_guc(void) NULL); - DefineCustomIntVariable("pg_stat_monitor.pgsm_object_cache", - "Sets the maximum number of object cache", - NULL, - &PGSM_OBJECT_CACHE, - 50, - 50, - INT_MAX, - PGC_POSTMASTER, - 0, - NULL, - NULL, - NULL); - DefineCustomIntVariable("pg_stat_monitor.pgsm_respose_time_lower_bound", "Sets the time in millisecond.", NULL, diff --git a/hash_query.c b/hash_query.c index 78bb94c..02b4896 100644 --- a/hash_query.c +++ b/hash_query.c @@ -16,7 +16,6 @@ static pgssSharedState *pgss; static HTAB *pgss_hash; -static HTAB *pgss_object_hash; static HTAB* hash_init(const char *hash_name, int key_size, int entry_size, int hash_size); @@ -40,7 +39,6 @@ pgss_startup(void) pgss = NULL; pgss_hash = NULL; - pgss_object_hash = NULL; /* * Create or attach to the shared memory state, including hash table @@ -66,7 +64,6 @@ pgss_startup(void) } pgss_hash = hash_init("pg_stat_monitor: Queries hashtable", sizeof(pgssHashKey), sizeof(pgssEntry),PGSM_MAX); - pgss_object_hash = hash_init("pg_stat_monitor: Object hashtable", sizeof(pgssObjectHashKey), sizeof(pgssObjectEntry), PGSM_OBJECT_CACHE); LWLockRelease(AddinShmemInitLock); @@ -197,44 +194,6 @@ hash_entry_reset() LWLockRelease(pgss->lock); } -void -hash_alloc_object_entry(uint64 queryid, char *objects) -{ - pgssObjectEntry *entry = NULL; - bool found; - pgssObjectHashKey key; - - LWLockAcquire(pgss->lock, LW_EXCLUSIVE); - key.queryid = queryid; - entry = (pgssObjectEntry *) hash_search(pgss_object_hash, &key, HASH_ENTER, &found); - if (!found) - { - SpinLockAcquire(&entry->mutex); - snprintf(entry->tables_name, MAX_REL_LEN, "%s", objects); - SpinLockRelease(&entry->mutex); - } - LWLockRelease(pgss->lock); -} - -/* De-alocate memory */ -void -hash_dealloc_object_entry(uint64 queryid, char *objects) -{ - pgssObjectHashKey key; - pgssObjectEntry *entry; - - key.queryid = queryid; - - LWLockAcquire(pgss->lock, LW_EXCLUSIVE); - entry = (pgssObjectEntry *) hash_search(pgss_object_hash, &key, HASH_FIND, NULL); - if (entry != NULL) - { - snprintf(objects, MAX_REL_LEN, "%s", entry->tables_name); - hash_search(pgss_object_hash, &entry->key, HASH_REMOVE, NULL); - } - LWLockRelease(pgss->lock); -} - pgssEntry* hash_create_query_entry(unsigned int queryid, unsigned int userid, @@ -270,7 +229,6 @@ bool IsHashInitialize(void) { return (pgss != NULL && - pgss_hash != NULL && - pgss_object_hash !=NULL); + pgss_hash != NULL); } diff --git a/pg_stat_monitor--1.0.sql b/pg_stat_monitor--1.0.sql index 5c94dca..ff92374 100644 --- a/pg_stat_monitor--1.0.sql +++ b/pg_stat_monitor--1.0.sql @@ -22,6 +22,7 @@ CREATE FUNCTION pg_stat_monitor(IN showtext boolean, OUT queryid text, OUT query text, + OUT relations text, OUT cmd_type text, OUT elevel int, OUT sqlcode int, @@ -58,8 +59,7 @@ CREATE FUNCTION pg_stat_monitor(IN showtext boolean, OUT blk_write_time float8, OUT resp_calls text, OUT cpu_user_time float8, - OUT cpu_sys_time float8, - OUT tables_names text + OUT cpu_sys_time float8 ) RETURNS SETOF record AS 'MODULE_PATHNAME', 'pg_stat_monitor' @@ -97,6 +97,7 @@ CREATE VIEW pg_stat_monitor AS SELECT '0.0.0.0'::inet + client_ip AS client_ip, queryid, query, + (string_to_array(relations, ',')) relations, (string_to_array(cmd_type, ',')) cmd_type, elevel, sqlcode, @@ -128,8 +129,7 @@ CREATE VIEW pg_stat_monitor AS SELECT blk_write_time, (string_to_array(resp_calls, ',')) resp_calls, cpu_user_time, - cpu_sys_time, - (string_to_array(tables_names, ',')) tables_names + cpu_sys_time FROM pg_stat_monitor(TRUE); CREATE FUNCTION decode_error_level(elevel int) diff --git a/pg_stat_monitor.c b/pg_stat_monitor.c index 34c3c8c..69a7ae6 100644 --- a/pg_stat_monitor.c +++ b/pg_stat_monitor.c @@ -240,7 +240,6 @@ static void pgss_post_parse_analyze(ParseState *pstate, Query *query) { pgssJumbleState jstate; - char tables_name[MAX_REL_LEN] = {0}; if (prev_post_parse_analyze_hook) prev_post_parse_analyze_hook(pstate, query); @@ -264,40 +263,6 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query) } query->queryId = get_query_id(&jstate, query); - if (query->rtable) - { - ListCell *lc; - bool first = true; - foreach(lc, query->rtable) - { - RangeTblEntry *rte = lfirst_node(RangeTblEntry, lc); - if (rte->rtekind == RTE_RELATION) - { - char *relname = get_rel_name(rte->relid); - char *relspacename = get_namespace_name(get_rel_namespace(rte->relid)); - if (relname) - { - if (first) - { - if (relspacename) - snprintf(tables_name, MAX_REL_LEN, "%s.%s", relspacename, relname); - else - snprintf(tables_name, MAX_REL_LEN, "%s", relname); - first = false; - } - else - { - if (relspacename) - snprintf(tables_name, MAX_REL_LEN, "%s,%s.%s", tables_name, relspacename, relname); - else - snprintf(tables_name, MAX_REL_LEN, "%s,%s", tables_name, relname); - } - } - } - } - hash_alloc_object_entry(query->queryId, tables_name); - } - /* * If we are unlucky enough to get a hash of zero, use 1 instead, to * prevent confusion with the utility-statement case. @@ -463,15 +428,29 @@ pgss_ExecutorCheckPerms(List *rt, bool abort) { ListCell *lr; pgssSharedState *pgss = pgsm_get_ss(); + int i = 0; + int j = 0; LWLockAcquire(pgss->lock, LW_EXCLUSIVE); memset(pgss->cmdTag, 0x0, sizeof(pgss->cmdTag)); foreach(lr, rt) { + bool found = false; RangeTblEntry *rte = lfirst(lr); if (rte->rtekind != RTE_RELATION) continue; + + if (i < REL_LST) + { + for(j = 0; j < i; j++) + { + if (pgss->relations[j] == rte->relid) + found = true; + } + if (!found) + pgss->relations[i++] = rte->relid; + } if (rte->requiredPerms & ACL_INSERT) snprintf(pgss->cmdTag[0],CMD_LEN,"%s", "INSERT"); if (rte->requiredPerms & ACL_UPDATE) snprintf(pgss->cmdTag[1],CMD_LEN,"%s", "UPDATE"); if (rte->requiredPerms & ACL_DELETE) snprintf(pgss->cmdTag[2],CMD_LEN,"%s", "DELETE"); @@ -748,8 +727,6 @@ static void pgss_store(uint64 queryId, bool reset = false; bool found = false; int i,j; - char tables_name[MAX_REL_LEN] = {0}; - int len; pgssSharedState *pgss = pgsm_get_ss(); HTAB *pgss_hash = pgsm_get_hash(); int message_len = message ? strlen(message) : 0; @@ -800,9 +777,6 @@ static void pgss_store(uint64 queryId, if (queryId == UINT64CONST(0)) queryId = pgss_hash_string(query, query_len); - hash_dealloc_object_entry(queryId, tables_name); - len = strlen(tables_name); - for (i = 0; i < CMD_LST; i++) cmd_len[i] = strlen(pgss->cmdTag[i]); @@ -925,6 +899,15 @@ static void pgss_store(uint64 queryId, e->counters.resp_calls[MAX_RESPONSE_BUCKET - 1]++; } + for (i = 0; i < REL_LST; i++) + if (e->counters.info.relations[i] != 0) + found = true; + + if (!found) + for (i = 0; i < REL_LST; i++) + e->counters.info.relations[i] = pgss->relations[i]; + + found = false; /* This is bit ugly hack to check we already updated the counter or not */ for (i = 0; i < CMD_LST; i++) if (e->counters.info.cmd_type[i][0] != 0) @@ -964,8 +947,6 @@ static void pgss_store(uint64 queryId, e->counters.info.host = pg_get_client_addr(); e->counters.sysinfo.utime = utime; e->counters.sysinfo.stime = stime; - for(i = 0; i < len; i++) - e->counters.info.tables_name[i] = tables_name[i]; SpinLockRelease(&e->mutex); } } @@ -1064,13 +1045,14 @@ 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; - int kind; - Counters tmp; - double stddev; - int64 queryid = entry->key.queryid; + Datum values[PG_STAT_STATEMENTS_COLS]; + bool nulls[PG_STAT_STATEMENTS_COLS]; + int i = 0,j; + int len = 0; + int kind; + Counters tmp; + double stddev; + int64 queryid = entry->key.queryid; memset(values, 0, sizeof(values)); memset(nulls, 0, sizeof(nulls)); @@ -1130,6 +1112,17 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, else nulls[i++] = true; } + + len = 0; + for (j = 0; j < REL_LST; j++) + if (tmp.info.relations[j] != 0) + len++; + + if (len == 0) + nulls[i++] = true; + else + values[i++] = IntArrayGetTextDatum(tmp.info.relations, len); + values[i++] = TextArrayGetTextDatum(tmp.info.cmd_type, CMD_LST); values[i++] = Int64GetDatumFast(tmp.error.elevel); values[i++] = Int64GetDatumFast(tmp.error.sqlcode); @@ -1169,10 +1162,6 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, values[i++] = IntArrayGetTextDatum(tmp.resp_calls, 10); values[i++] = Float8GetDatumFast(tmp.sysinfo.utime); values[i++] = Float8GetDatumFast(tmp.sysinfo.stime); - if (strlen(tmp.info.tables_name) == 0) - nulls[i++] = true; - else - values[i++] = CStringGetTextDatum(tmp.info.tables_name); tuplestore_putvalues(tupstore, tupdesc, values, nulls); } free(query_txt); @@ -2165,7 +2154,7 @@ intarray_get_datum(int32 arr[], int len) first = false; continue; } - snprintf(tmp, 10, ", %d", arr[j]); + snprintf(tmp, 10, ",%d", arr[j]); strcat(str,tmp); } return CStringGetTextDatum(str); diff --git a/pg_stat_monitor.h b/pg_stat_monitor.h index 7735af7..bcdaf10 100644 --- a/pg_stat_monitor.h +++ b/pg_stat_monitor.h @@ -59,9 +59,9 @@ #define MAX_RESPONSE_BUCKET 10 #define MAX_REL_LEN 255 #define MAX_BUCKETS 10 -#define MAX_OBJECT_CACHE 100 #define TEXT_LEN 255 #define ERROR_MESSAGE_LEN 100 +#define REL_LST 10 #define CMD_LST 10 #define CMD_LEN 20 @@ -102,18 +102,6 @@ typedef enum AGG_KEY AGG_KEY_HOST } AGG_KEY; -typedef struct pgssObjectHashKey -{ - uint64 queryid; /* query id */ -} pgssObjectHashKey; - -typedef struct pgssObjectEntry -{ - pgssObjectHashKey key; /* hash key of entry - MUST BE FIRST */ - char tables_name[MAX_REL_LEN]; /* table names involved in the query */ - slock_t mutex; /* protects the counters only */ -} pgssObjectEntry; - #define MAX_QUERY_LEN 1024 /* shared nenory storage for the query */ @@ -133,8 +121,8 @@ typedef struct QueryInfo Oid dbid; /* database OID */ uint host; /* client IP */ int64 type; /* type of query, options are query, info, warning, error, fatal */ - char cmd_type[CMD_LST][CMD_LEN]; /* query command type SELECT/UPDATE/DELETE/INSERT */ - char tables_name[MAX_REL_LEN]; /* table names involved in the query */ + int32 relations[REL_LST]; + char cmd_type[CMD_LST][CMD_LEN]; /* query command type SELECT/UPDATE/DELETE/INSERT */ } QueryInfo; typedef struct ErrorInfo @@ -220,13 +208,14 @@ typedef struct pgssSharedState double cur_median_usage; /* current median usage in hashtable */ slock_t mutex; /* protects following fields only: */ Size extent; /* current extent of query file */ - int n_writers; /* number of active writers to query file */ + int64 n_writers; /* number of active writers to query file */ uint64 current_wbucket; uint64 prev_bucket_usec; uint64 bucket_overflow[MAX_BUCKETS]; uint64 bucket_entry[MAX_BUCKETS]; - int query_buf_size_bucket; - char cmdTag[CMD_LST][20]; + int64 query_buf_size_bucket; + int32 relations[REL_LST]; + char cmdTag[CMD_LST][CMD_LEN]; Timestamp bucket_start_time[MAX_BUCKETS]; /* start time of the bucket */ } pgssSharedState; @@ -285,8 +274,6 @@ void init_guc(void); GucVariable *get_conf(int i); /* hash_create.c */ -void hash_alloc_object_entry(uint64 queryid, char *objects); -void hash_dealloc_object_entry(uint64 queryid, char *objects); bool IsHashInitialize(void); void pgss_shmem_startup(void); void pgss_shmem_shutdown(int code, Datum arg); @@ -313,10 +300,9 @@ void pgss_startup(void); #define PGSM_NORMALIZED_QUERY get_conf(4)->guc_variable #define PGSM_MAX_BUCKETS get_conf(5)->guc_variable #define PGSM_BUCKET_TIME get_conf(6)->guc_variable -#define PGSM_OBJECT_CACHE get_conf(7)->guc_variable -#define PGSM_RESPOSE_TIME_LOWER_BOUND get_conf(8)->guc_variable -#define PGSM_RESPOSE_TIME_STEP get_conf(9)->guc_variable -#define PGSM_QUERY_BUF_SIZE get_conf(10)->guc_variable -#define PGSM_TRACK_PLANNING get_conf(11)->guc_variable +#define PGSM_RESPOSE_TIME_LOWER_BOUND get_conf(7)->guc_variable +#define PGSM_RESPOSE_TIME_STEP get_conf(8)->guc_variable +#define PGSM_QUERY_BUF_SIZE get_conf(9)->guc_variable +#define PGSM_TRACK_PLANNING get_conf(10)->guc_variable #endif