diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c index fe991cf..6dcfe7c 100644 --- a/src/backend/access/hash/hashpage.c +++ b/src/backend/access/hash/hashpage.c @@ -185,7 +185,7 @@ _hash_getinitbuf(Relation rel, BlockNumber blkno) Buffer _hash_getnewbuf(Relation rel, BlockNumber blkno, ForkNumber forkNum) { - BlockNumber nblocks = RelationGetNumberOfBlocksInFork(rel, forkNum); + BlockNumber nblocks = RelationGetNumberOfBlocksInFork(rel, forkNum, false); Buffer buf; if (blkno == P_NEW) @@ -340,7 +340,7 @@ _hash_metapinit(Relation rel, double num_tuples, ForkNumber forkNum) uint32 i; /* safety check */ - if (RelationGetNumberOfBlocksInFork(rel, forkNum) != 0) + if (RelationGetNumberOfBlocksInFork(rel, forkNum, false) != 0) elog(ERROR, "cannot initialize non-empty hash index \"%s\"", RelationGetRelationName(rel)); diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 01a492e..8045dda 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -1201,6 +1201,12 @@ heap_beginscan_internal(Relation relation, Snapshot snapshot, { HeapScanDesc scan; + /* Temporary/unlogged relations are unavailable during recovery. */ + if (!RelationNeedsWAL(relation) && RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged tables during recovery"))); + /* * increment relation ref count while scanning relation * diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c index 58bab7d..3b69600 100644 --- a/src/backend/access/heap/visibilitymap.c +++ b/src/backend/access/heap/visibilitymap.c @@ -366,7 +366,7 @@ visibilitymap_truncate(Relation rel, BlockNumber nheapblocks) else newnblocks = truncBlock; - if (smgrnblocks(rel->rd_smgr, VISIBILITYMAP_FORKNUM) <= newnblocks) + if (smgrnblocks(rel->rd_smgr, VISIBILITYMAP_FORKNUM, false) <= newnblocks) { /* nothing to do, the file was already smaller than requested size */ return; @@ -409,7 +409,8 @@ vm_readbuf(Relation rel, BlockNumber blkno, bool extend) { if (smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM)) rel->rd_smgr->smgr_vm_nblocks = smgrnblocks(rel->rd_smgr, - VISIBILITYMAP_FORKNUM); + VISIBILITYMAP_FORKNUM, + false); else rel->rd_smgr->smgr_vm_nblocks = 0; } @@ -472,7 +473,7 @@ vm_extend(Relation rel, BlockNumber vm_nblocks) !smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM)) smgrcreate(rel->rd_smgr, VISIBILITYMAP_FORKNUM, false); - vm_nblocks_now = smgrnblocks(rel->rd_smgr, VISIBILITYMAP_FORKNUM); + vm_nblocks_now = smgrnblocks(rel->rd_smgr, VISIBILITYMAP_FORKNUM, false); while (vm_nblocks_now < vm_nblocks) { diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index 27c37d6..e09af6f 100644 --- a/src/backend/access/index/indexam.c +++ b/src/backend/access/index/indexam.c @@ -280,6 +280,12 @@ index_beginscan_internal(Relation indexRelation, IndexScanDesc scan; FmgrInfo *procedure; + /* Temporary/unlogged relations are unavailable during recovery. */ + if (!RelationNeedsWAL(indexRelation) && RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged tables during recovery"))); + RELATION_CHECKS; GET_REL_PROCEDURE(ambeginscan); diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c index cbb61bb..b6309e6 100644 --- a/src/backend/access/transam/xlogutils.c +++ b/src/backend/access/transam/xlogutils.c @@ -288,7 +288,7 @@ XLogReadBufferExtended(RelFileNode rnode, ForkNumber forknum, */ smgrcreate(smgr, forknum, true); - lastblock = smgrnblocks(smgr, forknum); + lastblock = smgrnblocks(smgr, forknum, false); if (blkno < lastblock) { diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 60b66ec..5bb766f 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -7945,7 +7945,7 @@ copy_relation_data(SMgrRelation src, SMgrRelation dst, */ use_wal = XLogIsNeeded() && relpersistence == RELPERSISTENCE_PERMANENT; - nblocks = smgrnblocks(src, forkNum); + nblocks = smgrnblocks(src, forkNum, false); for (blkno = 0; blkno < nblocks; blkno++) { diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index fd8ea45..2bf05c2 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -374,8 +374,16 @@ estimate_rel_size(Relation rel, int32 *attr_widths, case RELKIND_RELATION: case RELKIND_INDEX: case RELKIND_TOASTVALUE: - /* it has storage, ok to call the smgr */ - curpages = RelationGetNumberOfBlocks(rel); + /* + * These types of relation normally have storage - although it's + * possible that, during recovery, an unlogged or temporary + * relation which appears in the catalogs may have no file on + * disk. Since it's not appropriate to fail here, we just let + * the smgr return 0 in such cases; the executor will throw an + * error at run-time. + */ + curpages = RelationGetNumberOfBlocksInFork(rel, MAIN_FORKNUM, + true); /* * HACK: if the relation has never yet been vacuumed, use a diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index f96685d..49f7ae8 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -306,7 +306,7 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, /* Substitute proper block number if caller asked for P_NEW */ if (isExtend) - blockNum = smgrnblocks(smgr, forkNum); + blockNum = smgrnblocks(smgr, forkNum, false); if (isLocalBuf) { @@ -1914,12 +1914,13 @@ FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln) * Determines the current number of pages in the relation. */ BlockNumber -RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum) +RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum, + bool missing_ok) { /* Open it at the smgr level if not already done */ RelationOpenSmgr(relation); - return smgrnblocks(relation->rd_smgr, forkNum); + return smgrnblocks(relation->rd_smgr, forkNum, missing_ok); } /* --------------------------------------------------------------------- diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c index 1a5a874..452446d 100644 --- a/src/backend/storage/freespace/freespace.c +++ b/src/backend/storage/freespace/freespace.c @@ -298,7 +298,7 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks) else { new_nfsmblocks = fsm_logical_to_physical(first_removed_address); - if (smgrnblocks(rel->rd_smgr, FSM_FORKNUM) <= new_nfsmblocks) + if (smgrnblocks(rel->rd_smgr, FSM_FORKNUM, false) <= new_nfsmblocks) return; /* nothing to do; the FSM was already smaller */ } @@ -518,7 +518,7 @@ fsm_readbuf(Relation rel, FSMAddress addr, bool extend) { if (smgrexists(rel->rd_smgr, FSM_FORKNUM)) rel->rd_smgr->smgr_fsm_nblocks = smgrnblocks(rel->rd_smgr, - FSM_FORKNUM); + FSM_FORKNUM, false); else rel->rd_smgr->smgr_fsm_nblocks = 0; } @@ -583,7 +583,7 @@ fsm_extend(Relation rel, BlockNumber fsm_nblocks) !smgrexists(rel->rd_smgr, FSM_FORKNUM)) smgrcreate(rel->rd_smgr, FSM_FORKNUM, false); - fsm_nblocks_now = smgrnblocks(rel->rd_smgr, FSM_FORKNUM); + fsm_nblocks_now = smgrnblocks(rel->rd_smgr, FSM_FORKNUM, false); while (fsm_nblocks_now < fsm_nblocks) { diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c index 5034a1d..66238eb 100644 --- a/src/backend/storage/smgr/md.c +++ b/src/backend/storage/smgr/md.c @@ -744,12 +744,17 @@ mdwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, * are present in the chain. */ BlockNumber -mdnblocks(SMgrRelation reln, ForkNumber forknum) +mdnblocks(SMgrRelation reln, ForkNumber forknum, bool missing_ok) { - MdfdVec *v = mdopen(reln, forknum, EXTENSION_FAIL); + MdfdVec *v; BlockNumber nblocks; BlockNumber segno = 0; + v = mdopen(reln, forknum, + missing_ok ? EXTENSION_RETURN_NULL : EXTENSION_FAIL); + if (!v) + return 0; + /* * Skip through any segments that aren't the last one, to avoid redundant * seeks on them. We have previously verified that these segments are @@ -815,7 +820,7 @@ mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks) * NOTE: mdnblocks makes sure we have opened all active segments, so that * truncation loop will get them all! */ - curnblk = mdnblocks(reln, forknum); + curnblk = mdnblocks(reln, forknum, false); if (nblocks > curnblk) { /* Bogus request ... but no complaint if InRecovery */ @@ -906,7 +911,7 @@ mdimmedsync(SMgrRelation reln, ForkNumber forknum) * NOTE: mdnblocks makes sure we have opened all active segments, so that * fsync loop will get them all! */ - mdnblocks(reln, forknum); + mdnblocks(reln, forknum, false); v = mdopen(reln, forknum, EXTENSION_FAIL); diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c index a6610bf..a07fd86 100644 --- a/src/backend/storage/smgr/smgr.c +++ b/src/backend/storage/smgr/smgr.c @@ -55,7 +55,8 @@ typedef struct f_smgr BlockNumber blocknum, char *buffer); void (*smgr_write) (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync); - BlockNumber (*smgr_nblocks) (SMgrRelation reln, ForkNumber forknum); + BlockNumber (*smgr_nblocks) (SMgrRelation reln, ForkNumber forknum, + bool missing_ok); void (*smgr_truncate) (SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks); void (*smgr_immedsync) (SMgrRelation reln, ForkNumber forknum); @@ -434,9 +435,10 @@ smgrwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, * supplied relation. */ BlockNumber -smgrnblocks(SMgrRelation reln, ForkNumber forknum) +smgrnblocks(SMgrRelation reln, ForkNumber forknum, bool missing_ok) { - return (*(smgrsw[reln->smgr_which].smgr_nblocks)) (reln, forknum); + return (*(smgrsw[reln->smgr_which].smgr_nblocks)) (reln, forknum, + missing_ok); } /* diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index b8fc87e..edd1674 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -178,7 +178,7 @@ extern void PrintBufferLeakWarning(Buffer buffer); extern void CheckPointBuffers(int flags); extern BlockNumber BufferGetBlockNumber(Buffer buffer); extern BlockNumber RelationGetNumberOfBlocksInFork(Relation relation, - ForkNumber forkNum); + ForkNumber forkNum, bool missing_ok); extern void FlushRelationBuffers(Relation rel); extern void FlushDatabaseBuffers(Oid dbid); extern void DropRelFileNodeBuffers(RelFileNodeBackend rnode, @@ -186,7 +186,7 @@ extern void DropRelFileNodeBuffers(RelFileNodeBackend rnode, extern void DropDatabaseBuffers(Oid dbid); #define RelationGetNumberOfBlocks(reln) \ - RelationGetNumberOfBlocksInFork(reln, MAIN_FORKNUM) + RelationGetNumberOfBlocksInFork(reln, MAIN_FORKNUM, true) #ifdef NOT_USED extern void PrintPinnedBufs(void); diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h index 13f7239..6878a53 100644 --- a/src/include/storage/smgr.h +++ b/src/include/storage/smgr.h @@ -90,7 +90,8 @@ extern void smgrread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer); extern void smgrwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync); -extern BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum); +extern BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum, + bool fail_if_missing); extern void smgrtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks); extern void smgrimmedsync(SMgrRelation reln, ForkNumber forknum); @@ -115,7 +116,8 @@ extern void mdread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer); extern void mdwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync); -extern BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum); +extern BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum, + bool fail_if_missing); extern void mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks); extern void mdimmedsync(SMgrRelation reln, ForkNumber forknum);