@@ -1018,6 +1018,12 @@ vac_truncate_clog(TransactionId frozenXID,
1018
1018
/*
1019
1019
* Scan pg_database to compute the minimum datfrozenxid/datminmxid
1020
1020
*
1021
+ * Since vac_update_datfrozenxid updates datfrozenxid/datminmxid in-place,
1022
+ * the values could change while we look at them. Fetch each one just
1023
+ * once to ensure sane behavior of the comparison logic. (Here, as in
1024
+ * many other places, we assume that fetching or updating an XID in shared
1025
+ * storage is atomic.)
1026
+ *
1021
1027
* Note: we need not worry about a race condition with new entries being
1022
1028
* inserted by CREATE DATABASE. Any such entry will have a copy of some
1023
1029
* existing DB's datfrozenxid, and that source DB cannot be ours because
@@ -1033,10 +1039,12 @@ vac_truncate_clog(TransactionId frozenXID,
1033
1039
1034
1040
while ((tuple = heap_getnext (scan ,ForwardScanDirection ))!= NULL )
1035
1041
{
1036
- Form_pg_database dbform = (Form_pg_database )GETSTRUCT (tuple );
1042
+ volatile FormData_pg_database * dbform = (Form_pg_database )GETSTRUCT (tuple );
1043
+ TransactionId datfrozenxid = dbform -> datfrozenxid ;
1044
+ TransactionId datminmxid = dbform -> datminmxid ;
1037
1045
1038
- Assert (TransactionIdIsNormal (dbform -> datfrozenxid ));
1039
- Assert (MultiXactIdIsValid (dbform -> datminmxid ));
1046
+ Assert (TransactionIdIsNormal (datfrozenxid ));
1047
+ Assert (MultiXactIdIsValid (datminmxid ));
1040
1048
1041
1049
/*
1042
1050
* If things are working properly, no database should have a
@@ -1047,21 +1055,21 @@ vac_truncate_clog(TransactionId frozenXID,
1047
1055
* databases have been scanned and cleaned up. (We will issue the
1048
1056
* "already wrapped" warning if appropriate, though.)
1049
1057
*/
1050
- if (TransactionIdPrecedes (lastSaneFrozenXid ,dbform -> datfrozenxid )||
1051
- MultiXactIdPrecedes (lastSaneMinMulti ,dbform -> datminmxid ))
1058
+ if (TransactionIdPrecedes (lastSaneFrozenXid ,datfrozenxid )||
1059
+ MultiXactIdPrecedes (lastSaneMinMulti ,datminmxid ))
1052
1060
bogus = true;
1053
1061
1054
- if (TransactionIdPrecedes (nextXID ,dbform -> datfrozenxid ))
1062
+ if (TransactionIdPrecedes (nextXID ,datfrozenxid ))
1055
1063
frozenAlreadyWrapped = true;
1056
- else if (TransactionIdPrecedes (dbform -> datfrozenxid ,frozenXID ))
1064
+ else if (TransactionIdPrecedes (datfrozenxid ,frozenXID ))
1057
1065
{
1058
- frozenXID = dbform -> datfrozenxid ;
1066
+ frozenXID = datfrozenxid ;
1059
1067
oldestxid_datoid = HeapTupleGetOid (tuple );
1060
1068
}
1061
1069
1062
- if (MultiXactIdPrecedes (dbform -> datminmxid ,minMulti ))
1070
+ if (MultiXactIdPrecedes (datminmxid ,minMulti ))
1063
1071
{
1064
- minMulti = dbform -> datminmxid ;
1072
+ minMulti = datminmxid ;
1065
1073
minmulti_datoid = HeapTupleGetOid (tuple );
1066
1074
}
1067
1075
}