Skip to content

Commit cafaf38

Browse files
jkavalikCommitfest Bot
authored andcommitted
ALTER TABLE progress support
1 parent 9106904 commit cafaf38

File tree

7 files changed

+83
-6
lines changed

7 files changed

+83
-6
lines changed

doc/src/sgml/monitoring.sgml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser
400400
<row>
401401
<entry><structname>pg_stat_progress_cluster</structname><indexterm><primary>pg_stat_progress_cluster</primary></indexterm></entry>
402402
<entry>One row for each backend running
403-
<command>CLUSTER</command> or <command>VACUUM FULL</command>, showing current progress.
403+
<command>CLUSTER</command>, <command>VACUUM FULL</command> or <command>ALTER TABLE</command>, showing current progress.
404404
See <xref linkend="cluster-progress-reporting"/>.
405405
</entry>
406406
</row>
@@ -5586,7 +5586,7 @@ FROM pg_stat_get_backend_idset() AS backendid;
55865586
<productname>PostgreSQL</productname> has the ability to report the progress of
55875587
certain commands during command execution. Currently, the only commands
55885588
which support progress reporting are <command>ANALYZE</command>,
5589-
<command>CLUSTER</command>,
5589+
<command>CLUSTER</command>, <command>ALTER TABLE</command>,
55905590
<command>CREATE INDEX</command>, <command>VACUUM</command>,
55915591
<command>COPY</command>,
55925592
and <xref linkend="protocol-replication-base-backup"/> (i.e., replication
@@ -5832,8 +5832,9 @@ FROM pg_stat_get_backend_idset() AS backendid;
58325832
</indexterm>
58335833

58345834
<para>
5835-
Whenever <command>CLUSTER</command> or <command>VACUUM FULL</command> is
5836-
running, the <structname>pg_stat_progress_cluster</structname> view will
5835+
Whenever <command>CLUSTER</command>, <command>VACUUM FULL</command>
5836+
or <command>ALTER TABLE</command> is running,
5837+
the <structname>pg_stat_progress_cluster</structname> view will
58375838
contain a row for each backend that is currently running either command.
58385839
The tables below describe the information that will be reported and
58395840
provide information about how to interpret it.
@@ -5895,7 +5896,7 @@ FROM pg_stat_get_backend_idset() AS backendid;
58955896
<structfield>command</structfield> <type>text</type>
58965897
</para>
58975898
<para>
5898-
The command that is running. Either <literal>CLUSTER</literal> or <literal>VACUUM FULL</literal>.
5899+
The command that is running. Either <literal>CLUSTER</literal>, <literal>VACUUM FULL</literal> or <literal>ALTER TABLE</literal>.
58995900
</para></entry>
59005901
</row>
59015902

@@ -5978,7 +5979,7 @@ FROM pg_stat_get_backend_idset() AS backendid;
59785979
</table>
59795980

59805981
<table id="cluster-phases">
5981-
<title>CLUSTER and VACUUM FULL Phases</title>
5982+
<title>CLUSTER, VACUUM FULL and ALTER TABLE Phases</title>
59825983
<tgroup cols="2">
59835984
<colspec colname="col1" colwidth="1*"/>
59845985
<colspec colname="col2" colwidth="2*"/>

doc/src/sgml/ref/alter_table.sgml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1869,6 +1869,16 @@ ALTER TABLE measurement
18691869
</para>
18701870
</refsect1>
18711871

1872+
<refsect1>
1873+
<title>Progress Reporting</title>
1874+
<para>
1875+
When an <command>ALTER TABLE</command> operation rewrites the table, progress
1876+
can be monitored via the <literal>pg_stat_progress_cluster</literal> system view,
1877+
similar to <command>CLUSTER</command> and <command>VACUUM FULL</command> commands.
1878+
The command type will be reported as <literal>'ALTER TABLE'</literal>.
1879+
</para>
1880+
</refsect1>
1881+
18721882
<refsect1>
18731883
<title>See Also</title>
18741884

src/backend/catalog/storage.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "access/xlogutils.h"
2727
#include "catalog/storage.h"
2828
#include "catalog/storage_xlog.h"
29+
#include "commands/progress.h"
2930
#include "miscadmin.h"
3031
#include "pgstat.h"
3132
#include "storage/bulk_write.h"
@@ -505,6 +506,9 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst,
505506

506507
nblocks = smgrnblocks(src, forkNum);
507508

509+
/* Report expected number of block to copy */
510+
pgstat_progress_update_param(PROGRESS_CLUSTER_TOTAL_HEAP_BLKS, nblocks);
511+
508512
for (blkno = 0; blkno < nblocks; blkno++)
509513
{
510514
BulkWriteBuffer buf;
@@ -556,6 +560,9 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst,
556560
* page including any unused space.
557561
*/
558562
smgr_bulk_write(bulkstate, blkno, buf, false);
563+
564+
/* Update progress report */
565+
pgstat_progress_update_param(PROGRESS_CLUSTER_HEAP_BLKS_SCANNED, blkno + 1);
559566
}
560567
smgr_bulk_finish(bulkstate);
561568
}

