Skip to content

Commit

Permalink
Replace RelationOpenSmgr() with RelationGetSmgr().
Browse files Browse the repository at this point in the history
The idea behind this patch is to design out bugs like the one fixed
by commit 9d52311.  Previously, once one did RelationOpenSmgr(rel),
it was considered okay to access rel->rd_smgr directly for some
not-very-clear interval.  But since that pointer will be cleared by
relcache flushes, we had bugs arising from overreliance on a previous
RelationOpenSmgr call still being effective.

Now, very little code except that in rel.h and relcache.c should ever
touch the rd_smgr field directly.  The normal coding rule is to use
RelationGetSmgr(rel) and not expect the result to be valid for longer
than one smgr function call.  There are a couple of places where using
the function every single time seemed like overkill, but they are now
annotated with large warning comments.

Amul Sul, after an idea of mine.

Discussion: https://postgr.es/m/CANiYTQsU7yMFpQYnv=BrcRVqK_3U3mtAzAsJCaqtzsDHfsUbdQ@mail.gmail.com
  • Loading branch information
tglsfdc committed Jul 12, 2021
1 parent 5b60cf3 commit f10f0ae
Show file tree
Hide file tree
Showing 21 changed files with 165 additions and 166 deletions.
3 changes: 1 addition & 2 deletions contrib/amcheck/verify_nbtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,7 @@ bt_index_check_internal(Oid indrelid, bool parentcheck, bool heapallindexed,
bool heapkeyspace,
allequalimage;

RelationOpenSmgr(indrel);
if (!smgrexists(indrel->rd_smgr, MAIN_FORKNUM))
if (!smgrexists(RelationGetSmgr(indrel), MAIN_FORKNUM))
ereport(ERROR,
(errcode(ERRCODE_INDEX_CORRUPTED),
errmsg("index \"%s\" lacks a main relation fork",
Expand Down
6 changes: 3 additions & 3 deletions contrib/bloom/blinsert.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,17 +177,17 @@ blbuildempty(Relation index)
* this even when wal_level=minimal.
*/
PageSetChecksumInplace(metapage, BLOOM_METAPAGE_BLKNO);
smgrwrite(index->rd_smgr, INIT_FORKNUM, BLOOM_METAPAGE_BLKNO,
smgrwrite(RelationGetSmgr(index), INIT_FORKNUM, BLOOM_METAPAGE_BLKNO,
(char *) metapage, true);
log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
log_newpage(&(RelationGetSmgr(index))->smgr_rnode.node, INIT_FORKNUM,
BLOOM_METAPAGE_BLKNO, metapage, true);

/*
* An immediate sync is required even if we xlog'd the page, because the
* write did not go through shared_buffers and therefore a concurrent
* checkpoint may have moved the redo pointer past our xlog record.
*/
smgrimmedsync(index->rd_smgr, INIT_FORKNUM);
smgrimmedsync(RelationGetSmgr(index), INIT_FORKNUM);
}

/*
Expand Down
4 changes: 1 addition & 3 deletions contrib/pg_prewarm/autoprewarm.c
Original file line number Diff line number Diff line change
Expand Up @@ -514,15 +514,13 @@ autoprewarm_database_main(Datum main_arg)
old_blk->filenode != blk->filenode ||
old_blk->forknum != blk->forknum)
{
RelationOpenSmgr(rel);

/*
* smgrexists is not safe for illegal forknum, hence check whether
* the passed forknum is valid before using it in smgrexists.
*/
if (blk->forknum > InvalidForkNumber &&
blk->forknum <= MAX_FORKNUM &&
smgrexists(rel->rd_smgr, blk->forknum))
smgrexists(RelationGetSmgr(rel), blk->forknum))
nblocks = RelationGetNumberOfBlocksInFork(rel, blk->forknum);
else
nblocks = 0;
Expand Down
5 changes: 2 additions & 3 deletions contrib/pg_prewarm/pg_prewarm.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,7 @@ pg_prewarm(PG_FUNCTION_ARGS)
aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind), get_rel_name(relOid));

/* Check that the fork exists. */
RelationOpenSmgr(rel);
if (!smgrexists(rel->rd_smgr, forkNumber))
if (!smgrexists(RelationGetSmgr(rel), forkNumber))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("fork \"%s\" does not exist for this relation",
Expand Down Expand Up @@ -178,7 +177,7 @@ pg_prewarm(PG_FUNCTION_ARGS)
for (block = first_block; block <= last_block; ++block)
{
CHECK_FOR_INTERRUPTS();
smgrread(rel->rd_smgr, forkNumber, block, blockbuffer.data);
smgrread(RelationGetSmgr(rel), forkNumber, block, blockbuffer.data);
++blocks_done;
}
}
Expand Down
6 changes: 3 additions & 3 deletions contrib/pg_visibility/pg_visibility.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,14 +391,14 @@ pg_truncate_visibility_map(PG_FUNCTION_ARGS)
/* Only some relkinds have a visibility map */
check_relation_relkind(rel);

RelationOpenSmgr(rel);
rel->rd_smgr->smgr_cached_nblocks[VISIBILITYMAP_FORKNUM] = InvalidBlockNumber;
/* Forcibly reset cached file size */
RelationGetSmgr(rel)->smgr_cached_nblocks[VISIBILITYMAP_FORKNUM] = InvalidBlockNumber;

block = visibilitymap_prepare_truncate(rel, 0);
if (BlockNumberIsValid(block))
{
fork = VISIBILITYMAP_FORKNUM;
smgrtruncate(rel->rd_smgr, &fork, 1, &block);
smgrtruncate(RelationGetSmgr(rel), &fork, 1, &block);
}

if (RelationNeedsWAL(rel))
Expand Down
14 changes: 6 additions & 8 deletions src/backend/access/gist/gistbuild.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,8 +409,7 @@ gist_indexsortbuild(GISTBuildState *state)
* replaced with the real root page at the end.
*/
page = palloc0(BLCKSZ);
RelationOpenSmgr(state->indexrel);
smgrextend(state->indexrel->rd_smgr, MAIN_FORKNUM, GIST_ROOT_BLKNO,
smgrextend(RelationGetSmgr(state->indexrel), MAIN_FORKNUM, GIST_ROOT_BLKNO,
page, true);
state->pages_allocated++;
state->pages_written++;
Expand Down Expand Up @@ -450,10 +449,9 @@ gist_indexsortbuild(GISTBuildState *state)
gist_indexsortbuild_flush_ready_pages(state);

/* Write out the root */
RelationOpenSmgr(state->indexrel);
PageSetLSN(pagestate->page, GistBuildLSN);
PageSetChecksumInplace(pagestate->page, GIST_ROOT_BLKNO);
smgrwrite(state->indexrel->rd_smgr, MAIN_FORKNUM, GIST_ROOT_BLKNO,
smgrwrite(RelationGetSmgr(state->indexrel), MAIN_FORKNUM, GIST_ROOT_BLKNO,
pagestate->page, true);
if (RelationNeedsWAL(state->indexrel))
log_newpage(&state->indexrel->rd_node, MAIN_FORKNUM, GIST_ROOT_BLKNO,
Expand Down Expand Up @@ -562,8 +560,6 @@ gist_indexsortbuild_flush_ready_pages(GISTBuildState *state)
if (state->ready_num_pages == 0)
return;

RelationOpenSmgr(state->indexrel);

for (int i = 0; i < state->ready_num_pages; i++)
{
Page page = state->ready_pages[i];
Expand All @@ -575,7 +571,8 @@ gist_indexsortbuild_flush_ready_pages(GISTBuildState *state)

PageSetLSN(page, GistBuildLSN);
PageSetChecksumInplace(page, blkno);
smgrextend(state->indexrel->rd_smgr, MAIN_FORKNUM, blkno, page, true);
smgrextend(RelationGetSmgr(state->indexrel), MAIN_FORKNUM, blkno, page,
true);

state->pages_written++;
}
Expand Down Expand Up @@ -860,7 +857,8 @@ gistBuildCallback(Relation index,
*/
if ((buildstate->buildMode == GIST_BUFFERING_AUTO &&
buildstate->indtuples % BUFFERING_MODE_SWITCH_CHECK_STEP == 0 &&
effective_cache_size < smgrnblocks(index->rd_smgr, MAIN_FORKNUM)) ||
effective_cache_size < smgrnblocks(RelationGetSmgr(index),
MAIN_FORKNUM)) ||
(buildstate->buildMode == GIST_BUFFERING_STATS &&
buildstate->indtuples >= BUFFERING_MODE_TUPLE_SIZE_STATS_TARGET))
{
Expand Down
4 changes: 2 additions & 2 deletions src/backend/access/hash/hashpage.c
Original file line number Diff line number Diff line change
Expand Up @@ -1024,9 +1024,9 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks)
zerobuf.data,
true);

RelationOpenSmgr(rel);
PageSetChecksumInplace(page, lastblock);
smgrextend(rel->rd_smgr, MAIN_FORKNUM, lastblock, zerobuf.data, false);
smgrextend(RelationGetSmgr(rel), MAIN_FORKNUM, lastblock, zerobuf.data,
false);

return true;
}
Expand Down
7 changes: 3 additions & 4 deletions src/backend/access/heap/heapam_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,6 @@ heapam_relation_copy_data(Relation rel, const RelFileNode *newrnode)
SMgrRelation dstrel;

dstrel = smgropen(*newrnode, rel->rd_backend);
RelationOpenSmgr(rel);

/*
* Since we copy the file directly without looking at the shared buffers,
Expand All @@ -645,14 +644,14 @@ heapam_relation_copy_data(Relation rel, const RelFileNode *newrnode)
RelationCreateStorage(*newrnode, rel->rd_rel->relpersistence);

/* copy main fork */
RelationCopyStorage(rel->rd_smgr, dstrel, MAIN_FORKNUM,
RelationCopyStorage(RelationGetSmgr(rel), dstrel, MAIN_FORKNUM,
rel->rd_rel->relpersistence);

/* copy those extra forks that exist */
for (ForkNumber forkNum = MAIN_FORKNUM + 1;
forkNum <= MAX_FORKNUM; forkNum++)
{
if (smgrexists(rel->rd_smgr, forkNum))
if (smgrexists(RelationGetSmgr(rel), forkNum))
{
smgrcreate(dstrel, forkNum, false);

Expand All @@ -664,7 +663,7 @@ heapam_relation_copy_data(Relation rel, const RelFileNode *newrnode)
(rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
forkNum == INIT_FORKNUM))
log_smgrcreate(newrnode, forkNum);
RelationCopyStorage(rel->rd_smgr, dstrel, forkNum,
RelationCopyStorage(RelationGetSmgr(rel), dstrel, forkNum,
rel->rd_rel->relpersistence);
}
}
Expand Down
15 changes: 4 additions & 11 deletions src/backend/access/heap/rewriteheap.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,8 @@ end_heap_rewrite(RewriteState state)

PageSetChecksumInplace(state->rs_buffer, state->rs_blockno);

RelationOpenSmgr(state->rs_new_rel);
smgrextend(state->rs_new_rel->rd_smgr, MAIN_FORKNUM, state->rs_blockno,
(char *) state->rs_buffer, true);
smgrextend(RelationGetSmgr(state->rs_new_rel), MAIN_FORKNUM,
state->rs_blockno, (char *) state->rs_buffer, true);
}

/*
Expand All @@ -339,11 +338,7 @@ end_heap_rewrite(RewriteState state)
* wrote before the checkpoint.
*/
if (RelationNeedsWAL(state->rs_new_rel))
{
/* for an empty table, this could be first smgr access */
RelationOpenSmgr(state->rs_new_rel);
smgrimmedsync(state->rs_new_rel->rd_smgr, MAIN_FORKNUM);
}
smgrimmedsync(RelationGetSmgr(state->rs_new_rel), MAIN_FORKNUM);

logical_end_heap_rewrite(state);

Expand Down Expand Up @@ -695,11 +690,9 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
* need for smgr to schedule an fsync for this write; we'll do it
* ourselves in end_heap_rewrite.
*/
RelationOpenSmgr(state->rs_new_rel);

PageSetChecksumInplace(page, state->rs_blockno);

smgrextend(state->rs_new_rel->rd_smgr, MAIN_FORKNUM,
smgrextend(RelationGetSmgr(state->rs_new_rel), MAIN_FORKNUM,
state->rs_blockno, (char *) page, true);

state->rs_blockno++;
Expand Down
53 changes: 27 additions & 26 deletions src/backend/access/heap/visibilitymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -455,13 +455,11 @@ visibilitymap_prepare_truncate(Relation rel, BlockNumber nheapblocks)
elog(DEBUG1, "vm_truncate %s %d", RelationGetRelationName(rel), nheapblocks);
#endif

RelationOpenSmgr(rel);

/*
* If no visibility map has been created yet for this relation, there's
* nothing to truncate.
*/
if (!smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM))
if (!smgrexists(RelationGetSmgr(rel), VISIBILITYMAP_FORKNUM))
return InvalidBlockNumber;

/*
Expand Down Expand Up @@ -528,7 +526,7 @@ visibilitymap_prepare_truncate(Relation rel, BlockNumber nheapblocks)
else
newnblocks = truncBlock;

if (smgrnblocks(rel->rd_smgr, VISIBILITYMAP_FORKNUM) <= newnblocks)
if (smgrnblocks(RelationGetSmgr(rel), VISIBILITYMAP_FORKNUM) <= newnblocks)
{
/* nothing to do, the file was already smaller than requested size */
return InvalidBlockNumber;
Expand All @@ -547,30 +545,29 @@ static Buffer
vm_readbuf(Relation rel, BlockNumber blkno, bool extend)
{
Buffer buf;
SMgrRelation reln;

/*
* We might not have opened the relation at the smgr level yet, or we
* might have been forced to close it by a sinval message. The code below
* won't necessarily notice relation extension immediately when extend =
* false, so we rely on sinval messages to ensure that our ideas about the
* size of the map aren't too far out of date.
* 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.
*/
RelationOpenSmgr(rel);
reln = RelationGetSmgr(rel);

/*
* If we haven't cached the size of the visibility map fork yet, check it
* first.
*/
if (rel->rd_smgr->smgr_cached_nblocks[VISIBILITYMAP_FORKNUM] == InvalidBlockNumber)
if (reln->smgr_cached_nblocks[VISIBILITYMAP_FORKNUM] == InvalidBlockNumber)
{
if (smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM))
smgrnblocks(rel->rd_smgr, VISIBILITYMAP_FORKNUM);
if (smgrexists(reln, VISIBILITYMAP_FORKNUM))
smgrnblocks(reln, VISIBILITYMAP_FORKNUM);
else
rel->rd_smgr->smgr_cached_nblocks[VISIBILITYMAP_FORKNUM] = 0;
reln->smgr_cached_nblocks[VISIBILITYMAP_FORKNUM] = 0;
}

/* Handle requests beyond EOF */
if (blkno >= rel->rd_smgr->smgr_cached_nblocks[VISIBILITYMAP_FORKNUM])
if (blkno >= reln->smgr_cached_nblocks[VISIBILITYMAP_FORKNUM])
{
if (extend)
vm_extend(rel, blkno + 1);
Expand Down Expand Up @@ -618,6 +615,7 @@ vm_extend(Relation rel, BlockNumber vm_nblocks)
{
BlockNumber vm_nblocks_now;
PGAlignedBlock pg;
SMgrRelation reln;

PageInit((Page) pg.data, BLCKSZ, 0);

Expand All @@ -633,29 +631,32 @@ vm_extend(Relation rel, BlockNumber vm_nblocks)
*/
LockRelationForExtension(rel, ExclusiveLock);

/* Might have to re-open if a cache flush happened */
RelationOpenSmgr(rel);
/*
* 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);

/*
* Create the file first if it doesn't exist. If smgr_vm_nblocks is
* positive then it must exist, no need for an smgrexists call.
*/
if ((rel->rd_smgr->smgr_cached_nblocks[VISIBILITYMAP_FORKNUM] == 0 ||
rel->rd_smgr->smgr_cached_nblocks[VISIBILITYMAP_FORKNUM] == InvalidBlockNumber) &&
!smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM))
smgrcreate(rel->rd_smgr, VISIBILITYMAP_FORKNUM, false);
if ((reln->smgr_cached_nblocks[VISIBILITYMAP_FORKNUM] == 0 ||
reln->smgr_cached_nblocks[VISIBILITYMAP_FORKNUM] == InvalidBlockNumber) &&
!smgrexists(reln, VISIBILITYMAP_FORKNUM))
smgrcreate(reln, VISIBILITYMAP_FORKNUM, false);

/* Invalidate cache so that smgrnblocks() asks the kernel. */
rel->rd_smgr->smgr_cached_nblocks[VISIBILITYMAP_FORKNUM] = InvalidBlockNumber;
vm_nblocks_now = smgrnblocks(rel->rd_smgr, VISIBILITYMAP_FORKNUM);
reln->smgr_cached_nblocks[VISIBILITYMAP_FORKNUM] = InvalidBlockNumber;
vm_nblocks_now = smgrnblocks(reln, VISIBILITYMAP_FORKNUM);

/* Now extend the file */
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);
smgrextend(reln, VISIBILITYMAP_FORKNUM, vm_nblocks_now, pg.data, false);
vm_nblocks_now++;
}

Expand All @@ -666,7 +667,7 @@ vm_extend(Relation rel, BlockNumber vm_nblocks)
* to keep checking for creation or extension of the file, which happens
* infrequently.
*/
CacheInvalidateSmgr(rel->rd_smgr->smgr_rnode);
CacheInvalidateSmgr(reln->smgr_rnode);

UnlockRelationForExtension(rel, ExclusiveLock);
}
6 changes: 3 additions & 3 deletions src/backend/access/nbtree/nbtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,17 +163,17 @@ btbuildempty(Relation index)
* this even when wal_level=minimal.
*/
PageSetChecksumInplace(metapage, BTREE_METAPAGE);
smgrwrite(index->rd_smgr, INIT_FORKNUM, BTREE_METAPAGE,
smgrwrite(RelationGetSmgr(index), INIT_FORKNUM, BTREE_METAPAGE,
(char *) metapage, true);
log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
log_newpage(&RelationGetSmgr(index)->smgr_rnode.node, INIT_FORKNUM,
BTREE_METAPAGE, metapage, true);

/*
* An immediate sync is required even if we xlog'd the page, because the
* write did not go through shared_buffers and therefore a concurrent
* checkpoint may have moved the redo pointer past our xlog record.
*/
smgrimmedsync(index->rd_smgr, INIT_FORKNUM);
smgrimmedsync(RelationGetSmgr(index), INIT_FORKNUM);
}

/*
Expand Down
Loading

0 comments on commit f10f0ae

Please sign in to comment.