Add progress reporting for CLUSTER and VACUUM FULL.
authorRobert Haas <rhaas@postgresql.org>
Mon, 25 Mar 2019 14:59:04 +0000 (10:59 -0400)
committerRobert Haas <rhaas@postgresql.org>
Mon, 25 Mar 2019 14:59:04 +0000 (10:59 -0400)
This uses the same progress reporting infrastructure added in commit
c16dc1aca5e01e6acaadfcf38f5fc964a381dc62 and extends it to these
additional cases.  We lack the ability to track the internal progress
of sorts and index builds so the information reported is
coarse-grained for some parts of the operation, but it still seems
like a significant improvement over having nothing at all.

Tatsuro Yamada, reviewed by Thomas Munro, Masahiko Sawada, Michael
Paquier, Jeff Janes, Alvaro Herrera, Rafia Sabih, and by me.  A fair
amount of polishing also by me.

Discussion: http://postgr.es/m/59A77072.3090401@lab.ntt.co.jp

doc/src/sgml/monitoring.sgml
src/backend/catalog/index.c
src/backend/catalog/system_views.sql
src/backend/commands/cluster.c
src/backend/utils/adt/pgstatfuncs.c
src/include/catalog/catversion.h
src/include/commands/progress.h
src/include/pgstat.h
src/test/regress/expected/rules.out

index ac2721c8ad7a3e463ca51b1354274c224991ff68..f1df14bdea880b3588a14b11f6655d4a22279820 100644 (file)
@@ -344,6 +344,14 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
       </entry>
      </row>
 
+     <row>
+      <entry><structname>pg_stat_progress_cluster</structname><indexterm><primary>pg_stat_progress_cluster</primary></indexterm></entry>
+      <entry>One row for each backend running
+       <command>CLUSTER</command> or <command>VACUUM FULL</command>, showing current progress.
+       See <xref linkend='cluster-progress-reporting'/>.
+      </entry>
+     </row>
+
     </tbody>
    </tgroup>
   </table>
@@ -3394,9 +3402,9 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
 
   <para>
    <productname>PostgreSQL</productname> has the ability to report the progress of
-   certain commands during command execution.  Currently, the only command
-   which supports progress reporting is <command>VACUUM</command>.  This may be
-   expanded in the future.
+   certain commands during command execution.  Currently, the only commands
+   which support progress reporting are <command>VACUUM</command> and
+   <command>CLUSTER</command>. This may be expanded in the future.
   </para>
 
  <sect2 id="vacuum-progress-reporting">
@@ -3408,9 +3416,11 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
    one row for each backend (including autovacuum worker processes) that is
    currently vacuuming.  The tables below describe the information
    that will be reported and provide information about how to interpret it.
-   Progress reporting is not currently supported for <command>VACUUM FULL</command>
-   and backends running <command>VACUUM FULL</command> will not be listed in this
-   view.
+   Progress for <command>VACUUM FULL</command> commands is reported via
+   <structname>pg_stat_progress_cluster</structname>
+   because both <command>VACUUM FULL</command> and <command>CLUSTER</command> 
+   rewrite the table, while regular <command>VACUUM</command> only modifies it 
+   in place. See <xref linkend='cluster-progress-reporting'/>.
   </para>
 
   <table id="pg-stat-progress-vacuum-view" xreflabel="pg_stat_progress_vacuum">
@@ -3587,6 +3597,183 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
    </tgroup>
   </table>
 
