From: Justin Pryzby <pryzby@telsasoft.com>
To: Masahiko Sawada <masahiko.sawada@2ndquadrant.com>
Cc: Amit Kapila <amit.kapila16@gmail.com>
Cc: Alvaro Herrera <alvherre@2ndquadrant.com>
Cc: Andres Freund <andres@anarazel.de>
Cc: Michael Paquier <michael@paquier.xyz>
Cc: pgsql-hackers@postgresql.org
Subject: Re: error context for vacuum to include block number
Date: Thu, 26 Mar 2020 17:17:52 -0500
Message-ID: <20200326221752.GR17431@telsasoft.com> (raw)
In-Reply-To: <20200326150457.GB17431@telsasoft.com>
References: <20200325101229.GR21443@telsasoft.com>
<CAA4eK1KwcMWa7Jwewh48xC9o9pExzd=CuRuox94+AHvYr3F7Qg@mail.gmail.com>
<CA+fd4k6-zFG=mvkZzgsLQZ3v+df5Bk_0d8tpSzcRV0u40dM0rw@mail.gmail.com>
<20200325124155.GU21443@telsasoft.com>
<CAA4eK1+=ToXurzjOcPyQ4j6Vz2nG2C-cUdg=yZoUpN+g1k5m6w@mail.gmail.com>
<20200326044115.GB28385@telsasoft.com>
<CAA4eK1LBtp+qpsz8uR-oj2h6jzhLEVo9TEdm46anKM-n=8nS0g@mail.gmail.com>
<CAA4eK1L33gvQ1z-CHctzTWng2HfmFn0cDJif_mpBOvG47Mymow@mail.gmail.com>
<CA+fd4k61uPzeAWT1EZOwPWq7DkhgVTrC_wmUNCzVW+MbP9Wjfg@mail.gmail.com>
<20200326150457.GB17431@telsasoft.com>
On Thu, Mar 26, 2020 at 10:04:57AM -0500, Justin Pryzby wrote:
> Does that address your comment ?
I hope so.
> > I'm not sure why "free_oldindname" is necessary. Since we initialize
> > vacrelstats->indname with NULL and revert the callback arguments at
> > the end of functions that needs update them, vacrelstats->indname is
> > NULL at the beginning of lazy_vacuum_index() and lazy_cleanup_index().
> > And we make a copy of index name in update_vacuum_error_cbarg(). So I
> > think we can pfree the old index name if errcbarg->indname is not NULL.
>
> We want to avoid doing this:
> olderrcbarg = *vacrelstats // saves a pointer
> update_vacuum_error_cbarg(... NULL); // frees the pointer and sets indname to NULL
> update_vacuum_error_cbarg(... olderrcbarg.oldindnam) // puts back the pointer, which has been freed
> // hit an error, and the callback accesses the pfreed pointer
>
> I think that's only an issue for lazy_vacuum_index().
>
> And I think you're right: we only save state when the calling function has a
> indname=NULL, so we never "put back" a non-NULL indname. We go from having a
> indname=NULL at lazy_scan_heap to not not-NULL at lazy_vacuum_index, and never
> the other way around. So once we've "reverted back", 1) the pointer is null;
> and, 2) the callback function doesn't access it for the previous/reverted phase
> anyway.
I removed the free_oldindname argument.
> Hm, I was just wondering what happens if an error happens *during*
> update_vacuum_error_cbarg(). It seems like if we set
> errcbarg->phase=VACUUM_INDEX before setting errcbarg->indname=indname, then an
> error would cause a crash. And if we pfree and set indname before phase, it'd
> be a problem when going from an index phase to non-index phase. So maybe we
> have to set errcbarg->phase=VACUUM_ERRCB_PHASE_UNKNOWN while in the function,
> and errcbarg->phase=phase last.
And addressed that.
Also, I realized that lazy_cleanup_index has an early "return", so the "Revert
back" was ineffective. We talked about how that wasn't needed, since we never
go back to a previous phase. Amit wanted to keep it there for consistency, but
I'd prefer to put any extra effort into calling out the special treatment
needed/given to lazy_vacuum_heap/index, rather than making everything
"consistent".
Amit: I also moved the TRUNCATE_HEAP bit back to truncate_heap(), since 1) it's
odd if we don't have anything in truncate_heap() about error reporting except
for "vacrelstats->blkno = blkno"; and, 2) it's nice to set the err callback arg
right after pgstat_progress, and outside of any loop. In previous versions, it
was within the loop, because it closely wrapped RelationTruncate() and
count_nondeletable_pages() - a previous version used separate phases.
--
Justin
Attachments:
[text/x-diff] v36-0001-Introduce-vacuum-errcontext-to-display-additiona.patch (21.4K, ../20200326221752.GR17431@telsasoft.com/2-v36-0001-Introduce-vacuum-errcontext-to-display-additiona.patch)
download | inline diff:
From bfc574979f85c0f0722d182ae8ae03097fb5f9c4 Mon Sep 17 00:00:00 2001
From: Justin Pryzby <pryzbyj@telsasoft.com>
Date: Thu, 12 Dec 2019 20:54:37 -0600
Subject: [PATCH v36 1/3] Introduce vacuum errcontext to display additional
information.
The additional information displayed will be block number for error
occurring while processing heap and index name for error occurring
while processing the index.
This will help us in diagnosing the problems that occur during a vacuum.
For ex. due to corruption (either caused by bad hardware or by some bug)
if we get some error while vacuuming, it can help us identify the block
in heap and or additional index information.
It sets up an error context callback to display additional information
with the error. During different phases of vacuum (heap scan, heap
vacuum, index vacuum, index clean up, heap truncate), we update the error
context callback to display appropriate information. We can extend it to
a bit more granular level like adding the phases for FSM operations or for
prefetching the blocks while truncating. However, I felt that it requires
adding many more error callback function calls and can make the code a bit
complex, so left those for now.
Author: Justin Pryzby, with few changes by Amit Kapila
Reviewed-by: Alvaro Herrera, Amit Kapila, Andres Freund, Michael Paquier
and Sawada Masahiko
Discussion: https://www.postgresql.org/message-id/20191120210600.GC30362@telsasoft.com
---
src/backend/access/heap/vacuumlazy.c | 240 ++++++++++++++++++++++++---
src/tools/pgindent/typedefs.list | 1 +
2 files changed, 216 insertions(+), 25 deletions(-)
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.cindex 03c43efc32..e98e6b45d3 100644--- a/src/backend/access/heap/vacuumlazy.c+++ b/src/backend/access/heap/vacuumlazy.c@@ -144,6 +144,17 @@
*/
#define ParallelVacuumIsActive(lps) PointerIsValid(lps)
+/* Phases of vacuum during which we report error context. */+typedef enum+{+ VACUUM_ERRCB_PHASE_UNKNOWN,+ VACUUM_ERRCB_PHASE_SCAN_HEAP,+ VACUUM_ERRCB_PHASE_VACUUM_INDEX,+ VACUUM_ERRCB_PHASE_VACUUM_HEAP,+ VACUUM_ERRCB_PHASE_INDEX_CLEANUP,+ VACUUM_ERRCB_PHASE_TRUNCATE+} VacErrCbPhase;+
/*
* LVDeadTuples stores the dead tuple TIDs collected during the heap scan.
* This is allocated in the DSM segment in parallel mode and in local memory
@@ -270,6 +281,8 @@ typedef struct LVParallelState
typedef struct LVRelStats
{
+ char *relnamespace;+ char *relname;
/* useindex = true means two-pass strategy; false means one-pass */
bool useindex;
/* Overall statistics about rel */
@@ -290,8 +303,12 @@ typedef struct LVRelStats
int num_index_scans;
TransactionId latestRemovedXid;
bool lock_waiter_detected;
-} LVRelStats;+ /* Used for error callback */+ char *indname;+ BlockNumber blkno; /* used only for heap operations */+ VacErrCbPhase phase;+} LVRelStats;
/* A few variables that don't seem worth passing around as parameters */
static int elevel = -1;
@@ -314,10 +331,10 @@ static void lazy_vacuum_all_indexes(Relation onerel, Relation *Irel,
LVRelStats *vacrelstats, LVParallelState *lps,
int nindexes);
static void lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats,
- LVDeadTuples *dead_tuples, double reltuples);+ LVDeadTuples *dead_tuples, double reltuples, LVRelStats *vacrelstats);
static void lazy_cleanup_index(Relation indrel,
IndexBulkDeleteResult **stats,
- double reltuples, bool estimated_count);+ double reltuples, bool estimated_count, LVRelStats *vacrelstats);
static int lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
int tupindex, LVRelStats *vacrelstats, Buffer *vmbuffer);
static bool should_attempt_truncation(VacuumParams *params,
@@ -337,13 +354,13 @@ static void lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult *
int nindexes);
static void parallel_vacuum_index(Relation *Irel, IndexBulkDeleteResult **stats,
LVShared *lvshared, LVDeadTuples *dead_tuples,
- int nindexes);+ int nindexes, LVRelStats *vacrelstats);
static void vacuum_indexes_leader(Relation *Irel, IndexBulkDeleteResult **stats,
LVRelStats *vacrelstats, LVParallelState *lps,
int nindexes);
static void vacuum_one_index(Relation indrel, IndexBulkDeleteResult **stats,
LVShared *lvshared, LVSharedIndStats *shared_indstats,
- LVDeadTuples *dead_tuples);+ LVDeadTuples *dead_tuples, LVRelStats *vacrelstats);
static void lazy_cleanup_all_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
LVRelStats *vacrelstats, LVParallelState *lps,
int nindexes);
@@ -361,6 +378,9 @@ static void end_parallel_vacuum(Relation *Irel, IndexBulkDeleteResult **stats,
LVParallelState *lps, int nindexes);
static LVSharedIndStats *get_indstats(LVShared *lvshared, int n);
static bool skip_parallel_vacuum_index(Relation indrel, LVShared *lvshared);
+static void vacuum_error_callback(void *arg);+static void update_vacuum_error_cbarg(LVRelStats *errcbarg, int phase,+ BlockNumber blkno, char *indname);
/*
@@ -394,6 +414,7 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
double new_live_tuples;
TransactionId new_frozen_xid;
MultiXactId new_min_multi;
+ ErrorContextCallback errcallback;
Assert(params != NULL);
Assert(params->index_cleanup != VACOPT_TERNARY_DEFAULT);
@@ -460,6 +481,10 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats));
+ vacrelstats->relnamespace = get_namespace_name(RelationGetNamespace(onerel));+ vacrelstats->relname = pstrdup(RelationGetRelationName(onerel));+ vacrelstats->indname = NULL;+ vacrelstats->phase = VACUUM_ERRCB_PHASE_UNKNOWN;
vacrelstats->old_rel_pages = onerel->rd_rel->relpages;
vacrelstats->old_live_tuples = onerel->rd_rel->reltuples;
vacrelstats->num_index_scans = 0;
@@ -471,6 +496,22 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
vacrelstats->useindex = (nindexes > 0 &&
params->index_cleanup == VACOPT_TERNARY_ENABLED);
+ /*+ * Setup error traceback support for ereport(). The idea is to set up an+ * error context callback to display additional information on any error+ * during a vacuum. During different phases of vacuum (heap scan, heap+ * vacuum, index vacuum, index clean up, heap truncate), we update the+ * error context callback to display appropriate information.+ *+ * Note that the index vacuum and heap vacuum phases may be called multiple+ * times in the middle of the heap scan phase. So the old phase information+ * is restored at the end of those phases.+ */+ errcallback.callback = vacuum_error_callback;+ errcallback.arg = vacrelstats;+ errcallback.previous = error_context_stack;+ error_context_stack = &errcallback;+
/* Do the vacuuming */
lazy_scan_heap(onerel, params, vacrelstats, Irel, nindexes, aggressive);
@@ -499,6 +540,9 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
if (should_attempt_truncation(params, vacrelstats))
lazy_truncate_heap(onerel, vacrelstats);
+ /* Pop the error context stack */+ error_context_stack = errcallback.previous;+
/* Report that we are now doing final cleanup */
pgstat_progress_update_param(PROGRESS_VACUUM_PHASE,
PROGRESS_VACUUM_PHASE_FINAL_CLEANUP);
@@ -699,7 +743,6 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
BlockNumber nblocks,
blkno;
HeapTupleData tuple;
- char *relname;
TransactionId relfrozenxid = onerel->rd_rel->relfrozenxid;
TransactionId relminmxid = onerel->rd_rel->relminmxid;
BlockNumber empty_pages,
@@ -727,17 +770,16 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
pg_rusage_init(&ru0);
- relname = RelationGetRelationName(onerel);
if (aggressive)
ereport(elevel,
(errmsg("aggressively vacuuming \"%s.%s\"",
- get_namespace_name(RelationGetNamespace(onerel)),- relname)));+ vacrelstats->relnamespace,+ vacrelstats->relname)));
else
ereport(elevel,
(errmsg("vacuuming \"%s.%s\"",
- get_namespace_name(RelationGetNamespace(onerel)),- relname)));+ vacrelstats->relnamespace,+ vacrelstats->relname)));
empty_pages = vacuumed_pages = 0;
next_fsm_block_to_vacuum = (BlockNumber) 0;
@@ -893,6 +935,9 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
pgstat_progress_update_param(PROGRESS_VACUUM_HEAP_BLKS_SCANNED, blkno);
+ update_vacuum_error_cbarg(vacrelstats, VACUUM_ERRCB_PHASE_SCAN_HEAP,+ blkno, NULL);+
if (blkno == next_unskippable_block)
{
/* Time to advance next_unskippable_block */
@@ -1534,7 +1579,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
&& VM_ALL_VISIBLE(onerel, blkno, &vmbuffer))
{
elog(WARNING, "page is not marked all-visible but visibility map bit is set in relation \"%s\" page %u",
- relname, blkno);+ vacrelstats->relname, blkno);
visibilitymap_clear(onerel, blkno, vmbuffer,
VISIBILITYMAP_VALID_BITS);
}
@@ -1555,7 +1600,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
else if (PageIsAllVisible(page) && has_dead_tuples)
{
elog(WARNING, "page containing dead tuples is marked as all-visible in relation \"%s\" page %u",
- relname, blkno);+ vacrelstats->relname, blkno);
PageClearAllVisible(page);
MarkBufferDirty(buf);
visibilitymap_clear(onerel, blkno, vmbuffer,
@@ -1744,7 +1789,7 @@ lazy_vacuum_all_indexes(Relation onerel, Relation *Irel,
for (idx = 0; idx < nindexes; idx++)
lazy_vacuum_index(Irel[idx], &stats[idx], vacrelstats->dead_tuples,
- vacrelstats->old_live_tuples);+ vacrelstats->old_live_tuples, vacrelstats);
}
/* Increase and report the number of index scans */
@@ -1772,11 +1817,17 @@ lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats)
int npages;
PGRUsage ru0;
Buffer vmbuffer = InvalidBuffer;
+ LVRelStats olderrcbarg;
/* Report that we are now vacuuming the heap */
pgstat_progress_update_param(PROGRESS_VACUUM_PHASE,
PROGRESS_VACUUM_PHASE_VACUUM_HEAP);
+ /* Update error traceback information */+ olderrcbarg = *vacrelstats;+ update_vacuum_error_cbarg(vacrelstats, VACUUM_ERRCB_PHASE_VACUUM_HEAP,+ InvalidBlockNumber, NULL);+
pg_rusage_init(&ru0);
npages = 0;
@@ -1791,6 +1842,7 @@ lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats)
vacuum_delay_point();
tblk = ItemPointerGetBlockNumber(&vacrelstats->dead_tuples->itemptrs[tupindex]);
+ vacrelstats->blkno = tblk;
buf = ReadBufferExtended(onerel, MAIN_FORKNUM, tblk, RBM_NORMAL,
vac_strategy);
if (!ConditionalLockBufferForCleanup(buf))
@@ -1822,6 +1874,12 @@ lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats)
RelationGetRelationName(onerel),
tupindex, npages),
errdetail_internal("%s", pg_rusage_show(&ru0))));
++ /* Revert back to the old phase information for error traceback */+ update_vacuum_error_cbarg(vacrelstats,+ olderrcbarg.phase,+ olderrcbarg.blkno,+ olderrcbarg.indname);
}
/*
@@ -1844,9 +1902,15 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
int uncnt = 0;
TransactionId visibility_cutoff_xid;
bool all_frozen;
+ LVRelStats olderrcbarg;
pgstat_progress_update_param(PROGRESS_VACUUM_HEAP_BLKS_VACUUMED, blkno);
+ /* Update error traceback information */+ olderrcbarg = *vacrelstats;+ update_vacuum_error_cbarg(vacrelstats, VACUUM_ERRCB_PHASE_VACUUM_HEAP,+ blkno, NULL);+
START_CRIT_SECTION();
for (; tupindex < dead_tuples->num_tuples; tupindex++)
@@ -1923,6 +1987,11 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
*vmbuffer, visibility_cutoff_xid, flags);
}
+ /* Revert back to the old phase information for error traceback */+ update_vacuum_error_cbarg(vacrelstats,+ olderrcbarg.phase,+ olderrcbarg.blkno,+ olderrcbarg.indname);
return tupindex;
}
@@ -2083,7 +2152,7 @@ lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
* indexes in the case where no workers are launched.
*/
parallel_vacuum_index(Irel, stats, lps->lvshared,
- vacrelstats->dead_tuples, nindexes);+ vacrelstats->dead_tuples, nindexes, vacrelstats);
/* Wait for all vacuum workers to finish */
WaitForParallelWorkersToFinish(lps->pcxt);
@@ -2106,7 +2175,7 @@ lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
static void
parallel_vacuum_index(Relation *Irel, IndexBulkDeleteResult **stats,
LVShared *lvshared, LVDeadTuples *dead_tuples,
- int nindexes)+ int nindexes, LVRelStats *vacrelstats)
{
/*
* Increment the active worker count if we are able to launch any worker.
@@ -2140,7 +2209,7 @@ parallel_vacuum_index(Relation *Irel, IndexBulkDeleteResult **stats,
/* Do vacuum or cleanup of the index */
vacuum_one_index(Irel[idx], &(stats[idx]), lvshared, shared_indstats,
- dead_tuples);+ dead_tuples, vacrelstats);
}
/*
@@ -2180,7 +2249,8 @@ vacuum_indexes_leader(Relation *Irel, IndexBulkDeleteResult **stats,
if (shared_indstats == NULL ||
skip_parallel_vacuum_index(Irel[i], lps->lvshared))
vacuum_one_index(Irel[i], &(stats[i]), lps->lvshared,
- shared_indstats, vacrelstats->dead_tuples);+ shared_indstats, vacrelstats->dead_tuples,+ vacrelstats);
}
/*
@@ -2200,7 +2270,7 @@ vacuum_indexes_leader(Relation *Irel, IndexBulkDeleteResult **stats,
static void
vacuum_one_index(Relation indrel, IndexBulkDeleteResult **stats,
LVShared *lvshared, LVSharedIndStats *shared_indstats,
- LVDeadTuples *dead_tuples)+ LVDeadTuples *dead_tuples, LVRelStats *vacrelstats)
{
IndexBulkDeleteResult *bulkdelete_res = NULL;
@@ -2220,10 +2290,10 @@ vacuum_one_index(Relation indrel, IndexBulkDeleteResult **stats,
/* Do vacuum or cleanup of the index */
if (lvshared->for_cleanup)
lazy_cleanup_index(indrel, stats, lvshared->reltuples,
- lvshared->estimated_count);+ lvshared->estimated_count, vacrelstats);
else
lazy_vacuum_index(indrel, stats, dead_tuples,
- lvshared->reltuples);+ lvshared->reltuples, vacrelstats);
/*
* Copy the index bulk-deletion result returned from ambulkdelete and
@@ -2298,7 +2368,8 @@ lazy_cleanup_all_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
for (idx = 0; idx < nindexes; idx++)
lazy_cleanup_index(Irel[idx], &stats[idx],
vacrelstats->new_rel_tuples,
- vacrelstats->tupcount_pages < vacrelstats->rel_pages);+ vacrelstats->tupcount_pages < vacrelstats->rel_pages,+ vacrelstats);
}
}
@@ -2313,11 +2384,12 @@ lazy_cleanup_all_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
*/
static void
lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats,
- LVDeadTuples *dead_tuples, double reltuples)+ LVDeadTuples *dead_tuples, double reltuples, LVRelStats *vacrelstats)
{
IndexVacuumInfo ivinfo;
const char *msg;
PGRUsage ru0;
+ LVRelStats olderrcbarg;
pg_rusage_init(&ru0);
@@ -2329,6 +2401,13 @@ lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats,
ivinfo.num_heap_tuples = reltuples;
ivinfo.strategy = vac_strategy;
+ /* Update error traceback information */+ olderrcbarg = *vacrelstats;+ update_vacuum_error_cbarg(vacrelstats,+ VACUUM_ERRCB_PHASE_VACUUM_INDEX,+ InvalidBlockNumber,+ RelationGetRelationName(indrel));+
/* Do bulk deletion */
*stats = index_bulk_delete(&ivinfo, *stats,
lazy_tid_reaped, (void *) dead_tuples);
@@ -2343,6 +2422,12 @@ lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats,
RelationGetRelationName(indrel),
dead_tuples->num_tuples),
errdetail_internal("%s", pg_rusage_show(&ru0))));
++ /* Revert back to the old phase information for error traceback */+ update_vacuum_error_cbarg(vacrelstats,+ olderrcbarg.phase,+ olderrcbarg.blkno,+ olderrcbarg.indname);
}
/*
@@ -2354,7 +2439,7 @@ lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats,
static void
lazy_cleanup_index(Relation indrel,
IndexBulkDeleteResult **stats,
- double reltuples, bool estimated_count)+ double reltuples, bool estimated_count, LVRelStats *vacrelstats)
{
IndexVacuumInfo ivinfo;
const char *msg;
@@ -2371,6 +2456,12 @@ lazy_cleanup_index(Relation indrel,
ivinfo.num_heap_tuples = reltuples;
ivinfo.strategy = vac_strategy;
+ /* Update error traceback information */+ update_vacuum_error_cbarg(vacrelstats,+ VACUUM_ERRCB_PHASE_INDEX_CLEANUP,+ InvalidBlockNumber,+ RelationGetRelationName(indrel));+
*stats = index_vacuum_cleanup(&ivinfo, *stats);
if (!(*stats))
@@ -2445,6 +2536,14 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
pgstat_progress_update_param(PROGRESS_VACUUM_PHASE,
PROGRESS_VACUUM_PHASE_TRUNCATE);
+ /*+ * Update error traceback information. This is the last phase during+ * which we add context information to errors, so we don't need to+ * revert to the previous phase.+ */+ update_vacuum_error_cbarg(vacrelstats, VACUUM_ERRCB_PHASE_TRUNCATE,+ vacrelstats->nonempty_pages, NULL);+
/*
* Loop until no more truncating can be done.
*/
@@ -2517,6 +2616,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
* were vacuuming.
*/
new_rel_pages = count_nondeletable_pages(onerel, vacrelstats);
+ vacrelstats->blkno = new_rel_pages;
if (new_rel_pages >= old_rel_pages)
{
@@ -3320,6 +3420,8 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
int nindexes;
char *sharedquery;
IndexBulkDeleteResult **stats;
+ LVRelStats vacrelstats;+ ErrorContextCallback errcallback;
lvshared = (LVShared *) shm_toc_lookup(toc, PARALLEL_VACUUM_KEY_SHARED,
false);
@@ -3369,10 +3471,98 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
if (lvshared->maintenance_work_mem_worker > 0)
maintenance_work_mem = lvshared->maintenance_work_mem_worker;
+ /*+ * Initialize vacrelstats for use as error callback arg by parallel+ * worker.+ */+ vacrelstats.relnamespace = get_namespace_name(RelationGetNamespace(onerel));+ vacrelstats.relname = pstrdup(RelationGetRelationName(onerel));+ vacrelstats.indname = NULL;+ vacrelstats.phase = VACUUM_ERRCB_PHASE_UNKNOWN; /* Not yet processing */++ /* Setup error traceback support for ereport() */+ errcallback.callback = vacuum_error_callback;+ errcallback.arg = &vacrelstats;+ errcallback.previous = error_context_stack;+ error_context_stack = &errcallback;+
/* Process indexes to perform vacuum/cleanup */
- parallel_vacuum_index(indrels, stats, lvshared, dead_tuples, nindexes);+ parallel_vacuum_index(indrels, stats, lvshared, dead_tuples, nindexes,+ &vacrelstats);++ /* Pop the error context stack */+ error_context_stack = errcallback.previous;
vac_close_indexes(nindexes, indrels, RowExclusiveLock);
table_close(onerel, ShareUpdateExclusiveLock);
pfree(stats);
}
++/*+ * Error context callback for errors occurring during vacuum.+ */+static void+vacuum_error_callback(void *arg)+{+ LVRelStats *cbarg = arg;++ switch (cbarg->phase)+ {+ case VACUUM_ERRCB_PHASE_SCAN_HEAP:+ if (BlockNumberIsValid(cbarg->blkno))+ errcontext("while scanning block %u of relation \"%s.%s\"",+ cbarg->blkno, cbarg->relnamespace, cbarg->relname);+ break;++ case VACUUM_ERRCB_PHASE_VACUUM_HEAP:+ if (BlockNumberIsValid(cbarg->blkno))+ errcontext("while vacuuming block %u of relation \"%s.%s\"",+ cbarg->blkno, cbarg->relnamespace, cbarg->relname);+ break;++ case VACUUM_ERRCB_PHASE_VACUUM_INDEX:+ errcontext("while vacuuming index \"%s\" of relation \"%s.%s\"",+ cbarg->indname, cbarg->relnamespace, cbarg->relname);+ break;++ case VACUUM_ERRCB_PHASE_INDEX_CLEANUP:+ errcontext("while cleaning up index \"%s\" of relation \"%s.%s\"",+ 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_UNKNOWN:+ default:+ return; /* do nothing; the cbarg may not be+ * initialized */+ }+}++/* Update vacuum error callback for the current phase, block, and index. */+static void+update_vacuum_error_cbarg(LVRelStats *errcbarg, int phase, BlockNumber blkno,+ char *indname)+{+ /*+ * Set phase to unknown to avoid crashing if an error occurs between+ * setting phase and setting indname (either while phase=VACUUM_INDEX but+ * indname is unset, or if we pfree(indname) but still have+ * phase=VACUUM_INDEX).+ */+ errcbarg->phase = VACUUM_ERRCB_PHASE_UNKNOWN;++ /* Free index name from any previous phase */+ if (errcbarg->indname)+ pfree(errcbarg->indname);++ /* For index phases, save the name of the current index for the callback */+ errcbarg->indname = indname ? pstrdup(indname) : NULL;++ errcbarg->blkno = blkno;+ errcbarg->phase = phase;+}diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.listindex ca2d9ec8fb..518393344b 100644--- a/src/tools/pgindent/typedefs.list+++ b/src/tools/pgindent/typedefs.list@@ -2565,6 +2565,7 @@ UserMapping
UserOpts
VacAttrStats
VacAttrStatsP
+VacErrCbPhase
VacOptTernaryValue
VacuumParams
VacuumRelation
--
2.17.0
[text/x-diff] v36-0002-Drop-reltuples.patch (4.0K, ../20200326221752.GR17431@telsasoft.com/3-v36-0002-Drop-reltuples.patch)
download | inline diff:
From 5ecabfa06e9fed215a606fbc351154fc613cc6f0 Mon Sep 17 00:00:00 2001
From: Justin Pryzby <pryzbyj@telsasoft.com>
Date: Wed, 4 Mar 2020 12:28:50 -0600
Subject: [PATCH v36 2/3] Drop reltuples
---
src/backend/access/heap/vacuumlazy.c | 24 +++++++++++-------------
1 file changed, 11 insertions(+), 13 deletions(-)
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.cindex e98e6b45d3..a996d73e48 100644--- a/src/backend/access/heap/vacuumlazy.c+++ b/src/backend/access/heap/vacuumlazy.c@@ -331,10 +331,10 @@ static void lazy_vacuum_all_indexes(Relation onerel, Relation *Irel,
LVRelStats *vacrelstats, LVParallelState *lps,
int nindexes);
static void lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats,
- LVDeadTuples *dead_tuples, double reltuples, LVRelStats *vacrelstats);+ LVDeadTuples *dead_tuples, LVRelStats *vacrelstats);
static void lazy_cleanup_index(Relation indrel,
IndexBulkDeleteResult **stats,
- double reltuples, bool estimated_count, LVRelStats *vacrelstats);+ LVRelStats *vacrelstats);
static int lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
int tupindex, LVRelStats *vacrelstats, Buffer *vmbuffer);
static bool should_attempt_truncation(VacuumParams *params,
@@ -1789,7 +1789,7 @@ lazy_vacuum_all_indexes(Relation onerel, Relation *Irel,
for (idx = 0; idx < nindexes; idx++)
lazy_vacuum_index(Irel[idx], &stats[idx], vacrelstats->dead_tuples,
- vacrelstats->old_live_tuples, vacrelstats);+ vacrelstats);
}
/* Increase and report the number of index scans */
@@ -2289,11 +2289,10 @@ vacuum_one_index(Relation indrel, IndexBulkDeleteResult **stats,
/* Do vacuum or cleanup of the index */
if (lvshared->for_cleanup)
- lazy_cleanup_index(indrel, stats, lvshared->reltuples,- lvshared->estimated_count, vacrelstats);+ lazy_cleanup_index(indrel, stats, vacrelstats);
else
lazy_vacuum_index(indrel, stats, dead_tuples,
- lvshared->reltuples, vacrelstats);+ vacrelstats);
/*
* Copy the index bulk-deletion result returned from ambulkdelete and
@@ -2367,8 +2366,6 @@ lazy_cleanup_all_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
{
for (idx = 0; idx < nindexes; idx++)
lazy_cleanup_index(Irel[idx], &stats[idx],
- vacrelstats->new_rel_tuples,- vacrelstats->tupcount_pages < vacrelstats->rel_pages,
vacrelstats);
}
}
@@ -2384,7 +2381,7 @@ lazy_cleanup_all_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
*/
static void
lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats,
- LVDeadTuples *dead_tuples, double reltuples, LVRelStats *vacrelstats)+ LVDeadTuples *dead_tuples, LVRelStats *vacrelstats)
{
IndexVacuumInfo ivinfo;
const char *msg;
@@ -2398,7 +2395,7 @@ lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats,
ivinfo.report_progress = false;
ivinfo.estimated_count = true;
ivinfo.message_level = elevel;
- ivinfo.num_heap_tuples = reltuples;+ ivinfo.num_heap_tuples = vacrelstats->old_live_tuples;
ivinfo.strategy = vac_strategy;
/* Update error traceback information */
@@ -2439,7 +2436,7 @@ lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats,
static void
lazy_cleanup_index(Relation indrel,
IndexBulkDeleteResult **stats,
- double reltuples, bool estimated_count, LVRelStats *vacrelstats)+ LVRelStats *vacrelstats)
{
IndexVacuumInfo ivinfo;
const char *msg;
@@ -2450,10 +2447,11 @@ lazy_cleanup_index(Relation indrel,
ivinfo.index = indrel;
ivinfo.analyze_only = false;
ivinfo.report_progress = false;
- ivinfo.estimated_count = estimated_count;+ ivinfo.estimated_count = (bool)(vacrelstats->tupcount_pages <+ vacrelstats->rel_pages);
ivinfo.message_level = elevel;
- ivinfo.num_heap_tuples = reltuples;+ ivinfo.num_heap_tuples = vacrelstats->new_rel_tuples;
ivinfo.strategy = vac_strategy;
/* Update error traceback information */
--
2.17.0
[text/x-diff] v36-0003-Avoid-some-calls-to-RelationGetRelationName.patch (3.7K, ../20200326221752.GR17431@telsasoft.com/4-v36-0003-Avoid-some-calls-to-RelationGetRelationName.patch)
download | inline diff:
From c85e2960f519bea4074e972d6362700172274eeb Mon Sep 17 00:00:00 2001
From: Justin Pryzby <pryzbyj@telsasoft.com>
Date: Wed, 26 Feb 2020 19:22:55 -0600
Subject: [PATCH v36 3/3] Avoid some calls to RelationGetRelationName
---
src/backend/access/heap/vacuumlazy.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.cindex a996d73e48..36b92f207f 100644--- a/src/backend/access/heap/vacuumlazy.c+++ b/src/backend/access/heap/vacuumlazy.c@@ -643,8 +643,8 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
}
appendStringInfo(&buf, msgfmt,
get_database_name(MyDatabaseId),
- get_namespace_name(RelationGetNamespace(onerel)),- RelationGetRelationName(onerel),+ vacrelstats->relnamespace,+ vacrelstats->relname,
vacrelstats->num_index_scans);
appendStringInfo(&buf, _("pages: %u removed, %u remain, %u skipped due to pins, %u skipped frozen\n"),
vacrelstats->pages_removed,
@@ -815,7 +815,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
if (params->nworkers > 0)
ereport(WARNING,
(errmsg("disabling parallel option of vacuum on \"%s\" --- cannot vacuum temporary tables in parallel",
- RelationGetRelationName(onerel))));+ vacrelstats->relname)));
}
else
lps = begin_parallel_vacuum(RelationGetRelid(onerel), Irel,
@@ -1710,7 +1710,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
if (vacuumed_pages)
ereport(elevel,
(errmsg("\"%s\": removed %.0f row versions in %u pages",
- RelationGetRelationName(onerel),+ vacrelstats->relname,
tups_vacuumed, vacuumed_pages)));
/*
@@ -1739,7 +1739,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
ereport(elevel,
(errmsg("\"%s\": found %.0f removable, %.0f nonremovable row versions in %u out of %u pages",
- RelationGetRelationName(onerel),+ vacrelstats->relname,
tups_vacuumed, num_tuples,
vacrelstats->scanned_pages, nblocks),
errdetail_internal("%s", buf.data)));
@@ -1871,7 +1871,7 @@ lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats)
ereport(elevel,
(errmsg("\"%s\": removed %d row versions in %d pages",
- RelationGetRelationName(onerel),+ vacrelstats->relname,
tupindex, npages),
errdetail_internal("%s", pg_rusage_show(&ru0))));
@@ -2416,7 +2416,7 @@ lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats,
ereport(elevel,
(errmsg(msg,
- RelationGetRelationName(indrel),+ vacrelstats->indname,
dead_tuples->num_tuples),
errdetail_internal("%s", pg_rusage_show(&ru0))));
@@ -2581,7 +2581,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
vacrelstats->lock_waiter_detected = true;
ereport(elevel,
(errmsg("\"%s\": stopping truncate due to conflicting lock request",
- RelationGetRelationName(onerel))));+ vacrelstats->relname)));
return;
}
@@ -2647,7 +2647,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
ereport(elevel,
(errmsg("\"%s\": truncated %u to %u pages",
- RelationGetRelationName(onerel),+ vacrelstats->relname,
old_rel_pages, new_rel_pages),
errdetail_internal("%s",
pg_rusage_show(&ru0))));
@@ -2712,7 +2712,7 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats)
{
ereport(elevel,
(errmsg("\"%s\": suspending truncate due to conflicting lock request",
- RelationGetRelationName(onerel))));+ vacrelstats->relname)));
vacrelstats->lock_waiter_detected = true;
return blkno;
--
2.17.0
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: pgsql-hackers@postgresql.org
Cc: pryzby@telsasoft.com, masahiko.sawada@2ndquadrant.com, amit.kapila16@gmail.com, alvherre@2ndquadrant.com, andres@anarazel.de, michael@paquier.xyz
Subject: Re: error context for vacuum to include block number
In-Reply-To: <20200326221752.GR17431@telsasoft.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox