diff options
Diffstat (limited to 'src/backend/access/heap/visibilitymap.c')
-rw-r--r-- | src/backend/access/heap/visibilitymap.c | 70 |
1 files changed, 69 insertions, 1 deletions
diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c index 0414ce1945c..2f5e61e2392 100644 --- a/src/backend/access/heap/visibilitymap.c +++ b/src/backend/access/heap/visibilitymap.c @@ -14,7 +14,8 @@ * visibilitymap_clear - clear 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 + * visibilitymap_set - set bit(s) in a previously pinned page and log + * visibilitymap_set_vmbits - set bit(s) in a pinned page * visibilitymap_get_status - get status of bits * visibilitymap_count - count number of bits set in visibility map * visibilitymap_prepare_truncate - @@ -323,6 +324,73 @@ visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf, } /* + * Set VM (visibility map) flags in the VM block in vmBuf. + * + * This function is intended for callers that log VM changes together + * with the heap page modifications that rendered the page all-visible. + * Callers that log VM changes separately should use visibilitymap_set(). + * + * vmBuf must be pinned and exclusively locked, and it must cover the VM bits + * corresponding to heapBlk. + * + * In normal operation (not recovery), this must be called inside a critical + * section that also applies the necessary heap page changes and, if + * applicable, emits WAL. + * + * The caller is responsible for ensuring consistency between the heap page + * and the VM page by holding a pin and exclusive lock on the buffer + * containing heapBlk. + * + * rlocator is used only for debugging messages. + */ +uint8 +visibilitymap_set_vmbits(BlockNumber heapBlk, + Buffer vmBuf, uint8 flags, + const RelFileLocator rlocator) +{ + BlockNumber mapBlock = HEAPBLK_TO_MAPBLOCK(heapBlk); + uint32 mapByte = HEAPBLK_TO_MAPBYTE(heapBlk); + uint8 mapOffset = HEAPBLK_TO_OFFSET(heapBlk); + Page page; + uint8 *map; + uint8 status; + +#ifdef TRACE_VISIBILITYMAP + elog(DEBUG1, "vm_set flags 0x%02X for %s %d", + flags, + relpathbackend(rlocator, MyProcNumber, MAIN_FORKNUM).str, + heapBlk); +#endif + + /* Call in same critical section where WAL is emitted. */ + Assert(InRecovery || CritSectionCount > 0); + + /* Flags should be valid. Also never clear bits with this function */ + Assert((flags & VISIBILITYMAP_VALID_BITS) == flags); + + /* Must never set all_frozen bit without also setting all_visible bit */ + Assert(flags != VISIBILITYMAP_ALL_FROZEN); + + /* Check that we have the right VM page pinned */ + if (!BufferIsValid(vmBuf) || BufferGetBlockNumber(vmBuf) != mapBlock) + elog(ERROR, "wrong VM buffer passed to visibilitymap_set"); + + Assert(BufferIsLockedByMeInMode(vmBuf, BUFFER_LOCK_EXCLUSIVE)); + + page = BufferGetPage(vmBuf); + map = (uint8 *) PageGetContents(page); + + status = (map[mapByte] >> mapOffset) & VISIBILITYMAP_VALID_BITS; + if (flags != status) + { + map[mapByte] |= (flags << mapOffset); + MarkBufferDirty(vmBuf); + } + + return status; +} + +/* * visibilitymap_get_status - get status of bits * * Are all tuples on heapBlk visible to all or are marked frozen, according |