src/backend/catalog/system_views.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,6 +1277,7 @@ CREATE VIEW pg_stat_progress_cluster AS
12771277
S.relid AS relid,
12781278
CASE S.param1 WHEN 1 THEN 'CLUSTER'
12791279
WHEN 2 THEN 'VACUUM FULL'
1280+
WHEN 3 THEN 'ALTER TABLE'
12801281
END AS command,
12811282
CASE S.param2 WHEN 0 THEN 'initializing'
12821283
WHEN 1 THEN 'seq scanning heap'
@@ -1286,6 +1287,7 @@ CREATE VIEW pg_stat_progress_cluster AS
12861287
WHEN 5 THEN 'swapping relation files'
12871288
WHEN 6 THEN 'rebuilding index'
12881289
WHEN 7 THEN 'performing final cleanup'
1290+
WHEN 8 THEN 'checking foreign key constraints'
12891291
END AS phase,
12901292
CAST(S.param3 AS oid) AS cluster_index_relid,
12911293
S.param4 AS heap_tuples_scanned,

src/backend/commands/tablecmds.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
#include "commands/comment.h"
6161
#include "commands/defrem.h"
6262
#include "commands/event_trigger.h"
63+
#include "commands/progress.h"
6364
#include "commands/sequence.h"
6465
#include "commands/tablecmds.h"
6566
#include "commands/tablespace.h"
@@ -5841,6 +5842,10 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
58415842
if (!RELKIND_HAS_STORAGE(tab->relkind))
58425843
continue;
58435844

5845+
/* Start progress reporting */
5846+
pgstat_progress_start_command(PROGRESS_COMMAND_CLUSTER, tab->relid);
5847+
pgstat_progress_update_param(PROGRESS_CLUSTER_COMMAND, PROGRESS_CLUSTER_COMMAND_ALTER_TABLE);
5848+
58445849
/*
58455850
* If we change column data types, the operation has to be propagated
58465851
* to tables that use this table's rowtype as a column type.
@@ -5981,6 +5986,9 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
59815986
*/
59825987
ATRewriteTable(tab, OIDNewHeap);
59835988

5989+
/* Report that we are now swapping relation files */
5990+
pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE,
5991+
PROGRESS_CLUSTER_PHASE_SWAP_REL_FILES);
59845992
/*
59855993
* Swap the physical files of the old and new heaps, then rebuild
59865994
* indexes and discard the old heap. We can use RecentXmin for
@@ -6092,6 +6100,10 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
60926100
table_close(rel, NoLock);
60936101
}
60946102

6103+
/* Report that we are now doing clean up */
6104+
pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE,
6105+
PROGRESS_CLUSTER_PHASE_FINAL_CLEANUP);
6106+
60956107
/* Finally, run any afterStmts that were queued up */
60966108
foreach(ltab, *wqueue)
60976109
{
@@ -6106,6 +6118,8 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
61066118
CommandCounterIncrement();
61076119
}
61086120
}
6121+
6122+
pgstat_progress_end_command();
61096123
}
61106124

