@@ -1066,6 +1066,12 @@ vac_truncate_clog(TransactionId frozenXID,
10661066 /*
10671067 * Scan pg_database to compute the minimum datfrozenxid/datminmxid
10681068 *
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+ *
10691075 * Note: we need not worry about a race condition with new entries being
10701076 * inserted by CREATE DATABASE. Any such entry will have a copy of some
10711077 * existing DB's datfrozenxid, and that source DB cannot be ours because
@@ -1081,10 +1087,12 @@ vac_truncate_clog(TransactionId frozenXID,
10811087
10821088 while ((tuple = heap_getnext (scan , ForwardScanDirection )) != NULL )
10831089 {
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 ;
10851093
1086- Assert (TransactionIdIsNormal (dbform -> datfrozenxid ));
1087- Assert (MultiXactIdIsValid (dbform -> datminmxid ));
1094+ Assert (TransactionIdIsNormal (datfrozenxid ));
1095+ Assert (MultiXactIdIsValid (datminmxid ));
10881096
10891097 /*
10901098 * If things are working properly, no database should have a
@@ -1095,21 +1103,21 @@ vac_truncate_clog(TransactionId frozenXID,
10951103 * databases have been scanned and cleaned up. (We will issue the
10961104 * "already wrapped" warning if appropriate, though.)
10971105 */
1098- if (TransactionIdPrecedes (lastSaneFrozenXid , dbform -> datfrozenxid ) ||
1099- MultiXactIdPrecedes (lastSaneMinMulti , dbform -> datminmxid ))
1106+ if (TransactionIdPrecedes (lastSaneFrozenXid , datfrozenxid ) ||
1107+ MultiXactIdPrecedes (lastSaneMinMulti , datminmxid ))
11001108 bogus = true;
11011109
1102- if (TransactionIdPrecedes (nextXID , dbform -> datfrozenxid ))
1110+ if (TransactionIdPrecedes (nextXID , datfrozenxid ))
11031111 frozenAlreadyWrapped = true;
1104- else if (TransactionIdPrecedes (dbform -> datfrozenxid , frozenXID ))
1112+ else if (TransactionIdPrecedes (datfrozenxid , frozenXID ))
11051113 {
1106- frozenXID = dbform -> datfrozenxid ;
1114+ frozenXID = datfrozenxid ;
11071115 oldestxid_datoid = HeapTupleGetOid (tuple );
11081116 }
11091117
1110- if (MultiXactIdPrecedes (dbform -> datminmxid , minMulti ))
1118+ if (MultiXactIdPrecedes (datminmxid , minMulti ))
11111119 {
1112- minMulti = dbform -> datminmxid ;
1120+ minMulti = datminmxid ;
11131121 minmulti_datoid = HeapTupleGetOid (tuple );
11141122 }
11151123 }
0 commit comments