Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)