+ </sect2>
+
+ <sect2 id="cluster-progress-reporting">
+  <title>CLUSTER Progress Reporting</title>
+
+  <para>
+   Whenever <command>CLUSTER</command> or <command>VACUUM FULL</command> is
+   running, the <structname>pg_stat_progress_cluster</structname> view will
+   contain a row for each backend that is currently running either command. 
+   The tables below describe the information that will be reported and
+   provide information about how to interpret it.
+  </para>
+
+  <table id="pg-stat-progress-cluster-view" xreflabel="pg_stat_progress_cluster">
+   <title><structname>pg_stat_progress_cluster</structname> View</title>
+   <tgroup cols="3">
+    <thead>
+    <row>
+      <entry>Column</entry>
+      <entry>Type</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+   <tbody>
+    <row>
+     <entry><structfield>pid</structfield></entry>
+     <entry><type>integer</type></entry>
+     <entry>Process ID of backend.</entry>
+    </row>
+    <row>
+     <entry><structfield>datid</structfield></entry>
+     <entry><type>oid</type></entry>
+     <entry>OID of the database to which this backend is connected.</entry>
+    </row>
+    <row>
+     <entry><structfield>datname</structfield></entry>
+     <entry><type>name</type></entry>
+     <entry>Name of the database to which this backend is connected.</entry>
+    </row>
+    <row>
+     <entry><structfield>relid</structfield></entry>
+     <entry><type>oid</type></entry>
+     <entry>OID of the table being clustered.</entry>
+    </row>
+    <row>
+     <entry><structfield>command</structfield></entry>
+     <entry><type>text</type></entry>
+     <entry>
+       The command that is running. Either CLUSTER or VACUUM FULL.
+     </entry>
+    </row>
+    <row>
+     <entry><structfield>phase</structfield></entry>
+     <entry><type>text</type></entry>
+     <entry>
+       Current processing phase. See <xref linkend='cluster-phases' />.
+     </entry>
+    </row>
+    <row>
+     <entry><structfield>cluster_index_relid</structfield></entry>
+     <entry><type>bigint</type></entry>
+     <entry>
+       If the table is being scanned using an index, this is the OID of the
+       index being used; otherwise, it is zero.
+     </entry>
+    </row>
+    <row>
+     <entry><structfield>heap_tuples_scanned</structfield></entry>
+     <entry><type>bigint</type></entry>
+     <entry>
+       Number of heap tuples scanned.
+       This counter only advances when the phase is
+       <literal>seq scanning heap</literal>,
+       <literal>index scanning heap</literal>
+       or <literal>writing new heap</literal>.
+     </entry>
+    </row>
+    <row>
+     <entry><structfield>heap_tuples_written</structfield></entry>
+     <entry><type>bigint</type></entry>
+     <entry>
+       Number of heap tuples written.
+       This counter only advances when the phase is
+       <literal>seq scanning heap</literal>,
+       <literal>index scanning heap</literal>
+       or <literal>writing new heap</literal>.
+     </entry>
+    </row>
+    <row>
+     <entry><structfield>heap_blks_total</structfield></entry>
+     <entry><type>bigint</type></entry>
+     <entry>
+       Total number of heap blocks in the table.  This number is reported
+       as of the beginning of <literal>seq scanning heap</literal>.
+     </entry>
+    </row>
+    <row>
+     <entry><structfield>heap_blks_scanned</structfield></entry>
+     <entry><type>bigint</type></entry>
+     <entry>
+       Number of heap blocks scanned.  This counter only advances when the
+       phase is <literal>seq scanning heap</literal>.
+     </entry>
+    </row>
+    <row>
+     <entry><structfield>index_rebuild_count</structfield></entry>
+     <entry><type>bigint</type></entry>
+     <entry>
+       Number of indexes rebuilt.  This counter only advances when the phase
+       is <literal>rebuilding index</literal>.
+     </entry>
+    </row>
+   </tbody>
+   </tgroup>
+  </table>
+
+  <table id="cluster-phases">
+   <title>CLUSTER and VACUUM FULL phases</title>
+   <tgroup cols="2">
+    <thead>
+    <row>
+      <entry>Phase</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+   <tbody>
+    <row>
+     <entry><literal>initializing</literal></entry>
+     <entry>
+       The command is preparing to begin scanning the heap.  This phase is
+       expected to be very brief.
+     </entry>
+    </row>
+    <row>
+     <entry><literal>seq scanning heap</literal></entry>
+     <entry>
+       The command is currently scanning the table using a sequential scan.
+     </entry>
+    </row>
+    <row>
+     <entry><literal>index scanning heap</literal></entry>
+     <entry>
+       <command>CLUSTER</command> is currently scanning the table using an index scan.
+     </entry>
+    </row>
+    <row>
+     <entry><literal>sorting tuples</literal></entry>
+     <entry>
+       <command>CLUSTER</command> is currently sorting tuples. 
+     </entry>
+    </row>
+    <row>
+     <entry><literal>swapping relation files</literal></entry>
+     <entry>
+       The command is currently swapping newly-built files into place.
+     </entry>
+    </row>
+    <row>
+     <entry><literal>rebuilding index</literal></entry>
+     <entry>
+       The command is currently rebuilding an index.
+     </entry>
+    </row>
+    <row>
+     <entry><literal>performing final cleanup</literal></entry>
+     <entry>
+       The command is performing final cleanup.  When this phase is 
+       completed, <command>CLUSTER</command>
+       or <command>VACUUM FULL</command> will end.
+     </entry>
+    </row>
+   </tbody>
+   </tgroup>
+  </table>
+
  </sect2>
  </sect1>
 
