src/backend/storage/freespace/freespace.c
static Buffer
fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
{
	BlockNumber blkno = fsm_logical_to_physical(addr);
	Buffer		buf;
	SMgrRelation reln;

	/*
	 * Caution: re-using this smgr pointer could fail if the relcache entry
	 * gets closed.  It's safe as long as we only do smgr-level operations
	 * between here and the last use of the pointer.
	 */
	reln = RelationGetSmgr(rel);

	/*
	 * If we haven't cached the size of the FSM yet, check it first.  Also
	 * recheck if the requested block seems to be past end, since our cached
	 * value might be stale.  (We send smgr inval messages on truncation, but
	 * not on extension.)
	 */
	if (reln->smgr_cached_nblocks[FSM_FORKNUM] == InvalidBlockNumber ||
		blkno >= reln->smgr_cached_nblocks[FSM_FORKNUM])
	{
		/* Invalidate the cache so smgrnblocks asks the kernel. */
		reln->smgr_cached_nblocks[FSM_FORKNUM] = InvalidBlockNumber;
		if (smgrexists(reln, FSM_FORKNUM))
			smgrnblocks(reln, FSM_FORKNUM);
		else
			reln->smgr_cached_nblocks[FSM_FORKNUM] = 0;
	}

	/* Handle requests beyond EOF */
	if (blkno >= reln->smgr_cached_nblocks[FSM_FORKNUM])
	{
		if (extend)
			fsm_extend(rel, blkno + 1);
		else
			return InvalidBuffer;
	}

	/*
	 * Use ZERO_ON_ERROR mode, and initialize the page if necessary. The FSM
	 * information is not accurate anyway, so it's better to clear corrupt
	 * pages than error out. Since the FSM changes are not WAL-logged, the
	 * so-called torn page problem on crash can lead to pages with corrupt
	 * headers, for example.
	 *
	 * The initialize-the-page part is trickier than it looks, because of the
	 * possibility of multiple backends doing this concurrently, and our
	 * desire to not uselessly take the buffer lock in the normal path where
	 * the page is OK.  We must take the lock to initialize the page, so
	 * recheck page newness after we have the lock, in case someone else
	 * already did it.  Also, because we initially check PageIsNew with no
	 * lock, it's possible to fall through and return the buffer while someone
	 * else is still initializing the page (i.e., we might see pd_upper as set
	 * but other page header fields are still zeroes).  This is harmless for
	 * callers that will take a buffer lock themselves, but some callers
	 * inspect the page without any lock at all.  The latter is OK only so
	 * long as it doesn't depend on the page header having correct contents.
	 * Current usage is safe because PageGetContents() does not require that.
	 */
	buf = ReadBufferExtended(rel, FSM_FORKNUM, blkno, RBM_ZERO_ON_ERROR, NULL);
	if (PageIsNew(BufferGetPage(buf)))
	{
		LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
		if (PageIsNew(BufferGetPage(buf)))
			PageInit(BufferGetPage(buf), BLCKSZ, 0);
		LockBuffer(buf, BUFFER_LOCK_UNLOCK);
	}
	return buf;
}
/*
 * Read a FSM page.
 *
 * If the page doesn't exist, InvalidBuffer is returned, or if 'extend' is
 * true, the FSM file is extended.
 */
