1 概述

1.1 vm接口调用点

heap_insert()
    buffer = RelationGetBufferForTuple()
    RelationPutHeapTuple(buffer, heaptup)
    if PageIsAllVisible(buffer):
        PageClearAllVisible(buffer)
        visibilitymap_clear(ItemPointerGetBlockNumber(heaptup), vmbuffer)
    MarkBufferDirty(buffer)

#define PageIsAllVisible(page) ((page)->pd_flags & PD_ALL_VISIBLE)

1.2 vm模块对外接口

visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer buf, uint8 flags)
    int mapByte = HEAPBLK_TO_MAPBYTE(heapBlk)
    LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE)
    char *map = PageGetContents(buf)
    if map[mapByte]

1.3 vmmap结构与定位

/* 8192 - 24 = 8168 */
#define MAPSIZE (BLCKSZ - MAXALIGN(SizeOfPageHeaderData))

/* 1字节 2bit表示1页 : | 00 00 00 00 | */
#define BITS_PER_BYTE 8
#define BITS_PER_HEAPBLOCK 2
/* 1字节 可映射4个heapblock */
#define HEAPBLOCKS_PER_BYTE (BITS_PER_BYTE / BITS_PER_HEAPBLOCK)

/* 计算heapblock对应的vmblock, vmbyte, vmoffset的位置 */
/* 1vmblock可映射4 * 8168个datablock */
#define HEAPBLOCKS_PER_PAGE (MAPSIZE * HEAPBLOCKS_PER_BYTE)
#define HEAPBLK_TO_MAPBLOCK(x) ((x) / HEAPBLOCKS_PER_PAGE)
#define HEAPBLK_TO_MAPBYTE(x) (((x) % HEAPBLOCKS_PER_PAGE) / HEAPBLOCKS_PER_BYTE)
#define HEAPBLK_TO_OFFSET(x) (((x) % HEAPBLOCKS_PER_BYTE) * BITS_PER_HEAPBLOCK)

#define VISIBILITYMAP_ALL_VISIBLE	0x01
#define VISIBILITYMAP_ALL_FROZEN	0x02
#define VISIBILITYMAP_VALID_BITS	0x03

1.4 vmblock读写

vm_extend(Relation rel, BlockNumber vm_nblocks)
    PGAlignedBlock pg
    PageInit((Page) pg.data, BLCKSZ, 0)
    LockRelationForExtension(rel, ExclusiveLock)
    BlockNumber vm_nblocks_now = smgrnblocks(rel->rd_smgr, VISIBILITYMAP_FORKNUM)
    while vm_nblocks_now < vm_nblocks:
        PageSetChecksumInplace((Page) pg.data, vm_nblocks_now)
        smgrextend(rel->rd_smgr, VISIBILITYMAP_FORKNUM, vm_nblocks_now,
				   pg.data, false)
        vm_nblocks_now++
    /* 让其他postgres进程smgrclose(rel) */
    CacheInvalidateSmgr(rel->rd_smgr->smgr_rnode) {
        SharedInvalidationMessage msg
        msg.sm.id = SHAREDINVALSMGR_ID;
        msg.sm.backend_hi = rnode.backend >> 16;
        msg.sm.backend_lo = rnode.backend & 0xffff;
        msg.sm.rnode = rnode.node;
        VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg))
        SendSharedInvalidMessages(&msg, 1)
    }
    rel->rd_smgr->smgr_vm_nblocks = vm_nblocks_now
    UnlockRelationForExtension(rel, ExclusiveLock)

Buffer
vm_readbuf(Relation rel, BlockNumber blkno, bool extend)
    RelationOpenSmgr(rel)
    if blkno >= rel->rd_smgr->smgr_vm_nblocks:
        if extend:
            vm_extend(rel, blkno + 1)
    buf = ReadBufferExtended(rel , VISIBILITYMAP_FORKNUM, blkno,RBM_ZERO_ON_ERROR)
    if PageIsNew(buf):
        PageInit(buf, BLKSZ, 0)
    return buf

1.5 vm模块对外接口

void visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf, XLogRecPtr recptr, Buffer vmBuf, TransactionId cutoff_xid, uint8 flags)
uint8 visibilitymap_get_status(Relation rel, BlockNumber heapBlk, Buffer *vmbuf)
bool visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer vmbuf, uint8 flags)

/* 每个heapblock有3种状态 */
uint8
visibilitymap_get_status(Relation rel, BlockNumber heapBlk, Buffer *buf)
	BlockNumber mapBlock = HEAPBLK_TO_MAPBLOCK(heapBlk)
	uint32 mapByte = HEAPBLK_TO_MAPBYTE(heapBlk)
	uint8 mapOffset = HEAPBLK_TO_OFFSET(heapBlk)

    /* 比较传入的buf和计算的mapblock是否为同一个 */
    if BufferIsValid(*buf):
        if BufferGetBlockNumber(*buf) != mapBlock:
            *buf = InvalidBuffer
    if !BufferIsValid(*buf):
        *buf = vm_readbuf(rel, mapBlock, false)

    map = PageGetContents(BufferGetPage(*buf))
    /* 每个heapbuf有01 10 11共3种状态 */
    unit8 result = ((map[mapByte] >> mapOffset) & VISIBILITYMAP_VALID_BITS)
    return uint8

void visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf, XLogRecPtr recptr, Buffer vmBuf, TransactionId cutoff_xid, uint8 flags)
    ...