aboutsummaryrefslogtreecommitdiff
path: root/src/backend/catalog/storage.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/catalog/storage.c')
-rw-r--r--src/backend/catalog/storage.c44
1 files changed, 30 insertions, 14 deletions
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
index 5c76e7a39ba..3525a771af5 100644
--- a/src/backend/catalog/storage.c
+++ b/src/backend/catalog/storage.c
@@ -232,24 +232,24 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
{
bool fsm;
bool vm;
-
- /* Open it at the smgr level if not already done */
- RelationOpenSmgr(rel);
+ SMgrRelation reln;
/*
- * Make sure smgr_targblock etc aren't pointing somewhere past new end
+ * Make sure smgr_targblock etc aren't pointing somewhere past new end.
+ * (Note: don't rely on this reln pointer below here.)
*/
- rel->rd_smgr->smgr_targblock = InvalidBlockNumber;
- rel->rd_smgr->smgr_fsm_nblocks = InvalidBlockNumber;
- rel->rd_smgr->smgr_vm_nblocks = InvalidBlockNumber;
+ reln = RelationGetSmgr(rel);
+ reln->smgr_targblock = InvalidBlockNumber;
+ reln->smgr_fsm_nblocks = InvalidBlockNumber;
+ reln->smgr_vm_nblocks = InvalidBlockNumber;
/* Truncate the FSM first if it exists */
- fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM);
+ fsm = smgrexists(reln, FSM_FORKNUM);
if (fsm)
FreeSpaceMapTruncateRel(rel, nblocks);
/* Truncate the visibility map too if it exists. */
- vm = smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM);
+ vm = smgrexists(RelationGetSmgr(rel), VISIBILITYMAP_FORKNUM);
if (vm)
visibilitymap_truncate(rel, nblocks);
@@ -312,7 +312,7 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
* longer exist after truncation is complete, and then truncate the
* corresponding files on disk.
*/
- smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks);
+ smgrtruncate(RelationGetSmgr(rel), MAIN_FORKNUM, nblocks);
/* We've done all the critical work, so checkpoints are OK now. */
MyProc->delayChkptEnd = false;
@@ -324,6 +324,12 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
* Note that this requires that there is no dirty data in shared buffers. If
* it's possible that there are, callers need to flush those using
* e.g. FlushRelationBuffers(rel).
+ *
+ * Also note that this is frequently called via locutions such as
+ * RelationCopyStorage(RelationGetSmgr(rel), ...);
+ * That's safe only because we perform only smgr and WAL operations here.
+ * If we invoked anything else, a relcache flush could cause our SMgrRelation
+ * argument to become a dangling pointer.
*/
void
RelationCopyStorage(SMgrRelation src, SMgrRelation dst,
@@ -364,13 +370,23 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst,
if (!PageIsVerifiedExtended(page, blkno,
PIV_LOG_WARNING | PIV_REPORT_STAT))
+ {
+ /*
+ * For paranoia's sake, capture the file path before invoking the
+ * ereport machinery. This guards against the possibility of a
+ * relcache flush caused by, e.g., an errcontext callback.
+ * (errcontext callbacks shouldn't be risking any such thing, but
+ * people have been known to forget that rule.)
+ */
+ char *relpath = relpathbackend(src->smgr_rnode.node,
+ src->smgr_rnode.backend,
+ forkNum);
+
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
errmsg("invalid page in block %u of relation %s",
- blkno,
- relpathbackend(src->smgr_rnode.node,
- src->smgr_rnode.backend,
- forkNum))));
+ blkno, relpath)));
+ }
/*
* WAL-log the copied page. Unfortunately we don't know what kind of a