public inbox for [email protected]  
help / color / mirror / Atom feed
From: Imseih (AWS), Sami <[email protected]>
To: Masahiko Sawada <[email protected]>
To: Peter Geoghegan <[email protected]>
Cc: Bossart, Nathan <[email protected]>
Cc: [email protected] <[email protected]>
Subject: Re: Add index scan progress to pg_stat_progress_vacuum
Date: Wed, 29 Dec 2021 16:44:31 +0000
Message-ID: <[email protected]> (raw)
In-Reply-To: <[email protected]>
References: <[email protected]>
	<[email protected]>
	<CAH2-Wzmz4Z+UYqRgYHuyxYHha4Gn-aBprydmG0n+m6J2J_ABSA@mail.gmail.com>
	<CAD21AoCKOFjU8XpPjXgfNrP3-V71AL5NKY+3or7eeRnNMKqi0g@mail.gmail.com>
	<[email protected]>

Attached is the latest revision of the patch.

In "pg_stat_progress_vacuum", introduce 2 columns:

* total_index_vacuum : This is the # of indexes that will be vacuumed. Keep in mind that if failsafe mode kicks in mid-flight to the vacuum, Postgres may choose to forgo index scans. This value will be adjusted accordingly.
* max_index_vacuum_cycle_time : The total elapsed time for a index vacuum cycle is calculated and this value will be updated to reflect the longest vacuum cycle. Until the first cycle completes, this value will be 0. The purpose of this column is to give the user an idea of how long an index vacuum cycle takes to complete.

postgres=# \d pg_stat_progress_vacuum
View "pg_catalog.pg_stat_progress_vacuum"
Column | Type | Collation | Nullable | Default
-----------------------------+---------+-----------+----------+---------
pid | integer | | |
datid | oid | | |
datname | name | | |
relid | oid | | |
phase | text | | |
heap_blks_total | bigint | | |
heap_blks_scanned | bigint | | |
heap_blks_vacuumed | bigint | | |
index_vacuum_count | bigint | | |
max_dead_tuples | bigint | | |
num_dead_tuples | bigint | | |
total_index_vacuum | bigint | | |
max_index_vacuum_cycle_time | bigint | | |



Introduce a new view called "pg_stat_progress_vacuum_index". This view will track the progress of a worker ( or leader PID ) while it's vacuuming an index. It will expose some key columns:

* pid: The PID of the worker process

* leader_pid: The PID of the leader process. This is the column that can be joined with "pg_stat_progress_vacuum". leader_pid and pid can have the same value as a leader can also perform an index vacuum.

* indrelid: The relid of the index currently being vacuumed

* vacuum_cycle_ordinal_position: The processing position of the index being vacuumed. This can be useful to determine how many indexes out of the total indexes ( pg_stat_progress_vacuum.total_index_vacuum ) have been vacuumed

* index_tuples_vacuumed: This is the number of index tuples vacuumed for the index overall. This is useful to show that the vacuum is actually doing work, as the # of tuples keeps increasing. 

postgres=# \d pg_stat_progress_vacuum_index
View "pg_catalog.pg_stat_progress_vacuum_index"
Column | Type | Collation | Nullable | Default
-------------------------------+---------+-----------+----------+---------
pid | integer | | |
leader_pid | bigint | | |
indrelid | bigint | | |
vacuum_cycle_ordinal_position | bigint | | |
index_tuples_vacuumed | bigint | | |








