From a47c62bd1e21da60515f4d0700ffb74510bbfbd3 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Wed, 1 Jun 2016 10:37:28 +0300 Subject: [PATCH] Avoid "HEAP_MOVED_OFF was expected" errors in VACUUM FULL. If a page has hint bits set, but the buffer has not been marked as dirty, and it gets evicted between the 1st and 2nd vacuum pass, the 2nd pass gets upset. That can't happen in the upstream, as setting a hint bit always marks the buffer as dirty, but that is not guaranteed in GPDB, because of gp_disable_tuple_hints. --- src/backend/commands/vacuum.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 715756a340..39248f5da3 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -3279,6 +3279,25 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, * processing this or a higher numbered block. * --- */ + + /* + * In PostgreSQL, we assume that the first pass of vacuum already + * set the hint bit. However, we cannot rely on that in GPDB, + * because of gp_disable_tuple_hints GUC. If it's ever set, then + * the first pass might've seen that all the hint bits on the page + * were already set, but the backend that set those bits didn't + * mark the buffer as dirty. If the buffer is subsequently evicted + * from the buffer cache, the hint bit updates are lost, and we + * will see them as not set here, even though they were set in the + * first pass. + * + * To fix that, just call HeapTupleSatisfiesVacuum() here to set + * the hint bits again, if not set already. + */ + LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); + (void) HeapTupleSatisfiesVacuum(tuple.t_data, OldestXmin, buf); + LockBuffer(buf, BUFFER_LOCK_UNLOCK); + if (!(tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED)) { if (tuple.t_data->t_infomask & HEAP_MOVED_IN) -- GitLab