61116125
/*
@@ -6131,6 +6145,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
61316145
BulkInsertState bistate;
61326146
int ti_options;
61336147
ExprState *partqualstate = NULL;
6148+
int64 numTuples = 0;
61346149

61356150
/*
61366151
* Open the relation(s). We have surely already locked the existing
@@ -6140,6 +6155,9 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
61406155
oldTupDesc = tab->oldDesc;
61416156
newTupDesc = RelationGetDescr(oldrel); /* includes all mods */
61426157

6158+
/* Update progress reporting - we are actually scanning and possibly rewriting the table */
6159+
pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE, PROGRESS_CLUSTER_PHASE_SEQ_SCAN_HEAP);
6160+
61436161
if (OidIsValid(OIDNewHeap))
61446162
{
61456163
Assert(CheckRelationOidLockedByMe(OIDNewHeap, AccessExclusiveLock,
@@ -6247,6 +6265,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
62476265
TupleTableSlot *oldslot;
62486266
TupleTableSlot *newslot;
62496267
TableScanDesc scan;
6268+
HeapScanDesc heapScan;
62506269
MemoryContext oldCxt;
62516270
List *dropped_attrs = NIL;
62526271
ListCell *lc;
@@ -6346,6 +6365,9 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
63466365
*/
63476366
snapshot = RegisterSnapshot(GetLatestSnapshot());
63486367
scan = table_beginscan(oldrel, snapshot, 0, NULL);
6368+
heapScan = (HeapScanDesc) scan;
6369+
pgstat_progress_update_param(PROGRESS_CLUSTER_TOTAL_HEAP_BLKS,
6370+
heapScan->rs_nblocks);
63496371

63506372
/*
63516373
* Switch to per-tuple memory context and reset it for each tuple
@@ -6356,6 +6378,13 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
63566378
while (table_scan_getnextslot(scan, ForwardScanDirection, oldslot))
63576379
{
63586380
TupleTableSlot *insertslot;
6381+
pgstat_progress_update_param(PROGRESS_CLUSTER_HEAP_BLKS_SCANNED,
6382+
(heapScan->rs_cblock +
6383+
heapScan->rs_nblocks -
6384+
heapScan->rs_startblock
6385+
) % heapScan->rs_nblocks + 1);
6386+
pgstat_progress_update_param(PROGRESS_CLUSTER_HEAP_TUPLES_SCANNED,
6387+
++numTuples);
63596388

63606389
if (tab->rewrite > 0)
63616390
{
@@ -6404,6 +6433,9 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
64046433

64056434
ExecStoreVirtualTuple(newslot);
64066435

6436+
pgstat_progress_update_param(PROGRESS_CLUSTER_HEAP_TUPLES_WRITTEN,
6437+
numTuples);
6438+
64076439
/*
64086440
* Now, evaluate any expressions whose inputs come from the
64096441
* new tuple. We assume these columns won't reference each
@@ -6524,6 +6556,8 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
65246556

65256557
CHECK_FOR_INTERRUPTS();
65266558
}
6559+
pgstat_progress_update_param(PROGRESS_CLUSTER_HEAP_BLKS_SCANNED,
6560+
heapScan->rs_nblocks);
65276561

65286562
MemoryContextSwitchTo(oldCxt);
65296563
table_endscan(scan);
@@ -13692,10 +13726,12 @@ validateForeignKeyConstraint(char *conname,
1369213726
{
1369313727
TupleTableSlot *slot;
1369413728
TableScanDesc scan;
13729+
HeapScanDesc heapScan;
1369513730
Trigger trig = {0};
1369613731
Snapshot snapshot;
1369713732
MemoryContext oldcxt;
1369813733
MemoryContext perTupCxt;
13734+
int64 numTuples = 0;
1369913735

1370013736
ereport(DEBUG1,
1370113737
(errmsg_internal("validating foreign key constraint \"%s\"", conname)));
@@ -13714,6 +13750,10 @@ validateForeignKeyConstraint(char *conname,
1371413750
trig.tginitdeferred = false;
1371513751
/* we needn't fill in remaining fields */
1371613752

13753+
/* Report that we are now checking foreign keys */
13754+
pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE,
13755+
PROGRESS_CLUSTER_PHASE_CHECK_FKEYS);
13756+
1371713757
/*
1371813758
* See if we can do it with a single LEFT JOIN query. A false result
1371913759
* indicates we must proceed with the fire-the-trigger method. We can't do
@@ -13731,6 +13771,7 @@ validateForeignKeyConstraint(char *conname,
1373113771
snapshot = RegisterSnapshot(GetLatestSnapshot());
1373213772
slot = table_slot_create(rel, NULL);
1373313773
scan = table_beginscan(rel, snapshot, 0, NULL);
13774+
heapScan = (HeapScanDesc) scan;
1373413775

1373513776
perTupCxt = AllocSetContextCreate(CurrentMemoryContext,
1373613777
"validateForeignKeyConstraint",
@@ -13766,6 +13807,14 @@ validateForeignKeyConstraint(char *conname,
1376613807
RI_FKey_check_ins(fcinfo);
1376713808

1376813809
MemoryContextReset(perTupCxt);
13810+
13811+
pgstat_progress_update_param(PROGRESS_CLUSTER_HEAP_BLKS_SCANNED,
13812+
(heapScan->rs_cblock +
13813+
heapScan->rs_nblocks -
13814+
heapScan->rs_startblock
13815+
) % heapScan->rs_nblocks + 1);
13816+
pgstat_progress_update_param(PROGRESS_CLUSTER_HEAP_TUPLES_SCANNED,
13817+
++numTuples);
1376913818
}
1377013819

1377113820
MemoryContextSwitchTo(oldcxt);
@@ -16856,6 +16905,10 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
1685616905
*/
1685716906
rel = relation_open(tableOid, lockmode);
1685816907

16908+
/* Update progress reporting - we are copying the table */
16909+
pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE, PROGRESS_CLUSTER_PHASE_WRITE_NEW_HEAP);
16910+
pgstat_progress_update_param(PROGRESS_CLUSTER_TOTAL_HEAP_BLKS, RelationGetNumberOfBlocks(rel));
16911+
1685916912
/* Check first if relation can be moved to new tablespace */
1686016913
if (!CheckRelationTableSpaceMove(rel, newTableSpace))
1686116914
{

src/include/commands/progress.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,12 @@
7474
#define PROGRESS_CLUSTER_PHASE_SWAP_REL_FILES 5
7575
#define PROGRESS_CLUSTER_PHASE_REBUILD_INDEX 6
7676
#define PROGRESS_CLUSTER_PHASE_FINAL_CLEANUP 7
77+
#define PROGRESS_CLUSTER_PHASE_CHECK_FKEYS 8
7778

7879
/* Commands of PROGRESS_CLUSTER */
7980
#define PROGRESS_CLUSTER_COMMAND_CLUSTER 1
8081
#define PROGRESS_CLUSTER_COMMAND_VACUUM_FULL 2
82+
#define PROGRESS_CLUSTER_COMMAND_ALTER_TABLE 3 /* New command type */
8183

8284
/* Progress parameters for CREATE INDEX */
8385
/* 3, 4 and 5 reserved for "waitfor" metrics */

src/test/regress/expected/rules.out

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2001,6 +2001,7 @@ pg_stat_progress_cluster| SELECT s.pid,
20012001
CASE s.param1
20022002
WHEN 1 THEN 'CLUSTER'::text
20032003
WHEN 2 THEN 'VACUUM FULL'::text
2004+
WHEN 3 THEN 'ALTER TABLE'::text
20042005
ELSE NULL::text
20052006
END AS command,
20062007
CASE s.param2
@@ -2012,6 +2013,7 @@ pg_stat_progress_cluster| SELECT s.pid,
20122013
WHEN 5 THEN 'swapping relation files'::text
20132014
WHEN 6 THEN 'rebuilding index'::text
20142015
WHEN 7 THEN 'performing final cleanup'::text
2016+
WHEN 8 THEN 'checking foreign key constraints'::text
20152017
ELSE NULL::text
20162018
END AS phase,
20172019
(s.param3)::oid AS cluster_index_relid,

0 commit comments

Comments
 (0)