On 12/27/21, 6:12 PM, "Imseih (AWS), Sami" <[email protected]> wrote:

    I do agree that tracking progress by # of blocks scanned is not deterministic for all index types.

    Based on this feedback, I went back to the drawing board on this. 

    Something like below may make more sense.

    In pg_stat_progress_vacuum, introduce 2 new columns:

    1. total_index_vacuum   - total # of indexes to vacuum
    2. max_cycle_time - the time in seconds of the longest index cycle. 

    Introduce another view called pg_stat_progress_vacuum_index_cycle:

    postgres=# \d pg_stat_progress_vacuum_index_cycle
           View "public.pg_stat_progress_vacuum_worker"
         Column     |  Type   | Collation | Nullable | Default
    ----------------+---------+-----------+----------+---------
    pid            | integer |           |          |				<<<-- the PID of the vacuum worker ( or leader if it's doing index vacuuming )
    leader_pid     | bigint  |           |          |				<<<-- the leader PID to allow this view to be joined back to pg_stat_progress_vacuum
    indrelid       | bigint  |           |          |				<<<- the index relid of the index being vacuumed
    ordinal_position | bigint |           |          |				<<<- the processing position, which will give an idea of the processing position of the index being vacuumed. 
    dead_tuples_removed | bigint | |				<<<- the number of dead rows removed in the current cycle for the index.

    Having this information, one can

    1. Determine which index is being vacuumed. For monitoring tools, this can help identify the index that accounts for most of the index vacuuming time.
    2. Having the processing order of the current index will allow the user to determine how many of the total indexes has been completed in the current cycle.
    3. dead_tuples_removed will show progress on the index vacuum in the current cycle.
    4. the max_cycle_time will give an idea on how long the longest index cycle took for the current vacuum operation.


    On 12/23/21, 2:46 AM, "Masahiko Sawada" <[email protected]> wrote:

        CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you can confirm the sender and know the content is safe.



        On Tue, Dec 21, 2021 at 3:37 AM Peter Geoghegan <[email protected]> wrote:
        >
        > On Wed, Dec 15, 2021 at 2:10 PM Bossart, Nathan <[email protected]> wrote:
        > > nitpick: Shouldn't index_blks_scanned be index_blks_vacuumed?  IMO it
        > > is more analogous to heap_blks_vacuumed.
        >
        > +1.
        >
        > > This will tell us which indexes are currently being vacuumed and the
        > > current progress of those operations, but it doesn't tell us which
        > > indexes have already been vacuumed or which ones are pending vacuum.
        >
        > VACUUM will process a table's indexes in pg_class OID order (outside
        > of parallel VACUUM, I suppose). See comments about sort order above
        > RelationGetIndexList().

        Right.

        >
        > Anyway, it might be useful to add ordinal numbers to each index, that
        > line up with this processing/OID order. It would also be reasonable to
        > display the same number in log_autovacuum* (and VACUUM VERBOSE)
        > per-index output, to reinforce the idea. Note that we don't
        > necessarily display a distinct line for each distinct index in this
        > log output, which is why including the ordinal number there makes
        > sense.

        An alternative idea would be to show the number of indexes on the
        table and the number of indexes that have been processed in the
        leader's entry of pg_stat_progress_vacuum. Even in parallel vacuum
        cases, since we have index vacuum status for each index it would not
        be hard for the leader process to count how many indexes have been
        processed.

        Regarding the details of the progress of index vacuum, I'm not sure
        this progress information can fit for pg_stat_progress_vacuum. As
        Peter already mentioned, the behavior quite varies depending on index
        AM.

        Regards,


        --
        Masahiko Sawada
        EDB:  https://www.enterprisedb.com/




Attachments:

  [application/octet-stream] 0001-Add-index-scan-progress-to-pg_stat_progress_vacuum.patch (16.6K, ../[email protected]/2-0001-Add-index-scan-progress-to-pg_stat_progress_vacuum.patch)
  download | inline diff:
From 149631ce5c8c5cb5b05c92a7df1de3d8e431a3c2 Mon Sep 17 00:00:00 2001
From: "Imseih (AWS), Sami" <[email protected]>
Date: Tue, 28 Dec 2021 22:00:43 +0000
Subject: [PATCH 1/1] Add index scan progress to pg_stat_progress_vacuum.

Expose progress for the "vacuuming indexes" phase
of a VACUUM operation.

Author: Sami Imseih, based on suggestions by Nathan Bossart, Peter Geoghegan and Masahiko Sawada
Discussion: https://www.postgresql.org/message-id/5478DFCD-2333-401A-B2F0-0D186AB09228%40amazon.com
---
 src/backend/access/gin/ginvacuum.c    |  4 ++
 src/backend/access/gist/gistvacuum.c  |  4 ++
 src/backend/access/hash/hash.c        |  4 ++
 src/backend/access/heap/vacuumlazy.c  | 32 ++++++++++++++-
 src/backend/access/nbtree/nbtree.c    |  4 ++
 src/backend/access/spgist/spgvacuum.c |  4 ++
 src/backend/catalog/system_views.sql  | 15 ++++++-
 src/backend/commands/vacuumparallel.c | 22 +++++++++--
 src/backend/utils/misc/pg_rusage.c    | 56 ++++++++++++++++++++-------
 src/include/commands/progress.h       | 20 ++++++----
 src/include/utils/pg_rusage.h         |  1 +
 11 files changed, 137 insertions(+), 29 deletions(-)

diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c
index a276eb020b..07fd5271a1 100644
--- a/src/backend/access/gin/ginvacuum.c
+++ b/src/backend/access/gin/ginvacuum.c
@@ -24,6 +24,8 @@
 #include "storage/lmgr.h"
 #include "storage/predicate.h"
 #include "utils/memutils.h"
+#include "commands/progress.h"
+#include "pgstat.h"
 
 struct GinVacuumState
 {
@@ -60,6 +62,8 @@ ginVacuumItemPointers(GinVacuumState *gvs, ItemPointerData *items,
 		if (gvs->callback(items + i, gvs->callback_state))
 		{
 			gvs->result->tuples_removed += 1;
+			pgstat_progress_update_param(PROGRESS_VACUUM_DEAD_TUPLES_VACUUMED, gvs->result->tuples_removed);
+
 			if (!tmpitems)
 			{
 				/*
diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c
index 0663193531..ee77e5e405 100644
--- a/src/backend/access/gist/gistvacuum.c
+++ b/src/backend/access/gist/gistvacuum.c
@@ -23,6 +23,8 @@
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
 #include "utils/memutils.h"
+#include "commands/progress.h"
+#include "pgstat.h"
 
 /* Working state needed by gistbulkdelete */
 typedef struct
@@ -375,6 +377,8 @@ restart:
 			END_CRIT_SECTION();
 
 			vstate->stats->tuples_removed += ntodelete;
+			pgstat_progress_update_param(PROGRESS_VACUUM_DEAD_TUPLES_VACUUMED, vstate->stats->tuples_removed);
+
 			/* must recompute maxoff */
 			maxoff = PageGetMaxOffsetNumber(page);
 		}
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index 81c7da7ec6..0ac59fdb7e 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -31,6 +31,8 @@
 #include "utils/builtins.h"
 #include "utils/index_selfuncs.h"
 #include "utils/rel.h"
+#include "commands/progress.h"
+#include "pgstat.h"
 
 /* Working state for hashbuild and its callback */
 typedef struct
@@ -631,6 +633,8 @@ loop_top:
 	stats->estimated_count = false;
 	stats->num_index_tuples = num_index_tuples;
 	stats->tuples_removed += tuples_removed;
+	pgstat_progress_update_param(PROGRESS_VACUUM_DEAD_TUPLES_VACUUMED, stats->tuples_removed);
+
 	/* hashvacuumcleanup will fill in num_pages */
 
 	return stats;
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index cd603e6aa4..f0cda3d162 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -167,6 +167,8 @@ typedef struct LVRelState
 	/* VACUUM operation's cutoff for freezing XIDs and MultiXactIds */
 	TransactionId FreezeLimit;
 	MultiXactId MultiXactCutoff;
+	/* VACCUM operation's longest index scan cycle */
+	int64 max_index_cycle_time;
 
 	/* Error reporting state */
 	char	   *relnamespace;
@@ -343,6 +345,7 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
 
 	pgstat_progress_start_command(PROGRESS_COMMAND_VACUUM,
 								  RelationGetRelid(rel));
+	pgstat_progress_update_param(PROGRESS_VACUUM_LEADER_PID, MyProcPid);
 
 	vacuum_set_xid_limits(rel,
 						  params->freeze_min_age,
@@ -2038,6 +2041,8 @@ static bool
 lazy_vacuum_all_indexes(LVRelState *vacrel)
 {
 	bool		allindexes = true;
+	PGRUsage	ru0;
+	int64		index_cycle_elapsed_ms = 0;
 
 	Assert(vacrel->nindexes > 0);
 	Assert(vacrel->do_index_vacuuming);
@@ -2056,6 +2061,10 @@ lazy_vacuum_all_indexes(LVRelState *vacrel)
 	pgstat_progress_update_param(PROGRESS_VACUUM_PHASE,
 								 PROGRESS_VACUUM_PHASE_VACUUM_INDEX);
 
+	pgstat_progress_update_param(PROGRESS_VACUUM_TOTAL_INDEX_VACUUM, vacrel->nindexes);
+
+	pg_rusage_init(&ru0);
+
 	if (!ParallelVacuumIsActive(vacrel))
 	{
 		for (int idx = 0; idx < vacrel->nindexes; idx++)
@@ -2063,14 +2072,22 @@ lazy_vacuum_all_indexes(LVRelState *vacrel)
 			Relation	indrel = vacrel->indrels[idx];
 			IndexBulkDeleteResult *istat = vacrel->indstats[idx];
 
+			/* Advertise the index that is being vacuumed and the vacuum order of the index */
+			pgstat_progress_update_param(PROGRESS_VACUUM_CURRENT_INDRELID, indrel->rd_id);
+			pgstat_progress_update_param(PROGRESS_VACUUM_INDEX_ORDINAL, idx + 1);
+
 			vacrel->indstats[idx] =
 				lazy_vacuum_one_index(indrel, istat, vacrel->old_live_tuples,
 									  vacrel);
 
+			/* Advertise that we are done vacuuming the index */
+			pgstat_progress_update_param(PROGRESS_VACUUM_CURRENT_INDRELID, 0);
+
 			if (lazy_check_wraparound_failsafe(vacrel))
 			{
 				/* Wraparound emergency -- end current index scan */
 				allindexes = false;
+				pgstat_progress_update_param(PROGRESS_VACUUM_TOTAL_INDEX_VACUUM, 0);
 				break;
 			}
 		}
@@ -2085,8 +2102,10 @@ lazy_vacuum_all_indexes(LVRelState *vacrel)
 		 * Do a postcheck to consider applying wraparound failsafe now.  Note
 		 * that parallel VACUUM only gets the precheck and this postcheck.
 		 */
-		if (lazy_check_wraparound_failsafe(vacrel))
+		if (lazy_check_wraparound_failsafe(vacrel)) {
 			allindexes = false;
+			pgstat_progress_update_param(PROGRESS_VACUUM_TOTAL_INDEX_VACUUM, 0);
+		}
 	}
 
 	/*
@@ -2110,6 +2129,17 @@ lazy_vacuum_all_indexes(LVRelState *vacrel)
 	pgstat_progress_update_param(PROGRESS_VACUUM_NUM_INDEX_VACUUMS,
 								 vacrel->num_index_scans);
 
+	/*
+	 * Set the Maximum index vacuum cycle time.
+	 *
+	 * If this cycle took longer than any previous cycle, reset the max_index_cycle_time time.
+	 */
+	index_cycle_elapsed_ms = pg_rusage_elapsed_ms(&ru0);
+	if (index_cycle_elapsed_ms > vacrel->max_index_cycle_time) {
+		vacrel->max_index_cycle_time = index_cycle_elapsed_ms;
+		pgstat_progress_update_param(PROGRESS_VACUUM_MAX_CYCLE_TIME, index_cycle_elapsed_ms);
+	}
+
 	return allindexes;
 }
 
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index dfce06dc49..ed6e6ac42c 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -36,6 +36,8 @@
 #include "utils/builtins.h"
 #include "utils/index_selfuncs.h"
 #include "utils/memutils.h"
+#include "commands/progress.h"
+#include "pgstat.h"
 
 
 /*
@@ -1272,6 +1274,8 @@ backtrack:
 								nupdatable);
 
 			stats->tuples_removed += nhtidsdead;
+			pgstat_progress_update_param(PROGRESS_VACUUM_DEAD_TUPLES_VACUUMED, stats->tuples_removed);
+
 			/* must recompute maxoff */
 			maxoff = PageGetMaxOffsetNumber(page);
 
diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c
index 76fb0374c4..6040761f33 100644
--- a/src/backend/access/spgist/spgvacuum.c
+++ b/src/backend/access/spgist/spgvacuum.c
@@ -27,6 +27,8 @@
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
 #include "utils/snapmgr.h"
+#include "commands/progress.h"
+#include "pgstat.h"
 
 
 /* Entry in pending-list of TIDs we need to revisit */
@@ -160,6 +162,7 @@ vacuumLeafPage(spgBulkDeleteState *bds, Relation index, Buffer buffer,
 				bds->stats->tuples_removed += 1;
 				deletable[i] = true;
 				nDeletable++;
+				pgstat_progress_update_param(PROGRESS_VACUUM_DEAD_TUPLES_VACUUMED, bds->stats->tuples_removed);
 			}
 			else
 			{
@@ -430,6 +433,7 @@ vacuumLeafRoot(spgBulkDeleteState *bds, Relation index, Buffer buffer)
 				bds->stats->tuples_removed += 1;
 				toDelete[xlrec.nDelete] = i;
 				xlrec.nDelete++;
+				pgstat_progress_update_param(PROGRESS_VACUUM_DEAD_TUPLES_VACUUMED, bds->stats->tuples_removed);
 			}
 			else
 			{
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 61b515cdb8..70f35092f6 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1124,9 +1124,20 @@ CREATE VIEW pg_stat_progress_vacuum AS
                       END AS phase,
         S.param2 AS heap_blks_total, S.param3 AS heap_blks_scanned,
         S.param4 AS heap_blks_vacuumed, S.param5 AS index_vacuum_count,
-        S.param6 AS max_dead_tuples, S.param7 AS num_dead_tuples
+        S.param6 AS max_dead_tuples, S.param7 AS num_dead_tuples,
+		S.param11 AS total_index_vacuum, S.param12 AS max_index_vacuum_cycle_time
     FROM pg_stat_get_progress_info('VACUUM') AS S
-        LEFT JOIN pg_database D ON S.datid = D.oid;
+        LEFT JOIN pg_database D ON S.datid = D.oid
+	WHERE S.pid = S.param9; -- show vacuum progress for the leader PID only
+
+CREATE VIEW pg_stat_progress_vacuum_index AS
+	SELECT
+		S.pid AS pid, S.param9 AS leader_pid,
+		S.param8 AS indrelid, S.param10 vacuum_cycle_ordinal_position,
+		S.param13 index_rows_vacuumed
+	FROM pg_stat_get_progress_info('VACUUM') AS S
+		LEFT JOIN pg_database D ON S.datid = D.oid
+	WHERE S.param8 > 0; -- show vacuum progress for a PID that has advertised an index relid
 
 CREATE VIEW pg_stat_progress_cluster AS
     SELECT
diff --git a/src/backend/commands/vacuumparallel.c b/src/backend/commands/vacuumparallel.c
index 0d61c8ec74..983fc823bb 100644
--- a/src/backend/commands/vacuumparallel.c
+++ b/src/backend/commands/vacuumparallel.c
@@ -35,6 +35,7 @@
 #include "storage/bufmgr.h"
 #include "tcop/tcopprot.h"
 #include "utils/lsyscache.h"
+#include "commands/progress.h"
 
 /*
  * DSM keys for parallel vacuum.  Unlike other parallel execution code, since
@@ -206,7 +207,7 @@ static void parallel_vacuum_process_all_indexes(ParallelVacuumState *pvs, int nu
 static void parallel_vacuum_process_safe_indexes(ParallelVacuumState *pvs);
 static void parallel_vacuum_process_unsafe_indexes(ParallelVacuumState *pvs);
 static void parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation indrel,
-											  PVIndStats *indstats);
+											  PVIndStats *indstats, int ordinal_position);
 static bool parallel_vacuum_index_is_parallel_safe(Relation indrel, int num_index_scans,
 												   bool vacuum);
 static void parallel_vacuum_error_callback(void *arg);
@@ -754,7 +755,7 @@ parallel_vacuum_process_safe_indexes(ParallelVacuumState *pvs)
 			continue;
 
 		/* Do vacuum or cleanup of the index */
-		parallel_vacuum_process_one_index(pvs, pvs->indrels[idx], indstats);
+		parallel_vacuum_process_one_index(pvs, pvs->indrels[idx], indstats, idx + 1);
 	}
 
 	/*
@@ -795,7 +796,7 @@ parallel_vacuum_process_unsafe_indexes(ParallelVacuumState *pvs)
 			continue;
 
 		/* Do vacuum or cleanup of the index */
-		parallel_vacuum_process_one_index(pvs, pvs->indrels[i], indstats);
+		parallel_vacuum_process_one_index(pvs, pvs->indrels[i], indstats, i + 1);
 	}
 
 	/*
@@ -814,7 +815,7 @@ parallel_vacuum_process_unsafe_indexes(ParallelVacuumState *pvs)
  */
 static void
 parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation indrel,
-								  PVIndStats *indstats)
+								  PVIndStats *indstats, int ordinal_position)
 {
 	IndexBulkDeleteResult *istat = NULL;
 	IndexBulkDeleteResult *istat_res;
@@ -842,7 +843,14 @@ parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation indrel,
 	switch (indstats->status)
 	{
 		case PARALLEL_INDVAC_STATUS_NEED_BULKDELETE:
+			/* Advertise the index that is being vacuumed and the vacuum order of the index */
+			pgstat_progress_update_param(PROGRESS_VACUUM_CURRENT_INDRELID, indrel->rd_id);
+			pgstat_progress_update_param(PROGRESS_VACUUM_INDEX_ORDINAL, ordinal_position);
+
 			istat_res = vac_bulkdel_one_index(&ivinfo, istat, pvs->dead_items);
+
+			/* Advertise that we are done vacuuming the index */
+			pgstat_progress_update_param(PROGRESS_VACUUM_CURRENT_INDRELID, 0);
 			break;
 		case PARALLEL_INDVAC_STATUS_NEED_CLEANUP:
 			istat_res = vac_cleanup_one_index(&ivinfo, istat);
@@ -942,6 +950,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
 	int			nindexes;
 	char	   *sharedquery;
 	ErrorContextCallback errcallback;
+	PGPROC     *leader = MyProc->lockGroupLeader;
 
 	/*
 	 * A parallel vacuum worker must have only PROC_IN_VACUUM flag since we
@@ -965,6 +974,10 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
 	 */
 	rel = table_open(shared->relid, ShareUpdateExclusiveLock);
 
+	pgstat_progress_start_command(PROGRESS_COMMAND_VACUUM,
+								  RelationGetRelid(rel));
+	pgstat_progress_update_param(PROGRESS_VACUUM_LEADER_PID, leader->pid);
+
 	/*
 	 * Open all indexes. indrels are sorted in order by OID, which should be
 	 * matched to the leader's one.
@@ -1035,6 +1048,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
 	vac_close_indexes(nindexes, indrels, RowExclusiveLock);
 	table_close(rel, ShareUpdateExclusiveLock);
 	FreeAccessStrategy(pvs.bstrategy);
+	pgstat_progress_end_command();
 }
 
 /*
diff --git a/src/backend/utils/misc/pg_rusage.c b/src/backend/utils/misc/pg_rusage.c
index bb5d9e7c85..14362d7d65 100644
--- a/src/backend/utils/misc/pg_rusage.c
+++ b/src/backend/utils/misc/pg_rusage.c
@@ -19,6 +19,27 @@
 
 #include "utils/pg_rusage.h"
 
+void rusage_adjust(const PGRUsage *ru0, PGRUsage *ru1);
+
+void
+rusage_adjust(const PGRUsage *ru0, PGRUsage *ru1)
+{
+	if (ru1->tv.tv_usec < ru0->tv.tv_usec)
+	{
+		ru1->tv.tv_sec--;
+		ru1->tv.tv_usec += 1000000;
+	}
+	if (ru1->ru.ru_stime.tv_usec < ru0->ru.ru_stime.tv_usec)
+	{
+		ru1->ru.ru_stime.tv_sec--;
+		ru1->ru.ru_stime.tv_usec += 1000000;
+	}
+	if (ru1->ru.ru_utime.tv_usec < ru0->ru.ru_utime.tv_usec)
+	{
+		ru1->ru.ru_utime.tv_sec--;
+		ru1->ru.ru_utime.tv_usec += 1000000;
+	}
+}
 
 /*
  * Initialize usage snapshot.
@@ -44,21 +65,7 @@ pg_rusage_show(const PGRUsage *ru0)
 
 	pg_rusage_init(&ru1);
 
-	if (ru1.tv.tv_usec < ru0->tv.tv_usec)
-	{
-		ru1.tv.tv_sec--;
-		ru1.tv.tv_usec += 1000000;
-	}
-	if (ru1.ru.ru_stime.tv_usec < ru0->ru.ru_stime.tv_usec)
-	{
-		ru1.ru.ru_stime.tv_sec--;
-		ru1.ru.ru_stime.tv_usec += 1000000;
-	}
-	if (ru1.ru.ru_utime.tv_usec < ru0->ru.ru_utime.tv_usec)
-	{
-		ru1.ru.ru_utime.tv_sec--;
-		ru1.ru.ru_utime.tv_usec += 1000000;
-	}
+	rusage_adjust(ru0, &ru1);
 
 	snprintf(result, sizeof(result),
 			 _("CPU: user: %d.%02d s, system: %d.%02d s, elapsed: %d.%02d s"),
@@ -71,3 +78,22 @@ pg_rusage_show(const PGRUsage *ru0)
 
 	return result;
 }
+
+/*
+ * Compute elapsed time since ru0 usage snapshot, and return the
+ * value in Milliseconds.
+ */
+const int64
+pg_rusage_elapsed_ms(const PGRUsage *ru0)
+{
+	static int64 result;
+	PGRUsage    ru1;
+
+	pg_rusage_init(&ru1);
+
+	rusage_adjust(ru0, &ru1);
+
+	result = (int64) (ru1.tv.tv_sec - ru0->tv.tv_sec) * 1000 + ((int64) (ru1.tv.tv_usec - ru0->tv.tv_usec) / 1000);
+
+	return result;
+}
diff --git a/src/include/commands/progress.h b/src/include/commands/progress.h
index d7bf16368b..1d25a6b345 100644
--- a/src/include/commands/progress.h
+++ b/src/include/commands/progress.h
@@ -18,13 +18,19 @@
 #define PROGRESS_H
 
 /* Progress parameters for (lazy) vacuum */
-#define PROGRESS_VACUUM_PHASE					0
-#define PROGRESS_VACUUM_TOTAL_HEAP_BLKS			1
-#define PROGRESS_VACUUM_HEAP_BLKS_SCANNED		2
-#define PROGRESS_VACUUM_HEAP_BLKS_VACUUMED		3
-#define PROGRESS_VACUUM_NUM_INDEX_VACUUMS		4
-#define PROGRESS_VACUUM_MAX_DEAD_TUPLES			5
-#define PROGRESS_VACUUM_NUM_DEAD_TUPLES			6
+#define PROGRESS_VACUUM_PHASE					 0
+#define PROGRESS_VACUUM_TOTAL_HEAP_BLKS			 1
+#define PROGRESS_VACUUM_HEAP_BLKS_SCANNED		 2
+#define PROGRESS_VACUUM_HEAP_BLKS_VACUUMED		 3
+#define PROGRESS_VACUUM_NUM_INDEX_VACUUMS		 4
+#define PROGRESS_VACUUM_MAX_DEAD_TUPLES			 5
+#define PROGRESS_VACUUM_NUM_DEAD_TUPLES			 6
+#define PROGRESS_VACUUM_CURRENT_INDRELID         7
+#define PROGRESS_VACUUM_LEADER_PID               8
+#define PROGRESS_VACUUM_INDEX_ORDINAL			 9
+#define PROGRESS_VACUUM_TOTAL_INDEX_VACUUM		 10
+#define PROGRESS_VACUUM_MAX_CYCLE_TIME			 11
+#define PROGRESS_VACUUM_DEAD_TUPLES_VACUUMED	 12
 
 /* Phases of vacuum (as advertised via PROGRESS_VACUUM_PHASE) */
 #define PROGRESS_VACUUM_PHASE_SCAN_HEAP			1
diff --git a/src/include/utils/pg_rusage.h b/src/include/utils/pg_rusage.h
index c0def804ee..026f823155 100644
--- a/src/include/utils/pg_rusage.h
+++ b/src/include/utils/pg_rusage.h
@@ -33,5 +33,6 @@ typedef struct PGRUsage
 
 extern void pg_rusage_init(PGRUsage *ru0);
 extern const char *pg_rusage_show(const PGRUsage *ru0);
+extern const int64 pg_rusage_elapsed_ms(const PGRUsage *ru0);
 
 #endif							/* PG_RUSAGE_H */
-- 
2.32.0



view thread (44+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected], [email protected]
  Subject: Re: Add index scan progress to pg_stat_progress_vacuum
  In-Reply-To: <[email protected]>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox