Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ece01aa

Browse files
committed
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
1 parent 5baf6da commit ece01aa

File tree

9 files changed

+150
-23
lines changed

9 files changed

+150
-23
lines changed

src/backend/access/transam/twophase.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,12 +1356,8 @@ FinishPreparedTransaction(const char *gid, bool isCommit)
13561356
for (i = 0; i < ndelrels; i++)
13571357
{
13581358
SMgrRelation srel = smgropen(delrels[i], InvalidBackendId);
1359-
ForkNumber fork;
13601359

1361-
for (fork = 0; fork <= MAX_FORKNUM; fork++)
1362-
{
1363-
smgrdounlink(srel, fork, false);
1364-
}
1360+
smgrdounlink(srel, false);
13651361
smgrclose(srel);
13661362
}
13671363

src/backend/access/transam/xact.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4638,10 +4638,8 @@ xact_redo_commit_internal(TransactionId xid, XLogRecPtr lsn,
46384638
ForkNumber fork;
46394639

46404640
for (fork = 0; fork <= MAX_FORKNUM; fork++)
4641-
{
46424641
XLogDropRelation(xnodes[i], fork);
4643-
smgrdounlink(srel, fork, true);
4644-
}
4642+
smgrdounlink(srel, true);
46454643
smgrclose(srel);
46464644
}
46474645

@@ -4778,10 +4776,8 @@ xact_redo_abort(xl_xact_abort *xlrec, TransactionId xid)
47784776
ForkNumber fork;
47794777

47804778
for (fork = 0; fork <= MAX_FORKNUM; fork++)
4781-
{
47824779
XLogDropRelation(xlrec->xnodes[i], fork);
4783-
smgrdounlink(srel, fork, true);
4784-
}
4780+
smgrdounlink(srel, true);
47854781
smgrclose(srel);
47864782
}
47874783
}

src/backend/catalog/storage.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -356,13 +356,9 @@ smgrDoPendingDeletes(bool isCommit)
356356
if (pending->atCommit == isCommit)
357357
{
358358
SMgrRelation srel;
359-
int i;
360359

361360
srel = smgropen(pending->relnode, pending->backend);
362-
for (i = 0; i <= MAX_FORKNUM; i++)
363-
{
364-
smgrdounlink(srel, i, false);
365-
}
361+
smgrdounlink(srel, false);
366362
smgrclose(srel);
367363
}
368364
/* must explicitly free the list entry */

src/backend/storage/buffer/bufmgr.c

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2020,7 +2020,7 @@ BufferIsPermanent(Buffer buffer)
20202020
* DropRelFileNodeBuffers
20212021
*
20222022
* This function removes from the buffer pool all the pages of the
2023-
* specified relation that have block numbers >= firstDelBlock.
2023+
* specified relation fork that have block numbers >= firstDelBlock.
20242024
* (In particular, with firstDelBlock = 0, all pages are removed.)
20252025
* Dirty pages are simply dropped, without bothering to write them
20262026
* out first. Therefore, this is NOT rollback-able, and so should be
@@ -2089,6 +2089,46 @@ DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber forkNum,
20892089
}
20902090
}
20912091