index cb2c0010171cc0a3dce1c107a38e02f90afbdf41..d2e284f6de6115e2fc77f0eaccad4f3570fe8f88 100644 (file)
@@ -52,6 +52,7 @@
 #include "catalog/storage.h"
 #include "commands/tablecmds.h"
 #include "commands/event_trigger.h"
+#include "commands/progress.h"
 #include "commands/trigger.h"
 #include "executor/executor.h"
 #include "miscadmin.h"
@@ -59,6 +60,7 @@
 #include "nodes/nodeFuncs.h"
 #include "optimizer/optimizer.h"
 #include "parser/parser.h"
+#include "pgstat.h"
 #include "rewrite/rewriteManip.h"
 #include "storage/bufmgr.h"
 #include "storage/lmgr.h"
@@ -3846,6 +3848,7 @@ reindex_relation(Oid relid, int flags, int options)
        List       *indexIds;
        bool            is_pg_class;
        bool            result;
+       int                     i;
 
        /*
         * Open and lock the relation.  ShareLock is sufficient since we only need
@@ -3933,6 +3936,7 @@ reindex_relation(Oid relid, int flags, int options)
 
                /* Reindex all the indexes. */
                doneIndexes = NIL;
+               i = 1;
                foreach(indexId, indexIds)
                {
                        Oid                     indexOid = lfirst_oid(indexId);
@@ -3950,6 +3954,11 @@ reindex_relation(Oid relid, int flags, int options)
 
                        if (is_pg_class)
                                doneIndexes = lappend_oid(doneIndexes, indexOid);
+
+                       /* Set index rebuild count */
+                       pgstat_progress_update_param(PROGRESS_CLUSTER_INDEX_REBUILD_COUNT,
+                                                                                i);
+                       i++;
                }
        }
        PG_CATCH();
index d962648bc5c599e92f6bba3cc339ef63f3064574..b89df70653e70331738dbfaadc67b468a4331120 100644 (file)
@@ -907,6 +907,33 @@ CREATE VIEW pg_stat_progress_vacuum AS
     FROM pg_stat_get_progress_info('VACUUM') AS S
                LEFT JOIN pg_database D ON S.datid = D.oid;
 
+CREATE VIEW pg_stat_progress_cluster AS
+    SELECT
+        S.pid AS pid,
+        S.datid AS datid,
+        D.datname AS datname,
+        S.relid AS relid,
+        CASE S.param1 WHEN 1 THEN 'CLUSTER'
+                      WHEN 2 THEN 'VACUUM FULL'
+                      END AS command,
+        CASE S.param2 WHEN 0 THEN 'initializing'
+                      WHEN 1 THEN 'seq scanning heap'
+                      WHEN 2 THEN 'index scanning heap'
+                      WHEN 3 THEN 'sorting tuples'
+                      WHEN 4 THEN 'writing new heap'
+                      WHEN 5 THEN 'swapping relation files'
+                      WHEN 6 THEN 'rebuilding index'
+                      WHEN 7 THEN 'performing final cleanup'
+                      END AS phase,
+        S.param3 AS cluster_index_relid,
+        S.param4 AS heap_tuples_scanned,
+        S.param5 AS heap_tuples_written,
+        S.param6 AS heap_blks_total,
+        S.param7 AS heap_blks_scanned,
+        S.param8 AS index_rebuild_count
+    FROM pg_stat_get_progress_info('CLUSTER') AS S
+        LEFT JOIN pg_database D ON S.datid = D.oid;
+
 CREATE VIEW pg_user_mappings AS
     SELECT
         U.oid       AS umid,
index 3e2a807640ff168b72d1057bd8819d4a70f985ed..205070b83d228efff11b42e73791414a24d3c5cf 100644 (file)
 #include "catalog/objectaccess.h"
 #include "catalog/toasting.h"
 #include "commands/cluster.h"
+#include "commands/progress.h"
 #include "commands/tablecmds.h"
 #include "commands/vacuum.h"
 #include "miscadmin.h"
 #include "optimizer/optimizer.h"
+#include "pgstat.h"
 #include "storage/bufmgr.h"
 #include "storage/lmgr.h"
 #include "storage/predicate.h"
