diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c index 1372bb638f..75b6d96440 100644 *** a/contrib/pg_visibility/pg_visibility.c --- b/contrib/pg_visibility/pg_visibility.c *************** *** 383,388 **** pg_truncate_visibility_map(PG_FUNCTION_ARGS) --- 383,390 ---- { Oid relid = PG_GETARG_OID(0); Relation rel; + ForkNumber fork; + BlockNumber block; rel = relation_open(relid, AccessExclusiveLock); *************** *** 392,398 **** pg_truncate_visibility_map(PG_FUNCTION_ARGS) RelationOpenSmgr(rel); rel->rd_smgr->smgr_vm_nblocks = InvalidBlockNumber; ! visibilitymap_truncate(rel, 0); if (RelationNeedsWAL(rel)) { --- 394,405 ---- RelationOpenSmgr(rel); rel->rd_smgr->smgr_vm_nblocks = InvalidBlockNumber; ! block = visibilitymap_prepare_truncate(rel, 0); ! if (BlockNumberIsValid(block)) ! { ! fork = VISIBILITYMAP_FORKNUM; ! smgrtruncate(rel->rd_smgr, &fork, 1, &block); ! } if (RelationNeedsWAL(rel)) { *************** *** 418,424 **** pg_truncate_visibility_map(PG_FUNCTION_ARGS) * here and when we sent the messages at our eventual commit. However, * we're currently only sending a non-transactional smgr invalidation, * which will have been posted to shared memory immediately from within ! * visibilitymap_truncate. Therefore, there should be no race here. * * The reason why it's desirable to release the lock early here is because * of the possibility that someone will need to use this to blow away many --- 425,431 ---- * here and when we sent the messages at our eventual commit. However, * we're currently only sending a non-transactional smgr invalidation, * which will have been posted to shared memory immediately from within ! * smgr_truncate. Therefore, there should be no race here. * * The reason why it's desirable to release the lock early here is because * of the possibility that someone will need to use this to blow away many diff --git a/src/backend/access/heap/visibilindex a08922b079..262876772f 100644 *** a/src/backend/access/heap/visibilitymap.c --- b/src/backend/access/heap/visibilitymap.c *************** *** 17,23 **** * visibilitymap_set - set a bit in a previously pinned page * visibilitymap_get_status - get status of bits * visibilitymap_count - count number of bits set in visibility map ! * visibilitymap_truncate - truncate the visibility map * * NOTES * --- 17,24 ---- * visibilitymap_set - set a bit in a previously pinned page * visibilitymap_get_status - get status of bits * visibilitymap_count - count number of bits set in visibility map ! * visibilitymap_prepare_truncate - ! * prepare for truncation of the visibility map * * NOTES * *************** *** 430,445 **** visibilitymap_count(Relation rel, BlockNumber *all_visible, BlockNumber *all_fro } /* ! * visibilitymap_truncate - truncate the visibility map ! * ! * The caller must hold AccessExclusiveLock on the relation, to ensure that ! * other backends receive the smgr invalidation event that this function sends ! * before they access the VM again. * * nheapblocks is the new size of the heap. */ ! void ! visibilitymap_truncate(Relation rel, BlockNumber nheapblocks) { BlockNumber newnblocks; --- 431,448 ---- } /* ! * visibilitymap_prepare_truncate - ! * prepare for truncation of the visibility map * * nheapblocks is the new size of the heap. + * + * Return the number of blocks of new visibility map after it's truncated. + * If it's InvalidBlockNumber, there is nothing to truncate; + * otherwise the caller is responsible for calling smgrtruncate() + * to truncate the visibility map pages. */ ! BlockNumber ! visibilitymap_prepare_truncate(Relation rel, BlockNumber nheapblocks) { BlockNumber newnblocks; *************** *** 459,465 **** visibilitymap_truncate(Relation rel, BlockNumber nheapblocks) * nothing to truncate. */ if (!smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM)) ! return; /* * Unless the new size is exactly at a visibility map page boundary, the --- 462,468 ---- * nothing to truncate. */ if (!smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM)) ! return InvalidBlockNumber; /* * Unless the new size is exactly at a visibility map page boundary, the *************** *** 480,486 **** visibilitymap_truncate(Relation rel, BlockNumber nheapblocks) if (!BufferIsValid(mapBuffer)) { /* nothing to do, the file was already smaller */ ! return; } page = BufferGetPage(mapBuffer); --- 483,489 ---- if (!BufferIsValid(mapBuffer)) { /* nothing to do, the file was already smaller */ ! return InvalidBlockNumber; } page = BufferGetPage(mapBuffer); *************** *** 528,547 **** visibilitymap_truncate(Relation rel, BlockNumber nheapblocks) if (smgrnblocks(rel->rd_smgr, VISIBILITYMAP_FORKNUM) <= newnblocks) { /* nothing to do, the file was already smaller than requested size */ ! return; } ! /* Truncate the unused VM pages, and send smgr inval message */ ! smgrtruncate(rel->rd_smgr, VISIBILITYMAP_FORKNUM, newnblocks); ! ! /* ! * We might as well update the local smgr_vm_nblocks setting. smgrtruncate ! * sent an smgr cache inval message, which will cause other backends to ! * invalidate their copy of smgr_vm_nblocks, and this one too at the next ! * command boundary. But this ensures it isn't outright wrong until then. ! */ ! if (rel->rd_smgr) ! rel->rd_smgr->smgr_vm_nblocks = newnblocks; } /* --- 531,540 ---- if (smgrnblocks(rel->rd_smgr, VISIBILITYMAP_FORKNUM) <= newnblocks) { /* nothing to do, the file was already smaller than requested size */ ! return InvalidBlockNumber; } ! return newnblocks; } /* diff --git a/src/backend/catalog/storage.c b/sindex 3cc886f7fe..b8c9b6f9c6 100644 *** a/src/backend/catalog/storage.c --- b/src/backend/catalog/storage.c *************** *** 231,236 **** RelationTruncate(Relation rel, BlockNumber nblocks) --- 231,240 ---- { 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,256 **** 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 */ fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM); if (fsm) ! FreeSpaceMapTruncateRel(rel, nblocks); ! /* Truncate the visibility map too if it exists. */ vm = smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM); if (vm) ! visibilitymap_truncate(rel, nblocks); /* * We WAL-log the truncation before actually truncating, which means --- 246,280 ---- rel->rd_smgr->smgr_fsm_nblocks = InvalidBlockNumber; rel->rd_smgr->smgr_vm_nblocks = InvalidBlockNumber; ! /* 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) ! { ! blocks[nforks] = FreeSpaceMapPrepareTruncateRel(rel, nblocks); ! if (BlockNumberIsValid(blocks[nforks])) ! { ! forks[nforks] = FSM_FORKNUM; ! nforks++; ! need_fsm_vacuum = true; ! } ! } ! /* Prepare for truncation of the visibility map too if it exists */ vm = smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM); if (vm) ! { ! 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,297 **** RelationTruncate(Relation rel, BlockNumber nblocks) XLogFlush(lsn); } ! /* Do the real work */ ! smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks); } /* --- 314,329 ---- XLogFlush(lsn); } ! /* 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,593 **** smgr_redo(XLogReaderState *record) --- 620,629 ---- 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,638 **** smgr_redo(XLogReaderState *record) */ XLogFlush(lsn); if ((xlrec->flags & SMGR_TRUNCATE_HEAP) != 0) { ! smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno); /* Also tell xlogutils.c about it */ XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno); } ! /* Truncate FSM and VM too */ rel = CreateFakeRelcacheEntry(xlrec->rnode); if ((xlrec->flags & SMGR_TRUNCATE_FSM) != 0 && smgrexists(reln, FSM_FORKNUM)) ! FreeSpaceMapTruncateRel(rel, xlrec->blkno); if ((xlrec->flags & SMGR_TRUNCATE_VM) != 0 && smgrexists(reln, VISIBILITYMAP_FORKNUM)) ! visibilitymap_truncate(rel, xlrec->blkno); FreeFakeRelcacheEntry(rel); } --- 652,705 ---- */ XLogFlush(lsn); + /* Prepare for truncation of MAIN fork */ if ((xlrec->flags & SMGR_TRUNCATE_HEAP) != 0) { ! forks[nforks] = MAIN_FORKNUM; ! blocks[nforks] = xlrec->blkno; ! nforks++; /* Also tell xlogutils.c about it */ XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno); } ! /* Prepare for truncation of FSM and VM too */ rel = CreateFakeRelcacheEntry(xlrec->rnode); if ((xlrec->flags & SMGR_TRUNCATE_FSM) != 0 && smgrexists(reln, FSM_FORKNUM)) ! { ! 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)) ! { ! 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); } diff --git a/src/backend/storage/bufindex 6f3a402854..483f705305 100644 *** a/src/backend/storage/buffer/bufmgr.c --- b/src/backend/storage/buffer/bufmgr.c *************** *** 2901,2907 **** BufferGetLSNAtomic(Buffer buffer) * DropRelFileNodeBuffers * * This function removes from the buffer pool all the pages of the ! * specified relation fork that have block numbers >= firstDelBlock. * (In particular, with firstDelBlock = 0, all pages are removed.) * Dirty pages are simply dropped, without bothering to write them * out first. Therefore, this is NOT rollback-able, and so should be --- 2901,2907 ---- * DropRelFileNodeBuffers * * This function removes from the buffer pool all the pages of the ! * specified relation forks that have block numbers >= firstDelBlock. * (In particular, with firstDelBlock = 0, all pages are removed.) * Dirty pages are simply dropped, without bothering to write them * out first. Therefore, this is NOT rollback-able, and so should be *************** *** 2924,2939 **** BufferGetLSNAtomic(Buffer buffer) * -------------------------------------------------------------------- */ void ! DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber forkNum, ! BlockNumber firstDelBlock) { int i; /* If it's a local relation, it's localbuf.c's problem. */ if (RelFileNodeBackendIsTemp(rnode)) { if (rnode.backend == MyBackendId) ! DropRelFileNodeLocalBuffers(rnode.node, forkNum, firstDelBlock); return; } --- 2924,2944 ---- * -------------------------------------------------------------------- */ void ! DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber *forkNum, ! int nforks, BlockNumber *firstDelBlock) { int i; + int j; /* If it's a local relation, it's localbuf.c's problem. */ if (RelFileNodeBackendIsTemp(rnode)) { if (rnode.backend == MyBackendId) ! { ! for (j = 0; j < nforks; j++) ! DropRelFileNodeLocalBuffers(rnode.node, forkNum[j], ! firstDelBlock[j]); ! } return; } *************** *** 2962,2972 **** DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber forkNum, continue; buf_state = LockBufHdr(bufHdr); ! if (RelFileNodeEquals(bufHdr->tag.rnode, rnode.node) && ! bufHdr->tag.forkNum == forkNum && ! bufHdr->tag.blockNum >= firstDelBlock) ! InvalidateBuffer(bufHdr); /* releases spinlock */ ! else UnlockBufHdr(bufHdr, buf_state); } } --- 2967,2984 ---- continue; buf_state = LockBufHdr(bufHdr); ! ! for (j = 0; j < nforks; j++) ! { ! if (RelFileNodeEquals(bufHdr->tag.rnode, rnode.node) && ! bufHdr->tag.forkNum == forkNum[j] && ! bufHdr->tag.blockNum >= firstDelBlock[j]) ! { ! InvalidateBuffer(bufHdr); /* releases spinlock */ ! break; ! } ! } ! if (j >= nforks) UnlockBufHdr(bufHdr, buf_state); } } diff --git a/src/backend/storage/freespaceindex 2383094cfd..b7a048c96c 100644 *** a/src/backend/storage/freespace/freespace.c --- b/src/backend/storage/freespace/freespace.c *************** *** 247,262 **** GetRecordedFreeSpace(Relation rel, BlockNumber heapBlk) } /* ! * FreeSpaceMapTruncateRel - adjust for truncation of a relation. ! * ! * The caller must hold AccessExclusiveLock on the relation, to ensure that ! * other backends receive the smgr invalidation event that this function sends ! * before they access the FSM again. * * nblocks is the new size of the heap. */ ! void ! FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks) { BlockNumber new_nfsmblocks; FSMAddress first_removed_address; --- 247,264 ---- } /* ! * FreeSpaceMapPrepareTruncateRel - prepare for truncation of a relation. * * nblocks is the new size of the heap. + * + * Return the number of blocks of new FSM after it's truncated. + * If it's InvalidBlockNumber, there is nothing to truncate; + * otherwise the caller is responsible for calling smgrtruncate() + * to truncate the FSM pages, and FreeSpaceMapVacuumRange() + * to update upper-level pages in the FSM. */ ! BlockNumber ! FreeSpaceMapPrepareTruncateRel(Relation rel, BlockNumber nblocks) { BlockNumber new_nfsmblocks; FSMAddress first_removed_address; *************** *** 270,276 **** FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks) * truncate. */ if (!smgrexists(rel->rd_smgr, FSM_FORKNUM)) ! return; /* Get the location in the FSM of the first removed heap block */ first_removed_address = fsm_get_location(nblocks, &first_removed_slot); --- 272,278 ---- * truncate. */ if (!smgrexists(rel->rd_smgr, FSM_FORKNUM)) ! return InvalidBlockNumber; /* Get the location in the FSM of the first removed heap block */ first_removed_address = fsm_get_location(nblocks, &first_removed_slot); *************** *** 285,291 **** FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks) { buf = fsm_readbuf(rel, first_removed_address, false); if (!BufferIsValid(buf)) ! return; /* nothing to do; the FSM was already smaller */ LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); /* NO EREPORT(ERROR) from here till changes are logged */ --- 287,293 ---- { buf = fsm_readbuf(rel, first_removed_address, false); if (!BufferIsValid(buf)) ! return InvalidBlockNumber; /* nothing to do; the FSM was already smaller */ LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); /* NO EREPORT(ERROR) from here till changes are logged */ *************** *** 315,342 **** FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks) { new_nfsmblocks = fsm_logical_to_physical(first_removed_address); if (smgrnblocks(rel->rd_smgr, FSM_FORKNUM) <= new_nfsmblocks) ! return; /* nothing to do; the FSM was already smaller */ } ! /* Truncate the unused FSM pages, and send smgr inval message */ ! smgrtruncate(rel->rd_smgr, FSM_FORKNUM, new_nfsmblocks); ! ! /* ! * We might as well update the local smgr_fsm_nblocks setting. ! * smgrtruncate sent an smgr cache inval message, which will cause other ! * backends to invalidate their copy of smgr_fsm_nblocks, and this one too ! * at the next command boundary. But this ensures it isn't outright wrong ! * until then. ! */ ! if (rel->rd_smgr) ! rel->rd_smgr->smgr_fsm_nblocks = new_nfsmblocks; ! ! /* ! * 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. ! */ ! FreeSpaceMapVacuumRange(rel, nblocks, InvalidBlockNumber); } /* --- 317,326 ---- { new_nfsmblocks = fsm_logical_to_physical(first_removed_address); if (smgrnblocks(rel->rd_smgr, FSM_FORKNUM) <= new_nfsmblocks) ! return InvalidBlockNumber; /* nothing to do; the FSM was already smaller */ } ! return new_nfsmblocks; } /* diff --git a/src/backend/storage/smgr/smgr.c b/sindex 5b5a80e890..b50c69b438 100644 *** a/src/backend/storage/smgr/smgr.c --- b/src/backend/storage/smgr/smgr.c *************** *** 469,474 **** smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo) --- 469,475 ---- pfree(rnodes); } + /* * smgrextend() -- Add a new block to a file. * *************** *** 557,575 **** smgrnblocks(SMgrRelation reln, ForkNumber forknum) } /* ! * smgrtruncate() -- Truncate supplied relation to the specified number ! * of blocks * * The truncation is done immediately, so this can't be rolled back. */ void ! smgrtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks) { /* * Get rid of any buffers for the about-to-be-deleted blocks. bufmgr will * just drop them without bothering to write the contents. */ ! DropRelFileNodeBuffers(reln->smgr_rnode, forknum, nblocks); /* * Send a shared-inval message to force other backends to close any smgr --- 558,582 ---- } /* ! * smgrtruncate() -- Truncate the given forks of supplied relation to ! * each specified numbers of blocks * * The truncation is done immediately, so this can't be rolled back. + * + * The caller must hold AccessExclusiveLock on the relation, to ensure that + * other backends receive the smgr invalidation event that this function sends + * before they access any forks of the relation again. */ void ! smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber *nblocks) { + int i; + /* * Get rid of any buffers for the about-to-be-deleted blocks. bufmgr will * just drop them without bothering to write the contents. */ ! DropRelFileNodeBuffers(reln->smgr_rnode, forknum, nforks, nblocks); /* * Send a shared-inval message to force other backends to close any smgr *************** *** 583,592 **** smgrtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks) */ CacheInvalidateSmgr(reln->smgr_rnode); ! /* ! * Do the truncation. ! */ ! smgrsw[reln->smgr_which].smgr_truncate(reln, forknum, nblocks); } /* --- 590,613 ---- */ CacheInvalidateSmgr(reln->smgr_rnode); ! /* Do the truncation */ ! for (i = 0; i < nforks; i++) ! { ! smgrsw[reln->smgr_which].smgr_truncate(reln, forknum[i], nblocks[i]); ! ! /* ! * We might as well update the local smgr_fsm_nblocks and ! * smgr_vm_nblocks settings. The smgr cache inval message that ! * this function sent will cause other backends to invalidate ! * their copies of smgr_fsm_nblocks and smgr_vm_nblocks, ! * and these ones too at the next command boundary. ! * But these ensure they aren't outright wrong until then. ! */ ! if (forknum[i] == FSM_FORKNUM) ! reln->smgr_fsm_nblocks = nblocks[i]; ! if (forknum[i] == VISIBILITYMAP_FORKNUM) ! reln->smgr_vm_nblocks = nblocks[i]; ! } } /* diff --git a/src/include/access/visibiindex 2d8804351a..0532b04e34 100644 *** a/src/include/access/visibilitymap.h --- b/src/include/access/visibilitymap.h *************** *** 44,49 **** extern void visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf, uint8 flags); extern uint8 visibilitymap_get_status(Relation rel, BlockNumber heapBlk, Buffer *vmbuf); extern void visibilitymap_count(Relation rel, BlockNumber *all_visible, BlockNumber *all_frozen); ! extern void visibilitymap_truncate(Relation rel, BlockNumber nheapblocks); #endif /* VISIBILITYMAP_H */ --- 44,50 ---- uint8 flags); extern uint8 visibilitymap_get_status(Relation rel, BlockNumber heapBlk, Buffer *vmbuf); extern void visibilitymap_count(Relation rel, BlockNumber *all_visible, BlockNumber *all_frozen); ! extern BlockNumber visibilitymap_prepare_truncate(Relation rel, ! BlockNumber nheapblocks); #endif /* VISIBILITYMAP_H */ diff --git a/src/include/storage/bufmgr.hindex 509f4b7ef1..17b97f7e38 100644 *** a/src/include/storage/bufmgr.h --- b/src/include/storage/bufmgr.h *************** *** 190,197 **** extern BlockNumber RelationGetNumberOfBlocksInFork(Relation relation, extern void FlushOneBuffer(Buffer buffer); extern void FlushRelationBuffers(Relation rel); extern void FlushDatabaseBuffers(Oid dbid); ! extern void DropRelFileNodeBuffers(RelFileNodeBackend rnode, ! ForkNumber forkNum, BlockNumber firstDelBlock); extern void DropRelFileNodesAllBuffers(RelFileNodeBackend *rnodes, int nnodes); extern void DropDatabaseBuffers(Oid dbid); --- 190,197 ---- extern void FlushOneBuffer(Buffer buffer); extern void FlushRelationBuffers(Relation rel); extern void FlushDatabaseBuffers(Oid dbid); ! extern void DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber *forkNum, ! int nforks, BlockNumber *firstDelBlock); extern void DropRelFileNodesAllBuffers(RelFileNodeBackend *rnodes, int nnodes); extern void DropDatabaseBuffers(Oid dbid); diff --git a/src/include/storage/frindex 8d8c465d7b..b75f6fe946 100644 *** a/src/include/storage/freespace.h --- b/src/include/storage/freespace.h *************** *** 30,36 **** extern void RecordPageWithFreeSpace(Relation rel, BlockNumber heapBlk, extern void XLogRecordPageWithFreeSpace(RelFileNode rnode, BlockNumber heapBlk, Size spaceAvail); ! extern void FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks); extern void FreeSpaceMapVacuum(Relation rel); extern void FreeSpaceMapVacuumRange(Relation rel, BlockNumber start, BlockNumber end); --- 30,37 ---- extern void XLogRecordPageWithFreeSpace(RelFileNode rnode, BlockNumber heapBlk, Size spaceAvail); ! extern BlockNumber FreeSpaceMapPrepareTruncateRel(Relation rel, ! BlockNumber nblocks); extern void FreeSpaceMapVacuum(Relation rel); extern void FreeSpaceMapVacuumRange(Relation rel, BlockNumber start, BlockNumber end); diff --git a/src/include/storage/smgr.index 7393727a4b..1543d8d870 100644 *** a/src/include/storage/smgr.h --- b/src/include/storage/smgr.h *************** *** 101,108 **** extern void smgrwrite(SMgrRelation reln, ForkNumber forknum, extern void smgrwriteback(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, BlockNumber nblocks); extern BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum); ! extern void smgrtruncate(SMgrRelation reln, ForkNumber forknum, ! BlockNumber nblocks); extern void smgrimmedsync(SMgrRelation reln, ForkNumber forknum); extern void AtEOXact_SMgr(void); --- 101,108 ---- extern void smgrwriteback(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, BlockNumber nblocks); extern BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum); ! extern void smgrtruncate(SMgrRelation reln, ForkNumber *forknum, ! int nforks, BlockNumber *nblocks); extern void smgrimmedsync(SMgrRelation reln, ForkNumber forknum); extern void AtEOXact_SMgr(void);