@@ -66,7 +66,10 @@ static BufferAccessStrategy vac_strategy;
66
66
67
67
/* non-export function prototypes */
68
68
static List * get_rel_oids (Oid relid , const RangeVar * vacrel );
69
- static void vac_truncate_clog (TransactionId frozenXID , MultiXactId minMulti );
69
+ static void vac_truncate_clog (TransactionId frozenXID ,
70
+ MultiXactId minMulti ,
71
+ TransactionId lastSaneFrozenXid ,
72
+ MultiXactId lastSaneMinMulti );
70
73
static bool vacuum_rel (Oid relid , VacuumStmt * vacstmt , bool do_toast ,
71
74
bool for_wraparound );
72
75
@@ -733,19 +736,33 @@ vac_update_relstats(Relation relation,
733
736
}
734
737
735
738
/*
736
- * relfrozenxid should never go backward. Caller can pass
737
- * InvalidTransactionId if it has no new data.
739
+ * Update relfrozenxid, unless caller passed InvalidTransactionId
740
+ * indicating it has no new data.
741
+ *
742
+ * Ordinarily, we don't let relfrozenxid go backwards: if things are
743
+ * working correctly, the only way the new frozenxid could be older would
744
+ * be if a previous VACUUM was done with a tighter freeze_min_age, in
745
+ * which case we don't want to forget the work it already did. However,
746
+ * if the stored relfrozenxid is "in the future", then it must be corrupt
747
+ * and it seems best to overwrite it with the cutoff we used this time.
748
+ * See vac_update_datfrozenxid() concerning what we consider to be "in the
749
+ * future".
738
750
*/
739
751
if (TransactionIdIsNormal (frozenxid ) &&
740
- TransactionIdPrecedes (pgcform -> relfrozenxid , frozenxid ))
752
+ pgcform -> relfrozenxid != frozenxid &&
753
+ (TransactionIdPrecedes (pgcform -> relfrozenxid , frozenxid ) ||
754
+ TransactionIdPrecedes (GetOldestXmin (NULL , true),
755
+ pgcform -> relfrozenxid )))
741
756
{
742
757
pgcform -> relfrozenxid = frozenxid ;
743
758
dirty = true;
744
759
}
745
760
746
- /* relminmxid must never go backward, either */
761
+ /* Similarly for relminmxid */
747
762
if (MultiXactIdIsValid (minmulti ) &&
748
- MultiXactIdPrecedes (pgcform -> relminmxid , minmulti ))
763
+ pgcform -> relminmxid != minmulti &&
764
+ (MultiXactIdPrecedes (pgcform -> relminmxid , minmulti ) ||
765
+ MultiXactIdPrecedes (GetOldestMultiXactId (), pgcform -> relminmxid )))
749
766
{
750
767
pgcform -> relminmxid = minmulti ;
751
768
dirty = true;
@@ -772,8 +789,8 @@ vac_update_relstats(Relation relation,
772
789
* truncate pg_clog and pg_multixact.
773
790
*
774
791
* We violate transaction semantics here by overwriting the database's
775
- * existing pg_database tuple with the new value . This is reasonably
776
- * safe since the new value is correct whether or not this transaction
792
+ * existing pg_database tuple with the new values . This is reasonably
793
+ * safe since the new values are correct whether or not this transaction
777
794
* commits. As with vac_update_relstats, this avoids leaving dead tuples
778
795
* behind after a VACUUM.
779
796
*/
@@ -786,7 +803,10 @@ vac_update_datfrozenxid(void)
786
803
SysScanDesc scan ;
787
804
HeapTuple classTup ;
788
805
TransactionId newFrozenXid ;
806
+ TransactionId lastSaneFrozenXid ;
789
807
MultiXactId newMinMulti ;
808
+ MultiXactId lastSaneMinMulti ;
809
+ bool bogus = false;
790
810
bool dirty = false;
791
811
792
812
/*
@@ -795,13 +815,13 @@ vac_update_datfrozenxid(void)
795
815
* committed pg_class entries for new tables; see AddNewRelationTuple().
796
816
* So we cannot produce a wrong minimum by starting with this.
797
817
*/
798
- newFrozenXid = GetOldestXmin (NULL , true);
818
+ newFrozenXid = lastSaneFrozenXid = GetOldestXmin (NULL , true);
799
819
800
820
/*
801
821
* Similarly, initialize the MultiXact "min" with the value that would be
802
822
* used on pg_class for new tables. See AddNewRelationTuple().
803
823
*/
804
- newMinMulti = GetOldestMultiXactId ();
824
+ newMinMulti = lastSaneMinMulti = GetOldestMultiXactId ();
805
825
806
826
/*
807
827
* We must seqscan pg_class to find the minimum Xid, because there is no
@@ -828,6 +848,21 @@ vac_update_datfrozenxid(void)
828
848
Assert (TransactionIdIsNormal (classForm -> relfrozenxid ));
829
849
Assert (MultiXactIdIsValid (classForm -> relminmxid ));
830
850
851
+ /*
852
+ * If things are working properly, no relation should have a
853
+ * relfrozenxid or relminmxid that is "in the future". However, such
854
+ * cases have been known to arise due to bugs in pg_upgrade. If we
855
+ * see any entries that are "in the future", chicken out and don't do
856
+ * anything. This ensures we won't truncate clog before those
857
+ * relations have been scanned and cleaned up.
858
+ */
859
+ if (TransactionIdPrecedes (lastSaneFrozenXid , classForm -> relfrozenxid ) ||
860
+ MultiXactIdPrecedes (lastSaneMinMulti , classForm -> relminmxid ))
861
+ {
862
+ bogus = true;
863
+ break ;
864
+ }
865
+
831
866
if (TransactionIdPrecedes (classForm -> relfrozenxid , newFrozenXid ))
832
867
newFrozenXid = classForm -> relfrozenxid ;
833
868
@@ -839,6 +874,10 @@ vac_update_datfrozenxid(void)
839
874
systable_endscan (scan );
840
875
heap_close (relation , AccessShareLock );
841
876
877
+ /* chicken out if bogus data found */
878
+ if (bogus )
879
+ return ;
880
+
842
881
Assert (TransactionIdIsNormal (newFrozenXid ));
843
882
Assert (MultiXactIdIsValid (newMinMulti ));
844
883
@@ -852,21 +891,30 @@ vac_update_datfrozenxid(void)
852
891
dbform = (Form_pg_database ) GETSTRUCT (tuple );
853
892
854
893
/*
855
- * Don't allow datfrozenxid to go backward (probably can't happen anyway);
856
- * and detect the common case where it doesn't go forward either.
894
+ * As in vac_update_relstats(), we ordinarily don't want to let
895
+ * datfrozenxid go backward; but if it's "in the future" then it must be
896
+ * corrupt and it seems best to overwrite it.
857
897
*/
858
- if (TransactionIdPrecedes (dbform -> datfrozenxid , newFrozenXid ))
898
+ if (dbform -> datfrozenxid != newFrozenXid &&
899
+ (TransactionIdPrecedes (dbform -> datfrozenxid , newFrozenXid ) ||
900
+ TransactionIdPrecedes (lastSaneFrozenXid , dbform -> datfrozenxid )))
859
901
{
860
902
dbform -> datfrozenxid = newFrozenXid ;
861
903
dirty = true;
862
904
}
905
+ else
906
+ newFrozenXid = dbform -> datfrozenxid ;
863
907
864
- /* ditto */
865
- if (MultiXactIdPrecedes (dbform -> datminmxid , newMinMulti ))
908
+ /* Ditto for datminmxid */
909
+ if (dbform -> datminmxid != newMinMulti &&
910
+ (MultiXactIdPrecedes (dbform -> datminmxid , newMinMulti ) ||
911
+ MultiXactIdPrecedes (lastSaneMinMulti , dbform -> datminmxid )))
866
912
{
867
913
dbform -> datminmxid = newMinMulti ;
868
914
dirty = true;
869
915
}
916
+ else
917
+ newMinMulti = dbform -> datminmxid ;
870
918
871
919
if (dirty )
872
920
heap_inplace_update (relation , tuple );
@@ -875,12 +923,13 @@ vac_update_datfrozenxid(void)
875
923
heap_close (relation , RowExclusiveLock );
876
924
877
925
/*
878
- * If we were able to advance datfrozenxid, see if we can truncate
879
- * pg_clog. Also do it if the shared XID-wrap-limit info is stale, since
880
- * this action will update that too.
926
+ * If we were able to advance datfrozenxid or datminmxid , see if we can
927
+ * truncate pg_clog and/or pg_multixact. Also do it if the shared
928
+ * XID-wrap-limit info is stale, since this action will update that too.
881
929
*/
882
930
if (dirty || ForceTransactionIdLimitUpdate ())
883
- vac_truncate_clog (newFrozenXid , newMinMulti );
931
+ vac_truncate_clog (newFrozenXid , newMinMulti ,
932
+ lastSaneFrozenXid , lastSaneMinMulti );
884
933
}
885
934
886
935
@@ -890,31 +939,38 @@ vac_update_datfrozenxid(void)
890
939
* Scan pg_database to determine the system-wide oldest datfrozenxid,
891
940
* and use it to truncate the transaction commit log (pg_clog).
892
941
* Also update the XID wrap limit info maintained by varsup.c.
942
+ * Likewise for datminmxid.
893
943
*
894
- * The passed XID is simply the one I just wrote into my pg_database
895
- * entry. It's used to initialize the "min" calculation.
944
+ * The passed frozenXID and minMulti are the updated values for my own
945
+ * pg_database entry. They're used to initialize the "min" calculations.
946
+ * The caller also passes the "last sane" XID and MXID, since it has
947
+ * those at hand already.
896
948
*
897
949
* This routine is only invoked when we've managed to change our
898
- * DB's datfrozenxid entry , or we found that the shared XID-wrap-limit
899
- * info is stale.
950
+ * DB's datfrozenxid/datminmxid values , or we found that the shared
951
+ * XID-wrap-limit info is stale.
900
952
*/
901
953
static void
902
- vac_truncate_clog (TransactionId frozenXID , MultiXactId minMulti )
954
+ vac_truncate_clog (TransactionId frozenXID ,
955
+ MultiXactId minMulti ,
956
+ TransactionId lastSaneFrozenXid ,
957
+ MultiXactId lastSaneMinMulti )
903
958
{
904
959
TransactionId myXID = GetCurrentTransactionId ();
905
960
Relation relation ;
906
961
HeapScanDesc scan ;
907
962
HeapTuple tuple ;
908
963
Oid oldestxid_datoid ;
909
964
Oid minmulti_datoid ;
965
+ bool bogus = false;
910
966
bool frozenAlreadyWrapped = false;
911
967
912
- /* init oldest datoids to sync with my frozen values */
968
+ /* init oldest datoids to sync with my frozenXID/minMulti values */
913
969
oldestxid_datoid = MyDatabaseId ;
914
970
minmulti_datoid = MyDatabaseId ;
915
971
916
972
/*
917
- * Scan pg_database to compute the minimum datfrozenxid
973
+ * Scan pg_database to compute the minimum datfrozenxid/datminmxid
918
974
*
919
975
* Note: we need not worry about a race condition with new entries being
920
976
* inserted by CREATE DATABASE. Any such entry will have a copy of some
@@ -936,6 +992,19 @@ vac_truncate_clog(TransactionId frozenXID, MultiXactId minMulti)
936
992
Assert (TransactionIdIsNormal (dbform -> datfrozenxid ));
937
993
Assert (MultiXactIdIsValid (dbform -> datminmxid ));
938
994
995
+ /*
996
+ * If things are working properly, no database should have a
997
+ * datfrozenxid or datminmxid that is "in the future". However, such
998
+ * cases have been known to arise due to bugs in pg_upgrade. If we
999
+ * see any entries that are "in the future", chicken out and don't do
1000
+ * anything. This ensures we won't truncate clog before those
1001
+ * databases have been scanned and cleaned up. (We will issue the
1002
+ * "already wrapped" warning if appropriate, though.)
1003
+ */
1004
+ if (TransactionIdPrecedes (lastSaneFrozenXid , dbform -> datfrozenxid ) ||
1005
+ MultiXactIdPrecedes (lastSaneMinMulti , dbform -> datminmxid ))
1006
+ bogus = true;
1007
+
939
1008
if (TransactionIdPrecedes (myXID , dbform -> datfrozenxid ))
940
1009
frozenAlreadyWrapped = true;
941
1010
else if (TransactionIdPrecedes (dbform -> datfrozenxid , frozenXID ))
@@ -969,6 +1038,10 @@ vac_truncate_clog(TransactionId frozenXID, MultiXactId minMulti)
969
1038
return ;
970
1039
}
971
1040
1041
+ /* chicken out if data is bogus in any other way */
1042
+ if (bogus )
1043
+ return ;
1044
+
972
1045
/*
973
1046
* Truncate CLOG to the oldest computed value. Note we don't truncate
974
1047
* multixacts; that will be done by the next checkpoint.
0 commit comments