2092+
/* ---------------------------------------------------------------------
2093+
* DropRelFileNodeAllBuffers
2094+
*
2095+
* This function removes from the buffer pool all the pages of all
2096+
* forks of the specified relation. It's equivalent to calling
2097+
* DropRelFileNodeBuffers once per fork with firstDelBlock = 0.
2098+
* --------------------------------------------------------------------
2099+
*/
2100+
void
2101+
DropRelFileNodeAllBuffers(RelFileNodeBackend rnode)
2102+
{
2103+
int i;
2104+
2105+
/* If it's a local relation, it's localbuf.c's problem. */
2106+
if (rnode.backend != InvalidBackendId)
2107+
{
2108+
if (rnode.backend == MyBackendId)
2109+
DropRelFileNodeAllLocalBuffers(rnode.node);
2110+
return;
2111+
}
2112+
2113+
for (i = 0; i < NBuffers; i++)
2114+
{
2115+
volatile BufferDesc *bufHdr = &BufferDescriptors[i];
2116+
2117+
/*
2118+
* As in DropRelFileNodeBuffers, an unlocked precheck should be safe
2119+
* and saves some cycles.
2120+
*/
2121+
if (!RelFileNodeEquals(bufHdr->tag.rnode, rnode.node))
2122+
continue;
2123+
2124+
LockBufHdr(bufHdr);
2125+
if (RelFileNodeEquals(bufHdr->tag.rnode, rnode.node))
2126+
InvalidateBuffer(bufHdr); /* releases spinlock */
2127+
else
2128+
UnlockBufHdr(bufHdr);
2129+
}
2130+
}
2131+
20922132
/* ---------------------------------------------------------------------
20932133
* DropDatabaseBuffers
20942134
*

src/backend/storage/buffer/localbuf.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,46 @@ DropRelFileNodeLocalBuffers(RelFileNode rnode, ForkNumber forkNum,
330330
}
331331
}
332332

333+
/*
334+
* DropRelFileNodeAllLocalBuffers
335+
* This function removes from the buffer pool all pages of all forks
336+
* of the specified relation.
337+
*
338+
* See DropRelFileNodeAllBuffers in bufmgr.c for more notes.
339+
*/
340+
void
341+
DropRelFileNodeAllLocalBuffers(RelFileNode rnode)
342+
{
343+
int i;
344+
345+
for (i = 0; i < NLocBuffer; i++)
346+
{
347+
BufferDesc *bufHdr = &LocalBufferDescriptors[i];
348+
LocalBufferLookupEnt *hresult;
349+
350+
if ((bufHdr->flags & BM_TAG_VALID) &&
351+
RelFileNodeEquals(bufHdr->tag.rnode, rnode))
352+
{
353+
if (LocalRefCount[i] != 0)
354+
elog(ERROR, "block %u of %s is still referenced (local %u)",
355+
bufHdr->tag.blockNum,
356+
relpathbackend(bufHdr->tag.rnode, MyBackendId,
357+
bufHdr->tag.forkNum),
358+
LocalRefCount[i]);
359+
/* Remove entry from hashtable */
360+
hresult = (LocalBufferLookupEnt *)
361+
hash_search(LocalBufHash, (void *) &bufHdr->tag,
362+
HASH_REMOVE, NULL);
363+
if (!hresult) /* shouldn't happen */
364+
elog(ERROR, "local buffer hash table corrupted");
365+
/* Mark buffer invalid */
366+
CLEAR_BUFFERTAG(bufHdr->tag);
367+
bufHdr->flags = 0;
368+
bufHdr->usage_count = 0;
369+
}
370+
}
371+
}
372+
333373
/*
334374
* InitLocalBuffers -
335375
* init the local buffer cache. Since most queries (esp. multi-user ones)

src/backend/storage/smgr/smgr.c

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,64 @@ smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
329329
}
330330

331331
/*
332-
* smgrdounlink() -- Immediately unlink a relation.
332+
* smgrdounlink() -- Immediately unlink all forks of a relation.
333+
*
334+
* All forks of the relation are removed from the store. This should
335+
* not be used during transactional operations, since it can't be undone.
336+
*
337+
* If isRedo is true, it is okay for the underlying file(s) to be gone
338+
* already.
339+
*
340+
* This is equivalent to calling smgrdounlinkfork for each fork, but
341+
* it's significantly quicker so should be preferred when possible.
342+
*/
343+
void
344+
smgrdounlink(SMgrRelation reln, bool isRedo)
345+
{
346+
RelFileNodeBackend rnode = reln->smgr_rnode;
347+
int which = reln->smgr_which;
348+
ForkNumber forknum;
349+
350+
/* Close the forks at smgr level */
351+
for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
352+
(*(smgrsw[which].smgr_close)) (reln, forknum);
353+
354+
/*
355+
* Get rid of any remaining buffers for the relation. bufmgr will just
356+
* drop them without bothering to write the contents.
357+
*/
358+
DropRelFileNodeAllBuffers(rnode);
359+
360+
/*
361+
* It'd be nice to tell the stats collector to forget it immediately, too.
362+
* But we can't because we don't know the OID (and in cases involving
363+
* relfilenode swaps, it's not always clear which table OID to forget,
364+
* anyway).
365+
*/
366+
367+
/*
368+
* Send a shared-inval message to force other backends to close any
369+
* dangling smgr references they may have for this rel. We should do this
370+
* before starting the actual unlinking, in case we fail partway through
371+
* that step. Note that the sinval message will eventually come back to
372+
* this backend, too, and thereby provide a backstop that we closed our
373+
* own smgr rel.
374+
*/
375+
CacheInvalidateSmgr(rnode);
376+
377+
/*
378+
* Delete the physical file(s).
379+
*
380+
* Note: smgr_unlink must treat deletion failure as a WARNING, not an
381+
* ERROR, because we've already decided to commit or abort the current
382+
* xact.
383+
*/
384+
for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
385+
(*(smgrsw[which].smgr_unlink)) (rnode, forknum, isRedo);
386+
}
387+
388+
/*
389+
* smgrdounlinkfork() -- Immediately unlink one fork of a relation.
333390
*
334391
* The specified fork of the relation is removed from the store. This
335392
* should not be used during transactional operations, since it can't be
@@ -339,16 +396,16 @@ smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
339396
* already.
340397
*/
341398
void
342-
smgrdounlink(SMgrRelation reln, ForkNumber forknum, bool isRedo)
399+
smgrdounlinkfork(SMgrRelation reln, ForkNumber forknum, bool isRedo)
343400
{
344401
RelFileNodeBackend rnode = reln->smgr_rnode;
345402
int which = reln->smgr_which;
346403

347-
/* Close the fork */
404+
/* Close the fork at smgr level */
348405
(*(smgrsw[which].smgr_close)) (reln, forknum);
349406

350407
/*
351-
* Get rid of any remaining buffers for the relation. bufmgr will just
408+
* Get rid of any remaining buffers for the fork. bufmgr will just
352409
* drop them without bothering to write the contents.
353410
*/
354411
DropRelFileNodeBuffers(rnode, forknum, 0);

src/include/storage/buf_internals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ extern BufferDesc *LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum,
210210
extern void MarkLocalBufferDirty(Buffer buffer);
211211
extern void DropRelFileNodeLocalBuffers(RelFileNode rnode, ForkNumber forkNum,
212212
BlockNumber firstDelBlock);
213+
extern void DropRelFileNodeAllLocalBuffers(RelFileNode rnode);
213214
extern void AtEOXact_LocalBuffers(bool isCommit);
214215

215216
#endif /* BUFMGR_INTERNALS_H */

src/include/storage/bufmgr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ extern void FlushRelationBuffers(Relation rel);
188188
extern void FlushDatabaseBuffers(Oid dbid);
189189
extern void DropRelFileNodeBuffers(RelFileNodeBackend rnode,
190190
ForkNumber forkNum, BlockNumber firstDelBlock);
191+
extern void DropRelFileNodeAllBuffers(RelFileNodeBackend rnode);
191192
extern void DropDatabaseBuffers(Oid dbid);
192193

193194
#define RelationGetNumberOfBlocks(reln) \

src/include/storage/smgr.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ extern void smgrclose(SMgrRelation reln);
8080
extern void smgrcloseall(void);
8181
extern void smgrclosenode(RelFileNodeBackend rnode);
8282
extern void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo);
83-
extern void smgrdounlink(SMgrRelation reln, ForkNumber forknum,
84-
bool isRedo);
83+
extern void smgrdounlink(SMgrRelation reln, bool isRedo);
84+
extern void smgrdounlinkfork(SMgrRelation reln, ForkNumber forknum, bool isRedo);
8585
extern void smgrextend(SMgrRelation reln, ForkNumber forknum,
8686
BlockNumber blocknum, char *buffer, bool skipFsync);
8787
extern void smgrprefetch(SMgrRelation reln, ForkNumber forknum,

0 commit comments

Comments
 (0)