From 969e07a05b0b067cba1ca02f549c522fba5873d0 Mon Sep 17 00:00:00 2001 From: Kirk Jamison Date: Thu, 4 Jul 2019 10:59:05 +0000 Subject: [PATCH] Speedup truncates of relation forks Whenever we truncate relations, it involves several scans of the shared buffers for every call of smgrtruncate() for each fork which is time-consuming. This patch reduces the scan for all forks into one instead of three, and improves the relation truncates by initially marking the pages-to-be-truncated of relation forks, then simultaneously truncating them, resulting to an improved performance in VACUUM, autovacuum operations and their recovery performance. --- contrib/pg_visibility/pg_visibility.c | 11 ++- src/backend/access/heap/visibilitymap.c | 36 ++++------ src/backend/catalog/storage.c | 111 ++++++++++++++++++++++++++---- src/backend/storage/buffer/bufmgr.c | 48 +++++++++---- src/backend/storage/freespace/freespace.c | 41 ++++------- src/backend/storage/smgr/smgr.c | 49 ++++++++----- src/include/access/visibilitymap.h | 2 +- src/include/storage/bufmgr.h | 4 +- src/include/storage/freespace.h | 2 +- src/include/storage/smgr.h | 7 +- 10 files changed, 211 insertions(+), 100 deletions(-) diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c index 1372bb6..1aabde2 100644 --- a/contrib/pg_visibility/pg_visibility.c +++ b/contrib/pg_visibility/pg_visibility.c @@ -383,6 +383,9 @@ pg_truncate_visibility_map(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); Relation rel; + ForkNumber fork; + BlockNumber block; + BlockNumber newnblocks = InvalidBlockNumber; rel = relation_open(relid, AccessExclusiveLock); @@ -392,7 +395,13 @@ pg_truncate_visibility_map(PG_FUNCTION_ARGS) RelationOpenSmgr(rel); rel->rd_smgr->smgr_vm_nblocks = InvalidBlockNumber; - visibilitymap_truncate(rel, 0); + block = visibilitymap_truncate_prepare(rel, 0); + if (BlockNumberIsValid(block) + { + fork = VISIBILITYMAP_FORKNUM; + newnblocks = block; + } + smgrtruncate(rel->rd_smgr, &fork, 1, &block); if (RelationNeedsWAL(rel)) { diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c index 64dfe06..4cc7977 100644 --- a/src/backend/access/heap/visibilitymap.c +++ b/src/backend/access/heap/visibilitymap.c @@ -17,7 +17,7 @@ * 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 + * visibilitymap_truncate_prepare - truncate only tail bits of map pages * * NOTES * @@ -430,16 +430,18 @@ visibilitymap_count(Relation rel, BlockNumber *all_visible, BlockNumber *all_fro } /* - * visibilitymap_truncate - truncate the visibility map + * visibilitymap_truncate_prepare - truncate only tail bits of map page + * and return the block number for actual + * truncation later * - * 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. + * Note that this does not truncate the actual visibility map pages. + * When this function is called, the caller must eventually follow it with + * smgrtruncate() call to actually truncate visibility map pages. * * nheapblocks is the new size of the heap. */ -void -visibilitymap_truncate(Relation rel, BlockNumber nheapblocks) +BlockNumber +visibilitymap_truncate_prepare(Relation rel, BlockNumber nheapblocks) { BlockNumber newnblocks; @@ -459,7 +461,7 @@ visibilitymap_truncate(Relation rel, BlockNumber nheapblocks) * nothing to truncate. */ if (!smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM)) - return; + return InvalidBlockNumber; /* * Unless the new size is exactly at a visibility map page boundary, the @@ -480,7 +482,7 @@ visibilitymap_truncate(Relation rel, BlockNumber nheapblocks) if (!BufferIsValid(mapBuffer)) { /* nothing to do, the file was already smaller */ - return; + return InvalidBlockNumber; } page = BufferGetPage(mapBuffer); @@ -528,20 +530,10 @@ 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; + return InvalidBlockNumber; } - - /* 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; + else + return newnblocks; } /* diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c index 3cc886f..c9fd637 100644 --- a/src/backend/catalog/storage.c +++ b/src/backend/catalog/storage.c @@ -231,6 +231,12 @@ RelationTruncate(Relation rel, BlockNumber nblocks) { bool fsm; bool vm; + ForkNumber forks[MAX_FORKNUM]; + BlockNumber blocks[MAX_FORKNUM]; + BlockNumber first_removed_nblocks = InvalidBlockNumber; + BlockNumber new_nfsmblocks = InvalidBlockNumber; + BlockNumber newnblocks = InvalidBlockNumber; + int nforks = 0; /* Open it at the smgr level if not already done */ RelationOpenSmgr(rel); @@ -242,15 +248,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 */ + /* Mark the dirty FSM page and return a block number. */ fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM); if (fsm) - FreeSpaceMapTruncateRel(rel, nblocks); + { + blocks[nforks] = MarkFreeSpaceMapTruncateRel(rel, nblocks); + if (BlockNumberIsValid(blocks[nforks])) + { + first_removed_nblocks = nblocks; + forks[nforks] = FSM_FORKNUM; + new_nfsmblocks= blocks[nforks]; + nforks++; + } + } - /* Truncate the visibility map too if it exists. */ + /* + * Truncate only the tail bits of VM and return the block number + * for actual truncation later in smgrtruncate. + */ vm = smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM); if (vm) - visibilitymap_truncate(rel, nblocks); + { + blocks[nforks] = visibilitymap_truncate_prepare(rel, nblocks); + if (BlockNumberIsValid(blocks[nforks])) + { + forks[nforks] = VISIBILITYMAP_FORKNUM; + newnblocks = blocks[nforks]; + nforks++; + } + } /* * We WAL-log the truncation before actually truncating, which means @@ -290,8 +316,21 @@ RelationTruncate(Relation rel, BlockNumber nblocks) XLogFlush(lsn); } - /* Do the real work */ - smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks); + /* Mark the MAIN fork */ + forks[nforks] = MAIN_FORKNUM; + blocks[nforks] = nblocks; + nforks++; + + /* Truncate relation forks simultaneously */ + 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. + */ + //FreeSpaceMapVacuumRange(rel, new_nfsmblocks, InvalidBlockNumber); + FreeSpaceMapVacuumRange(rel, first_removed_nblocks, InvalidBlockNumber); } /* @@ -588,6 +627,15 @@ 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]; + BlockNumber first_removed_nblocks = InvalidBlockNumber; + BlockNumber new_nfsmblocks = InvalidBlockNumber; + BlockNumber newnblocks = InvalidBlockNumber; + int nforks = 0; + bool fsm_fork = false; + bool main_fork = false; + bool vm_fork = false; reln = smgropen(xlrec->rnode, InvalidBackendId); @@ -616,23 +664,60 @@ smgr_redo(XLogReaderState *record) */ XLogFlush(lsn); + /* + * To speedup recovery, we mark the about-to-be-truncated blocks of + * relation forks first, then truncate those simultaneously later. + */ 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); + forks[nforks] = MAIN_FORKNUM; + blocks[nforks] = xlrec->blkno; + nforks++; + main_fork = true; } - /* Truncate 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] = MarkFreeSpaceMapTruncateRel(rel, xlrec->blkno); + if (BlockNumberIsValid(blocks[nforks])) + { + first_removed_nblocks = xlrec->blkno; + forks[nforks] = FSM_FORKNUM; + new_nfsmblocks= blocks[nforks]; + nforks++; + fsm_fork = true; + } + } if ((xlrec->flags & SMGR_TRUNCATE_VM) != 0 && smgrexists(reln, VISIBILITYMAP_FORKNUM)) - visibilitymap_truncate(rel, xlrec->blkno); + { + blocks[nforks] = visibilitymap_truncate_prepare(rel, xlrec->blkno); + if (BlockNumberIsValid(blocks[nforks])) + { + forks[nforks] = VISIBILITYMAP_FORKNUM; + newnblocks = blocks[nforks]; + nforks++; + vm_fork = true; + } + } + + /* Truncate relation forks simultaneously */ + if (main_fork || fsm_fork || vm_fork) + smgrtruncate(reln, forks, nforks, blocks); + + /* Also tell xlogutils.c about it */ + if (main_fork) + XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno); + + /* + * 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, first_removed_nblocks, InvalidBlockNumber); FreeFakeRelcacheEntry(rel); } diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 7332e6b..512c8a1 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -2899,8 +2899,8 @@ BufferGetLSNAtomic(Buffer buffer) /* --------------------------------------------------------------------- * DropRelFileNodeBuffers * - * This function removes from the buffer pool all the pages of the - * specified relation fork that have block numbers >= firstDelBlock. + * This function simultaneously removes from the buffer pool all the + * pages of the 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 @@ -2923,23 +2923,36 @@ BufferGetLSNAtomic(Buffer buffer) * -------------------------------------------------------------------- */ void -DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber forkNum, - BlockNumber firstDelBlock) +DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber *forkNum, + int nforks, BlockNumber *firstDelBlock) { - int i; + BlockNumber minBlock = InvalidBlockNumber; /* If it's a local relation, it's localbuf.c's problem. */ if (RelFileNodeBackendIsTemp(rnode)) { if (rnode.backend == MyBackendId) - DropRelFileNodeLocalBuffers(rnode.node, forkNum, firstDelBlock); + { + for (int i = 0; i < nforks; i++) + DropRelFileNodeLocalBuffers(rnode.node, forkNum[i], + firstDelBlock[i]); + } return; } - for (i = 0; i < NBuffers; i++) + /* Get the lower bound of target block number we're interested in */ + for (int i = 0; i < nforks; i++) + { + if (!BlockNumberIsValid(minBlock) || + minBlock > firstDelBlock[i]) + minBlock = firstDelBlock[i]; + } + + for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr = GetBufferDescriptor(i); uint32 buf_state; + int j = 0; /* * We can make this a tad faster by prechecking the buffer tag before @@ -2960,12 +2973,23 @@ DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber forkNum, if (!RelFileNodeEquals(bufHdr->tag.rnode, rnode.node)) continue; + /* Check with the lower bound block number and skip the loop */ + if (bufHdr->tag.blockNum < minBlock) + continue; /* skip checking the buffer pool scan */ + buf_state = LockBufHdr(bufHdr); - if (RelFileNodeEquals(bufHdr->tag.rnode, rnode.node) && - bufHdr->tag.forkNum == forkNum && - bufHdr->tag.blockNum >= firstDelBlock) - InvalidateBuffer(bufHdr); /* releases spinlock */ - else + + 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/freespace/freespace.c b/src/backend/storage/freespace/freespace.c index c17b3f4..9c29604 100644 --- a/src/backend/storage/freespace/freespace.c +++ b/src/backend/storage/freespace/freespace.c @@ -247,16 +247,16 @@ GetRecordedFreeSpace(Relation rel, BlockNumber heapBlk) } /* - * FreeSpaceMapTruncateRel - adjust for truncation of a relation. + * MarkFreeSpaceMapTruncateRel - 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. + * This function marks the dirty page and returns a block number. + * The caller of this function must eventually call smgrtruncate() to actually + * truncate FSM pages. * * nblocks is the new size of the heap. */ -void -FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks) +BlockNumber +MarkFreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks) { BlockNumber new_nfsmblocks; FSMAddress first_removed_address; @@ -270,7 +270,7 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks) * truncate. */ if (!smgrexists(rel->rd_smgr, FSM_FORKNUM)) - return; + 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,7 +285,7 @@ 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 */ + return InvalidBlockNumber; /* nothing to do; the FSM was already smaller */ LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); /* NO EREPORT(ERROR) from here till changes are logged */ @@ -310,33 +310,16 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks) UnlockReleaseBuffer(buf); new_nfsmblocks = fsm_logical_to_physical(first_removed_address) + 1; + return new_nfsmblocks; } else { 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 */ + return InvalidBlockNumber; /* nothing to do; the FSM was already smaller */ + else + return new_nfsmblocks; } - - /* 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); } /* diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c index dba8c39..ea57de7 100644 --- a/src/backend/storage/smgr/smgr.c +++ b/src/backend/storage/smgr/smgr.c @@ -498,29 +498,30 @@ smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo) } /* - * smgrdounlinkfork() -- Immediately unlink one fork of a relation. + * smgrdounlinkfork() -- Immediately unlink each fork of a relation. * - * The specified fork of the relation is removed from the store. This - * should not be used during transactional operations, since it can't be - * undone. + * Each fork of the relation is removed from the store. This should + * not be used during transactional operations, since it can't be undone. * * If isRedo is true, it is okay for the underlying file to be gone * already. */ void -smgrdounlinkfork(SMgrRelation reln, ForkNumber forknum, bool isRedo) +smgrdounlinkfork(SMgrRelation reln, ForkNumber *forknum, int nforks, bool isRedo) { RelFileNodeBackend rnode = reln->smgr_rnode; int which = reln->smgr_which; + int i; - /* Close the fork at smgr level */ - smgrsw[which].smgr_close(reln, forknum); + /* Close each fork at smgr level */ + for (i = 0; i < nforks; i++) + smgrsw[which].smgr_close(reln, forknum[i]); /* - * Get rid of any remaining buffers for the fork. bufmgr will just drop + * Get rid of any remaining buffers for each fork. bufmgr will just drop * them without bothering to write the contents. */ - DropRelFileNodeBuffers(rnode, forknum, 0); + DropRelFileNodeBuffers(rnode, forknum, nforks, 0); /* * It'd be nice to tell the stats collector to forget it immediately, too. @@ -546,7 +547,8 @@ smgrdounlinkfork(SMgrRelation reln, ForkNumber forknum, bool isRedo) * ERROR, because we've already decided to commit or abort the current * xact. */ - smgrsw[which].smgr_unlink(rnode, forknum, isRedo); + for (i = 0; i < nforks; i++) + smgrsw[which].smgr_unlink(rnode, forknum[i], isRedo); } /* @@ -643,13 +645,15 @@ smgrnblocks(SMgrRelation reln, ForkNumber forknum) * The truncation is done immediately, so this can't be rolled back. */ void -smgrtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks) +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, nblocks); + DropRelFileNodeBuffers(reln->smgr_rnode, forknum, nforks, nblocks); /* * Send a shared-inval message to force other backends to close any smgr @@ -663,10 +667,23 @@ smgrtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks) */ CacheInvalidateSmgr(reln->smgr_rnode); - /* - * Do the truncation. - */ - smgrsw[reln->smgr_which].smgr_truncate(reln, forknum, nblocks); + /* 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 + * setting. smgrtruncate sent an smgr cache inval message, which will + * cause other backends to invalidate their copy of smgr_fsm_nblocks and + * smgr_vm_nblocks, and these ones too at the next command boundary. But + * this ensures these 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/visibilitymap.h b/src/include/access/visibilitymap.h index 2d88043..1ab6a81 100644 --- a/src/include/access/visibilitymap.h +++ b/src/include/access/visibilitymap.h @@ -44,6 +44,6 @@ 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); +extern BlockNumber visibilitymap_truncate_prepare(Relation rel, BlockNumber nheapblocks); #endif /* VISIBILITYMAP_H */ diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index 509f4b7..17b97f7 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -190,8 +190,8 @@ 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 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/freespace.h b/src/include/storage/freespace.h index 8d8c465..bf19a67 100644 --- a/src/include/storage/freespace.h +++ b/src/include/storage/freespace.h @@ -30,7 +30,7 @@ extern void RecordPageWithFreeSpace(Relation rel, BlockNumber heapBlk, extern void XLogRecordPageWithFreeSpace(RelFileNode rnode, BlockNumber heapBlk, Size spaceAvail); -extern void FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks); +extern BlockNumber MarkFreeSpaceMapTruncateRel(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.h b/src/include/storage/smgr.h index d286c8c..a24532c 100644 --- a/src/include/storage/smgr.h +++ b/src/include/storage/smgr.h @@ -90,7 +90,8 @@ extern void smgrclosenode(RelFileNodeBackend rnode); extern void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo); extern void smgrdounlink(SMgrRelation reln, bool isRedo); extern void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo); -extern void smgrdounlinkfork(SMgrRelation reln, ForkNumber forknum, bool isRedo); +extern void smgrdounlinkfork(SMgrRelation reln, ForkNumber *forknum, + int nforks, bool isRedo); extern void smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync); extern void smgrprefetch(SMgrRelation reln, ForkNumber forknum, @@ -102,8 +103,8 @@ 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 smgrtruncate(SMgrRelation reln, ForkNumber *forknum, + int nforks, BlockNumber *nblocks); extern void smgrimmedsync(SMgrRelation reln, ForkNumber forknum); extern void AtEOXact_SMgr(void); -- 1.8.3.1