]> granicus.if.org Git - postgresql/commitdiff
Track temporary file count and size in pg_stat_database
authorMagnus Hagander <magnus@hagander.net>
Thu, 26 Jan 2012 13:41:19 +0000 (14:41 +0100)
committerMagnus Hagander <magnus@hagander.net>
Thu, 26 Jan 2012 13:41:19 +0000 (14:41 +0100)
Add counters for number and size of temporary files used
for spill-to-disk queries for each database to the
pg_stat_database view.

Tomas Vondra, review by Magnus Hagander

doc/src/sgml/monitoring.sgml
src/backend/catalog/system_views.sql
src/backend/postmaster/pgstat.c
src/backend/storage/file/fd.c
src/backend/utils/adt/pgstatfuncs.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/pgstat.h
src/test/regress/expected/rules.out

index fef2a35ba7d5ae7231ac33cc55d88dd98001cd0c..1e4cb24455f521cd33b8530a9ed2fb85623aa1c4 100644 (file)
@@ -283,7 +283,8 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
       read requests avoided by finding the block already in buffer cache),
       number of rows returned, fetched, inserted, updated and deleted, the
       total number of queries canceled due to conflict with recovery (on
-      standby servers), and time of last statistics reset.
+      standby servers), number and size of temporary files used, and time
+      of last statistics reset.
      </entry>
      </row>
 
@@ -886,6 +887,28 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
       </entry>
      </row>
 
+     <row>
+      <entry><literal><function>pg_stat_get_db_temp_bytes</function>(<type>oid</type>)</literal></entry>
+      <entry><type>bigint</type></entry>
+      <entry>
+       Amount of data written to temporary files by queries in the database.
+       All temporary files are counted, regardless of why the temporary file
+       was created (sorting or hash), and regardless of the
+       <xref linkend="guc-log-temp-files"> setting.
+      </entry>
+     </row>
+
+     <row>
+      <entry><literal><function>pg_stat_get_db_temp_files</function>(<type>oid</type>)</literal></entry>
+      <entry><type>bigint</type></entry>
+      <entry>
+       Number of temporary files written by queries in the database. All temporary
+       files are counted, regardless of why the temporary file was created
+       (sorting or hash) or file size, and regardless of the
+       <xref linkend="guc-log-temp-files"> setting.
+      </entry>
+     </row>
+
      <row>
       <entry><literal><function>pg_stat_get_numscans</function>(<type>oid</type>)</literal></entry>
       <entry><type>bigint</type></entry>
index e25914b3065de6b3809ddfb998d7493563f15d06..873d67f0ea99ce0fe8f8d4900046137943b398f5 100644 (file)
@@ -576,6 +576,8 @@ CREATE VIEW pg_stat_database AS
             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_conflict_all(D.oid) AS conflicts,
+            pg_stat_get_db_temp_files(D.oid) AS temp_files,
+            pg_stat_get_db_temp_bytes(D.oid) AS temp_bytes,
             pg_stat_get_db_stat_reset_time(D.oid) AS stats_reset
     FROM pg_database D;
 
index e5bafd3c2d552d54776d89d2518497ae9352fa73..3b7aa07014d4cd342bb5b31d1309b26aabcb8194 100644 (file)
@@ -286,6 +286,7 @@ static void pgstat_recv_bgwriter(PgStat_MsgBgWriter *msg, int len);
 static void pgstat_recv_funcstat(PgStat_MsgFuncstat *msg, int len);
 static void pgstat_recv_funcpurge(PgStat_MsgFuncpurge *msg, int len);
 static void pgstat_recv_recoveryconflict(PgStat_MsgRecoveryConflict *msg, int len);
+static void pgstat_recv_tempfile(PgStat_MsgTempFile *msg, int len);
 
 
 /* ------------------------------------------------------------
@@ -1339,6 +1340,29 @@ pgstat_report_recovery_conflict(int reason)
        pgstat_send(&msg, sizeof(msg));
 }
 
+
+/* --------
+ * pgstat_report_tempfile() -
+ *
+ *     Tell the collector about a temporary file.
+ * --------
+ */
+void
+pgstat_report_tempfile(size_t filesize)
+{
+       PgStat_MsgTempFile msg;
+
+       if (pgStatSock == PGINVALID_SOCKET || !pgstat_track_counts)
+               return;
+
+       pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_TEMPFILE);
+       msg.m_databaseid = MyDatabaseId;
+       msg.m_filesize = filesize;
+       pgstat_send(&msg, sizeof(msg));
+}
+
+;
+
 /* ----------
  * pgstat_ping() -
  *
@@ -3218,6 +3242,10 @@ PgstatCollectorMain(int argc, char *argv[])
                                        pgstat_recv_recoveryconflict((PgStat_MsgRecoveryConflict *) &msg, len);
                                        break;
 
+                               case PGSTAT_MTYPE_TEMPFILE:
+                                       pgstat_recv_tempfile((PgStat_MsgTempFile *) &msg, len);
+                                       break;
+
                                default:
                                        break;
                        }
@@ -3299,6 +3327,8 @@ pgstat_get_db_entry(Oid databaseid, bool create)
                result->n_conflict_snapshot = 0;
                result->n_conflict_bufferpin = 0;
                result->n_conflict_startup_deadlock = 0;
+               result->n_temp_files = 0;
+               result->n_temp_bytes = 0;
 
                result->stat_reset_timestamp = GetCurrentTimestamp();
 
@@ -4210,6 +4240,8 @@ pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len)
        dbentry->n_tuples_updated = 0;
        dbentry->n_tuples_deleted = 0;
        dbentry->last_autovac_time = 0;
+       dbentry->n_temp_bytes = 0;
+       dbentry->n_temp_files = 0;
 
        dbentry->stat_reset_timestamp = GetCurrentTimestamp();
 
@@ -4435,6 +4467,24 @@ pgstat_recv_recoveryconflict(PgStat_MsgRecoveryConflict *msg, int len)
        }
 }
 
+/* ----------
+ * pgstat_recv_tempfile() -
+ *
+ *     Process as PGSTAT_MTYPE_TEMPFILE message.
+ * ----------
+ */
+static void
+pgstat_recv_tempfile(PgStat_MsgTempFile *msg, int len)
+{
+       PgStat_StatDBEntry *dbentry;
+
+       dbentry = pgstat_get_db_entry(msg->m_databaseid, true);
+
+       dbentry->n_temp_bytes += msg->m_filesize;
+       dbentry->n_temp_files += 1;
+
+}
+
 /* ----------
  * pgstat_recv_funcstat() -
  *
index 43bc43ab10f53a61d4fcff5930154cd0993eb5c5..673b25db3472d8a97917497347b8583cec792789 100644 (file)
@@ -1088,6 +1088,9 @@ FileClose(File file)
         */
        if (vfdP->fdstate & FD_TEMPORARY)
        {
+               struct stat filestats;
+               int                     stat_errno;
+
                /*
                 * If we get an error, as could happen within the ereport/elog calls,
                 * we'll come right back here during transaction abort.  Reset the
@@ -1101,23 +1104,22 @@ FileClose(File file)
                temporary_files_size -= vfdP->fileSize;
                vfdP->fileSize = 0;
 
-               if (log_temp_files >= 0)
-               {
-                       struct stat filestats;
-                       int                     stat_errno;
+               /* first try the stat() */
+               if (stat(vfdP->fileName, &filestats))
+                       stat_errno = errno;
+               else
+                       stat_errno = 0;
 
-                       /* first try the stat() */
-                       if (stat(vfdP->fileName, &filestats))
-                               stat_errno = errno;
-                       else
-                               stat_errno = 0;
+               /* in any case do the unlink */
+               if (unlink(vfdP->fileName))
+                       elog(LOG, "could not unlink file \"%s\": %m", vfdP->fileName);
 
-                       /* in any case do the unlink */
-                       if (unlink(vfdP->fileName))
-                               elog(LOG, "could not unlink file \"%s\": %m", vfdP->fileName);
+               /* and last report the stat results */
+               if (stat_errno == 0)
+               {
+                       pgstat_report_tempfile(filestats.st_size);
 
-                       /* and last report the stat results */
-                       if (stat_errno == 0)
+                       if (log_temp_files >= 0)
                        {
                                if ((filestats.st_size / 1024) >= log_temp_files)
                                        ereport(LOG,
@@ -1131,12 +1133,6 @@ FileClose(File file)
                                elog(LOG, "could not stat file \"%s\": %m", vfdP->fileName);
                        }
                }
-               else
-               {
-                       /* easy case, just do the unlink */
-                       if (unlink(vfdP->fileName))
-                               elog(LOG, "could not unlink file \"%s\": %m", vfdP->fileName);
-               }
        }
 
        /* Unregister it from the resource owner */
index ed39f27ef48cc620f4b26a54b8524c452dc7ecea..c7b91a8c8252080ce42e8594c7dbdff82a2c0bfc 100644 (file)
@@ -79,6 +79,8 @@ extern Datum pg_stat_get_db_conflict_bufferpin(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_db_conflict_startup_deadlock(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_db_conflict_all(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_db_temp_files(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_db_temp_bytes(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);
@@ -1213,6 +1215,37 @@ pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS)
                PG_RETURN_TIMESTAMPTZ(result);
 }
 
+Datum
+pg_stat_get_db_temp_files(PG_FUNCTION_ARGS)
+{
+       Oid             dbid = PG_GETARG_OID(0);
+       int64   result;
+       PgStat_StatDBEntry *dbentry;
+
+       if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+               result = 0;
+       else
+               result = dbentry->n_temp_files;
+
+       PG_RETURN_INT64(result);
+}
+
+
+Datum
+pg_stat_get_db_temp_bytes(PG_FUNCTION_ARGS)
+{
+       Oid             dbid = PG_GETARG_OID(0);
+       int64   result;
+       PgStat_StatDBEntry *dbentry;
+
+       if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+               result = 0;
+       else
+               result = dbentry->n_temp_bytes;
+
+       PG_RETURN_INT64(result);
+}
+
 Datum
 pg_stat_get_db_conflict_tablespace(PG_FUNCTION_ARGS)
 {
index 285fae3e4abb804624778279c3f691a6fe5329ad..cbce29ca6975c851b355751102c7dd9ce5131888 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201201192
+#define CATALOG_VERSION_NO     201201261
 
 #endif
index ef5ca3047d93ca374eff003db431ece7dbd9a215..6b121735f9c91ff48430c547d1577526c33dfb96 100644 (file)
@@ -2636,6 +2636,10 @@ DATA(insert OID = 3070 (  pg_stat_get_db_conflict_all PGNSP PGUID 12 1 0 0 0 f f
 DESCR("statistics: recovery conflicts in database");
 DATA(insert OID = 3074 (  pg_stat_get_db_stat_reset_time PGNSP PGUID 12 1 0 0 0 f f f t f s 1 0 1184 "26" _null_ _null_ _null_ _null_ pg_stat_get_db_stat_reset_time _null_ _null_ _null_ ));
 DESCR("statistics: last reset for a database");
+DATA(insert OID = 3150 (  pg_stat_get_db_temp_files PGNSP PGUID 12 1 0 0 0 f f f t f s 1 0 20 "26" _null_ _null_ _null_ _null_ pg_stat_get_db_temp_files _null_ _null_ _null_ ));
+DESCR("statistics: number of temporary files written");
+DATA(insert OID = 3151 (  pg_stat_get_db_temp_bytes PGNSP PGUID 12 1 0 0 0 f f f t f s 1 0 20 "26" _null_ _null_ _null_ _null_ pg_stat_get_db_temp_bytes _null_ _null_ _null_ ));
+DESCR("statistics: number of bytes in temporary files written");
 DATA(insert OID = 2769 ( pg_stat_get_bgwriter_timed_checkpoints PGNSP PGUID 12 1 0 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 0 f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_requested_checkpoints _null_ _null_ _null_ ));
index fa52447048dea94dbabf27a0bf7d532b498e6ba0..e91a0e8d89c2a0d818d7910d11b7edd659e02690 100644 (file)
@@ -47,7 +47,8 @@ typedef enum StatMsgType
        PGSTAT_MTYPE_BGWRITER,
        PGSTAT_MTYPE_FUNCSTAT,
        PGSTAT_MTYPE_FUNCPURGE,
-       PGSTAT_MTYPE_RECOVERYCONFLICT
+       PGSTAT_MTYPE_RECOVERYCONFLICT,
+       PGSTAT_MTYPE_TEMPFILE
 } StatMsgType;
 
 /* ----------
@@ -376,6 +377,18 @@ typedef struct PgStat_MsgRecoveryConflict
        int                     m_reason;
 } PgStat_MsgRecoveryConflict;
 
+/* ----------
+ * PgStat_MsgTempFile  Sent by the backend upon creating a temp file
+ * ----------
+ */
+typedef struct PgStat_MsgTempFile
+{
+       PgStat_MsgHdr m_hdr;
+
+       Oid                     m_databaseid;
+       size_t          m_filesize;
+} PgStat_MsgTempFile;
+
 /* ----------
  * PgStat_FunctionCounts       The actual per-function counts kept by a backend
  *
@@ -507,6 +520,9 @@ typedef struct PgStat_StatDBEntry
        PgStat_Counter n_conflict_snapshot;
        PgStat_Counter n_conflict_bufferpin;
        PgStat_Counter n_conflict_startup_deadlock;
+       PgStat_Counter n_temp_files;
+       PgStat_Counter n_temp_bytes;
+
        TimestampTz stat_reset_timestamp;
 
 
@@ -735,6 +751,7 @@ extern void pgstat_initialize(void);
 extern void pgstat_bestart(void);
 
 extern void pgstat_report_activity(BackendState state, const char *cmd_str);
+extern void pgstat_report_tempfile(size_t filesize);
 extern void pgstat_report_appname(const char *appname);
 extern void pgstat_report_xact_timestamp(TimestampTz tstamp);
 extern void pgstat_report_waiting(bool waiting);
index d26881f887434abe22cb8e7223b549b4e1e27c82..8d25e8050da66c4913452a9ff6a93123c3c25dfc 100644 (file)
@@ -1296,7 +1296,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
  pg_stat_all_indexes             | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"]));
  pg_stat_all_tables              | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, pg_stat_get_numscans(c.oid) AS seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, (sum(pg_stat_get_numscans(i.indexrelid)))::bigint AS idx_scan, ((sum(pg_stat_get_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_tuples_fetched(c.oid)) AS idx_tup_fetch, pg_stat_get_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_tuples_updated(c.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(c.oid) AS n_tup_del, pg_stat_get_tuples_hot_updated(c.oid) AS n_tup_hot_upd, pg_stat_get_live_tuples(c.oid) AS n_live_tup, pg_stat_get_dead_tuples(c.oid) AS n_dead_tup, pg_stat_get_last_vacuum_time(c.oid) AS last_vacuum, 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_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, pg_stat_get_autoanalyze_count(c.oid) AS autoanalyze_count FROM ((pg_class c LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"])) GROUP BY c.oid, n.nspname, c.relname;
  pg_stat_bgwriter                | SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed, pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req, pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint, pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean, pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean, pg_stat_get_buf_written_backend() AS buffers_backend, pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync, pg_stat_get_buf_alloc() AS buffers_alloc, pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
- pg_stat_database                | SELECT d.oid AS datid, d.datname, pg_stat_get_db_numbackends(d.oid) AS numbackends, pg_stat_get_db_xact_commit(d.oid) AS xact_commit, pg_stat_get_db_xact_rollback(d.oid) AS xact_rollback, (pg_stat_get_db_blocks_fetched(d.oid) - pg_stat_get_db_blocks_hit(d.oid)) AS blks_read, pg_stat_get_db_blocks_hit(d.oid) AS blks_hit, pg_stat_get_db_tuples_returned(d.oid) AS tup_returned, 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_conflict_all(d.oid) AS conflicts, pg_stat_get_db_stat_reset_time(d.oid) AS stats_reset FROM pg_database d;
+ pg_stat_database                | SELECT d.oid AS datid, d.datname, pg_stat_get_db_numbackends(d.oid) AS numbackends, pg_stat_get_db_xact_commit(d.oid) AS xact_commit, pg_stat_get_db_xact_rollback(d.oid) AS xact_rollback, (pg_stat_get_db_blocks_fetched(d.oid) - pg_stat_get_db_blocks_hit(d.oid)) AS blks_read, pg_stat_get_db_blocks_hit(d.oid) AS blks_hit, pg_stat_get_db_tuples_returned(d.oid) AS tup_returned, 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_conflict_all(d.oid) AS conflicts, pg_stat_get_db_temp_files(d.oid) AS temp_files, pg_stat_get_db_temp_bytes(d.oid) AS temp_bytes, pg_stat_get_db_stat_reset_time(d.oid) AS stats_reset FROM pg_database d;
  pg_stat_database_conflicts      | SELECT d.oid AS datid, d.datname, pg_stat_get_db_conflict_tablespace(d.oid) AS confl_tablespace, pg_stat_get_db_conflict_lock(d.oid) AS confl_lock, pg_stat_get_db_conflict_snapshot(d.oid) AS confl_snapshot, pg_stat_get_db_conflict_bufferpin(d.oid) AS confl_bufferpin, pg_stat_get_db_conflict_startup_deadlock(d.oid) AS confl_deadlock FROM pg_database d;
  pg_stat_replication             | SELECT s.pid, s.usesysid, u.rolname AS usename, s.application_name, s.client_addr, s.client_hostname, s.client_port, s.backend_start, w.state, w.sent_location, w.write_location, w.flush_location, w.replay_location, w.sync_priority, w.sync_state FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port), pg_authid u, pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state) WHERE ((s.usesysid = u.oid) AND (s.pid = w.pid));
  pg_stat_sys_indexes             | SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.indexrelid, pg_stat_all_indexes.schemaname, pg_stat_all_indexes.relname, pg_stat_all_indexes.indexrelname, pg_stat_all_indexes.idx_scan, pg_stat_all_indexes.idx_tup_read, pg_stat_all_indexes.idx_tup_fetch FROM pg_stat_all_indexes WHERE ((pg_stat_all_indexes.schemaname = ANY (ARRAY['pg_catalog'::name, 'information_schema'::name])) OR (pg_stat_all_indexes.schemaname ~ '^pg_toast'::text));