From 081d8dd086a66c65784b1b30d9713f906346439e Mon Sep 17 00:00:00 2001
From: Justin Pryzby <pryzbyj@telsasoft.com>
Date: Sun, 16 Feb 2020 20:25:13 -0600
Subject: [PATCH v28 4/5] add callback for truncation

---
 src/backend/access/heap/vacuumlazy.c | 56 ++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index feee066722..b8ac28d609 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -275,6 +275,8 @@ typedef enum
 	VACUUM_ERRCB_PHASE_VACUUM_INDEX,
 	VACUUM_ERRCB_PHASE_VACUUM_HEAP,
 	VACUUM_ERRCB_PHASE_INDEX_CLEANUP,
+	VACUUM_ERRCB_PHASE_TRUNCATE,
+	VACUUM_ERRCB_PHASE_TRUNCATE_PREFETCH,
 } errcb_phase;
 
 typedef struct LVRelStats
@@ -2535,6 +2537,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
 	BlockNumber old_rel_pages = vacrelstats->rel_pages;
 	BlockNumber new_rel_pages;
 	int			lock_retry;
+	LVRelStats olderrcbarg;
 
 	/* Report that we are now truncating */
 	pgstat_progress_update_param(PROGRESS_VACUUM_PHASE,
@@ -2620,11 +2623,24 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
 			return;
 		}
 
+		/* Setup error traceback support for ereport() */
+		olderrcbarg = *vacrelstats;
+		update_vacuum_error_cbarg(vacrelstats,
+				VACUUM_ERRCB_PHASE_TRUNCATE, new_rel_pages, NULL,
+				false);
+
 		/*
 		 * Okay to truncate.
 		 */
 		RelationTruncate(onerel, new_rel_pages);
 
+		/* Clear the error traceback phase */
+		update_vacuum_error_cbarg(vacrelstats,
+								  olderrcbarg.phase,
+								  olderrcbarg.blkno,
+								  olderrcbarg.indname,
+								  true);
+
 		/*
 		 * We can release the exclusive lock as soon as we have truncated.
 		 * Other backends can't safely access the relation until they have
@@ -2664,6 +2680,7 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats)
 	BlockNumber blkno;
 	BlockNumber prefetchedUntil;
 	instr_time	starttime;
+	LVRelStats	olderrcbarg;
 
 	/* Initialize the starttime if we check for conflicting lock requests */
 	INSTR_TIME_SET_CURRENT(starttime);
@@ -2678,6 +2695,13 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats)
 	StaticAssertStmt((PREFETCH_SIZE & (PREFETCH_SIZE - 1)) == 0,
 					 "prefetch size must be power of 2");
 	prefetchedUntil = InvalidBlockNumber;
+
+	/* Setup error traceback support for ereport() */
+	olderrcbarg = *vacrelstats;
+	update_vacuum_error_cbarg(vacrelstats,
+			VACUUM_ERRCB_PHASE_TRUNCATE_PREFETCH, blkno, NULL,
+			false);
+
 	while (blkno > vacrelstats->nonempty_pages)
 	{
 		Buffer		buf;
@@ -2736,6 +2760,11 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats)
 			prefetchStart = blkno & ~(PREFETCH_SIZE - 1);
 			for (pblkno = prefetchStart; pblkno <= blkno; pblkno++)
 			{
+				/* Setup error traceback support for ereport() */
+				update_vacuum_error_cbarg(vacrelstats,
+						VACUUM_ERRCB_PHASE_TRUNCATE_PREFETCH, blkno, NULL,
+						NULL);
+
 				PrefetchBuffer(onerel, MAIN_FORKNUM, pblkno);
 				CHECK_FOR_INTERRUPTS();
 			}
@@ -2783,9 +2812,24 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats)
 
 		/* Done scanning if we found a tuple here */
 		if (hastup)
+		{
+			/* Clear the error traceback phase */
+			update_vacuum_error_cbarg(vacrelstats,
+									  olderrcbarg.phase,
+									  olderrcbarg.blkno,
+									  olderrcbarg.indname,
+									  true);
 			return blkno + 1;
+		}
 	}
 
+	/* Clear the error traceback phase */
+	update_vacuum_error_cbarg(vacrelstats,
+							  olderrcbarg.phase,
+							  olderrcbarg.blkno,
+							  olderrcbarg.indname,
+							  true);
+
 	/*
 	 * If we fall out of the loop, all the previously-thought-to-be-empty
 	 * pages still are; we need not bother to look at the last known-nonempty
@@ -3522,6 +3566,18 @@ vacuum_error_callback(void *arg)
 					   cbarg->indname, cbarg->relnamespace, cbarg->relname);
 			break;
 
+		case VACUUM_ERRCB_PHASE_TRUNCATE:
+			if (BlockNumberIsValid(cbarg->blkno))
+				errcontext("while truncating relation \"%s.%s\" to %u blocks",
+						cbarg->relnamespace, cbarg->relname, cbarg->blkno);
+			break;
+
+		case VACUUM_ERRCB_PHASE_TRUNCATE_PREFETCH:
+			if (BlockNumberIsValid(cbarg->blkno))
+				errcontext("while prefetching block %u to truncate relation \"%s.%s\"",
+						cbarg->blkno, cbarg->relnamespace, cbarg->relname);
+			break;
+
 		case VACUUM_ERRCB_PHASE_UNKNOWN:
 		default:
 			return;				/* do nothing; the cbarg may not be
-- 
2.17.0

