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.c87
1 files changed, 77 insertions, 10 deletions
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
index 3cc886f7fe2..b8c9b6f9c68 100644
--- a/src/backend/catalog/storage.c
+++ b/src/backend/catalog/storage.c
@@ -231,6 +231,10 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
{
bool fsm;
bool vm;
+ bool need_fsm_vacuum = false;
+ ForkNumber forks[MAX_FORKNUM];
+ BlockNumber blocks[MAX_FORKNUM];
+ int nforks = 0;
/* Open it at the smgr level if not already done */
RelationOpenSmgr(rel);
@@ -242,15 +246,35 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
rel->rd_smgr->smgr_fsm_nblocks = InvalidBlockNumber;
rel->rd_smgr->smgr_vm_nblocks = InvalidBlockNumber;
- /* Truncate the FSM first if it exists */
+ /* Prepare for truncation of MAIN fork of the relation */
+ forks[nforks] = MAIN_FORKNUM;
+ blocks[nforks] = nblocks;
+ nforks++;
+
+ /* Prepare for truncation of the FSM if it exists */
fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM);
if (fsm)
- FreeSpaceMapTruncateRel(rel, nblocks);
+ {
+ blocks[nforks] = FreeSpaceMapPrepareTruncateRel(rel, nblocks);
+ if (BlockNumberIsValid(blocks[nforks]))
+ {
+ forks[nforks] = FSM_FORKNUM;
+ nforks++;
+ need_fsm_vacuum = true;
+ }
+ }
- /* Truncate the visibility map too if it exists. */
+ /* Prepare for truncation of the visibility map too if it exists */
vm = smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM);
if (vm)
- visibilitymap_truncate(rel, nblocks);
+ {
+ blocks[nforks] = visibilitymap_prepare_truncate(rel, nblocks);
+ if (BlockNumberIsValid(blocks[nforks]))
+ {
+ forks[nforks] = VISIBILITYMAP_FORKNUM;
+ nforks++;
+ }
+ }
/*
* We WAL-log the truncation before actually truncating, which means
@@ -290,8 +314,16 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
XLogFlush(lsn);
}
- /* Do the real work */
- smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks);
+ /* Do the real work to truncate relation forks */
+ smgrtruncate(rel->rd_smgr, forks, nforks, blocks);
+
+ /*
+ * Update upper-level FSM pages to account for the truncation.
+ * This is important because the just-truncated pages were likely
+ * marked as all-free, and would be preferentially selected.
+ */
+ if (need_fsm_vacuum)
+ FreeSpaceMapVacuumRange(rel, nblocks, InvalidBlockNumber);
}
/*
@@ -588,6 +620,10 @@ smgr_redo(XLogReaderState *record)
xl_smgr_truncate *xlrec = (xl_smgr_truncate *) XLogRecGetData(record);
SMgrRelation reln;
Relation rel;
+ ForkNumber forks[MAX_FORKNUM];
+ BlockNumber blocks[MAX_FORKNUM];
+ int nforks = 0;
+ bool need_fsm_vacuum = false;
reln = smgropen(xlrec->rnode, InvalidBackendId);
@@ -616,23 +652,54 @@ smgr_redo(XLogReaderState *record)
*/
XLogFlush(lsn);
+ /* Prepare for truncation of MAIN fork */
if ((xlrec->flags & SMGR_TRUNCATE_HEAP) != 0)
{
- smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno);
+ forks[nforks] = MAIN_FORKNUM;
+ blocks[nforks] = xlrec->blkno;
+ nforks++;
/* Also tell xlogutils.c about it */
XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno);
}
- /* Truncate FSM and VM too */
+ /* Prepare for truncation of FSM and VM too */
rel = CreateFakeRelcacheEntry(xlrec->rnode);
if ((xlrec->flags & SMGR_TRUNCATE_FSM) != 0 &&
smgrexists(reln, FSM_FORKNUM))
- FreeSpaceMapTruncateRel(rel, xlrec->blkno);
+ {
+ blocks[nforks] = FreeSpaceMapPrepareTruncateRel(rel, xlrec->blkno);
+ if (BlockNumberIsValid(blocks[nforks]))
+ {
+ forks[nforks] = FSM_FORKNUM;
+ nforks++;
+ need_fsm_vacuum = true;
+ }
+ }
if ((xlrec->flags & SMGR_TRUNCATE_VM) != 0 &&
smgrexists(reln, VISIBILITYMAP_FORKNUM))
- visibilitymap_truncate(rel, xlrec->blkno);
+ {
+ blocks[nforks] = visibilitymap_prepare_truncate(rel, xlrec->blkno);
+ if (BlockNumberIsValid(blocks[nforks]))
+ {
+ forks[nforks] = VISIBILITYMAP_FORKNUM;
+ nforks++;
+ }
+ }
+
+ /* Do the real work to truncate relation forks */
+ if (nforks > 0)
+ smgrtruncate(reln, forks, nforks, blocks);
+
+ /*
+ * Update upper-level FSM pages to account for the truncation.
+ * This is important because the just-truncated pages were likely
+ * marked as all-free, and would be preferentially selected.
+ */
+ if (need_fsm_vacuum)
+ FreeSpaceMapVacuumRange(rel, xlrec->blkno,
+ InvalidBlockNumber);
FreeFakeRelcacheEntry(rel);
}