@@ -1066,6 +1066,12 @@ vac_truncate_clog(TransactionId frozenXID,
1066
1066
/*
1067
1067
* Scan pg_database to compute the minimum datfrozenxid/datminmxid
1068
1068
*
1069
+ * Since vac_update_datfrozenxid updates datfrozenxid/datminmxid in-place,
1070
+ * the values could change while we look at them. Fetch each one just
1071
+ * once to ensure sane behavior of the comparison logic. (Here, as in
1072
+ * many other places, we assume that fetching or updating an XID in shared
1073
+ * storage is atomic.)
1074
+ *
1069
1075
* Note: we need not worry about a race condition with new entries being
1070
1076
* inserted by CREATE DATABASE. Any such entry will have a copy of some
1071
1077
* existing DB's datfrozenxid, and that source DB cannot be ours because
@@ -1081,10 +1087,12 @@ vac_truncate_clog(TransactionId frozenXID,
1081
1087
1082
1088
while ((tuple = heap_getnext (scan ,ForwardScanDirection ))!= NULL )
1083
1089
{
1084
- Form_pg_database dbform = (Form_pg_database )GETSTRUCT (tuple );
1090
+ volatile FormData_pg_database * dbform = (Form_pg_database )GETSTRUCT (tuple );
1091
+ TransactionId datfrozenxid = dbform -> datfrozenxid ;
1092
+ TransactionId datminmxid = dbform -> datminmxid ;
1085
1093
1086
- Assert (TransactionIdIsNormal (dbform -> datfrozenxid ));
1087
- Assert (MultiXactIdIsValid (dbform -> datminmxid ));
1094
+ Assert (TransactionIdIsNormal (datfrozenxid ));
1095
+ Assert (MultiXactIdIsValid (datminmxid ));
1088
1096
1089
1097
/*
1090
1098
* If things are working properly, no database should have a
@@ -1095,21 +1103,21 @@ vac_truncate_clog(TransactionId frozenXID,
1095
1103
* databases have been scanned and cleaned up. (We will issue the
1096
1104
* "already wrapped" warning if appropriate, though.)
1097
1105
*/
1098
- if (TransactionIdPrecedes (lastSaneFrozenXid ,dbform -> datfrozenxid )||
1099
- MultiXactIdPrecedes (lastSaneMinMulti ,dbform -> datminmxid ))
1106
+ if (TransactionIdPrecedes (lastSaneFrozenXid ,datfrozenxid )||
1107
+ MultiXactIdPrecedes (lastSaneMinMulti ,datminmxid ))
1100
1108
bogus = true;
1101
1109
1102
- if (TransactionIdPrecedes (nextXID ,dbform -> datfrozenxid ))
1110
+ if (TransactionIdPrecedes (nextXID ,datfrozenxid ))
1103
1111
frozenAlreadyWrapped = true;
1104
- else if (TransactionIdPrecedes (dbform -> datfrozenxid ,frozenXID ))
1112
+ else if (TransactionIdPrecedes (datfrozenxid ,frozenXID ))
1105
1113
{
1106
- frozenXID = dbform -> datfrozenxid ;
1114
+ frozenXID = datfrozenxid ;
1107
1115
oldestxid_datoid = HeapTupleGetOid (tuple );
1108
1116
}
1109
1117
1110
- if (MultiXactIdPrecedes (dbform -> datminmxid ,minMulti ))
1118
+ if (MultiXactIdPrecedes (datminmxid ,minMulti ))
1111
1119
{
1112
- minMulti = dbform -> datminmxid ;
1120
+ minMulti = datminmxid ;
1113
1121
minmulti_datoid = HeapTupleGetOid (tuple );
1114
1122
}
1115
1123
}