mirror of
https://github.com/postgres/postgres.git
synced 2025-07-05 07:21:24 +03:00
Fix two race conditions between the pending unlink mechanism that was put in
place to prevent reusing relation OIDs before next checkpoint, and DROP DATABASE. First, if a database was dropped, bgwriter would still try to unlink the files that the rmtree() call by the DROP DATABASE command has already deleted, or is just about to delete. Second, if a database is dropped, and another database is created with the same OID, bgwriter would in the worst case delete a relation in the new database that happened to get the same OID as 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 platforms Since ForgetDatabaseFsyncRequests() is asynchronous, the 2nd change isn't enough on its own to fix the problem of dropping and creating a database with same OID, but forcing a checkpoint on DROP DATABASE makes it sufficient. Per Tom Lane's bug report and proposal. Backpatch to 8.3.
This commit is contained in:
@ -10,7 +10,7 @@
|
||||
* Win32 (NT, Win2k, XP). replace() doesn't work on Win95/98/Me.
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/port/dirmod.c,v 1.53 2008/04/11 23:53:00 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/port/dirmod.c,v 1.54 2008/04/18 06:48:38 heikki Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -406,8 +406,24 @@ rmtree(char *path, bool rmtopdir)
|
||||
{
|
||||
snprintf(filepath, MAXPGPATH, "%s/%s", path, *filename);
|
||||
|
||||
/*
|
||||
* It's ok if the file is not there anymore; we were just about to
|
||||
* delete it anyway.
|
||||
*
|
||||
* This is not an academic possibility. One scenario where this
|
||||
* happens is when bgwriter has a pending unlink request for a file
|
||||
* in a database that's being dropped. In dropdb(), we call
|
||||
* ForgetDatabaseFsyncRequests() to flush out any such pending unlink
|
||||
* requests, but because that's asynchronous, it's not guaranteed
|
||||
* that the bgwriter receives the message in time.
|
||||
*/
|
||||
if (lstat(filepath, &statbuf) != 0)
|
||||
goto report_and_fail;
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
goto report_and_fail;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
if (S_ISDIR(statbuf.st_mode))
|
||||
{
|
||||
@ -422,7 +438,10 @@ rmtree(char *path, bool rmtopdir)
|
||||
else
|
||||
{
|
||||
if (unlink(filepath) != 0)
|
||||
goto report_and_fail;
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
goto report_and_fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user