From 37e8901df9fe6aa6125059257dc6b8d659bb2929 Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Mon, 11 Jul 2016 12:44:57 -0700 Subject: [PATCH 2/2] Clear all-frozen bit on visibility map when xmax is set. --- src/backend/access/heap/heapam.c | 49 +++++++++++++++++++++++++++++++++ src/backend/access/heap/visibilitymap.c | 19 ++++++++++--- src/include/access/visibilitymap.h | 2 ++ 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index e7cb8ca..23e9b75 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -3947,6 +3947,14 @@ l2: oldtup.t_data->t_ctid = oldtup.t_self; already_marked = true; + /* Clear only the all-frozen bit on visibility map if needed */ + if (PageIsAllVisible(BufferGetPage(buffer)) && + VM_ALL_FROZEN(relation, block, &vmbuffer)) + { + visibilitymap_clear_extended(relation, block, vmbuffer, + VISIBILITYMAP_ALL_FROZEN); + } + MarkBufferDirty(buffer); if (RelationNeedsWAL(relation)) @@ -4538,6 +4546,8 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, ItemPointer tid = &(tuple->t_self); ItemId lp; Page page; + Buffer vmbuffer = InvalidBuffer; + BlockNumber block; TransactionId xid, xmax; uint16 old_infomask, @@ -4547,6 +4557,15 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, bool have_tuple_lock = false; *buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid)); + block = ItemPointerGetBlockNumber(tid); + + /* + * Before locking the buffer, pin the visibility map page if it appears to + * to be necessary + */ + if (PageIsAllVisible(BufferGetPage(*buffer))) + visibilitymap_pin(relation, block, &vmbuffer); + LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE); page = BufferGetPage(*buffer); @@ -5066,6 +5085,15 @@ failed: if (HEAP_XMAX_IS_LOCKED_ONLY(new_infomask)) tuple->t_data->t_ctid = *tid; + /* Clear only the all-frozen bit on visibility map if needed */ + if (PageIsAllVisible(page) && + VM_ALL_FROZEN(relation, block, &vmbuffer)) + { + visibilitymap_clear_extended(relation, block, vmbuffer, + VISIBILITYMAP_ALL_FROZEN); + } + + MarkBufferDirty(*buffer); /* @@ -5104,6 +5132,8 @@ failed: END_CRIT_SECTION(); LockBuffer(*buffer, BUFFER_LOCK_UNLOCK); + if (BufferIsValid(vmbuffer)) + ReleaseBuffer(vmbuffer); /* * Don't update the visibility map here. Locking a tuple doesn't change @@ -8726,6 +8756,25 @@ heap_xlog_lock(XLogReaderState *record) } HeapTupleHeaderSetXmax(htup, xlrec->locking_xid); HeapTupleHeaderSetCmax(htup, FirstCommandId, false); + + /* The all-frozen bit on visibility map need to be cleared if needed */ + if (PageIsAllVisible(BufferGetPage(buffer))) + { + RelFileNode rnode; + Buffer vmbuffer = InvalidBuffer; + BlockNumber block; + Relation reln; + + XLogRecGetBlockTag(record, 0, &rnode, NULL, &block); + reln = CreateFakeRelcacheEntry(rnode); + visibilitymap_pin(reln, block, &vmbuffer); + + if (VM_ALL_FROZEN(reln, block, &vmbuffer)) + visibilitymap_clear_extended(reln, block, vmbuffer, + VISIBILITYMAP_ALL_FROZEN); + ReleaseBuffer(vmbuffer); + } + PageSetLSN(page, lsn); MarkBufferDirty(buffer); } diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c index b472d31..c52c0b0 100644 --- a/src/backend/access/heap/visibilitymap.c +++ b/src/backend/access/heap/visibilitymap.c @@ -11,7 +11,7 @@ * src/backend/access/heap/visibilitymap.c * * INTERFACE ROUTINES - * visibilitymap_clear - clear a bit in the visibility map + * visibilitymap_clear - clear all bits for one page in the visibility map * visibilitymap_pin - pin a map page for setting a bit * visibilitymap_pin_ok - check whether correct map page is already pinned * visibilitymap_set - set a bit in a previously pinned page @@ -157,23 +157,34 @@ static const uint8 number_of_ones_for_frozen[256] = { static Buffer vm_readbuf(Relation rel, BlockNumber blkno, bool extend); static void vm_extend(Relation rel, BlockNumber nvmblocks); +/* + * A shorthand for visibilitymap_clear_extended, for clearing all bits for one + * page in visibility map with VISIBILITYMAP_VALID_BITS. + */ +void +visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer buf) +{ + visibilitymap_clear_extended(rel, heapBlk, buf, VISIBILITYMAP_VALID_BITS); +} /* - * visibilitymap_clear - clear all bits for one page in visibility map + * visibilitymap_clear_extended - clear bit(s) for one page in visibility map * * You must pass a buffer containing the correct map page to this function. * Call visibilitymap_pin first to pin the right one. This function doesn't do * any I/O. */ void -visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer buf) +visibilitymap_clear_extended(Relation rel, BlockNumber heapBlk, Buffer buf, uint8 flags) { BlockNumber mapBlock = HEAPBLK_TO_MAPBLOCK(heapBlk); int mapByte = HEAPBLK_TO_MAPBYTE(heapBlk); int mapOffset = HEAPBLK_TO_OFFSET(heapBlk); - uint8 mask = VISIBILITYMAP_VALID_BITS << mapOffset; + uint8 mask = flags << mapOffset; char *map; + Assert(flags & VISIBILITYMAP_VALID_BITS); + #ifdef TRACE_VISIBILITYMAP elog(DEBUG1, "vm_clear %s %d", RelationGetRelationName(rel), heapBlk); #endif diff --git a/src/include/access/visibilitymap.h b/src/include/access/visibilitymap.h index fca99ca..f305b03 100644 --- a/src/include/access/visibilitymap.h +++ b/src/include/access/visibilitymap.h @@ -36,6 +36,8 @@ extern void visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer vmbuf); +extern void visibilitymap_clear_extended(Relation rel, BlockNumber heapBlk, + Buffer vmbuf, uint8 flags); extern void visibilitymap_pin(Relation rel, BlockNumber heapBlk, Buffer *vmbuf); extern bool visibilitymap_pin_ok(BlockNumber heapBlk, Buffer vmbuf); -- 2.8.1