]> granicus.if.org Git - postgresql/commitdiff
Fix CLOG truncation code to not do the Wrong Thing when there are already
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 2 Apr 2002 05:11:55 +0000 (05:11 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 2 Apr 2002 05:11:55 +0000 (05:11 +0000)
wrapped-around databases.  The unvacuumed databases might be fine, or
they might not, but things will definitely not be fine if we remove the
wrong CLOG segments.  Per trouble report from Gary Wolfe, 1-Apr-2002.

src/backend/commands/vacuum.c

index fff0320eca2a17a48182239bdb0c12bc5b4330c9..ed3effab65190bc9eacc60e88c4fa517c054a523 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.221 2002/04/02 01:03:05 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.222 2002/04/02 05:11:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -557,10 +557,15 @@ vac_update_dbstats(Oid dbid,
 static void
 vac_truncate_clog(TransactionId vacuumXID, TransactionId frozenXID)
 {
+       TransactionId myXID;
        Relation        relation;
        HeapScanDesc scan;
        HeapTuple       tuple;
        int32           age;
+       bool            vacuumAlreadyWrapped = false;
+       bool            frozenAlreadyWrapped = false;
+
+       myXID = GetCurrentTransactionId();
 
        relation = heap_openr(DatabaseRelationName, AccessShareLock);
 
@@ -575,28 +580,55 @@ vac_truncate_clog(TransactionId vacuumXID, TransactionId frozenXID)
                if (!dbform->datallowconn)
                        continue;
 
-               if (TransactionIdIsNormal(dbform->datvacuumxid) &&
-                       TransactionIdPrecedes(dbform->datvacuumxid, vacuumXID))
-                       vacuumXID = dbform->datvacuumxid;
-               if (TransactionIdIsNormal(dbform->datfrozenxid) &&
-                       TransactionIdPrecedes(dbform->datfrozenxid, frozenXID))
-                       frozenXID = dbform->datfrozenxid;
+               if (TransactionIdIsNormal(dbform->datvacuumxid))
+               {
+                       if (TransactionIdPrecedes(myXID, dbform->datvacuumxid))
+                               vacuumAlreadyWrapped = true;
+                       else if (TransactionIdPrecedes(dbform->datvacuumxid, vacuumXID))
+                               vacuumXID = dbform->datvacuumxid;
+               }
+               if (TransactionIdIsNormal(dbform->datfrozenxid))
+               {
+                       if (TransactionIdPrecedes(myXID, dbform->datfrozenxid))
+                               frozenAlreadyWrapped = true;
+                       else if (TransactionIdPrecedes(dbform->datfrozenxid, frozenXID))
+                               frozenXID = dbform->datfrozenxid;
+               }
        }
 
        heap_endscan(scan);
 
        heap_close(relation, AccessShareLock);
 
+       /*
+        * Do not truncate CLOG if we seem to have suffered wraparound already;
+        * the computed minimum XID might be bogus.
+        */
+       if (vacuumAlreadyWrapped)
+       {
+               elog(WARNING, "Some databases have not been vacuumed in over 2 billion transactions."
+                        "\n\tYou may have already suffered transaction-wraparound data loss.");
+               return;
+       }
+
        /* Truncate CLOG to the oldest vacuumxid */
        TruncateCLOG(vacuumXID);
 
        /* Give warning about impending wraparound problems */
-       age = (int32) (GetCurrentTransactionId() - frozenXID);
-       if (age > (int32) ((MaxTransactionId >> 3) * 3))
-               elog(WARNING, "Some databases have not been vacuumed in %d transactions."
-                        "\n\tBetter vacuum them within %d transactions,"
-                        "\n\tor you may have a wraparound failure.",
-                        age, (int32) (MaxTransactionId >> 1) - age);
+       if (frozenAlreadyWrapped)
+       {
+               elog(WARNING, "Some databases have not been vacuumed in over 1 billion transactions."
+                        "\n\tBetter vacuum them soon, or you may have a wraparound failure.");
+       }
+       else
+       {
+               age = (int32) (myXID - frozenXID);
+               if (age > (int32) ((MaxTransactionId >> 3) * 3))
+                       elog(WARNING, "Some databases have not been vacuumed in %d transactions."
+                                "\n\tBetter vacuum them within %d transactions,"
+                                "\n\tor you may have a wraparound failure.",
+                                age, (int32) (MaxTransactionId >> 1) - age);
+       }
 }