Read a FSM page.
If the page doesn't exist, InvalidBuffer is returned, or if 'extend' is
true, the FSM file is extended.
Read a FSM page . If the page doesn ' t exist InvalidBuffer is returned or if ' extend ' is true the FSM file is extended .
static Buffer
fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
{
	BlockNumber blkno = fsm_logical_to_physical(addr);
	Buffer		buf;
	SMgrRelation reln;
	reln = RelationGetSmgr(rel);
	if (reln->smgr_cached_nblocks[FSM_FORKNUM] == InvalidBlockNumber ||
		blkno >= reln->smgr_cached_nblocks[FSM_FORKNUM])
	{
		reln->smgr_cached_nblocks[FSM_FORKNUM] = InvalidBlockNumber;
		if (smgrexists(reln, FSM_FORKNUM))
			smgrnblocks(reln, FSM_FORKNUM);
		else
			reln->smgr_cached_nblocks[FSM_FORKNUM] = 0;
	}
	if (blkno >= reln->smgr_cached_nblocks[FSM_FORKNUM])
	{
		if (extend)
			fsm_extend(rel, blkno + 1);
		else
			return InvalidBuffer;
	}
	buf = ReadBufferExtended(rel, FSM_FORKNUM, blkno, RBM_ZERO_ON_ERROR, NULL);
	if (PageIsNew(BufferGetPage(buf)))
	{
		LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
		if (PageIsNew(BufferGetPage(buf)))
			PageInit(BufferGetPage(buf), BLCKSZ, 0);
		LockBuffer(buf, BUFFER_LOCK_UNLOCK);
	}
	return buf;
}
static Buffer fsm_readbuf ( Relation rel , FSMAddress addr , bool extend ) { BlockNumber blkno = fsm_logical_to_physical ( addr ) ; Buffer buf ; SMgrRelation reln ; reln = RelationGetSmgr ( rel ) ; if ( reln -> smgr_cached_nblocks [ FSM_FORKNUM ] == InvalidBlockNumber || blkno >= reln -> smgr_cached_nblocks [ FSM_FORKNUM ] ) { reln -> smgr_cached_nblocks [ FSM_FORKNUM ] = InvalidBlockNumber ; if ( smgrexists ( reln , FSM_FORKNUM ) ) smgrnblocks ( reln , FSM_FORKNUM ) ; else reln -> smgr_cached_nblocks [ FSM_FORKNUM ] = 0 ; } if ( blkno >= reln -> smgr_cached_nblocks [ FSM_FORKNUM ] ) { if ( extend ) fsm_extend ( rel , blkno + 1 ) ; else return InvalidBuffer ; } buf = ReadBufferExtended ( rel , FSM_FORKNUM , blkno , RBM_ZERO_ON_ERROR , NULL ) ; if ( PageIsNew ( BufferGetPage ( buf ) ) ) { LockBuffer ( buf , BUFFER_LOCK_EXCLUSIVE ) ; if ( PageIsNew ( BufferGetPage ( buf ) ) ) PageInit ( BufferGetPage ( buf ) , BLCKSZ , 0 ) ; LockBuffer ( buf , BUFFER_LOCK_UNLOCK ) ; } return buf ; }
Read a FSM page.
Read a FSM page .
/*
	 * Caution: re-using this smgr pointer could fail if the relcache entry
	 * gets closed.  It's safe as long as we only do smgr-level operations
	 * between here and the last use of the pointer.
	 */ /*
	 * If we haven't cached the size of the FSM yet, check it first.  Also
	 * recheck if the requested block seems to be past end, since our cached
	 * value might be stale.  (We send smgr inval messages on truncation, but
	 * not on extension.)
	 */ /* Invalidate the cache so smgrnblocks asks the kernel. */ /* Handle requests beyond EOF */ /*
	 * Use ZERO_ON_ERROR mode, and initialize the page if necessary. The FSM
	 * information is not accurate anyway, so it's better to clear corrupt
	 * pages than error out. Since the FSM changes are not WAL-logged, the
	 * so-called torn page problem on crash can lead to pages with corrupt
	 * headers, for example.
	 *
	 * The initialize-the-page part is trickier than it looks, because of the
	 * possibility of multiple backends doing this concurrently, and our
	 * desire to not uselessly take the buffer lock in the normal path where
	 * the page is OK.  We must take the lock to initialize the page, so
	 * recheck page newness after we have the lock, in case someone else
	 * already did it.  Also, because we initially check PageIsNew with no
	 * lock, it's possible to fall through and return the buffer while someone
	 * else is still initializing the page (i.e., we might see pd_upper as set
	 * but other page header fields are still zeroes).  This is harmless for
	 * callers that will take a buffer lock themselves, but some callers
	 * inspect the page without any lock at all.  The latter is OK only so
	 * long as it doesn't depend on the page header having correct contents.
	 * Current usage is safe because PageGetContents() does not require that.
	 */