提交 ece01aae 编写于 作者: T Tom Lane

Scan the buffer pool just once, not once per fork, during relation drop.

This provides a speedup of about 4X when NBuffers is large enough.
There is also a useful reduction in sinval traffic, since we
only do CacheInvalidateSmgr() once not once per fork.

Simon Riggs, reviewed and somewhat revised by Tom Lane
上级 5baf6da7
...@@ -1356,12 +1356,8 @@ FinishPreparedTransaction(const char *gid, bool isCommit) ...@@ -1356,12 +1356,8 @@ FinishPreparedTransaction(const char *gid, bool isCommit)
for (i = 0; i < ndelrels; i++) for (i = 0; i < ndelrels; i++)
{ {
SMgrRelation srel = smgropen(delrels[i], InvalidBackendId); SMgrRelation srel = smgropen(delrels[i], InvalidBackendId);
ForkNumber fork;
for (fork = 0; fork <= MAX_FORKNUM; fork++) smgrdounlink(srel, false);
{
smgrdounlink(srel, fork, false);
}
smgrclose(srel); smgrclose(srel);
} }
......
...@@ -4638,10 +4638,8 @@ xact_redo_commit_internal(TransactionId xid, XLogRecPtr lsn, ...@@ -4638,10 +4638,8 @@ xact_redo_commit_internal(TransactionId xid, XLogRecPtr lsn,
ForkNumber fork; ForkNumber fork;
for (fork = 0; fork <= MAX_FORKNUM; fork++) for (fork = 0; fork <= MAX_FORKNUM; fork++)
{
XLogDropRelation(xnodes[i], fork); XLogDropRelation(xnodes[i], fork);
smgrdounlink(srel, fork, true); smgrdounlink(srel, true);
}
smgrclose(srel); smgrclose(srel);
} }
...@@ -4778,10 +4776,8 @@ xact_redo_abort(xl_xact_abort *xlrec, TransactionId xid) ...@@ -4778,10 +4776,8 @@ xact_redo_abort(xl_xact_abort *xlrec, TransactionId xid)
ForkNumber fork; ForkNumber fork;
for (fork = 0; fork <= MAX_FORKNUM; fork++) for (fork = 0; fork <= MAX_FORKNUM; fork++)
{
XLogDropRelation(xlrec->xnodes[i], fork); XLogDropRelation(xlrec->xnodes[i], fork);
smgrdounlink(srel, fork, true); smgrdounlink(srel, true);
}
smgrclose(srel); smgrclose(srel);
} }
} }
......
...@@ -356,13 +356,9 @@ smgrDoPendingDeletes(bool isCommit) ...@@ -356,13 +356,9 @@ smgrDoPendingDeletes(bool isCommit)
if (pending->atCommit == isCommit) if (pending->atCommit == isCommit)
{ {
SMgrRelation srel; SMgrRelation srel;
int i;
srel = smgropen(pending->relnode, pending->backend); srel = smgropen(pending->relnode, pending->backend);
for (i = 0; i <= MAX_FORKNUM; i++) smgrdounlink(srel, false);
{
smgrdounlink(srel, i, false);
}
smgrclose(srel); smgrclose(srel);
} }
/* must explicitly free the list entry */ /* must explicitly free the list entry */
......
...@@ -2020,7 +2020,7 @@ BufferIsPermanent(Buffer buffer) ...@@ -2020,7 +2020,7 @@ BufferIsPermanent(Buffer buffer)
* DropRelFileNodeBuffers * DropRelFileNodeBuffers
* *
* This function removes from the buffer pool all the pages of the * This function removes from the buffer pool all the pages of the
* specified relation that have block numbers >= firstDelBlock. * specified relation fork that have block numbers >= firstDelBlock.
* (In particular, with firstDelBlock = 0, all pages are removed.) * (In particular, with firstDelBlock = 0, all pages are removed.)
* Dirty pages are simply dropped, without bothering to write them * Dirty pages are simply dropped, without bothering to write them
* out first. Therefore, this is NOT rollback-able, and so should be * out first. Therefore, this is NOT rollback-able, and so should be
...@@ -2089,6 +2089,46 @@ DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber forkNum, ...@@ -2089,6 +2089,46 @@ DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber forkNum,
} }
} }
/* ---------------------------------------------------------------------
* DropRelFileNodeAllBuffers
*
* This function removes from the buffer pool all the pages of all
* forks of the specified relation. It's equivalent to calling
* DropRelFileNodeBuffers once per fork with firstDelBlock = 0.
* --------------------------------------------------------------------
*/
void
DropRelFileNodeAllBuffers(RelFileNodeBackend rnode)
{
int i;
/* If it's a local relation, it's localbuf.c's problem. */
if (rnode.backend != InvalidBackendId)
{
if (rnode.backend == MyBackendId)
DropRelFileNodeAllLocalBuffers(rnode.node);
return;
}
for (i = 0; i < NBuffers; i++)
{
volatile BufferDesc *bufHdr = &BufferDescriptors[i];
/*
* As in DropRelFileNodeBuffers, an unlocked precheck should be safe
* and saves some cycles.
*/
if (!RelFileNodeEquals(bufHdr->tag.rnode, rnode.node))
continue;
LockBufHdr(bufHdr);
if (RelFileNodeEquals(bufHdr->tag.rnode, rnode.node))
InvalidateBuffer(bufHdr); /* releases spinlock */
else
UnlockBufHdr(bufHdr);
}
}
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
* DropDatabaseBuffers * DropDatabaseBuffers
* *
......
...@@ -330,6 +330,46 @@ DropRelFileNodeLocalBuffers(RelFileNode rnode, ForkNumber forkNum, ...@@ -330,6 +330,46 @@ DropRelFileNodeLocalBuffers(RelFileNode rnode, ForkNumber forkNum,
} }
} }
/*
* DropRelFileNodeAllLocalBuffers
* This function removes from the buffer pool all pages of all forks
* of the specified relation.
*
* See DropRelFileNodeAllBuffers in bufmgr.c for more notes.
*/
void
DropRelFileNodeAllLocalBuffers(RelFileNode rnode)
{
int i;
for (i = 0; i < NLocBuffer; i++)
{
BufferDesc *bufHdr = &LocalBufferDescriptors[i];
LocalBufferLookupEnt *hresult;
if ((bufHdr->flags & BM_TAG_VALID) &&
RelFileNodeEquals(bufHdr->tag.rnode, rnode))
{
if (LocalRefCount[i] != 0)
elog(ERROR, "block %u of %s is still referenced (local %u)",
bufHdr->tag.blockNum,
relpathbackend(bufHdr->tag.rnode, MyBackendId,
bufHdr->tag.forkNum),
LocalRefCount[i]);
/* Remove entry from hashtable */
hresult = (LocalBufferLookupEnt *)
hash_search(LocalBufHash, (void *) &bufHdr->tag,
HASH_REMOVE, NULL);
if (!hresult) /* shouldn't happen */
elog(ERROR, "local buffer hash table corrupted");
/* Mark buffer invalid */
CLEAR_BUFFERTAG(bufHdr->tag);
bufHdr->flags = 0;
bufHdr->usage_count = 0;
}
}
}
/* /*
* InitLocalBuffers - * InitLocalBuffers -
* init the local buffer cache. Since most queries (esp. multi-user ones) * init the local buffer cache. Since most queries (esp. multi-user ones)
......
...@@ -329,7 +329,64 @@ smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo) ...@@ -329,7 +329,64 @@ smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
} }
/* /*
* smgrdounlink() -- Immediately unlink a relation. * smgrdounlink() -- Immediately unlink all forks of a relation.
*
* All forks of the relation are 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(s) to be gone
* already.
*
* This is equivalent to calling smgrdounlinkfork for each fork, but
* it's significantly quicker so should be preferred when possible.
*/
void
smgrdounlink(SMgrRelation reln, bool isRedo)
{
RelFileNodeBackend rnode = reln->smgr_rnode;
int which = reln->smgr_which;
ForkNumber forknum;
/* Close the forks at smgr level */
for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
(*(smgrsw[which].smgr_close)) (reln, forknum);
/*
* Get rid of any remaining buffers for the relation. bufmgr will just
* drop them without bothering to write the contents.
*/
DropRelFileNodeAllBuffers(rnode);
/*
* It'd be nice to tell the stats collector to forget it immediately, too.
* But we can't because we don't know the OID (and in cases involving
* relfilenode swaps, it's not always clear which table OID to forget,
* anyway).
*/
/*
* Send a shared-inval message to force other backends to close any
* dangling smgr references they may have for this rel. We should do this
* before starting the actual unlinking, in case we fail partway through
* that step. Note that the sinval message will eventually come back to
* this backend, too, and thereby provide a backstop that we closed our
* own smgr rel.
*/
CacheInvalidateSmgr(rnode);
/*
* Delete the physical file(s).
*
* Note: smgr_unlink must treat deletion failure as a WARNING, not an
* ERROR, because we've already decided to commit or abort the current
* xact.
*/
for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
(*(smgrsw[which].smgr_unlink)) (rnode, forknum, isRedo);
}
/*
* smgrdounlinkfork() -- Immediately unlink one fork of a relation.
* *
* The specified fork of the relation is removed from the store. This * The specified fork of the relation is removed from the store. This
* should not be used during transactional operations, since it can't be * should not be used during transactional operations, since it can't be
...@@ -339,16 +396,16 @@ smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo) ...@@ -339,16 +396,16 @@ smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
* already. * already.
*/ */
void void
smgrdounlink(SMgrRelation reln, ForkNumber forknum, bool isRedo) smgrdounlinkfork(SMgrRelation reln, ForkNumber forknum, bool isRedo)
{ {
RelFileNodeBackend rnode = reln->smgr_rnode; RelFileNodeBackend rnode = reln->smgr_rnode;
int which = reln->smgr_which; int which = reln->smgr_which;
/* Close the fork */ /* Close the fork at smgr level */
(*(smgrsw[which].smgr_close)) (reln, forknum); (*(smgrsw[which].smgr_close)) (reln, forknum);
/* /*
* Get rid of any remaining buffers for the relation. bufmgr will just * Get rid of any remaining buffers for the fork. bufmgr will just
* drop them without bothering to write the contents. * drop them without bothering to write the contents.
*/ */
DropRelFileNodeBuffers(rnode, forknum, 0); DropRelFileNodeBuffers(rnode, forknum, 0);
......
...@@ -210,6 +210,7 @@ extern BufferDesc *LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, ...@@ -210,6 +210,7 @@ extern BufferDesc *LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum,
extern void MarkLocalBufferDirty(Buffer buffer); extern void MarkLocalBufferDirty(Buffer buffer);
extern void DropRelFileNodeLocalBuffers(RelFileNode rnode, ForkNumber forkNum, extern void DropRelFileNodeLocalBuffers(RelFileNode rnode, ForkNumber forkNum,
BlockNumber firstDelBlock); BlockNumber firstDelBlock);
extern void DropRelFileNodeAllLocalBuffers(RelFileNode rnode);
extern void AtEOXact_LocalBuffers(bool isCommit); extern void AtEOXact_LocalBuffers(bool isCommit);
#endif /* BUFMGR_INTERNALS_H */ #endif /* BUFMGR_INTERNALS_H */
...@@ -188,6 +188,7 @@ extern void FlushRelationBuffers(Relation rel); ...@@ -188,6 +188,7 @@ extern void FlushRelationBuffers(Relation rel);
extern void FlushDatabaseBuffers(Oid dbid); extern void FlushDatabaseBuffers(Oid dbid);
extern void DropRelFileNodeBuffers(RelFileNodeBackend rnode, extern void DropRelFileNodeBuffers(RelFileNodeBackend rnode,
ForkNumber forkNum, BlockNumber firstDelBlock); ForkNumber forkNum, BlockNumber firstDelBlock);
extern void DropRelFileNodeAllBuffers(RelFileNodeBackend rnode);
extern void DropDatabaseBuffers(Oid dbid); extern void DropDatabaseBuffers(Oid dbid);
#define RelationGetNumberOfBlocks(reln) \ #define RelationGetNumberOfBlocks(reln) \
......
...@@ -80,8 +80,8 @@ extern void smgrclose(SMgrRelation reln); ...@@ -80,8 +80,8 @@ extern void smgrclose(SMgrRelation reln);
extern void smgrcloseall(void); extern void smgrcloseall(void);
extern void smgrclosenode(RelFileNodeBackend rnode); extern void smgrclosenode(RelFileNodeBackend rnode);
extern void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo); extern void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo);
extern void smgrdounlink(SMgrRelation reln, ForkNumber forknum, extern void smgrdounlink(SMgrRelation reln, bool isRedo);
bool isRedo); extern void smgrdounlinkfork(SMgrRelation reln, ForkNumber forknum, bool isRedo);
extern void smgrextend(SMgrRelation reln, ForkNumber forknum, extern void smgrextend(SMgrRelation reln, ForkNumber forknum,
BlockNumber blocknum, char *buffer, bool skipFsync); BlockNumber blocknum, char *buffer, bool skipFsync);
extern void smgrprefetch(SMgrRelation reln, ForkNumber forknum, extern void smgrprefetch(SMgrRelation reln, ForkNumber forknum,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册