Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9cb91f9

Browse files
committed
Fix two race conditions between the pending unlink mechanism that was put in
place to prevent reusing relation OIDs before next checkpoint, and DROPDATABASE. First, if a database was dropped, bgwriter would still try to unlinkthe files that the rmtree() call by the DROP DATABASE command has alreadydeleted, or is just about to delete. Second, if a database is dropped, andanother database is created with the same OID, bgwriter would in the worstcase delete a relation in the new database that happened to get the same OIDas a dropped relation in the old database.To fix these race conditions:- make rmtree() ignore ENOENT errors. This fixes the 1st race condition.- make ForgetDatabaseFsyncRequests forget unlink requests as well.- force checkpoint on in dropdb on all platformsSince ForgetDatabaseFsyncRequests() is asynchronous, the 2nd change isn'tenough on its own to fix the problem of dropping and creating a database withsame OID, but forcing a checkpoint on DROP DATABASE makes it sufficient.Per Tom Lane's bug report and proposal. Backpatch to 8.3.
1 parent87a2f05 commit9cb91f9

File tree

3 files changed

+59
-15
lines changed

3 files changed

+59
-15
lines changed

‎src/backend/commands/dbcommands.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
*
1515
* IDENTIFICATION
16-
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.206 2008/04/16 23:59:40 tgl Exp $
16+
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.207 2008/04/18 06:48:38 heikki Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -715,18 +715,20 @@ dropdb(const char *dbname, bool missing_ok)
715715
pgstat_drop_database(db_id);
716716

717717
/*
718-
* Tell bgwriter to forget any pending fsync requests for files in the
719-
* database; else it'll fail at next checkpoint.
718+
* Tell bgwriter to forget any pending fsync and unlink requests for files
719+
* in the database; else the fsyncs will fail at next checkpoint, or worse,
720+
* it will delete files that belong to a newly created database with the
721+
* same OID.
720722
*/
721723
ForgetDatabaseFsyncRequests(db_id);
722724

723725
/*
724-
* On Windows, force a checkpoint so that the bgwriter doesn't hold any
725-
* open files, which would cause rmdir() to fail.
726+
* Force a checkpoint to make sure the bgwriter has received the message
727+
* sent by ForgetDatabaseFsyncRequests. On Windows, this also ensures that
728+
* the bgwriter doesn't hold any open files, which would cause rmdir() to
729+
* fail.
726730
*/
727-
#ifdefWIN32
728731
RequestCheckpoint(CHECKPOINT_IMMEDIATE |CHECKPOINT_FORCE |CHECKPOINT_WAIT);
729-
#endif
730732

731733
/*
732734
* Remove all tablespace subdirs belonging to the database.

‎src/backend/storage/smgr/md.c

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/storage/smgr/md.c,v 1.136 2008/03/10 20:06:27 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/storage/smgr/md.c,v 1.137 2008/04/1806:48:38 heikki Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1196,8 +1196,11 @@ mdpostckpt(void)
11961196
if (unlink(path)<0)
11971197
{
11981198
/*
1199-
* ENOENT shouldn't happen either, but it doesn't really matter
1200-
* because we would've deleted it now anyway.
1199+
* There's a race condition, when the database is dropped at the
1200+
* same time that we process the pending unlink requests. If the
1201+
* DROP DATABASE deletes the file before we do, we will get ENOENT
1202+
* here. rmtree() also has to ignore ENOENT errors, to deal with
1203+
* the possibility that we delete the file first.
12011204
*/
12021205
if (errno!=ENOENT)
12031206
ereport(WARNING,
@@ -1321,7 +1324,11 @@ RememberFsyncRequest(RelFileNode rnode, BlockNumber segno)
13211324
/* Remove any pending requests for the entire database */
13221325
HASH_SEQ_STATUShstat;
13231326
PendingOperationEntry*entry;
1327+
ListCell*cell,
1328+
*prev,
1329+
*next;
13241330

1331+
/* Remove fsync requests */
13251332
hash_seq_init(&hstat,pendingOpsTable);
13261333
while ((entry= (PendingOperationEntry*)hash_seq_search(&hstat))!=NULL)
13271334
{
@@ -1331,6 +1338,22 @@ RememberFsyncRequest(RelFileNode rnode, BlockNumber segno)
13311338
entry->canceled= true;
13321339
}
13331340
}
1341+
1342+
/* Remove unlink requests */
1343+
prev=NULL;
1344+
for (cell=list_head(pendingUnlinks);cell;cell=next)
1345+
{
1346+
PendingUnlinkEntry*entry= (PendingUnlinkEntry*)lfirst(cell);
1347+
1348+
next=lnext(cell);
1349+
if (entry->rnode.dbNode==rnode.dbNode)
1350+
{
1351+
pendingUnlinks=list_delete_cell(pendingUnlinks,cell,prev);
1352+
pfree(entry);
1353+
}
1354+
else
1355+
prev=cell;
1356+
}
13341357
}
13351358
elseif (segno==UNLINK_RELATION_REQUEST)
13361359
{
@@ -1386,7 +1409,7 @@ RememberFsyncRequest(RelFileNode rnode, BlockNumber segno)
13861409
}
13871410

13881411
/*
1389-
* ForgetRelationFsyncRequests --ensure any fsyncs for a rel are forgotten
1412+
* ForgetRelationFsyncRequests --forget any fsyncs for a rel
13901413
*/
13911414
void
13921415
ForgetRelationFsyncRequests(RelFileNodernode)
@@ -1419,7 +1442,7 @@ ForgetRelationFsyncRequests(RelFileNode rnode)
14191442
}
14201443

14211444
/*
1422-
* ForgetDatabaseFsyncRequests --ensure any fsyncs for a DB are forgotten
1445+
* ForgetDatabaseFsyncRequests --forget any fsyncsand unlinksfor a DB
14231446
*/
14241447
void
14251448
ForgetDatabaseFsyncRequests(Oiddbid)

‎src/port/dirmod.c

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*Win32 (NT, Win2k, XP).replace() doesn't work on Win95/98/Me.
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/port/dirmod.c,v 1.53 2008/04/11 23:53:00 tgl Exp $
13+
* $PostgreSQL: pgsql/src/port/dirmod.c,v 1.54 2008/04/18 06:48:38 heikki Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -406,8 +406,24 @@ rmtree(char *path, bool rmtopdir)
406406
{
407407
snprintf(filepath,MAXPGPATH,"%s/%s",path,*filename);
408408

409+
/*
410+
* It's ok if the file is not there anymore; we were just about to
411+
* delete it anyway.
412+
*
413+
* This is not an academic possibility. One scenario where this
414+
* happens is when bgwriter has a pending unlink request for a file
415+
* in a database that's being dropped. In dropdb(), we call
416+
* ForgetDatabaseFsyncRequests() to flush out any such pending unlink
417+
* requests, but because that's asynchronous, it's not guaranteed
418+
* that the bgwriter receives the message in time.
419+
*/
409420
if (lstat(filepath,&statbuf)!=0)
410-
gotoreport_and_fail;
421+
{
422+
if (errno!=ENOENT)
423+
gotoreport_and_fail;
424+
else
425+
continue;
426+
}
411427

412428
if (S_ISDIR(statbuf.st_mode))
413429
{
@@ -422,7 +438,10 @@ rmtree(char *path, bool rmtopdir)
422438
else
423439
{
424440
if (unlink(filepath)!=0)
425-
gotoreport_and_fail;
441+
{
442+
if (errno!=ENOENT)
443+
gotoreport_and_fail;
444+
}
426445
}
427446
}
428447

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp