Commit d0024cd1 authored by Tom Lane's avatar Tom Lane

Avoid crashing when we have problems unlinking files post-commit.

smgrdounlink takes care to not throw an ERROR if it fails to unlink
something, but that caution was rendered useless by commit
33960006, which put an smgrexists call in
front of it; smgrexists *does* throw error if anything looks funny, such
as getting a permissions error from trying to open the file.  If that
happens post-commit, you get a PANIC, and what's worse the same logic
appears in the WAL replay code, so the database even fails to restart.

Restore the intended behavior by removing the smgrexists call --- it isn't
accomplishing anything that we can't do better by adjusting mdunlink's
ideas of whether it ought to warn about ENOENT or not.

Per report from Joseph Shraibman of unrecoverable crash after trying to
drop a table whose FSM fork had somehow gotten chmod'd to 000 permissions.
Backpatch to 8.4, where the bogus coding was introduced.
parent 72920557
...@@ -1366,7 +1366,6 @@ FinishPreparedTransaction(const char *gid, bool isCommit) ...@@ -1366,7 +1366,6 @@ FinishPreparedTransaction(const char *gid, bool isCommit)
for (fork = 0; fork <= MAX_FORKNUM; fork++) for (fork = 0; fork <= MAX_FORKNUM; fork++)
{ {
if (smgrexists(srel, fork))
smgrdounlink(srel, fork, false); smgrdounlink(srel, fork, false);
} }
smgrclose(srel); smgrclose(srel);
......
...@@ -4594,13 +4594,10 @@ xact_redo_commit_internal(TransactionId xid, XLogRecPtr lsn, ...@@ -4594,13 +4594,10 @@ xact_redo_commit_internal(TransactionId xid, XLogRecPtr lsn,
ForkNumber fork; ForkNumber fork;
for (fork = 0; fork <= MAX_FORKNUM; fork++) for (fork = 0; fork <= MAX_FORKNUM; fork++)
{
if (smgrexists(srel, fork))
{ {
XLogDropRelation(xnodes[i], fork); XLogDropRelation(xnodes[i], fork);
smgrdounlink(srel, fork, true); smgrdounlink(srel, fork, true);
} }
}
smgrclose(srel); smgrclose(srel);
} }
...@@ -4737,13 +4734,10 @@ xact_redo_abort(xl_xact_abort *xlrec, TransactionId xid) ...@@ -4737,13 +4734,10 @@ xact_redo_abort(xl_xact_abort *xlrec, TransactionId xid)
ForkNumber fork; ForkNumber fork;
for (fork = 0; fork <= MAX_FORKNUM; fork++) for (fork = 0; fork <= MAX_FORKNUM; fork++)
{
if (smgrexists(srel, fork))
{ {
XLogDropRelation(xlrec->xnodes[i], fork); XLogDropRelation(xlrec->xnodes[i], fork);
smgrdounlink(srel, fork, true); smgrdounlink(srel, fork, true);
} }
}
smgrclose(srel); smgrclose(srel);
} }
} }
......
...@@ -361,7 +361,6 @@ smgrDoPendingDeletes(bool isCommit) ...@@ -361,7 +361,6 @@ smgrDoPendingDeletes(bool isCommit)
srel = smgropen(pending->relnode, pending->backend); srel = smgropen(pending->relnode, pending->backend);
for (i = 0; i <= MAX_FORKNUM; i++) for (i = 0; i <= MAX_FORKNUM; i++)
{ {
if (smgrexists(srel, i))
smgrdounlink(srel, i, false); smgrdounlink(srel, i, false);
} }
smgrclose(srel); smgrclose(srel);
......
...@@ -323,7 +323,13 @@ mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo) ...@@ -323,7 +323,13 @@ mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
* number until it's safe, because relfilenode assignment skips over any * number until it's safe, because relfilenode assignment skips over any
* existing file. * existing file.
* *
* If isRedo is true, it's okay for the relation to be already gone. * All the above applies only to the relation's main fork; other forks can
* just be removed immediately, since they are not needed to prevent the
* relfilenode number from being recycled. Also, we do not carefully
* track whether other forks have been created or not, but just attempt to
* unlink them unconditionally; so we should never complain about ENOENT.
*
* If isRedo is true, it's unsurprising for the relation to be already gone.
* Also, we should remove the file immediately instead of queuing a request * Also, we should remove the file immediately instead of queuing a request
* for later, since during redo there's no possibility of creating a * for later, since during redo there's no possibility of creating a
* conflicting relation. * conflicting relation.
...@@ -351,14 +357,11 @@ mdunlink(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo) ...@@ -351,14 +357,11 @@ mdunlink(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo)
if (isRedo || forkNum != MAIN_FORKNUM) if (isRedo || forkNum != MAIN_FORKNUM)
{ {
ret = unlink(path); ret = unlink(path);
if (ret < 0) if (ret < 0 && errno != ENOENT)
{
if (!isRedo || errno != ENOENT)
ereport(WARNING, ereport(WARNING,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not remove file \"%s\": %m", path))); errmsg("could not remove file \"%s\": %m", path)));
} }
}
else else
{ {
/* truncate(2) would be easier here, but Windows hasn't got it */ /* truncate(2) would be easier here, but Windows hasn't got it */
...@@ -380,6 +383,9 @@ mdunlink(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo) ...@@ -380,6 +383,9 @@ mdunlink(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo)
ereport(WARNING, ereport(WARNING,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not truncate file \"%s\": %m", path))); errmsg("could not truncate file \"%s\": %m", path)));
/* Register request to unlink first segment later */
register_unlink(rnode);
} }
/* /*
...@@ -411,10 +417,6 @@ mdunlink(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo) ...@@ -411,10 +417,6 @@ mdunlink(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo)
} }
pfree(path); pfree(path);
/* Register request to unlink first segment later */
if (!isRedo && forkNum == MAIN_FORKNUM)
register_unlink(rnode);
} }
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment