stat-reset-timestamp.diff

text/plain

Filename: stat-reset-timestamp.diff
Type: text/plain
Part: 0
Message: Re: keeping a timestamp of the last stats reset (for a db, table and function)

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
File+
src/backend/catalog/system_views.sql 5 2
src/backend/postmaster/pgstat.c 71 1
src/backend/utils/adt/pgstatfuncs.c 57 0
src/include/catalog/pg_proc.h 6 0
src/include/pgstat.h 7 0
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 346eaaf..0ee59b1 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -310,6 +310,7 @@ CREATE VIEW pg_stat_all_tables AS
             pg_stat_get_last_autovacuum_time(C.oid) as last_autovacuum,
             pg_stat_get_last_analyze_time(C.oid) as last_analyze,
             pg_stat_get_last_autoanalyze_time(C.oid) as last_autoanalyze,
+	    pg_stat_get_last_stat_reset_time(C.oid) as last_stat_reset,
             pg_stat_get_vacuum_count(C.oid) AS vacuum_count,
             pg_stat_get_autovacuum_count(C.oid) AS autovacuum_count,
             pg_stat_get_analyze_count(C.oid) AS analyze_count,
@@ -502,7 +503,8 @@ CREATE VIEW pg_stat_database AS
             pg_stat_get_db_tuples_fetched(D.oid) AS tup_fetched,
             pg_stat_get_db_tuples_inserted(D.oid) AS tup_inserted,
             pg_stat_get_db_tuples_updated(D.oid) AS tup_updated,
-            pg_stat_get_db_tuples_deleted(D.oid) AS tup_deleted
+            pg_stat_get_db_tuples_deleted(D.oid) AS tup_deleted,
+            pg_stat_get_db_last_stat_reset_time(D.oid) AS last_stat_reset
     FROM pg_database D;
 
 CREATE VIEW pg_stat_user_functions AS
@@ -512,7 +514,8 @@ CREATE VIEW pg_stat_user_functions AS
             P.proname AS funcname,
             pg_stat_get_function_calls(P.oid) AS calls,
             pg_stat_get_function_time(P.oid) / 1000 AS total_time,
-            pg_stat_get_function_self_time(P.oid) / 1000 AS self_time
+            pg_stat_get_function_self_time(P.oid) / 1000 AS self_time,
+            pg_stat_get_function_last_stat_reset_time(P.oid) AS last_stat_reset
     FROM pg_proc P LEFT JOIN pg_namespace N ON (N.oid = P.pronamespace)
     WHERE P.prolang != 12  -- fast check to eliminate built-in functions
           AND pg_stat_get_function_calls(P.oid) IS NOT NULL;
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index c3c136a..f20a9ea 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -249,6 +249,8 @@ static void pgstat_sighup_handler(SIGNAL_ARGS);
 static PgStat_StatDBEntry *pgstat_get_db_entry(Oid databaseid, bool create);
 static PgStat_StatTabEntry *pgstat_get_tab_entry(PgStat_StatDBEntry *dbentry,
 					 Oid tableoid, bool create);
+static PgStat_StatFuncEntry *pgstat_get_func_entry(PgStat_StatDBEntry *dbentry,
+					 Oid funcoid, bool create);
 static void pgstat_write_statsfile(bool permanent);
 static HTAB *pgstat_read_statsfile(Oid onlydb, bool permanent);
 static void backend_read_statsfile(void);
@@ -3129,7 +3131,9 @@ pgstat_get_db_entry(Oid databaseid, bool create)
 		result->n_tuples_updated = 0;
 		result->n_tuples_deleted = 0;
 		result->last_autovac_time = 0;
-
+		
+		result->stat_reset_timestamp = GetCurrentTimestamp();
+		
 		memset(&hash_ctl, 0, sizeof(hash_ctl));
 		hash_ctl.keysize = sizeof(Oid);
 		hash_ctl.entrysize = sizeof(PgStat_StatTabEntry);
@@ -3196,11 +3200,48 @@ pgstat_get_tab_entry(PgStat_StatDBEntry *dbentry, Oid tableoid, bool create)
 		result->autovac_vacuum_count = 0;
 		result->analyze_count = 0;
 		result->autovac_analyze_count = 0;
+		
+		/* inherit stat time reset from dbentry */
+		result->stat_reset_timestamp = dbentry->stat_reset_timestamp;
+		
 	}
 
 	return result;
 }
 
+/*
+ * Lookup the hash table entry for the specified function. If no hash
+ * table entry exists, initialize it, if the create parameter is true.
+ * Else, return NULL.
+ */
+static PgStat_StatFuncEntry *
+pgstat_get_func_entry(PgStat_StatDBEntry *dbentry, Oid tableoid, bool create)
+{
+	PgStat_StatFuncEntry *result;
+	bool		found;
+	HASHACTION	action = (create ? HASH_ENTER : HASH_FIND);
+
+	/* Lookup or create the hash table entry for this table */
+	result = (PgStat_StatFuncEntry *) hash_search(dbentry->functions,
+												 &tableoid,
+												 action, &found);
+
+	if (!create && !found)
+		return NULL;
+
+	/* If not found, initialize the new one. */
+	if (!found)
+	{
+		result->f_numcalls = 0;
+		result->f_time = 0;
+		result->f_time_self = 0;
+		
+		/* inherit stat time reset from dbentry */
+		result->stat_reset_timestamp = dbentry->stat_reset_timestamp;
+	}
+
+	return result;
+}
 
 /* ----------
  * pgstat_write_statsfile() -
@@ -3867,6 +3908,8 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len)
 			tabentry->autovac_vacuum_timestamp = 0;
 			tabentry->analyze_timestamp = 0;
 			tabentry->autovac_analyze_timestamp = 0;
+			
+			tabentry->stat_reset_timestamp = dbentry->stat_reset_timestamp;
 		}
 		else
 		{
@@ -4010,6 +4053,8 @@ pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len)
 	dbentry->n_xact_rollback = 0;
 	dbentry->n_blocks_fetched = 0;
 	dbentry->n_blocks_hit = 0;
+	
+	dbentry->stat_reset_timestamp = GetCurrentTimestamp();
 
 	memset(&hash_ctl, 0, sizeof(hash_ctl));
 	hash_ctl.keysize = sizeof(Oid);
@@ -4060,6 +4105,8 @@ static void
 pgstat_recv_resetsinglecounter(PgStat_MsgResetsinglecounter *msg, int len)
 {
 	PgStat_StatDBEntry *dbentry;
+	PgStat_StatTabEntry *tabentry;
+	PgStat_StatFuncEntry *funcentry;
 
 	dbentry = pgstat_get_db_entry(msg->m_databaseid, false);
 
@@ -4069,9 +4116,29 @@ pgstat_recv_resetsinglecounter(PgStat_MsgResetsinglecounter *msg, int len)
 
 	/* Remove object if it exists, ignore it if not */
 	if (msg->m_resettype == RESET_TABLE)
+	{
 		(void) hash_search(dbentry->tables, (void *) &(msg->m_objectid), HASH_REMOVE, NULL);
+
+		/*
+		 * need to create it, so that I can set current timestamp (otherwise it would
+		 * be inherited from the database entry)
+		 */ 
+		tabentry = pgstat_get_tab_entry(dbentry, msg->m_objectid, true);
+		tabentry->stat_reset_timestamp = GetCurrentTimestamp();
+		
+	}
 	else if (msg->m_resettype == RESET_FUNCTION)
+	{
 		(void) hash_search(dbentry->functions, (void *) &(msg->m_objectid), HASH_REMOVE, NULL);
+
+		/*
+		 * need to create it, so that I can set current timestamp (otherwise it would
+		 * be inherited from the database entry)
+		 */ 
+		funcentry = pgstat_get_func_entry(dbentry, msg->m_objectid, true);
+		funcentry->stat_reset_timestamp = GetCurrentTimestamp();
+		
+	}
 }
 
 /* ----------
@@ -4227,6 +4294,9 @@ pgstat_recv_funcstat(PgStat_MsgFuncstat *msg, int len)
 			funcentry->f_numcalls = funcmsg->f_numcalls;
 			funcentry->f_time = funcmsg->f_time;
 			funcentry->f_time_self = funcmsg->f_time_self;
+			
+			funcentry->stat_reset_timestamp = dbentry->stat_reset_timestamp;
+			
 		}
 		else
 		{
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index adab948..2b4665c 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -38,6 +38,7 @@ extern Datum pg_stat_get_last_vacuum_time(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_last_autovacuum_time(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_last_stat_reset_time(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_vacuum_count(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_autovacuum_count(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_analyze_count(PG_FUNCTION_ARGS);
@@ -46,6 +47,7 @@ extern Datum pg_stat_get_autoanalyze_count(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_function_calls(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_function_time(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_function_self_time(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_function_last_stat_reset_time(PG_FUNCTION_ARGS);
 
 extern Datum pg_stat_get_backend_idset(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_activity(PG_FUNCTION_ARGS);
@@ -71,6 +73,7 @@ extern Datum pg_stat_get_db_tuples_fetched(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_db_tuples_inserted(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_db_tuples_updated(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_db_last_stat_reset_time(PG_FUNCTION_ARGS);
 
 extern Datum pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS);
@@ -352,6 +355,24 @@ pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS)
 }
 
 Datum
+pg_stat_get_last_stat_reset_time(PG_FUNCTION_ARGS)
+{
+	Oid			relid = PG_GETARG_OID(0);
+	TimestampTz result;
+	PgStat_StatTabEntry *tabentry;
+
+	if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
+		result = 0;
+	else
+		result = tabentry->stat_reset_timestamp;
+
+	if (result == 0)
+		PG_RETURN_NULL();
+	else
+		PG_RETURN_TIMESTAMPTZ(result);
+}
+
+Datum
 pg_stat_get_vacuum_count(PG_FUNCTION_ARGS)
 {
 	Oid			relid = PG_GETARG_OID(0);
@@ -445,6 +466,24 @@ pg_stat_get_function_self_time(PG_FUNCTION_ARGS)
 }
 
 Datum
+pg_stat_get_function_last_stat_reset_time(PG_FUNCTION_ARGS)
+{
+	Oid			funcid = PG_GETARG_OID(0);
+	TimestampTz result;
+	PgStat_StatFuncEntry *funcentry;
+
+	if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
+		result = 0;
+	else
+		result = funcentry->stat_reset_timestamp;
+
+	if (result == 0)
+		PG_RETURN_NULL();
+	else
+		PG_RETURN_TIMESTAMPTZ(result);
+}
+
+Datum
 pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
 {
 	FuncCallContext *funcctx;
@@ -1130,6 +1169,24 @@ pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS)
 }
 
 Datum
+pg_stat_get_db_last_stat_reset_time(PG_FUNCTION_ARGS)
+{
+	Oid			dbid = PG_GETARG_OID(0);
+	TimestampTz result;
+	PgStat_StatDBEntry *dbentry;
+
+	if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+		result = 0;
+	else
+		result = dbentry->stat_reset_timestamp;
+
+	if (result == 0)
+		PG_RETURN_NULL();
+	else
+		PG_RETURN_TIMESTAMPTZ(result);
+}
+
+Datum
 pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_global()->timed_checkpoints);
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index feae22e..53b21bd 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3055,6 +3055,8 @@ DATA(insert OID = 2783 (  pg_stat_get_last_analyze_time PGNSP PGUID 12 1 0 0 f f
 DESCR("statistics: last manual analyze time for a table");
 DATA(insert OID = 2784 (  pg_stat_get_last_autoanalyze_time PGNSP PGUID 12 1 0 0 f f f t f s 1 0 1184 "26" _null_ _null_ _null_ _null_	pg_stat_get_last_autoanalyze_time _null_ _null_ _null_ ));
 DESCR("statistics: last auto analyze time for a table");
+DATA(insert OID = 3115 (  pg_stat_get_last_stat_reset_time PGNSP PGUID 12 1 0 0 f f f t f s 1 0 1184 "26" _null_ _null_ _null_ _null_	pg_stat_get_last_stat_reset_time _null_ _null_ _null_ ));
+DESCR("statistics: last reset for a table");
 DATA(insert OID = 3054 ( pg_stat_get_vacuum_count PGNSP PGUID 12 1 0 0 f f f t f s 1 0 20 "26" _null_ _null_ _null_ _null_ pg_stat_get_vacuum_count _null_ _null_ _null_ ));
 DESCR("statistics: number of manual vacuums for a table");
 DATA(insert OID = 3055 ( pg_stat_get_autovacuum_count PGNSP PGUID 12 1 0 0 f f f t f s 1 0 20 "26" _null_ _null_ _null_ _null_ pg_stat_get_autovacuum_count _null_ _null_ _null_ ));
@@ -3109,6 +3111,8 @@ DATA(insert OID = 2761 (  pg_stat_get_db_tuples_updated PGNSP PGUID 12 1 0 0 f f
 DESCR("statistics: tuples updated in database");
 DATA(insert OID = 2762 (  pg_stat_get_db_tuples_deleted PGNSP PGUID 12 1 0 0 f f f t f s 1 0 20 "26" _null_ _null_ _null_ _null_ pg_stat_get_db_tuples_deleted _null_ _null_ _null_ ));
 DESCR("statistics: tuples deleted in database");
+DATA(insert OID = 3116 (  pg_stat_get_db_last_stat_reset_time PGNSP PGUID 12 1 0 0 f f f t f s 1 0 1184 "26" _null_ _null_ _null_ _null_	pg_stat_get_db_last_stat_reset_time _null_ _null_ _null_ ));
+DESCR("statistics: last reset for a database");
 DATA(insert OID = 2769 ( pg_stat_get_bgwriter_timed_checkpoints PGNSP PGUID 12 1 0 0 f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_timed_checkpoints _null_ _null_ _null_ ));
 DESCR("statistics: number of timed checkpoints started by the bgwriter");
 DATA(insert OID = 2770 ( pg_stat_get_bgwriter_requested_checkpoints PGNSP PGUID 12 1 0 0 f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_requested_checkpoints _null_ _null_ _null_ ));
@@ -3132,6 +3136,8 @@ DATA(insert OID = 2979 (  pg_stat_get_function_time			PGNSP PGUID 12 1 0 0 f f f
 DESCR("statistics: execution time of function");
 DATA(insert OID = 2980 (  pg_stat_get_function_self_time	PGNSP PGUID 12 1 0 0 f f f t f s 1 0 20 "26" _null_ _null_ _null_ _null_ pg_stat_get_function_self_time _null_ _null_ _null_ ));
 DESCR("statistics: self execution time of function");
+DATA(insert OID = 3117 (  pg_stat_get_function_last_stat_reset_time PGNSP PGUID 12 1 0 0 f f f t f s 1 0 1184 "26" _null_ _null_ _null_ _null_	pg_stat_get_function_last_stat_reset_time _null_ _null_ _null_ ));
+DESCR("statistics: last reset for a function");
 
 DATA(insert OID = 3037 (  pg_stat_get_xact_numscans				PGNSP PGUID 12 1 0 0 f f f t f v 1 0 20 "26" _null_ _null_ _null_ _null_ pg_stat_get_xact_numscans _null_ _null_ _null_ ));
 DESCR("statistics: number of scans done for table/index in current transaction");
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 42bf9c4..b514f4d 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -490,6 +490,7 @@ typedef struct PgStat_StatDBEntry
 	PgStat_Counter n_tuples_updated;
 	PgStat_Counter n_tuples_deleted;
 	TimestampTz last_autovac_time;
+	TimestampTz stat_reset_timestamp;
 
 	/*
 	 * tables and functions must be last in the struct, because we don't write
@@ -533,6 +534,9 @@ typedef struct PgStat_StatTabEntry
 	PgStat_Counter analyze_count;
 	TimestampTz autovac_analyze_timestamp;		/* autovacuum initiated */
 	PgStat_Counter autovac_analyze_count;
+	
+	TimestampTz stat_reset_timestamp;
+	
 } PgStat_StatTabEntry;
 
 
@@ -548,6 +552,9 @@ typedef struct PgStat_StatFuncEntry
 
 	PgStat_Counter f_time;		/* times in microseconds */
 	PgStat_Counter f_time_self;
+	
+	TimestampTz stat_reset_timestamp;
+	
 } PgStat_StatFuncEntry;