diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index dcaea7135fb..3eea215b852 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -698,6 +698,7 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap, Datum *values; bool *isnull; BufferHeapTupleTableSlot *hslot; + BlockNumber prev_cblock = InvalidBlockNumber; /* Remember if it's a system catalog */ is_system_catalog = IsSystemRelation(OldHeap); @@ -793,14 +794,38 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap, else { if (!table_scan_getnextslot(tableScan, ForwardScanDirection, slot)) + { + /* + * If the last pages of the scan were empty, we would go to + * the next phase while heap_blks_scanned != heap_blks_total. + * Instead, to ensure that heap_blks_scanned is equivalent to + * total_heap_blks after the table scan phase, this parameter + * is manually updated to the correct value when the table + * scan finishes. + */ + pgstat_progress_update_param(PROGRESS_CLUSTER_HEAP_BLKS_SCANNED, + heapScan->rs_nblocks); break; + } /* * In scan-and-sort mode and also VACUUM FULL, set heap blocks * scanned + * + * Note that heapScan may start at an offset and wrap around, i.e. + * rs_startblock may be >0, and rs_cblock may end with a number + * below rs_startblock. To prevent showing this wraparound to the + * user, we offset rs_cblock by rs_startblock (modulo rs_nblocks). */ - pgstat_progress_update_param(PROGRESS_CLUSTER_HEAP_BLKS_SCANNED, - heapScan->rs_cblock + 1); + if (prev_cblock != heapScan->rs_cblock) + { + pgstat_progress_update_param(PROGRESS_CLUSTER_HEAP_BLKS_SCANNED, + (heapScan->rs_cblock + + heapScan->rs_nblocks - + heapScan->rs_startblock + ) % heapScan->rs_nblocks + 1); + prev_cblock = heapScan->rs_cblock; + } } tuple = ExecFetchSlotHeapTuple(slot, false, NULL);