]> granicus.if.org Git - postgresql/commitdiff
Avoid crashing when we have problems unlinking files post-commit.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 20 Dec 2011 20:00:41 +0000 (15:00 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 20 Dec 2011 20:00:41 +0000 (15:00 -0500)
smgrdounlink takes care to not throw an ERROR if it fails to unlink
something, but that caution was rendered useless by commit
3396000684b41e7e9467d1abc67152b39e697035, 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.

src/backend/access/transam/twophase.c
src/backend/access/transam/xact.c
src/backend/catalog/storage.c
src/backend/storage/smgr/md.c

index 54176ee9df9f8c025f9aefc87b4e7b7b42625d1d..6d496b58044525e525489d8cf0a7bd1afcc54b3f 100644 (file)
@@ -1343,8 +1343,7 @@ FinishPreparedTransaction(const char *gid, bool isCommit)
 
                for (fork = 0; fork <= MAX_FORKNUM; fork++)
                {
-                       if (smgrexists(srel, fork))
-                               smgrdounlink(srel, fork, false);
+                       smgrdounlink(srel, fork, false);
                }
                smgrclose(srel);
        }
index 2ca1c1454993dbb9b7695ad41a96fa6c2932c503..7bdf38636b5ed7c7fbd8d7eb7b85f55d19fa2333 100644 (file)
@@ -4532,11 +4532,8 @@ xact_redo_commit(xl_xact_commit *xlrec, TransactionId xid, XLogRecPtr lsn)
 
                for (fork = 0; fork <= MAX_FORKNUM; fork++)
                {
-                       if (smgrexists(srel, fork))
-                       {
-                               XLogDropRelation(xlrec->xnodes[i], fork);
-                               smgrdounlink(srel, fork, true);
-                       }
+                       XLogDropRelation(xlrec->xnodes[i], fork);
+                       smgrdounlink(srel, fork, true);
                }
                smgrclose(srel);
        }
@@ -4637,11 +4634,8 @@ xact_redo_abort(xl_xact_abort *xlrec, TransactionId xid)
 
                for (fork = 0; fork <= MAX_FORKNUM; fork++)
                {
-                       if (smgrexists(srel, fork))
-                       {
-                               XLogDropRelation(xlrec->xnodes[i], fork);
-                               smgrdounlink(srel, fork, true);
-                       }
+                       XLogDropRelation(xlrec->xnodes[i], fork);
+                       smgrdounlink(srel, fork, true);
                }
                smgrclose(srel);
        }
index 57987be2c0aa922e964ae8c2add3035c092400c2..34d99bfd04ed28bec2b2bfddae110baf001e3a9b 100644 (file)
@@ -360,8 +360,7 @@ smgrDoPendingDeletes(bool isCommit)
                                srel = smgropen(pending->relnode, pending->backend);
                                for (i = 0; i <= MAX_FORKNUM; i++)
                                {
-                                       if (smgrexists(srel, i))
-                                               smgrdounlink(srel, i, false);
+                                       smgrdounlink(srel, i, false);
                                }
                                smgrclose(srel);
                        }
index 7f44606c1a9c6d78ebd022343b65c1969744d0dd..1d86e34aac9fb1add74edfd21f08918bfad4d84d 100644 (file)
@@ -322,7 +322,13 @@ mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
  * number until it's safe, because relfilenode assignment skips over any
  * 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
  * for later, since during redo there's no possibility of creating a
  * conflicting relation.
@@ -350,13 +356,10 @@ mdunlink(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo)
        if (isRedo || forkNum != MAIN_FORKNUM)
        {
                ret = unlink(path);
-               if (ret < 0)
-               {
-                       if (!isRedo || errno != ENOENT)
-                               ereport(WARNING,
-                                               (errcode_for_file_access(),
-                                                errmsg("could not remove file \"%s\": %m", path)));
-               }
+               if (ret < 0 && errno != ENOENT)
+                       ereport(WARNING,
+                                       (errcode_for_file_access(),
+                                        errmsg("could not remove file \"%s\": %m", path)));
        }
        else
        {
@@ -379,6 +382,9 @@ mdunlink(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo)
                        ereport(WARNING,
                                        (errcode_for_file_access(),
                                         errmsg("could not truncate file \"%s\": %m", path)));
+
+               /* Register request to unlink first segment later */
+               register_unlink(rnode);
        }
 
        /*
@@ -410,10 +416,6 @@ mdunlink(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo)
        }
 
        pfree(path);
-
-       /* Register request to unlink first segment later */
-       if (!isRedo && forkNum == MAIN_FORKNUM)
-               register_unlink(rnode);
 }
 
 /*