@@ -276,6 +278,14 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
        /* Check for user-requested abort. */
        CHECK_FOR_INTERRUPTS();
 
+       pgstat_progress_start_command(PROGRESS_COMMAND_CLUSTER, tableOid);
+       if (OidIsValid(indexOid))
+               pgstat_progress_update_param(PROGRESS_CLUSTER_COMMAND,
+                                                                        PROGRESS_CLUSTER_COMMAND_CLUSTER);
+       else
+               pgstat_progress_update_param(PROGRESS_CLUSTER_COMMAND,
+                                                                        PROGRESS_CLUSTER_COMMAND_VACUUM_FULL);
+
        /*
         * We grab exclusive access to the target rel and index for the duration
         * of the transaction.  (This is redundant for the single-transaction
@@ -286,7 +296,10 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
 
        /* If the table has gone away, we can skip processing it */
        if (!OldHeap)
+       {
+               pgstat_progress_end_command();
                return;
+       }
 
        /*
         * Since we may open a new transaction for each relation, we have to check
@@ -305,6 +318,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
                if (!pg_class_ownercheck(tableOid, GetUserId()))
                {
                        relation_close(OldHeap, AccessExclusiveLock);
+                       pgstat_progress_end_command();
                        return;
                }
 
@@ -319,6 +333,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
                if (RELATION_IS_OTHER_TEMP(OldHeap))
                {
                        relation_close(OldHeap, AccessExclusiveLock);
+                       pgstat_progress_end_command();
                        return;
                }
 
@@ -330,6 +345,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
                        if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(indexOid)))
                        {
                                relation_close(OldHeap, AccessExclusiveLock);
+                               pgstat_progress_end_command();
                                return;
                        }
 
@@ -340,6 +356,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
                        if (!HeapTupleIsValid(tuple))   /* probably can't happen */
                        {
                                relation_close(OldHeap, AccessExclusiveLock);
+                               pgstat_progress_end_command();
                                return;
                        }
                        indexForm = (Form_pg_index) GETSTRUCT(tuple);
@@ -347,6 +364,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
                        {
                                ReleaseSysCache(tuple);
                                relation_close(OldHeap, AccessExclusiveLock);
+                               pgstat_progress_end_command();
                                return;
                        }
                        ReleaseSysCache(tuple);
@@ -401,6 +419,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
                !RelationIsPopulated(OldHeap))
        {
                relation_close(OldHeap, AccessExclusiveLock);
+               pgstat_progress_end_command();
                return;
        }
 
@@ -416,6 +435,8 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
        rebuild_relation(OldHeap, indexOid, verbose);
 
        /* NB: rebuild_relation does table_close() on OldHeap */
+
+       pgstat_progress_end_command();
 }
 
 /*
@@ -928,6 +949,17 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
         */
        if (OldIndex != NULL && !use_sort)
        {
+               const int   ci_index[] = {
+                       PROGRESS_CLUSTER_PHASE,
+                       PROGRESS_CLUSTER_INDEX_RELID
+               };
+               int64       ci_val[2];
+
+               /* Set phase and OIDOldIndex to columns */
+               ci_val[0] = PROGRESS_CLUSTER_PHASE_INDEX_SCAN_HEAP;
+               ci_val[1] = OIDOldIndex;
+               pgstat_progress_update_multi_param(2, ci_index, ci_val);
+
                tableScan = NULL;
                heapScan = NULL;
                indexScan = index_beginscan(OldHeap, OldIndex, SnapshotAny, 0, 0);
@@ -935,9 +967,17 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
        }
        else
        {
+               /* In scan-and-sort mode and also VACUUM FULL, set phase */
+               pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE,
+                                                                        PROGRESS_CLUSTER_PHASE_SEQ_SCAN_HEAP);
+
                tableScan = table_beginscan(OldHeap, SnapshotAny, 0, (ScanKey) NULL);
                heapScan = (HeapScanDesc) tableScan;
                indexScan = NULL;
+
+               /* Set total heap blocks */
+               pgstat_progress_update_param(PROGRESS_CLUSTER_TOTAL_HEAP_BLKS,
+                                                                        heapScan->rs_nblocks);
        }
 
        slot = table_slot_create(OldHeap, NULL);
@@ -994,6 +1034,10 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
                                break;
 
                        buf = heapScan->rs_cbuf;
+
+                       /* In scan-and-sort mode and also VACUUM FULL, set heap blocks scanned */
+                       pgstat_progress_update_param(PROGRESS_CLUSTER_HEAP_BLKS_SCANNED,
+                                                                                heapScan->rs_cblock + 1);
                }
 
                LockBuffer(buf, BUFFER_LOCK_SHARE);
@@ -1064,12 +1108,31 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
 
                num_tuples += 1;
                if (tuplesort != NULL)
+               {
                        tuplesort_putheaptuple(tuplesort, tuple);
+
+                       /* In scan-and-sort mode, report increase in number of tuples scanned */
+                       pgstat_progress_update_param(PROGRESS_CLUSTER_HEAP_TUPLES_SCANNED,
+                                                                                num_tuples);
+               }
                else
+               {
+                       const int   ct_index[] = {
+                               PROGRESS_CLUSTER_HEAP_TUPLES_SCANNED,
+                               PROGRESS_CLUSTER_HEAP_TUPLES_WRITTEN
+                       };
+                       int64       ct_val[2];
+
                        reform_and_rewrite_tuple(tuple,
                                                                         oldTupDesc, newTupDesc,
                                                                         values, isnull,
                                                                         rwstate);
+
+                       /* In indexscan mode and also VACUUM FULL, report increase in number of tuples scanned and written */
+                       ct_val[0] = num_tuples;
+                       ct_val[1] = num_tuples;
+                       pgstat_progress_update_multi_param(2, ct_index, ct_val);
+               }
        }
 
        if (indexScan != NULL)
@@ -1085,8 +1148,17 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
         */
        if (tuplesort != NULL)
        {
+               double n_tuples = 0;
+               /* Report that we are now sorting tuples */
+               pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE,
+                                                                        PROGRESS_CLUSTER_PHASE_SORT_TUPLES);
+
                tuplesort_performsort(tuplesort);
 
+               /* Report that we are now writing new heap */
+               pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE,
+                                                                        PROGRESS_CLUSTER_PHASE_WRITE_NEW_HEAP);
+
                for (;;)
                {
                        HeapTuple       tuple;
@@ -1097,10 +1169,14 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
                        if (tuple == NULL)
                                break;
 
+                       n_tuples += 1;
                        reform_and_rewrite_tuple(tuple,
                                                                         oldTupDesc, newTupDesc,
                                                                         values, isnull,
                                                                         rwstate);
+                       /* Report n_tuples */
+                       pgstat_progress_update_param(PROGRESS_CLUSTER_HEAP_TUPLES_WRITTEN,
+                                                                                n_tuples);
                }
 
                tuplesort_end(tuplesort);
@@ -1539,6 +1615,10 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
        int                     reindex_flags;
        int                     i;
 
+       /* Report that we are now swapping relation files */
+       pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE,
+                                                                PROGRESS_CLUSTER_PHASE_SWAP_REL_FILES);
+
        /* Zero out possible results from swapped_relation_files */
        memset(mapped_tables, 0, sizeof(mapped_tables));
 
@@ -1586,8 +1666,16 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
        else if (newrelpersistence == RELPERSISTENCE_PERMANENT)
                reindex_flags |= REINDEX_REL_FORCE_INDEXES_PERMANENT;
 
+       /* Report that we are now reindexing relations */
+       pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE,
+                                                                PROGRESS_CLUSTER_PHASE_REBUILD_INDEX);
+
        reindex_relation(OIDOldHeap, reindex_flags, 0);
 
+       /* Report that we are now doing clean up */
+       pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE,
+                                                                PROGRESS_CLUSTER_PHASE_FINAL_CLEANUP);
+
        /*
         * If the relation being rebuild is pg_class, swap_relation_files()
         * couldn't update pg_class's own pg_class entry (check comments in
index da1d685c0811a476a5c8065f26af5ca606a83ad3..90a817a25c5b2a0ba1f3d4126570b0ecd1438fb2 100644 (file)
@@ -468,6 +468,8 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
        /* Translate command name into command type code. */
        if (pg_strcasecmp(cmd, "VACUUM") == 0)
                cmdtype = PROGRESS_COMMAND_VACUUM;
+       else if (pg_strcasecmp(cmd, "CLUSTER") == 0)
+               cmdtype = PROGRESS_COMMAND_CLUSTER;
        else
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
index d4dfe237c9907467faec8d58f72e62a814da9f76..c1e1d601ec52e5489d1aa16fea19708f340635c8 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201903221
+#define CATALOG_VERSION_NO     201903251
 
 #endif
