Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit b74e94d

Browse files
committed
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 4eb2176'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
1 parent 701d918 commit b74e94d

File tree

4 files changed

+52
-18
lines changed

4 files changed

+52
-18
lines changed

src/backend/storage/smgr/md.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ static MemoryContext MdCxt; /* context for all MdfdVec objects */
116116
* mdnblocks().
117117
*/
118118
#define EXTENSION_DONT_CHECK_SIZE (1 << 4)
119+
/* don't try to open a segment, if not already open */
120+
#define EXTENSION_DONT_OPEN (1 << 5)
119121

120122

121123
/* local routines */
@@ -551,12 +553,6 @@ mdclose(SMgrRelation reln, ForkNumber forknum)
551553
}
552554
}
553555

554-
void
555-
mdrelease(void)
556-
{
557-
closeAllVfds();
558-
}
559-
560556
/*
561557
* mdprefetch() -- Initiate asynchronous read of the specified block of a relation
562558
*/
@@ -605,11 +601,14 @@ mdwriteback(SMgrRelation reln, ForkNumber forknum,
605601
segnum_end;
606602

607603
v = _mdfd_getseg(reln, forknum, blocknum, true /* not used */ ,
608-
EXTENSION_RETURN_NULL);
604+
EXTENSION_DONT_OPEN);
609605

610606
/*
611607
* We might be flushing buffers of already removed relations, that's
612-
* ok, just ignore that case.
608+
* ok, just ignore that case. If the segment file wasn't open already
609+
* (ie from a recent mdwrite()), then we don't want to re-open it, to
610+
* avoid a race with PROCSIGNAL_BARRIER_SMGRRELEASE that might leave
611+
* us with a descriptor to a file that is about to be unlinked.
613612
*/
614613
if (!v)
615614
return;
@@ -1202,7 +1201,8 @@ _mdfd_getseg(SMgrRelation reln, ForkNumber forknum, BlockNumber blkno,
12021201

12031202
/* some way to handle non-existent segments needs to be specified */
12041203
Assert(behavior &
1205-
(EXTENSION_FAIL | EXTENSION_CREATE | EXTENSION_RETURN_NULL));
1204+
(EXTENSION_FAIL | EXTENSION_CREATE | EXTENSION_RETURN_NULL |
1205+
EXTENSION_DONT_OPEN));
12061206

12071207
targetseg = blkno / ((BlockNumber) RELSEG_SIZE);
12081208

@@ -1213,6 +1213,10 @@ _mdfd_getseg(SMgrRelation reln, ForkNumber forknum, BlockNumber blkno,
12131213
return v;
12141214
}
12151215

1216+
/* The caller only wants the segment if we already had it open. */
1217+
if (behavior & EXTENSION_DONT_OPEN)
1218+
return NULL;
1219+
12161220
/*
12171221
* The target segment is not yet open. Iterate over all the segments
12181222
* between the last opened and the target segment. This way missing

src/backend/storage/smgr/smgr.c

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ typedef struct f_smgr
4141
{
4242
void (*smgr_init) (void); /* may be NULL */
4343
void (*smgr_shutdown) (void); /* may be NULL */
44-
void (*smgr_release) (void); /* may be NULL */
4544
void (*smgr_open) (SMgrRelation reln);
4645
void (*smgr_close) (SMgrRelation reln, ForkNumber forknum);
4746
void (*smgr_create) (SMgrRelation reln, ForkNumber forknum,
@@ -70,7 +69,6 @@ static const f_smgr smgrsw[] = {
7069
{
7170
.smgr_init = mdinit,
7271
.smgr_shutdown = NULL,
73-
.smgr_release = mdrelease,
7472
.smgr_open = mdopen,
7573
.smgr_close = mdclose,
7674
.smgr_create = mdcreate,
@@ -281,6 +279,42 @@ smgrclose(SMgrRelation reln)
281279
*owner = NULL;
282280
}
283281

282+
/*
283+
* smgrrelease() -- Release all resources used by this object.
284+
*
285+
* The object remains valid.
286+
*/
287+
void
288+
smgrrelease(SMgrRelation reln)
289+
{
290+
for (ForkNumber forknum = 0; forknum <= MAX_FORKNUM; forknum++)
291+
{
292+
smgrsw[reln->smgr_which].smgr_close(reln, forknum);
293+
reln->smgr_cached_nblocks[forknum] = InvalidBlockNumber;
294+
}
295+
}
296+
297+
/*
298+
* smgrreleaseall() -- Release resources used by all objects.
299+
*
300+
* This is called for PROCSIGNAL_BARRIER_SMGRRELEASE.
301+
*/
302+
void
303+
smgrreleaseall(void)
304+
{
305+
HASH_SEQ_STATUS status;
306+
SMgrRelation reln;
307+
308+
/* Nothing to do if hashtable not set up */
309+
if (SMgrRelationHash == NULL)
310+
return;
311+
312+
hash_seq_init(&status, SMgrRelationHash);
313+
314+
while ((reln = (SMgrRelation) hash_seq_search(&status)) != NULL)
315+
smgrrelease(reln);
316+
}
317+
284318
/*
285319
* smgrcloseall() -- Close all existing SMgrRelation objects.
286320
*/
@@ -698,11 +732,6 @@ AtEOXact_SMgr(void)
698732
bool
699733
ProcessBarrierSmgrRelease(void)
700734
{
701-
for (int i = 0; i < NSmgr; i++)
702-
{
703-
if (smgrsw[i].smgr_release)
704-
smgrsw[i].smgr_release();
705-
}
706-
735+
smgrreleaseall();
707736
return true;
708737
}

src/include/storage/md.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
extern void mdinit(void);
2424
extern void mdopen(SMgrRelation reln);
2525
extern void mdclose(SMgrRelation reln, ForkNumber forknum);
26-
extern void mdrelease(void);
2726
extern void mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo);
2827
extern bool mdexists(SMgrRelation reln, ForkNumber forknum);
2928
extern void mdunlink(RelFileNodeBackend rnode, ForkNumber forknum, bool isRedo);

src/include/storage/smgr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ extern void smgrclearowner(SMgrRelation *owner, SMgrRelation reln);
8585
extern void smgrclose(SMgrRelation reln);
8686
extern void smgrcloseall(void);
8787
extern void smgrclosenode(RelFileNodeBackend rnode);
88+
extern void smgrrelease(SMgrRelation reln);
89+
extern void smgrreleaseall(void);
8890
extern void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo);
8991
extern void smgrdosyncall(SMgrRelation *rels, int nrels);
9092
extern void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo);

0 commit comments

Comments
 (0)