mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Add progress reporting for CLUSTER and VACUUM FULL.
This uses the same progress reporting infrastructure added in commit
c16dc1aca5
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
This commit is contained in:
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -36,10 +36,12 @@
|
||||
#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
|
||||
|
@ -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),
|
||||
|
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 201903221
|
||||
#define CATALOG_VERSION_NO 201903251
|
||||
|
||||
#endif
|
||||
|
@ -34,4 +34,27 @@
|
||||
#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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
Reference in New Issue
Block a user