index 9858b36a383aae73bfa33777bb70ad0b636ce8e5..04542d9e923b6786d9cc2efaeffde6d3cc808f71 100644 (file)
 #define PROGRESS_VACUUM_PHASE_TRUNCATE                 5
 #define PROGRESS_VACUUM_PHASE_FINAL_CLEANUP            6
 
+/* Progress parameters for cluster */
+#define PROGRESS_CLUSTER_COMMAND                               0
+#define PROGRESS_CLUSTER_PHASE                                 1
+#define PROGRESS_CLUSTER_INDEX_RELID                   2
+#define PROGRESS_CLUSTER_HEAP_TUPLES_SCANNED   3
+#define PROGRESS_CLUSTER_HEAP_TUPLES_WRITTEN   4
+#define PROGRESS_CLUSTER_TOTAL_HEAP_BLKS               5
+#define PROGRESS_CLUSTER_HEAP_BLKS_SCANNED             6
+#define PROGRESS_CLUSTER_INDEX_REBUILD_COUNT   7
+
+/* Phases of cluster (as dvertised via PROGRESS_CLUSTER_PHASE) */
+#define PROGRESS_CLUSTER_PHASE_SEQ_SCAN_HEAP   1
+#define PROGRESS_CLUSTER_PHASE_INDEX_SCAN_HEAP 2
+#define PROGRESS_CLUSTER_PHASE_SORT_TUPLES             3
+#define PROGRESS_CLUSTER_PHASE_WRITE_NEW_HEAP  4
+#define PROGRESS_CLUSTER_PHASE_SWAP_REL_FILES  5
+#define PROGRESS_CLUSTER_PHASE_REBUILD_INDEX   6
+#define PROGRESS_CLUSTER_PHASE_FINAL_CLEANUP   7
+
+/* Commands of PROGRESS_CLUSTER */
+#define PROGRESS_CLUSTER_COMMAND_CLUSTER               1
+#define PROGRESS_CLUSTER_COMMAND_VACUUM_FULL   2
+
 #endif
index ea6cc8b560f221b8e3314dfb4bc5bf8441006bc7..c080fa6388f4f04402af4e64a04ebd8c2d2dd40f 100644 (file)
@@ -950,7 +950,8 @@ typedef enum
 typedef enum ProgressCommandType
 {
        PROGRESS_COMMAND_INVALID,
-       PROGRESS_COMMAND_VACUUM
+       PROGRESS_COMMAND_VACUUM,
+       PROGRESS_COMMAND_CLUSTER
 } ProgressCommandType;
 
 #define PGSTAT_NUM_PROGRESS_PARAM      10
index 8c33cd999d6f3f70baffa2c9a05761660ef29bc6..d5f309fbfbea91cb0fae5c1149c4c0067a4572d9 100644 (file)
@@ -1830,6 +1830,34 @@ pg_stat_database_conflicts| SELECT d.oid AS datid,
     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_progress_cluster| SELECT s.pid,
+    s.datid,
+    d.datname,
+    s.relid,
+        CASE s.param1
+            WHEN 1 THEN 'CLUSTER'::text
+            WHEN 2 THEN 'VACUUM FULL'::text
+            ELSE NULL::text
+        END AS command,
+        CASE s.param2
+            WHEN 0 THEN 'initializing'::text
+            WHEN 1 THEN 'seq scanning heap'::text
+            WHEN 2 THEN 'index scanning heap'::text
+            WHEN 3 THEN 'sorting tuples'::text
+            WHEN 4 THEN 'writing new heap'::text
+            WHEN 5 THEN 'swapping relation files'::text
+            WHEN 6 THEN 'rebuilding index'::text
+            WHEN 7 THEN 'performing final cleanup'::text
+            ELSE NULL::text
+        END AS phase,
+    s.param3 AS cluster_index_relid,
+    s.param4 AS heap_tuples_scanned,
+    s.param5 AS heap_tuples_written,
+    s.param6 AS heap_blks_total,
+    s.param7 AS heap_blks_scanned,
+    s.param8 AS index_rebuild_count
+   FROM (pg_stat_get_progress_info('CLUSTER'::text) s(pid, datid, relid, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10)
+     LEFT JOIN pg_database d ON ((s.datid = d.oid)));
 pg_stat_progress_vacuum| SELECT s.pid,
     s.datid,
     d.datname,