mirror of
https://github.com/postgres/postgres.git
synced 2025-04-24 10:47:04 +03:00
Rethink PROCSIGNAL_BARRIER_SMGRRELEASE.
With sufficiently bad luck, it was possible for IssuePendingWritebacks() to reopen a file after we'd processed PROCSIGNAL_BARRIER_SMGRRELEASE and before the file was unlinked by some other backend. That left a small hole in commit 4eb21763's plan to fix all spurious errors from DROP TABLESPACE and similar on Windows. Fix by closing md.c's segments, instead of just closing fd.c's descriptors, and then teaching smgrwriteback() not to open files that aren't already open. Reported-by: Andres Freund <andres@anarazel.de> Reviewed-by: Robert Haas <robertmhaas@gmail.com> Discussion: https://postgr.es/m/20220209220004.kb3dgtn2x2k2gtdm%40alap3.anarazel.de
This commit is contained in:
parent
701d918a42
commit
b74e94dc27
@ -116,6 +116,8 @@ static MemoryContext MdCxt; /* context for all MdfdVec objects */
|
||||
* mdnblocks().
|
||||
*/
|
||||
#define EXTENSION_DONT_CHECK_SIZE (1 << 4)
|
||||
/* don't try to open a segment, if not already open */
|
||||
#define EXTENSION_DONT_OPEN (1 << 5)
|
||||
|
||||
|
||||
/* local routines */
|
||||
@ -551,12 +553,6 @@ mdclose(SMgrRelation reln, ForkNumber forknum)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mdrelease(void)
|
||||
{
|
||||
closeAllVfds();
|
||||
}
|
||||
|
||||
/*
|
||||
* mdprefetch() -- Initiate asynchronous read of the specified block of a relation
|
||||
*/
|
||||
@ -605,11 +601,14 @@ mdwriteback(SMgrRelation reln, ForkNumber forknum,
|
||||
segnum_end;
|
||||
|
||||
v = _mdfd_getseg(reln, forknum, blocknum, true /* not used */ ,
|
||||
EXTENSION_RETURN_NULL);
|
||||
EXTENSION_DONT_OPEN);
|
||||
|
||||
/*
|
||||
* We might be flushing buffers of already removed relations, that's
|
||||
* ok, just ignore that case.
|
||||
* ok, just ignore that case. If the segment file wasn't open already
|
||||
* (ie from a recent mdwrite()), then we don't want to re-open it, to
|
||||
* avoid a race with PROCSIGNAL_BARRIER_SMGRRELEASE that might leave
|
||||
* us with a descriptor to a file that is about to be unlinked.
|
||||
*/
|
||||
if (!v)
|
||||
return;
|
||||
@ -1202,7 +1201,8 @@ _mdfd_getseg(SMgrRelation reln, ForkNumber forknum, BlockNumber blkno,
|
||||
|
||||
/* some way to handle non-existent segments needs to be specified */
|
||||
Assert(behavior &
|
||||
(EXTENSION_FAIL | EXTENSION_CREATE | EXTENSION_RETURN_NULL));
|
||||
(EXTENSION_FAIL | EXTENSION_CREATE | EXTENSION_RETURN_NULL |
|
||||
EXTENSION_DONT_OPEN));
|
||||
|
||||
targetseg = blkno / ((BlockNumber) RELSEG_SIZE);
|
||||
|
||||
@ -1213,6 +1213,10 @@ _mdfd_getseg(SMgrRelation reln, ForkNumber forknum, BlockNumber blkno,
|
||||
return v;
|
||||
}
|
||||
|
||||
/* The caller only wants the segment if we already had it open. */
|
||||
if (behavior & EXTENSION_DONT_OPEN)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* The target segment is not yet open. Iterate over all the segments
|
||||
* between the last opened and the target segment. This way missing
|
||||
|
@ -41,7 +41,6 @@ typedef struct f_smgr
|
||||
{
|
||||
void (*smgr_init) (void); /* may be NULL */
|
||||
void (*smgr_shutdown) (void); /* may be NULL */
|
||||
void (*smgr_release) (void); /* may be NULL */
|
||||
void (*smgr_open) (SMgrRelation reln);
|
||||
void (*smgr_close) (SMgrRelation reln, ForkNumber forknum);
|
||||
void (*smgr_create) (SMgrRelation reln, ForkNumber forknum,
|
||||
@ -70,7 +69,6 @@ static const f_smgr smgrsw[] = {
|
||||
{
|
||||
.smgr_init = mdinit,
|
||||
.smgr_shutdown = NULL,
|
||||
.smgr_release = mdrelease,
|
||||
.smgr_open = mdopen,
|
||||
.smgr_close = mdclose,
|
||||
.smgr_create = mdcreate,
|
||||
@ -281,6 +279,42 @@ smgrclose(SMgrRelation reln)
|
||||
*owner = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* smgrrelease() -- Release all resources used by this object.
|
||||
*
|
||||
* The object remains valid.
|
||||
*/
|
||||
void
|
||||
smgrrelease(SMgrRelation reln)
|
||||
{
|
||||
for (ForkNumber forknum = 0; forknum <= MAX_FORKNUM; forknum++)
|
||||
{
|
||||
smgrsw[reln->smgr_which].smgr_close(reln, forknum);
|
||||
reln->smgr_cached_nblocks[forknum] = InvalidBlockNumber;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* smgrreleaseall() -- Release resources used by all objects.
|
||||
*
|
||||
* This is called for PROCSIGNAL_BARRIER_SMGRRELEASE.
|
||||
*/
|
||||
void
|
||||
smgrreleaseall(void)
|
||||
{
|
||||
HASH_SEQ_STATUS status;
|
||||
SMgrRelation reln;
|
||||
|
||||
/* Nothing to do if hashtable not set up */
|
||||
if (SMgrRelationHash == NULL)
|
||||
return;
|
||||
|
||||
hash_seq_init(&status, SMgrRelationHash);
|
||||
|
||||
while ((reln = (SMgrRelation) hash_seq_search(&status)) != NULL)
|
||||
smgrrelease(reln);
|
||||
}
|
||||
|
||||
/*
|
||||
* smgrcloseall() -- Close all existing SMgrRelation objects.
|
||||
*/
|
||||
@ -698,11 +732,6 @@ AtEOXact_SMgr(void)
|
||||
bool
|
||||
ProcessBarrierSmgrRelease(void)
|
||||
{
|
||||
for (int i = 0; i < NSmgr; i++)
|
||||
{
|
||||
if (smgrsw[i].smgr_release)
|
||||
smgrsw[i].smgr_release();
|
||||
}
|
||||
|
||||
smgrreleaseall();
|
||||
return true;
|
||||
}
|
||||
|
@ -23,7 +23,6 @@
|
||||
extern void mdinit(void);
|
||||
extern void mdopen(SMgrRelation reln);
|
||||
extern void mdclose(SMgrRelation reln, ForkNumber forknum);
|
||||
extern void mdrelease(void);
|
||||
extern void mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo);
|
||||
extern bool mdexists(SMgrRelation reln, ForkNumber forknum);
|
||||
extern void mdunlink(RelFileNodeBackend rnode, ForkNumber forknum, bool isRedo);
|
||||
|
@ -85,6 +85,8 @@ extern void smgrclearowner(SMgrRelation *owner, SMgrRelation reln);
|
||||
extern void smgrclose(SMgrRelation reln);
|
||||
extern void smgrcloseall(void);
|
||||
extern void smgrclosenode(RelFileNodeBackend rnode);
|
||||
extern void smgrrelease(SMgrRelation reln);
|
||||
extern void smgrreleaseall(void);
|
||||
extern void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo);
|
||||
extern void smgrdosyncall(SMgrRelation *rels, int nrels);
|
||||
extern void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo);
|
||||
|
Loading…
x
Reference in New Issue
Block a user